通用 Windows 平台 (UWP) 应用中的多重采样 Multisampling in Universal Windows Platform (UWP) apps

了解如何在使用 Direct3D 生成的通用 Windows 平台 (UWP) 应用中使用多重采样。Learn how to use multisampling in Universal Windows Platform (UWP) apps built with Direct3D. 多重采样(也称为多重采样抗锯齿)是一种图形技术,用于减少锯齿边缘的显示。Multisampling, also known as multi-sample antialiasing, is a graphics technique used to reduce the appearance of aliased edges. 它的工作方式是绘制比最终渲染目标中包含的实际像素更多的像素,然后取平均值以保留某些像素的“局部”边缘的显示。It works by drawing more pixels than are actually in the final render target, then averaging values to maintain the appearance of a "partial" edge in certain pixels. 有关多重采样在 Direct3D 中的实际工作方式的详细说明,请参阅多重采样抗锯齿光栅化规则For a detailed description of how multisampling actually works in Direct3D, see Multisample Anti-Aliasing Rasterization Rules.

多重采样和翻转模型交换链Multisampling and the flip model swap chain

使用 DirectX 的 UWP 应用必须使用翻转模型交换链。UWP apps that use DirectX must use flip model swap chains. 翻转模型交换链不直接支持多重采样,但仍然可以使用不同方式应用多重采样,方法是将场景渲染到多重采样的渲染目标视图,然后在呈现前将多重采样的渲染目标解析到后台缓冲区。Flip model swap chains don't support multisampling directly, but multisampling can still be applied in a different way by rendering the scene to a multisampled render target view, and then resolving the multisampled render target to the back buffer before presenting. 本文介绍将多重采样添加到 UWP 应用所需的步骤。This article explains the steps required to add multisampling to your UWP app.

如何使用多重采样How to use multisampling

