Multisampling in UWP-apps (Universal Windows Platform)

Meer informatie over het gebruik van multisampling in UWP-apps (Universal Windows Platform) die zijn gebouwd met Direct3D. Multisampling, ook wel bekend als multi-sample antialiasing, is een grafische techniek die wordt gebruikt om het uiterlijk van aliasranden te verminderen. Het werkt door meer pixels te tekenen dan in het uiteindelijke renderdoel en vervolgens gemiddelde waarden te berekenen om het uiterlijk van een 'gedeeltelijke' rand in bepaalde pixels te behouden. Voor een gedetailleerde beschrijving van de werking van multisampling in Direct3D, zie Multisample Anti-Aliasing Rasterization Rules.

Multisampling en de wisselketen van het flipmodel

UWP-apps die DirectX gebruiken, moeten gebruikmaken van wisselketens volgens het flipmodel. Flip model wisselketens ondersteunen niet rechtstreeks multisampling, maar multisampling kan nog steeds op een andere manier worden toegepast door de scène weer te geven in een multisampled renderdoel en vervolgens het multisampled renderdoel naar de backbuffer te resolven voordat presenteren. In dit artikel worden de stappen uitgelegd die nodig zijn om multisampling toe te voegen aan uw UWP-app.

Hoe multisampling te gebruiken

Direct3D-functieniveaus bieden ondersteuning voor specifieke, minimale mogelijkheden voor het aantal steekproeven en garanderen dat bepaalde bufferindelingen beschikbaar zijn die ondersteuning bieden voor multisampling. Grafische apparaten ondersteunen vaak een breder scala aan indelingen en voorbeeldaantallen dan het minimale aantal. Ondersteuning voor multisampling kan tijdens runtime worden bepaald door de functieondersteuning voor multisampling met specifieke DXGI-indelingen te controleren en vervolgens de voorbeeldaantallen te controleren die u kunt gebruiken met elke ondersteunde indeling.

  1. Roep ID3D11Device::CheckFeatureSupport aan om erachter te komen welke DXGI-formaten kunnen worden gebruikt met multisampling. Geef de renderdoelindelingen op die uw game kan gebruiken. Zowel het renderdoel als het oplosdoel moeten hetzelfde formaat gebruiken, dus controleer zowel op D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET als op D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE.

    **Functieniveau 9: ** Hoewel apparaten op functieniveau 9 ondersteuning bieden voor multisampled renderdoelindelingen, is ondersteuning voor multisample-oplossingsdoelen niet gegarandeerd. Deze controle is dus nodig voordat u de multisampling-techniek probeert te gebruiken die in dit onderwerp wordt beschreven.

    Met de volgende code wordt de ondersteuning voor multisampling gecontroleerd voor alle DXGI_FORMAT-waarden:

    // 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. Voor elke ondersteunde indeling voert u een query uit voor ondersteuning voor het aantal steekproeven door ID3D11Device::CheckMultisampleQualityLevelsaan te roepen.

    Met de volgende code wordt de ondersteuning van de steekproefgrootte voor ondersteunde DXGI-indelingen gecontroleerd.

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

    Opmerking Gebruik in plaats daarvan ID3D11Device2::CheckMultisampleQualityLevels1 als u in plaats daarvan de multisample-ondersteuning voor tegelresourcebuffers wilt controleren.

     

  3. Maak een buffer en geef de doelweergave weer met het gewenste aantal steekproeven. Gebruik dezelfde DXGI_FORMAT, breedte en hoogte als de swapketen, maar specificeer een steekproefaantal groter dan 1 en gebruik een multisampled textuurdimensie (bijvoorbeeldD3D11_RTV_DIMENSION_TEXTURE2DMS). Indien nodig kunt u de wisselketen opnieuw maken met nieuwe instellingen die optimaal zijn voor multisampling.

    Met de volgende code wordt een multisampled renderdoel gemaakt:

    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. De dieptebuffer moet dezelfde breedte, hoogte, aantal steekproeven en patroondimensie hebben, zodat deze overeenkomt met het multisampled renderdoel.

    Met de volgende code wordt een multisampled dieptebuffer gemaakt:

    // 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. Het is nu een goed moment om de viewport te maken, omdat de breedte en hoogte van de viewport ook moeten overeenkomen met het renderdoel.

    Met de volgende code wordt een viewport gemaakt:

    // 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. Geef ieder frame weer naar het multisampled renderdoel. Wanneer de rendering is voltooid, roept u ID3D11DeviceContext::ResolveSubresource aan voordat u het frame presenteert. Hierdoor wordt Direct3D geïnstrueerd om de multisampling-bewerking uit te voeren, de waarde van elke pixel voor weergave te berekenen en het resultaat in de backbuffer te plaatsen. De achterbuffer bevat vervolgens de uiteindelijke antialiasafbeelding en kan worden weergegeven.

    Met de volgende code wordt de subresource omgezet voordat het frame wordt weergegeven:

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