Compartilhar via


Multisampling em aplicativos da Plataforma Universal do Windows (UWP)

Saiba como usar multisampling em aplicativos UWP (Plataforma Universal do Windows) criados com o Direct3D. A multiamostragem, também conhecida como antialiasing de multiamostras, é uma técnica gráfica usada para reduzir a aparência de bordas serrilhadas. Ele funciona ao desenhar mais pixels do que realmente estão no alvo de renderização final e, em seguida, calcular a média desses valores para manter a aparência de uma borda "parcial" em determinados pixels. Para obter uma descrição detalhada de como a multiamostragem realmente funciona no Direct3D, consulte Regras de Rasterização para Anti-Aliasing de Multiamostragem.

Multisampling e a cadeia de troca de modelos flip

Os aplicativos UWP que usam o DirectX devem usar cadeias de troca de modelo de inversão. As cadeias de troca de modelo flip não dão suporte a multisampling diretamente, mas a multisampling ainda pode ser aplicada de uma maneira diferente renderizando a cena para uma exibição de destino de renderização multisampada e resolvendo o destino de renderização multisampada para o buffer de fundo antes de apresentar. Este artigo explica as etapas necessárias para adicionar multisampling ao seu aplicativo UWP.

Como usar multisampling

Os níveis de recursos do Direct3D garantem suporte para contagem mínima especificada de amostras e garantem que determinados formatos de buffer estarão disponíveis para suportar a multiamostragem. Os dispositivos gráficos geralmente oferecem suporte a uma gama mais ampla de formatos e contagens de amostras do que o mínimo necessário. O suporte a multiamostragem pode ser determinado em tempo de execução verificando o suporte a multiamostragem com formatos específicos de DXGI e, em seguida, verificando as contagens de amostras que você pode usar com cada formato compatível.

  1. Chame ID3D11Device::CheckFeatureSupport para descobrir quais formatos DXGI podem ser usados com multiamostragem. Forneça os formatos de destino de renderização que seu jogo pode usar. O destino de renderização e o destino de resolução devem usar o mesmo formato, portanto, verifique D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET e D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE.

    **Nível de recurso 9: ** Embora dispositivos de nível de recurso 9 garantam suporte para formatos de destino de renderização multiamostra, o suporte não é garantido para destinos de resolução de multiamostra. Portanto, essa verificação é necessária antes de tentar usar a técnica multisampling descrita neste tópico.

    O código a seguir verifica o suporte multisampling para todos os valores de DXGI_FORMAT:

    // 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. Para cada formato com suporte, consulte o suporte à contagem de amostras chamando ID3D11Device::CheckMultisampleQualityLevels.

    O código a seguir verifica o suporte aos diferentes tamanhos de amostra dos formatos DXGI compatíveis.

    // 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);
            }
        }
    }
    

    Observação Use ID3D11Device2::CheckMultisampleQualityLevels1 se precisar verificar o suporte para amostragem múltipla em buffers de recursos em bloco.

     

  3. Crie um buffer e uma vista de destino de renderização com a contagem de amostras desejada. Use o mesmo DXGI_FORMAT, largura e altura que o swap chain, mas especifique uma contagem de amostras maior que 1 e use uma dimensão de textura multiamostrada (D3D11_RTV_DIMENSION_TEXTURE2DMS por exemplo). Se necessário, você pode recriar a cadeia de troca com novas configurações ideais para multisampling.

    O código a seguir cria um destino de renderização multiamostrado.

    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. O buffer de profundidade deve ter a mesma largura, altura, contagem de amostras e dimensão de textura para corresponder ao alvo de renderização multiamostra.

    O código a seguir cria um buffer de profundidade multiamostrado:

    // 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. Agora é um bom momento para criar o visor, pois a largura e a altura do visor também devem corresponder ao destino de renderização.

    O código a seguir cria uma área de visualização:

    // 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. Renderize cada quadro para o alvo de renderização multiamostrado. Quando a renderização for concluída, chame ID3D11DeviceContext::ResolveSubresource antes de apresentar o quadro. Isso instrui o Direct3D a executar a operação multisampling, computando o valor de cada pixel para exibição e colocando o resultado no buffer de fundo. Em seguida, o buffer de fundo contém a imagem final anti-serrilhada e pode ser apresentado.

    O código a seguir resolve o sub-recurso antes de apresentar o quadro:

    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);