I followed this tutorial and things were looking good. However, when switching to Fullscreen from 800x600 using alt-enter, I noticed an error in debug output:
DXGI WARNING: IDXGISwapChain::Present: Fullscreen presentation inefficiencies incurred due to application not using IDXGISwapChain::ResizeBuffers appropriately, specifying a DXGI_MODE_DESC not available in IDXGIOutput::GetDisplayModeList, or not using DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH
So I followed MSDN's article about DXGI and fullscreen. I noticed a few things:
Implementing the MSDN article's code as is did not remove the error.
WM_SIZE
was being called in the function ran through with no errors thrown.Reading more, I added a section at the end (after viewport) to include
swapChain->ResizeTarget
. This didn't help.Normally, my
swapChainDesc.flags
is set to 0. I tried setting it toDXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH
as the error suggests, but thenWM_SIZE
is never sent to my application (with alt-enter), so the function to resizebuffers is never called.Implementing the MSDN code also caused switching to fullscreen to throw off my depth buffer(...I think). What happens is all models are drawn regardless of whether or not they are behind another model. Upon switching back to windowed mode via alt-enter, this behavior remains.
I've spent around 20 hours over the course of the week trying to figure out this fullscreen transition to no avail. I realize I could just run the Initialize()
function for the D3D class of Rastertek's and toggle the fullscreen
value, but that seems inefficient.
My code (I tried condensing it by removing error handling):
bool D3D::Initialize(int screenWidth, int screenHeight, bool vsync, HWND hWnd, bool fullscreen, float screenDepth, float screenNear)
{
HRESULT result;
IDXGIFactory* factory;
IDXGIAdapter* adapter;
IDXGIOutput* adapterOutput;
unsigned int numerator, denominator;
int error;
DXGI_SWAP_CHAIN_DESC swapChainDesc;
D3D_FEATURE_LEVEL featureLevel;
ID3D11Texture2D* backBufferPtr;
D3D11_TEXTURE2D_DESC depthBufferDesc;
D3D11_DEPTH_STENCIL_DESC depthStencilDesc;
D3D11_DEPTH_STENCIL_DESC depthDisabledStencilDesc;
D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc;
D3D11_RASTERIZER_DESC rasterDesc;
D3D11_VIEWPORT viewport;
float fieldOfView, screenAspect;
D3D11_BLEND_DESC blendStateDesc;
// Enumerate Display Modes and choose appropriate Refresh Rate
CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory);
factory->EnumAdapters(0, &adapter);
adapter->EnumOutputs(0, &adapterOutput);
adapterOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &numModes, NULL);
displayModeList = new DXGI_MODE_DESC[numModes];
adapterOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &numModes, displayModeList);
// Iterate through Display Modes. displayModeList is a member variable for later use.
GetRefreshRate(screenWidth, screenHeight, numerator, denominator);
adapterOutput->Release();
adapterOutput = 0;
adapter->Release();
adapter = 0;
factory->Release();
factory = 0;
// Swap Chain Description
ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));
swapChainDesc.BufferCount = 1;
swapChainDesc.BufferDesc.Width = screenWidth;
swapChainDesc.BufferDesc.Height = screenHeight;
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
// I'm going to assume VSYNC is enable for now
swapChainDesc.BufferDesc.RefreshRate.Numerator = numerator;
swapChainDesc.BufferDesc.RefreshRate.Denominator = denominator;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.OutputWindow = hWnd;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.Windowed = true;
swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
// Regarding Flags, I've mentioned above that when not set to 0, WM_SIZE is not called when ALT-ENTER is pressed.
//swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
swapChainDesc.Flags = 0;
featureLevel = D3D_FEATURE_LEVEL_11_0;
// Create Swap Chain, D3D Device and Device Context
D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, &featureLevel, 1, D3D11_SDK_VERSION, &swapChainDesc, &swapChain, &device, NULL, &deviceContext);
swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&backBufferPtr);
device->CreateRenderTargetView(backBufferPtr, NULL, &renderTargetView);
backBufferPtr->Release();
backBufferPtr = 0;
// Set up Depth and Stencil Buffers
ZeroMemory(&depthBufferDesc, sizeof(depthBufferDesc));
depthBufferDesc.Width = screenWidth;
depthBufferDesc.Height = screenHeight;
depthBufferDesc.MipLevels = 1;
depthBufferDesc.ArraySize = 1;
depthBufferDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthBufferDesc.SampleDesc.Count = 1;
depthBufferDesc.SampleDesc.Quality = 0;
depthBufferDesc.Usage = D3D11_USAGE_DEFAULT;
depthBufferDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
depthBufferDesc.CPUAccessFlags = 0;
depthBufferDesc.MiscFlags = 0;
// Create Depth/Stencil Buffer using description
device->CreateTexture2D(&depthBufferDesc, NULL, &depthStencilBuffer);
// Create Stencil State
ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc));
depthStencilDesc.DepthEnable = true;
depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
depthStencilDesc.DepthFunc = D3D11_COMPARISON_LESS;
depthStencilDesc.StencilEnable = true;
depthStencilDesc.StencilReadMask = 0xFF;
depthStencilDesc.StencilWriteMask = 0xFF;
// Stencil operation if Pixel is Front-Facing
depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
// Stencil operation if Pixel is Back-Facing
depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
// Create the Depth Stencil State
device->CreateDepthStencilState(&depthStencilDesc, &depthStencilState);
deviceContext->OMSetDepthStencilState(depthStencilState, 1);
// Similar steps for Disabled Depth Stencil State - Omitted
// Create Blend State - Omitted
// Depth Stencil View Description and Creation - Omitted
// Bind Depth Stencil and Render Target View to the Output Render Pipeline
deviceContext->OMSetRenderTargets(1, &renderTargetView, depthStencilView);
// Configure Rasterizer
rasterDesc.AntialiasedLineEnable = false;
rasterDesc.CullMode = D3D11_CULL_BACK;
rasterDesc.DepthBias = 0;
rasterDesc.DepthBiasClamp = 0.0f;
rasterDesc.DepthClipEnable = true;
rasterDesc.FillMode = D3D11_FILL_SOLID;
rasterDesc.FrontCounterClockwise = false;
rasterDesc.MultisampleEnable = false;
rasterDesc.ScissorEnable = false;
rasterDesc.SlopeScaledDepthBias = 0.0f;
device->CreateRasterizerState(&rasterDesc, &rasterState);
deviceContext->RSSetState(rasterState);
// Setup and Create Viewport
viewport.Width = (float)screenWidth;
viewport.Height = (float)screenHeight;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
viewport.TopLeftX = 0.0f;
viewport.TopLeftY = 0.0f;
deviceContext->RSSetViewports(1, &viewport);
// Create various Matrices
}
And the ToggleFullscreen
function (WM_SIZE
calls this, sending LPARAM
):
bool D3D::ToggleFullscreen(LPARAM lParam)
{
if (swapChain)
{
unsigned int numerator, denominator;
OutputDebugString(TEXT("Resizing\n"));
deviceContext->OMSetRenderTargets(0, 0, 0);
renderTargetView->Release();
swapChain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
ID3D11Texture2D* backBufferPtr;
swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&backBufferPtr);
device->CreateRenderTargetView(backBufferPtr, NULL, &renderTargetView);
backBufferPtr->Release();
backBufferPtr = 0;
// MSDN list a 0 for depthStencilview, so I figured it would make sense to call this the same way that I originally initialize.
// With a 0, models are drawn when switched to Fullscreen, but the depth buffer seems foobarred. With depthStencilView (member pointer, not freed until Shutdown()), NOTHING displays
// in Fullscreen, but when ALT-Enter to return to windowed, things are displaying properly.
deviceContext->OMSetRenderTargets(1, &renderTargetView, depthStencilView);
D3D11_VIEWPORT vp;
vp.Width = LOWORD(lParam);
vp.Height = HIWORD(lParam);
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
deviceContext->RSSetViewports(1, &vp);
// This whole last section was added because I thought perhaps the correct Refresh Rates were not apparent the SwapChain, as the program is initialized in Windowed mode
// numerator/denominator are passed By Ref
GetRefreshRate(LOWORD(lParam), HIWORD(lParam), numerator, denominator);
DXGI_SWAP_CHAIN_DESC dscd;
DXGI_MODE_DESC dmd;
swapChain->GetDesc(&dscd);
dmd = dscd.BufferDesc;
dmd.RefreshRate.Numerator = numerator;
dmd.RefreshRate.Denominator = denominator;
swapChain->ResizeTarget(&dmd);
}
return true;
}