Hey guys,
I've been trying to get fullscreen working for at least over 2 days now and the documentation does not mention all the annoying corner-cases. For example when I try to switch to fullscreen manually, I call IDXGISwapChain::ResizeTarget (with a valid mode!) and then IDXGISwapChain::SetFullscreenState. MSDN says that this is the correct way, beacause WM_SIZE will be sent which resizes the backbuffer. This seems to work for some modes, but not for all of them. For 1280x720 this works but with 800x600 I get that DXGI performance warning. Another weird corner-case is when the window has the size of a valid mode, like 1280x720, and you then switch to fullscreen via Alt+Enter. This works correctly the first time, but if you repeat this it gives you the performance warning again ...
I attached a minimalistic program, which replicates the Alt+Enter issue. Please somebody tell me what is going wrong here, I'm going crazy.
PS: I read all relevant threads here on the forum about this topic, but I can't find a solution.
#ifndef UNICODE
#define UNICODE
#endif
#include <Windows.h>
#include <d3d11.h>
#include <sstream>
#pragma comment(lib, "d3d11.lib")
namespace
{
bool isRunning = true;
HWND window = nullptr;
ID3D11Device* device = nullptr;
ID3D11DeviceContext* context = nullptr;
IDXGISwapChain* swapChain = nullptr;
ID3D11RenderTargetView* renderTargetView = nullptr;
}
void CreateBufferViews()
{
ID3D11Texture2D* backBuffer;
swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer));
device->CreateRenderTargetView(backBuffer, nullptr, &renderTargetView);
backBuffer->Release();
}
void ResizeBuffers()
{
context->ClearState();
context->Flush();
if (renderTargetView)
{
renderTargetView->Release();
renderTargetView = nullptr;
}
swapChain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH);
CreateBufferViews();
}
LRESULT CALLBACK WindowCallback(HWND window, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CLOSE:
DestroyWindow(window);
break;
case WM_DESTROY:
isRunning = false;
break;
case WM_SIZE:
{
if (wParam != SIZE_MINIMIZED && swapChain)
{
ResizeBuffers();
}
break;
}
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
{
if (wParam == VK_ESCAPE)
{
isRunning = false;
}
break;
}
default:
return DefWindowProcW(window, message, wParam, lParam);
}
return 0;
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR, int cmdShow)
{
WNDCLASSW windowClass{ };
windowClass.hCursor = LoadCursorW(nullptr, IDC_ARROW);
windowClass.hIcon = LoadIconW(nullptr, IDI_APPLICATION);
windowClass.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
windowClass.hInstance = hInstance;
windowClass.lpfnWndProc = &WindowCallback;
windowClass.lpszClassName = L"SandboxWindowClass";
windowClass.style = CS_HREDRAW | CS_VREDRAW;
RegisterClassW(&windowClass);
window = CreateWindowW(L"SandboxWindowClass", L"Sandbox",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
1280, 720, nullptr, nullptr, hInstance, nullptr);
ShowWindow(window, cmdShow);
D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_DEBUG,
nullptr, 0, D3D11_SDK_VERSION, &device, nullptr, &context);
IDXGIDevice1* dxgiDevice;
device->QueryInterface(IID_PPV_ARGS(&dxgiDevice));
IDXGIAdapter1* adapter;
dxgiDevice->GetParent(IID_PPV_ARGS(&adapter));
IDXGIFactory1* factory;
adapter->GetParent(IID_PPV_ARGS(&factory));
RECT clientRect;
GetClientRect(window, &clientRect);
DXGI_SWAP_CHAIN_DESC swapChainDesc{ };
swapChainDesc.BufferCount = 1;
swapChainDesc.BufferDesc.Width = clientRect.right;
swapChainDesc.BufferDesc.Height = clientRect.bottom;
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
swapChainDesc.OutputWindow = window;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapChainDesc.Windowed = true;
factory->CreateSwapChain(device, &swapChainDesc, &swapChain);
factory->MakeWindowAssociation(window, 0);
factory->Release();
adapter->Release();
dxgiDevice->Release();
CreateBufferViews();
MSG message;
while (isRunning)
{
if (PeekMessageW(&message, nullptr, 0, 0, PM_REMOVE))
{
TranslateMessage(&message);
DispatchMessageW(&message);
}
else
{
static const float color[] = { 1, 0, 1, 1 };
context->ClearRenderTargetView(renderTargetView, color);
context->OMSetRenderTargets(1, &renderTargetView, nullptr);
swapChain->Present(1, 0);
}
}
swapChain->SetFullscreenState(false, nullptr);
context->ClearState();
context->Flush();
renderTargetView->Release();
swapChain->Release();
context->Release();
device->Release();
UnregisterClassW(L"SandboxWindowClass", hInstance);
return 0;
}