Redimensionamento e sobreposição de cadeia de permuta

Applies to Windows only

Saiba como criar cadeias de permuta redimensionadas para permitir renderização mais rápida em dispositivos móveis e usar cadeias de permuta sobrepostas (quando disponíveis) para aumentar a qualidade visual.

Cadeias de permuta no DirectX 11.2

O Direct3D 11.2 permite criar aplicativos da Windows Store com cadeias de permuta que são ampliadas a partir de resoluções não nativas (reduzidas), permitindo taxas de preenchimento mais rápidas. O Direct3D 11.2 também inclui APIs para renderização com sobreposições de hardware para que você possa apresentar uma interface do usuário em outra cadeia de permuta com resolução nativa. Isso permite que o jogo desenhe a interface do usuário com resolução nativa total enquanto mantém uma alta taxa de quadros, assim fazendo o melhor uso de dispositivos móveis e telas de alto DPI (por exemplo, 3840 x 2160). Este artigo explica como usar cadeias de permuta sobrepostas.

O Direct3D 11.2 também introduz um novo recurso para permitir latência reduzida com cadeias de permuta de modelo invertido. Veja Reduzir latência com cadeias de permuta DXGI 1.3

Este tutorial passo a passo usa código do exemplo de cadeias de permuta de primeiro plano do DirectX.

Usar redimensionamento das cadeias de permuta

Quando seu jogo está sendo executado em hardware de nível inferior – ou hardware otimizado para economizar energia –, pode ser vantajoso renderizar conteúdo de jogo em tempo real em resolução mais baixa do que a capacidade nativa do vídeo. Para fazer isso, a cadeia de permuta usada para renderizar conteúdo de jogo precisa ser menor do que a resolução nativa, ou então uma sub-região da cadeia de permuta precisa ser usada.

  1. Primeiro, crie uma cadeia de permuta com resolução nativa total.

    
    DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
    
    swapChainDesc.Width = static_cast<UINT>(m_d3dRenderTargetSize.Width); // Match the size of the window.
    swapChainDesc.Height = static_cast<UINT>(m_d3dRenderTargetSize.Height);
    swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // This is the most common swap chain format.
    swapChainDesc.Stereo = false;
    swapChainDesc.SampleDesc.Count = 1; // Don't use multi-sampling.
    swapChainDesc.SampleDesc.Quality = 0;
    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapChainDesc.BufferCount = 2; // Use double-buffering to minimize latency.
    swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // All Windows Store apps must use this SwapEffect.
    swapChainDesc.Flags = 0;
    swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
    
    // This sequence obtains the DXGI factory that was used to create the Direct3D device above.
    ComPtr<IDXGIDevice3> dxgiDevice;
    DX::ThrowIfFailed(
        m_d3dDevice.As(&dxgiDevice)
        );
    
    ComPtr<IDXGIAdapter> dxgiAdapter;
    DX::ThrowIfFailed(
        dxgiDevice->GetAdapter(&dxgiAdapter)
        );
    
    ComPtr<IDXGIFactory2> dxgiFactory;
    DX::ThrowIfFailed(
        dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory))
        );
    
    ComPtr<IDXGISwapChain1> swapChain;
    DX::ThrowIfFailed(
        dxgiFactory->CreateSwapChainForCoreWindow(
            m_d3dDevice.Get(),
            reinterpret_cast<IUnknown*>(m_window.Get()),
            &swapChainDesc,
            nullptr,
            &swapChain
            )
        );
    
    DX::ThrowIfFailed(
        swapChain.As(&m_swapChain)
        );
    
    
    
  2. Depois, escolha uma sub-região da cadeia de permuta a ser ampliada definindo o tamanho de origem com uma resolução reduzida.

    O exemplo de cadeias de permuta de primeiro plano do DirectX calcula um tamanho reduzido com base em uma porcentagem:

    
    m_d3dRenderSizePercentage = percentage;
    
    UINT renderWidth = static_cast<UINT>(m_d3dRenderTargetSize.Width * percentage + 0.5f);
    UINT renderHeight = static_cast<UINT>(m_d3dRenderTargetSize.Height * percentage + 0.5f);
    
    // Change the region of the swap chain that will be presented to the screen.
    DX::ThrowIfFailed(
        m_swapChain->SetSourceSize(
            renderWidth,
            renderHeight
            )
        );
    
    
    
  3. Crie um visor para corresponder à sub-região da cadeia de permuta.

    
    // In Direct3D, change the Viewport to match the region of the swap
    // chain that will now be presented from.
    m_screenViewport = CD3D11_VIEWPORT(
        0.0f,
        0.0f,
        static_cast<float>(renderWidth),
        static_cast<float>(renderHeight)
        );
    
    m_d3dContext->RSSetViewports(1, &m_screenViewport);
    
    
    
  4. Se o Direct2D estiver sendo usado, a transformação de rotação precisará ser ajustada para compensar a região de origem.

