Condividi tramite


Multicampionamento nelle app UWP (Universal Windows Platform)

Scopri come usare il multicampionamento nelle app UWP (Universal Windows Platform) compilate con Direct3D. Il multicampionamento, noto anche come antialiasing multicampionamento, è una tecnica grafica usata per ridurre l'aspetto dei bordi con alias. Funziona generando più pixel di quanti ce ne siano effettivamente nell'immagine renderizzata finale, quindi calcolando la media dei valori per mantenere l'aspetto di un bordo "parziale" in determinati pixel. Per una descrizione dettagliata di come funziona effettivamente il multisampling in Direct3D, vedere Regole di rasterizzazione per l'anti-aliasing multisample.

Multicampionamento e catena di scambio del modello flip

Le app UWP che usano DirectX devono usare catene di scambio di modelli flip. Le catene di scambi del modello flip non supportano direttamente il multicampionamento, ma il multicampionamento può comunque essere applicato in modo diverso, eseguendo il rendering della scena in una visualizzazione di destinazione di rendering multicampionato e quindi risolvendo la destinazione di rendering multicampionato nel buffer di fondo prima della presentazione. Questo articolo illustra i passaggi necessari per aggiungere il multisampling all'app UWP.

Come usare il multicampionamento

I livelli di funzionalità Direct3D garantiscono il supporto per funzionalità specifiche e minime del conteggio dei campioni e garantiscono che alcuni formati di buffer siano disponibili che supportano il multicampionamento. I dispositivi grafici spesso supportano una gamma più ampia di formati e conteggi dei campioni rispetto al minimo richiesto. Il supporto per il multicampionamento può essere determinato in fase di esecuzione controllando il supporto delle funzionalità per il multicampionamento con formati DXGI specifici e quindi controllando i conteggi di esempio che è possibile usare con ogni formato supportato.

  1. Chiama ID3D11Device::CheckFeatureSupport per scoprire quali formati DXGI possono essere usati con multisampling. Fornisci i formati target di rendering che il gioco può usare. Sia la destinazione di rendering che la destinazione di risoluzione devono usare lo stesso formato, quindi verificare sia D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET che D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE.

    **Livello di funzionalità 9: ** Anche se i dispositivi di livello 9 garantiscono il supporto per i formati di destinazione di rendering multisample, il supporto non è garantito per i target di risoluzione multisample. Questo controllo è quindi necessario prima di provare a usare la tecnica di multicampionamento descritta in questo argomento.

    Il codice seguente controlla il supporto per il multicampionamento per tutti i valori 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. Per ogni formato supportato, eseguire una query per il supporto del conteggio dei campioni chiamando ID3D11Device::CheckMultisampleQualityLevels.

    Il codice seguente controlla il supporto delle dimensioni del campione per i formati DXGI supportati:

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

    Nota Usa ID3D11Device2::CheckMultisampleQualityLevels1 se devi controllare il supporto multisample per i buffer di risorse affiancate.

     

  3. Creare un buffer e visualizzare la destinazione di rendering con il numero di campioni desiderato. Usare lo stesso DXGI_FORMAT, larghezza e altezza della swap chain, ma specificare un numero di campioni maggiore di 1 e utilizzare una dimensione texture multisample (ad esempioD3D11_RTV_DIMENSION_TEXTURE2DMS). Se necessario, è possibile ricreare la chain di swap con nuove impostazioni ottimali per il multicampionamento.

    Il codice seguente crea una destinazione di rendering multicampionato:

    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. Il buffer di profondità deve avere la stessa larghezza, altezza, numero di campioni e dimensione della trama per corrispondere alla destinazione di rendering multisample.

    Il codice seguente crea un buffer di profondità multicampionato:

    // 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. Ora è un buon momento per creare il riquadro di visualizzazione, perché la larghezza e l'altezza del riquadro di visualizzazione devono corrispondere anche alla destinazione di rendering.

    Il codice seguente crea un 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. Effettuare il rendering di ogni fotogramma nel target di rendering multicampionato. Quando il rendering è completato, chiamare ID3D11DeviceContext::ResolveSubresource prima di presentare il frame. Ciò istruisce Direct3D a eseguire l'operazione di multicampionamento, calcolando il valore di ogni pixel per la visualizzazione e posizionando il risultato nel buffer posteriore. Il buffer nascosto contiene quindi l'immagine anti-aliasing finale e può essere presentata.

    Il codice seguente risolve la sottorisorsa prima di presentare il 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);