通用 Windows 平台 (UWP) app 中的多重取樣 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 app 必須使用翻轉模型交換鏈結。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 app 所需的步驟。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 格式是否 _ _ 支援 _ _ RENDERTARGET 和 **D3D11 _ 格式 _ 支援 _ _ **的多重取樣解析。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);