Compartilhar via


Multisampling em aplicativos UWP (Plataforma Universal do Windows)

Saiba como usar a multisampling em aplicativos UWP (Plataforma Universal do Windows) criados com o Direct3D. A multiamostragem, também conhecida como suavização de várias amostras, é uma técnica gráfica usada para reduzir a aparência de bordas com alias. Ele funciona desenhando mais pixels do que realmente no destino de renderização final e, em seguida, calculando a média dos 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 de anti-aliasing de várias amostras.

Multisampling e a cadeia de troca de modelo flip

Os aplicativos UWP que usam DirectX devem usar cadeias de troca de modelo de inversão. As cadeias de troca de modelo de inversão não dão suporte diretamente à multisamostragem, mas a multiamostragem ainda pode ser aplicada de uma maneira diferente, renderizando a cena em uma exibição de destino de renderização com várias amostras e, em seguida, resolvendo o destino de renderização com várias amostras no buffer traseiro antes da apresentação. Este artigo explica as etapas necessárias para adicionar várias amostras ao seu aplicativo UWP.

Como usar a amostragem múltipla

Os níveis de recursos do Direct3D garantem suporte para recursos específicos de contagem mínima de amostras e garantem que determinados formatos de buffer estejam disponíveis para dar suporte a multiamostragem. Os dispositivos gráficos geralmente suportam uma variedade maior de formatos e contagens de amostras do que o mínimo necessário. O suporte a várias amostras pode ser determinado em tempo de execução verificando o suporte a recursos para várias amostras com formatos DXGI específicos e, em seguida, verificando as contagens de amostra que você pode usar com cada formato com suporte.

  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. Tanto o destino de renderização quanto o destino de resolução devem usar o mesmo formato, portanto, verifique se há D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET e D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE.

    **Nível de recurso 9: ** Embora os dispositivos de nível de recurso 9 garantam suporte para formatos de destino de renderização com várias amostras, o suporte não é garantido para destinos de resolução de várias amostras. Portanto, essa verificação é necessária antes de tentar usar a técnica de amostragem múltipla descrita neste tópico.

    O código a seguir verifica o suporte a várias amostras para todos os valores 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 exemplos chamando ID3D11Device::CheckMultisampleQualityLevels.

    O código a seguir verifica o suporte de tamanho de exemplo para formatos DXGI com suporte:

    // 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 a várias amostras para buffers de recursos em blocos.

     

  3. Crie um buffer e renderize a exibição de destino com a contagem de amostra desejada. Use a mesma DXGI_FORMAT, largura e altura da cadeia de troca, mas especifique uma contagem de amostra maior que 1 e use uma dimensão de textura com várias amostras (D3D11_RTV_DIMENSION_TEXTURE2DMS por exemplo). Se necessário, você pode recriar a cadeia de troca com novas configurações ideais para multiamostragem.

    O código a seguir cria um destino de renderização com várias amostras:

    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 amostra e dimensão de textura para corresponder ao destino de renderização com várias amostras.

    O código a seguir cria um buffer de profundidade com várias amostras:

    // 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 a janela de visualização, pois a largura e a altura da janela de visualização também devem corresponder ao destino de renderização.

    O código a seguir cria um visor:

    // 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 destino de renderização com várias amostras. Quando a renderização for concluída, chame ID3D11DeviceContext::ResolveSubresource antes de apresentar o quadro. Isso instrui o Direct3D a executar a operação de multisampling, calculando o valor de cada pixel para exibição e colocando o resultado no buffer traseiro. O buffer traseiro contém a imagem final com suavização de serrilhado 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);