Sign in to follow this  
SyncViews

D3D11 Fullscreen Not Sticking

Recommended Posts

SyncViews    734

I am trying to add fullscreen to a D3D11 program I have (not just a borderless window). It seems to attempt to go fullscreen with the monitor going black for a moment but fail and revert to a window. I can't see what would cause this, and it happens if I use DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH and attempt to go fullscreen with Alt+Enter as well. VS debug output shows no complaining from the device.

 

The window is created with "WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU", and I have validated that the backbuffer and depth buffer get my native monitor resolution of 1920x1080. The device is created with "D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_DEBUG"

 

Given that I do not expierence this with any games or other software on my system, I am fairly sure its my code doing something wrong here.

 

Complete working code is below, should compile directly with MSVC (tested on 2013). I striped just the window and D3D creation out (including error handling and cleanup), although its still fairly long.

 
#include <Windows.h>
#include <dxgi.h>
#include <d3d11.h>
#include <stdexcept>
#include <string>

#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "DXGI.lib")

HWND hwnd = NULL;
bool run = true;
ID3D11Device *d3d11Device;
ID3D11DeviceContext *d3d11Context;
IDXGISwapChain *d3dSwapChain;
ID3D11Texture2D *d3d11BackBuffer;
ID3D11RenderTargetView *d3d11BackBufferTarget;
ID3D11DepthStencilView *d3d11DepthStencilView;

enum WindowMode
{
    WINDOW_WINDOWED,
    WINDOW_BORDERLESS,
    WINDOW_FULLSCREEN
};


void createWindow(unsigned width, unsigned height, WindowMode mode);
void createD3d11(unsigned width, unsigned height, WindowMode mode);
LRESULT __stdcall wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    
    WindowMode mode = WINDOW_FULLSCREEN;

    createWindow(1920, 1080, mode);

    RECT rect;
    if (mode == WINDOW_WINDOWED)
        GetClientRect(hwnd, &rect);
    else GetWindowRect(hwnd, &rect);
    createD3d11(rect.right - rect.left, rect.bottom - rect.top, mode);

    //loop
    while (run)
    {
        MSG msg;
        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        d3d11Context->ClearDepthStencilView(d3d11DepthStencilView, D3D11_CLEAR_DEPTH, 1, 0);
        float col[4] = { 0, 0, 1, 1 };
        d3d11Context->ClearRenderTargetView(d3d11BackBufferTarget, col);
        d3dSwapChain->Present(1, 0);
        Sleep(1000 / 30);
    }
    //exit
    return 0;
}


void createWindow(unsigned width, unsigned height, WindowMode mode)
{
    int style;
    if (mode == WINDOW_BORDERLESS)
        style = WS_POPUP;
    else style = WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;

    //Need a window class
    WNDCLASSEX cls = { 0 };
    cls.cbSize = sizeof(cls);
    cls.style = /*CS_DBLCLKS |*/ CS_OWNDC;
    cls.lpfnWndProc = &wndProc;
    cls.cbClsExtra = 0;
    cls.cbWndExtra = 0;
    cls.hInstance = NULL;
    cls.hIcon = NULL;
    cls.hCursor = LoadCursor(NULL, IDC_ARROW);
    cls.hbrBackground = 0; //(HBRUSH)(COLOR_WINDOW+1);
    cls.lpszMenuName = NULL;
    cls.lpszClassName = L"window";
    cls.hIconSm = NULL;

    RegisterClassEx(&cls);
    //Create the window
    DWORD styleEx = 0;
    hwnd = CreateWindowEx(styleEx, L"window", L"Test Window",
        style,
        CW_USEDEFAULT, CW_USEDEFAULT,
        width, height,
        NULL, NULL, NULL, NULL);
    ShowWindow(hwnd, SW_SHOW);
}

LRESULT __stdcall wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_CLOSE:
        run = false;
        return 0;
    default:
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
}


void createD3d11(unsigned width, unsigned height, WindowMode mode)
{
    IDXGIFactory1 *dxgiFactory = NULL;
    UINT flags = D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_DEBUG;

    D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0 };
    unsigned featureLevelsLen = (unsigned)(sizeof(featureLevels) / sizeof(featureLevels[0]));
    D3D_FEATURE_LEVEL featureLevel;

    CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&dxgiFactory);
    D3D11CreateDevice(
        NULL,
        D3D_DRIVER_TYPE_HARDWARE,
        NULL,
        flags,
        featureLevels,
        featureLevelsLen,
        D3D11_SDK_VERSION,//7
        &d3d11Device,
        &featureLevel,
        &d3d11Context);

    //Swap chain
    DXGI_SAMPLE_DESC renderTargetSampleDesc;
    renderTargetSampleDesc.Count = 4;
    renderTargetSampleDesc.Quality = D3D11_STANDARD_MULTISAMPLE_PATTERN;

    DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 };
    swapChainDesc.BufferCount = 1;
    swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    //TODO: This needs to be either user defined or taken from the monitor
    swapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
    swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
    swapChainDesc.BufferDesc.Width = width;
    swapChainDesc.BufferDesc.Height = height;
    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapChainDesc.OutputWindow = hwnd;
    swapChainDesc.SampleDesc = renderTargetSampleDesc;
    swapChainDesc.Windowed = mode != WINDOW_FULLSCREEN;
    swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
    swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;

    dxgiFactory->CreateSwapChain(d3d11Device, &swapChainDesc, &d3dSwapChain);
    //Depth stencil
    ID3D11Texture2D *d3d11DepthStencilTexture = NULL;
    D3D11_TEXTURE2D_DESC depthStencilTextureDesc;
    memset(&depthStencilTextureDesc, 0, sizeof(depthStencilTextureDesc));
    depthStencilTextureDesc.Width = width;
    depthStencilTextureDesc.Height = height;
    depthStencilTextureDesc.MipLevels = 1;
    depthStencilTextureDesc.ArraySize = 1;
    depthStencilTextureDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
    depthStencilTextureDesc.SampleDesc = renderTargetSampleDesc;
    depthStencilTextureDesc.Usage = D3D11_USAGE_DEFAULT;
    depthStencilTextureDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
    depthStencilTextureDesc.CPUAccessFlags = 0;
    depthStencilTextureDesc.MiscFlags = 0;
    d3d11Device->CreateTexture2D(&depthStencilTextureDesc, NULL, &d3d11DepthStencilTexture);

    D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc;
    memset(&depthStencilViewDesc, 0, sizeof(depthStencilViewDesc));
    depthStencilViewDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
    depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
    depthStencilViewDesc.Texture2D.MipSlice = 0;
    d3d11Device->CreateDepthStencilView(d3d11DepthStencilTexture, &depthStencilViewDesc, &d3d11DepthStencilView);


    //render target
    d3dSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&d3d11BackBuffer);
    d3d11Device->CreateRenderTargetView(d3d11BackBuffer, NULL, &d3d11BackBufferTarget);

    dxgiFactory->Release();


    d3d11Context->OMSetRenderTargets(1, &d3d11BackBufferTarget, d3d11DepthStencilView);
    //viewport
    D3D11_VIEWPORT viewport;
    viewport.TopLeftX = 0;
    viewport.TopLeftY = 0;
    viewport.Width = (float)width;
    viewport.Height = (float)height;
    viewport.MinDepth = 0;
    viewport.MaxDepth = 1;
    d3d11Context->RSSetViewports(1, &viewport);
}

Edited by SyncViews

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this