在DirectX 11中更改分辨率

时间:2014-12-04 18:41:50

标签: c++ winapi directx-11

如何更改DirectX 11中的屏幕分辨率?有没有一种简单的方法可以做到,或者我是否必须完全重新创建交换链,并创建一个新的后备缓冲区和rendertargetview?

1 个答案:

答案 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;模式分辨率发生变化,因此这种情况并不适用于它们。

请参阅DirectX Graphics Infrastructure (DXGI): Best Practices