如何更改DirectX 11中的屏幕分辨率?有没有一种简单的方法可以做到,或者我是否必须完全重新创建交换链,并创建一个新的后备缓冲区和rendertargetview?
答案 0 :(得分:4)
DXGI自动处理调整前端缓冲区的大小,即显示给用户的交换链部分。但是,应用程序负责调整后台缓冲区的大小。当你这样做时,你还应该处理重新创建所有依赖窗口大小的'资源。
基本逻辑非常简单:
// 1. Clear the existing references to the backbuffer
ID3D11RenderTargetView* nullViews [] = { nullptr };
m_d3dContext->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr);
m_renderTargetView.Reset(); // Microsoft::WRL::ComPtr here does a Release();
m_depthStencilView.Reset();
m_d3dContext->Flush();
// 2. Resize the existing swapchain
hr = m_swapChain->ResizeBuffers(2, backBufferWidth, backBufferHeight, backBufferFormat, 0);
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
// You have to destroy the device, swapchain, and all resources and
// recreate them to recover from this case. The device was hardware reset,
// physically removed, or the driver was updated and/or restarted
之后,其余步骤正是您第一次创建交换链时所执行的操作
// 3. Get the new backbuffer texture to use as a render target
hr = m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), &backBuffer);
hr = m_d3dDevice->CreateRenderTargetView(backBuffer.Get(), nullptr, &m_renderTargetView);
// 4. Create a depth/stencil buffer and create the depth stencil view
CD3D11_TEXTURE2D_DESC depthStencilDesc(depthBufferFormat, backBufferWidth, backBufferHeight, 1, 1, D3D11_BIND_DEPTH_STENCIL);
hr = m_d3dDevice->CreateTexture2D(&depthStencilDesc, nullptr, &depthStencil);
CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(D3D11_DSV_DIMENSION_TEXTURE2D);
hr = m_d3dDevice->CreateDepthStencilView(depthStencil.Get(), &depthStencilViewDesc, &m_depthStencilView));
// 5. Reset the rendering viewport to the new size
CD3D11_VIEWPORT viewPort(0.0f, 0.0f, static_cast<float>(backBufferWidth), static_cast<float>(backBufferHeight));
m_d3dContext->RSSetViewports(1, &viewPort);
// 6. Reset your camera's aspect ratio based on backBufferWidth/backBufferHeight
// 7. Set your render target view/depth stencil view for rendering
m_d3dContext->OMSetRenderTargets(1, m_renderTargetView.GetAddressOf(), m_depthStencilView.Get());
对于Win32桌面应用程序,诀窍是确切地知道何时来执行此过程。
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
static bool s_in_sizemove = false;
static bool s_minimized = false;
switch (message)
{
...
case WM_SIZE:
if (wParam == SIZE_MINIMIZED)
{
if (!s_minimized)
{
s_minimized = true;
// Your app should probably suspend
}
}
else if (s_minimized)
{
s_minimized = false;
// Your app should resume
}
else if ( !s_in_sizemove )
// HERE is where you'd trigger a resize based on MINIMIZE/MAXIMIZE/RESTORE
break;
case WM_ENTERSIZEMOVE:
s_in_sizemove = true;
break;
case WM_EXITSIZEMOVE:
s_in_sizemove = false;
// HERE is where you'd trigger a resize based on the user resizing the window
break;
case WM_GETMINMAXINFO:
{
// You should set a minimize window size that is reasonable for your app. Here I use 320x200
auto info = reinterpret_cast<MINMAXINFO*>(lParam);
info->ptMinTrackSize.x = 320;
info->ptMinTrackSize.y = 200;
}
break;
}
...
return DefWindowProc(hWnd, message, wParam, lParam);
}
对于Windows应用商店应用/ Windows手机应用,VS模板具有用于创建设备的独特功能,另一个用于创建依赖于设备的资源,另一个用于创建依赖于窗口大小的资源。调用最后一个用于调整大小。
全屏模式有点棘手,但基本上是相同的想法。如果您的应用程序不支持全屏,则应确保在首次创建交换链并设置HWND关联时调用此方法来禁用默认的ALT + ENTER行为:
dxgiFactory->MakeWindowAssociation(hWnd, DXGI_MWA_NO_ALT_ENTER);
Windows应用商店应用/ Windows手机应用不允许真正的全屏&#39;模式分辨率发生变化,因此这种情况并不适用于它们。