Criar uma cadeia de permuta de sobreposição de hardware para elementos da interface do usuário

Ao usar redimensionamento da cadeia de permuta, há uma desvantagem inerente no sentido de que a interface do usuário também é reduzida, possivelmente tornando-a desfocada e mais difícil de usar. Em dispositivos com suporte de hardware para cadeias de permuta de sobreposição, esse problema é contornado completamente com a renderização da interface do usuário em resolução nativa em uma cadeia de permuta separada do conteúdo do jogo em tempo real. Observe que essa técnica se aplica somente a cadeias de permuta CoreWindow– ela não pode ser usada com interop XAML.

Siga estas etapas para criar uma cadeia de permuta de primeiro plano que usa recurso de sobreposição de hardware. Estas etapas são executadas depois da criação de uma cadeia de permuta para conteúdo de jogo em tempo real conforme descrito anteriormente.

  1. Primeiro, determine se o adaptador DXGI dá suporte a sobreposições. Obtenha o adaptador de saída DXGI na cadeia de permuta:

    
    ComPtr<IDXGIAdapter> outputDxgiAdapter;
    DX::ThrowIfFailed(
        dxgiFactory->EnumAdapters(0, &outputDxgiAdapter)
        );
    
    ComPtr<IDXGIOutput> dxgiOutput;
    DX::ThrowIfFailed(
        outputDxgiAdapter->EnumOutputs(0, &dxgiOutput)
        );
    
    ComPtr<IDXGIOutput2> dxgiOutput2;
    DX::ThrowIfFailed(
        dxgiOutput.As(&dxgiOutput2)
        );
    
    
    

    O adaptador DXGI dá suporte a sobreposições de o adaptador de saída retorna True para SupportsOverlays.

    
    m_overlaySupportExists = dxgiOutput2->SupportsOverlays() ? true : false;
    
    
    

    Observação  Se o adaptador DXGI der suporte a sobreposições, continue com a próxima etapa. Se o dispositivo não ser suporte a sobreposições, a renderização com várias cadeias de permuta não será eficiente. Em vez disso, renderize a interface do usuário com resolução reduzida na mesma cadeia de permuta do conteúdo de jogo em tempo real. Veja o exemplo de cadeias de permuta de primeiro plano do DirectX para saber como retornar a uma única cadeia de permuta.

  2. Crie a cadeia de permuta de primeiro plano com IDXGIFactory2::CreateSwapChainForCoreWindow. As opções a seguir precisam ser definidas no DXGI_SWAP_CHAIN_DESC1 fornecido ao parâmetro pDesc:

    
     foregroundSwapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_FOREGROUND_LAYER;
     foregroundSwapChainDesc.Scaling = DXGI_SCALING_NONE;
     foregroundSwapChainDesc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED; // Foreground swap chain alpha values must be premultiplied.
    
    
    

    Observação  Defina DXGI_SWAP_CHAIN_FLAG_FOREGROUND_LAYER novamente sempre que a cadeia de permuta for redimensionada.

    
    HRESULT hr = m_foregroundSwapChain->ResizeBuffers(
        2, // Double-buffered swap chain.
        static_cast<UINT>(m_d3dRenderTargetSize.Width),
        static_cast<UINT>(m_d3dRenderTargetSize.Height),
        DXGI_FORMAT_B8G8R8A8_UNORM,
        DXGI_SWAP_CHAIN_FLAG_FOREGROUND_LAYER // The FOREGROUND_LAYER flag cannot be removed with ResizeBuffers.
        );
    
    
    
  3. Quando duas cadeias de permuta estão sendo usadas, aumente a latência de quadro máxima para 2 de maneira que o adaptador DXGI tenha tempo para apresentar ambas as cadeias de permuta simultaneamente (no mesmo intervalo VSync).

    
    // Create a render target view of the foreground swap chain's back buffer.
    if (m_foregroundSwapChain)
    {
        ComPtr<ID3D11Texture2D> foregroundBackBuffer;
        DX::ThrowIfFailed(
            m_foregroundSwapChain->GetBuffer(0, IID_PPV_ARGS(&foregroundBackBuffer))
            );
    
        DX::ThrowIfFailed(
            m_d3dDevice->CreateRenderTargetView(
                foregroundBackBuffer.Get(),
                nullptr,
                &m_d3dForegroundRenderTargetView
                )
            );
    }
    
    
    
  4. As cadeias de permuta de primeiro plano sempre usam alfa premultiplicado. Espera-se que os valores de cor de cada pixel já estejam multiplicados pelo valor alfa antes de o quadro ser apresentado. Por exemplo, um pixel BGRA de 100% branco em alfa de 50% é definido como (0,5 - 0,5 - 0,5 - 0,5).

    A etapa de premultiplicação de alfa pode ser executada no estágio de fusão de saída aplicando um estado de mesclagem de aplicativo (veja ID3D11BlendState) com o campo SrcBlend da estrutura D3D11_RENDER_TARGET_BLEND_DESC definido como D3D11_SRC_ALPHA. Ativos com valores alfa premultiplicados também podem ser usados.

    Se a etapa de premultiplicação de alfa não for executada, as cores na cadeia de permuta de primeiro plano estarão mais brilhantes do que o esperado.

  5. Dependendo de a cadeia de permuta de primeiro plano ter ou não ter sido criada, a superfície de desenho do Direct2D para elementos de interface do usuário poderá estar associada à cadeia de permuta de primeiro plano.

    Criando modos de exibição de destino de renderização:

    
    // Create a render target view of the foreground swap chain's back buffer.
    if (m_foregroundSwapChain)
    {
        ComPtr<ID3D11Texture2D> foregroundBackBuffer;
        DX::ThrowIfFailed(
            m_foregroundSwapChain->GetBuffer(0, IID_PPV_ARGS(&foregroundBackBuffer))
            );
    
        DX::ThrowIfFailed(
            m_d3dDevice->CreateRenderTargetView(
                foregroundBackBuffer.Get(),
                nullptr,
                &m_d3dForegroundRenderTargetView
                )
            );
    }
    
    
    
    
    // Create a render target view of the swap chain's back buffer.
    ComPtr<ID3D11Texture2D> backBuffer;
    DX::ThrowIfFailed(
        m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer))
        );
    
    DX::ThrowIfFailed(
        m_d3dDevice->CreateRenderTargetView(
            backBuffer.Get(),
            nullptr,
            &m_d3dRenderTargetView
            )
        );
    
    
    

    Criando a superfície de desenho do Direct2D:

    
    if (m_foregroundSwapChain)
    {
        // Create Direct2D target bitmap for foreground swap chain.
        ComPtr<IDXGISurface2> dxgiForegroundSwapChainBackBuffer;
        DX::ThrowIfFailed(
            m_foregroundSwapChain->GetBuffer(0, IID_PPV_ARGS(&dxgiForegroundSwapChainBackBuffer))
            );
    
        DX::ThrowIfFailed(
            m_d2dContext->CreateBitmapFromDxgiSurface(
                dxgiForegroundSwapChainBackBuffer.Get(),
                &bitmapProperties,
                &m_d2dTargetBitmap
                )
            );
    }
    else
    {
        // Create Direct2D target bitmap for swap chain.
        ComPtr<IDXGISurface2> dxgiSwapChainBackBuffer;
        DX::ThrowIfFailed(
            m_swapChain->GetBuffer(0, IID_PPV_ARGS(&dxgiSwapChainBackBuffer))
            );
    
        DX::ThrowIfFailed(
            m_d2dContext->CreateBitmapFromDxgiSurface(
                dxgiSwapChainBackBuffer.Get(),
                &bitmapProperties,
                &m_d2dTargetBitmap
                )
            );
    }
    
    m_d2dContext->SetTarget(m_d2dTargetBitmap.Get());
    
    
    
  6. Apresente a cadeia de permuta de primeiro plano junto com a cadeia de permuta redimensionada usada para conteúdo de jogo em tempo real. Como a latência de quadro estava definida como 2 para ambas as cadeias de permuta, o DXGI poderá apresentá-las no mesmo intervalo VSync.

    O exemplo de cadeias de permuta de primeiro plano do DirectX modifica DeviceResources.cpp da seguinte maneira para apresentar a cadeia de permuta de primeiro plano:

    
    // Present the contents of the swap chain to the screen.
    void DX::DeviceResources::Present()
    {
        // The first argument instructs DXGI to block until VSync, putting the application
        // to sleep until the next VSync. This ensures we don't waste any cycles rendering
        // frames that will never be displayed to the screen.
        HRESULT hr = m_swapChain->Present(1, 0);
    
        if (SUCCEEDED(hr) && m_foregroundSwapChain)
        {
            m_foregroundSwapChain->Present(1, 0);
        }
    
        // Discard the contents of the render targets.
        // This is a valid operation only when the existing contents will be entirely
        // overwritten. If dirty or scroll rects are used, this call should be removed.
        m_d3dContext->DiscardView(m_d3dRenderTargetView.Get());
        if (m_foregroundSwapChain)
        {
            m_d3dContext->DiscardView(m_d3dForegroundRenderTargetView.Get());
        }
    
        // Discard the contents of the depth stencil.
        m_d3dContext->DiscardView(m_d3dDepthStencilView.Get());
    
        // If the device was removed either by a disconnection or a driver upgrade, we
        // must recreate all device resources.
        if (hr == DXGI_ERROR_DEVICE_REMOVED)
        {
            HandleDeviceLost();
        }
        else
        {
            DX::ThrowIfFailed(hr);
        }
    }
    
    
    

 

 

Mostrar:
© 2014 Microsoft