Direct3D 功能级别保证支持特定的最小样本计数功能,并保证某些支持多重采样的缓冲区格式可用。Direct3D feature levels guarantee support for specific, minimum sample count capabilities, and guarantee certain buffer formats will be available that support multisampling. 图形设备支持的格式和样本计数通常多于最低要求。Graphics devices often support a wider range of formats and sample counts than the minimum required. 通过检查具有特定 DXGI 格式的多重采样支持功能,然后检查可以与每个支持的格式一起使用的样本计数,你可以在运行时确定多重采样支持。Multisampling support can be determined at run-time by checking feature support for multisampling with specific DXGI formats, and then checking the sample counts you can use with each supported format.

  1. 调用 ID3D11Device::CheckFeatureSupport 以了解哪些 DXGI 格式可以用于多重采用。Call ID3D11Device::CheckFeatureSupport to find out which DXGI formats can be used with multisampling. 提供游戏可以使用的呈现目标格式。Supply the render target formats your game can use. 呈现器目标和解析目标都必须使用相同的格式,因此,请检查 D3D11 _ 格式 _ 支持的 _ 多级 _ RENDERTARGETD3D11 _ 格式 _ 支持多级显示 _ _ 解析Both the render target and resolve target must use the same format, so check for both D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET and D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE.

    **功能级别9:  ** 尽管功能级别9设备 保证支持多级采样呈现目标格式,但不保证对多级显示解析目标的支持。**Feature level 9:  ** Although feature level 9 devices guarantee support for multisampled render target formats, support is not guaranteed for multisample resolve targets. 因此,在尝试使用本主题所述的多重采样技术之前,此检查是必要的。So this check is necessary before trying to use the multisampling technique described in this topic.

    下面的代码检查所有 DXGI 格式值的多级取样支持 _ :The following code checks multisampling support for all the DXGI_FORMAT values:

    // Determine the format support for multisampling.
    for (UINT i = 1; i < DXGI_FORMAT_MAX; i++)
    {
        DXGI_FORMAT inFormat = safe_cast<DXGI_FORMAT>(i);
        UINT formatSupport = 0;
        HRESULT hr = m_d3dDevice->CheckFormatSupport(inFormat, &formatSupport);
    
        if ((formatSupport & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE) &&
            (formatSupport & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET)
            )
        {
            m_supportInfo->SetFormatSupport(i, true);
        }
        else
        {
            m_supportInfo->SetFormatSupport(i, false);
        }
    }
    
  2. 对于每个支持的格式,通过调用 ID3D11Device::CheckMultisampleQualityLevels 查询样本计数支持。For each supported format, query for sample count support by calling ID3D11Device::CheckMultisampleQualityLevels.

    以下代码将检查受支持的 DXGI 格式的样本大小支持:The following code checks sample size support for supported DXGI formats:

    // Find available sample sizes for each supported format.
    for (unsigned int i = 0; i < DXGI_FORMAT_MAX; i++)
    {
        for (unsigned int j = 1; j < MAX_SAMPLES_CHECK; j++)
        {
            UINT numQualityFlags;
    
            HRESULT test = m_d3dDevice->CheckMultisampleQualityLevels(
                (DXGI_FORMAT) i,
                j,
                &numQualityFlags
                );
    
            if (SUCCEEDED(test) && (numQualityFlags > 0))
            {
                m_supportInfo->SetSampleSize(i, j, 1);
                m_supportInfo->SetQualityFlagsAt(i, j, numQualityFlags);
            }
        }
    }
    

    注意   如果需要检查对平铺资源缓冲区的多级支持,请改用ID3D11Device2:: CheckMultisampleQualityLevels1Note   Use ID3D11Device2::CheckMultisampleQualityLevels1 instead if you need to check multisample support for tiled resource buffers.

     

  3. 创建具有所需样本计数的缓冲区和呈现目标视图。Create a buffer and render target view with the desired sample count. 使用与交换链相同的 DXGI _ 格式、宽度和高度,但指定一个大于1的样本数,并使用多级采样纹理维度 (D3D11 _ RTV _ dimension _ TEXTURE2DMS 例如) 。Use the same DXGI_FORMAT, width, and height as the swap chain, but specify a sample count greater than 1 and use a multisampled texture dimension (D3D11_RTV_DIMENSION_TEXTURE2DMS for example). 如果必要,你可以使用为多重采样优化的新设置重新创建交换链。If necessary, you can re-create the swap chain with new settings that are optimal for multisampling.

    以下代码将创建多重采样渲染目标:The following code creates a multisampled render target:

    float widthMulti = m_d3dRenderTargetSize.Width;
    float heightMulti = m_d3dRenderTargetSize.Height;
    
    D3D11_TEXTURE2D_DESC offScreenSurfaceDesc;
    ZeroMemory(&offScreenSurfaceDesc, sizeof(D3D11_TEXTURE2D_DESC));
    
    offScreenSurfaceDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
    offScreenSurfaceDesc.Width = static_cast<UINT>(widthMulti);
    offScreenSurfaceDesc.Height = static_cast<UINT>(heightMulti);
    offScreenSurfaceDesc.BindFlags = D3D11_BIND_RENDER_TARGET;
    offScreenSurfaceDesc.MipLevels = 1;
    offScreenSurfaceDesc.ArraySize = 1;
    offScreenSurfaceDesc.SampleDesc.Count = m_sampleSize;
    offScreenSurfaceDesc.SampleDesc.Quality = m_qualityFlags;
    
    // Create a surface that's multisampled.
    DX::ThrowIfFailed(
        m_d3dDevice->CreateTexture2D(
        &offScreenSurfaceDesc,
        nullptr,
        &m_offScreenSurface)
        );
    
    // Create a render target view. 
    CD3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc(D3D11_RTV_DIMENSION_TEXTURE2DMS);
    DX::ThrowIfFailed(
        m_d3dDevice->CreateRenderTargetView(
        m_offScreenSurface.Get(),
        &renderTargetViewDesc,
        &m_d3dRenderTargetView
        )
        );
    
  4. 深度缓冲区必须具有相同的宽度、高度、样本计数和纹理大小以匹配多重采样渲染目标。The depth buffer must have the same width, height, sample count, and texture dimension to match the multisampled render target.

    以下代码将创建多重采样深度缓冲区:The following code creates a multisampled depth buffer:

    // Create a depth stencil view for use with 3D rendering if needed.
    CD3D11_TEXTURE2D_DESC depthStencilDesc(
        DXGI_FORMAT_D24_UNORM_S8_UINT,
        static_cast<UINT>(widthMulti),
        static_cast<UINT>(heightMulti),
        1, // This depth stencil view has only one texture.
        1, // Use a single mipmap level.
        D3D11_BIND_DEPTH_STENCIL,
        D3D11_USAGE_DEFAULT,
        0,
        m_sampleSize,
        m_qualityFlags
        );
    
    ComPtr<ID3D11Texture2D> depthStencil;
    DX::ThrowIfFailed(
        m_d3dDevice->CreateTexture2D(
        &depthStencilDesc,
        nullptr,
        &depthStencil
        )
        );
    
    CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(D3D11_DSV_DIMENSION_TEXTURE2DMS);
    DX::ThrowIfFailed(
        m_d3dDevice->CreateDepthStencilView(
        depthStencil.Get(),
        &depthStencilViewDesc,
        &m_d3dDepthStencilView
        )
        );
    
  5. 现在是创建视口的最佳时间,因为视口宽度和高度必须也匹配渲染目标。Now is a good time to create the viewport, because the viewport width and height must also match the render target.

    以下代码将创建视口:The following code creates a viewport:

    // Set the 3D rendering viewport to target the entire window.
    m_screenViewport = CD3D11_VIEWPORT(
        0.0f,
        0.0f,
        widthMulti / m_scalingFactor,
        heightMulti / m_scalingFactor
        );
    
    m_d3dContext->RSSetViewports(1, &m_screenViewport);
    
  6. 将每个帧渲染到多重采样渲染目标。Render each frame to the multisampled render target. 完成渲染后,先调用 ID3D11DeviceContext::ResolveSubresource,然后再呈现帧。When rendering is complete, call ID3D11DeviceContext::ResolveSubresource before presenting the frame. 此操作可指导 Direct3D 执行多重采样操作、计算每个像素值以供显示,并将结果放置在后台缓冲区中。This instructs Direct3D to peform the multisampling operation, computing the value of each pixel for display and placing the result in the back buffer. 然后,后台缓冲区可包含最终抗锯齿图像并可供呈现。The back buffer then contains the final anti-aliased image and can be presented.

    以下代码在呈现帧之前将解析子资源:The following code resolves the subresource before presenting the frame:

    if (m_sampleSize > 1)
    {
        unsigned int sub = D3D11CalcSubresource(0, 0, 1);
    
        m_d3dContext->ResolveSubresource(
            m_backBuffer.Get(),
            sub,
            m_offScreenSurface.Get(),
            sub,
            DXGI_FORMAT_B8G8R8A8_UNORM
            );
    }
    
    // The first argument instructs DXGI to block until VSync, putting the application
    // to sleep until the next VSync. This ensures that we don't waste any cycles rendering
    // frames that will never be displayed to the screen.
    hr = m_swapChain->Present(1, 0);