在 DirectX 11 中更改分辨率

Change resolution in DirectX 11

本文关键字:分辨率 DirectX      更新时间:2023-10-16

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

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 关联时调用 this 来禁用默认的 ALT+ENTER 行为:

dxgiFactory->MakeWindowAssociation(hWnd, DXGI_MWA_NO_ALT_ENTER);
Windows

应用商店应用/Windows 手机应用不允许真正的"全屏"模式分辨率更改,因此这种情况不适用于它们。

请参阅 DirectX 图形基础结构 (DXGI(:最佳做法