Swapchainskalierung und ÜberlagerungenSwap chain scaling and overlays

Hier erfahren Sie, wie Sie skalierte Swapchains zum schnelleren Rendern auf mobilen Geräten erstellen und Überlagerungsswapchains (falls verfügbar) verwenden, um die visuelle Qualität zu steigern.Learn how to create scaled swap chains for faster rendering on mobile devices, and use overlay swap chains (when available) to increase the visual quality.

Swapchains unter DirectX 11.2Swap chains in DirectX 11.2

Unter Direct3D 11.2 können Sie UWP-Apps (Universelle Windows-Plattform) mit Swapchains erstellen, die von nicht systemeigenen (reduzierten) Auflösungen skaliert werden, um höhere Füllraten zu ermöglichen.Direct3D 11.2 allows you to create Universal Windows Platform (UWP) apps with swap chains that are scaled up from non-native (reduced) resolutions, enabling faster fill rates. Außerdem enthält Direct3D 11.2 APIs zum Rendern mit Hardwareüberlagerungen, damit Sie eine UI in einer anderen Swapchain mit systemeigener Auflösung darstellen können.Direct3D 11.2 also includes APIs for rendering with hardware overlays so that you can present a UI in another swap chain at native resolution. So kann das Spiel die UI mit der höchsten systemeigenen Auflösung zeichnen und gleichzeitig eine hohe Framerate erzielen. Mobile Geräte und Anzeigen mit hohem DPI-Wert (z. B. 3840 x 2160) lassen sich auf diese Weise bestmöglich nutzen.This allows your game to draw UI at full native resolution while maintaining a high framerate, thereby making the best use of mobile devices and high DPI displays (such as 3840 by 2160). In diesem Artikel wird erläutert, wie Sie sich überlappende Swapchains verwenden.This article explains how to use overlapping swap chains.

Mit Direct3D 11.2 wird auch ein neues Feature zur Erzielung einer geringeren Latenz mithilfe von Flipmodell-Swapchains eingeführt.Direct3D 11.2 also introduces a new feature for reduced latency with flip model swap chains. Weitere Informationen finden Sie unter Reduzieren der Latenz mit DXGI 1.3-Swapchains.See Reduce latency with DXGI 1.3 swap chains.

Verwenden der SwapchainskalierungUse swap chain scaling

Wenn Ihr Spiel nicht auf der neuesten Hardware ausgeführt wird – oder auf Hardware, die für sparsamen Betrieb optimiert ist –, kann es von Vorteil sein, Echtzeitinhalte des Spiels mit einer niedrigeren Auflösung als der Auflösung zu rendern, die das Display standardmäßig leisten kann.When your game is running on downlevel hardware - or hardware optimized for power savings - it can be beneficial to render real-time game content at a lower resolution than the display is natively capable of. Dazu muss die zum Rendern der Spielinhalte verwendete Swapchain kleiner als die systemeigene Auflösung sein, oder es muss ein Unterbereich der Swapchain verwendet werden.To do this, the swap chain that is used for rendering game content must be smaller than the native resolution, or a subregion of the swapchain must be used.

  1. Erstellen Sie zuerst eine Swapchain mit der höchstmöglichen systemeigenen Auflösung.First, create a swap chain at full native resolution.

    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 UWP 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. Wählen Sie anschließend einen Unterbereich der Swapchain für die Skalierung aus, indem Sie die Quellgröße auf eine niedrigere Auflösung festlegen.Then, choose a subregion of the swap chain to scale up by setting the source size to a reduced resolution.

    Im Beispiel zu DX-Vordergrund-Swapchains wird anhand eines Prozentsatzes eine reduzierte Größe berechnet:The DX Foreground Swap Chains sample calculates a reduced size based on a percentage:

    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. Erstellen Sie einen Viewport für den Unterbereich der Swapchain.Create a viewport to match the subregion of the swap chain.

    // 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. Bei Verwendung von Direct2D muss die Drehungstransformation angepasst werden, um die Quellregion entsprechend zu berücksichtigen.If Direct2D is being used, the rotation transform needs to be adjusted to compensate for the source region.

Erstellen einer Hardware-ÜberlagerungsSwapchain für UI-ElementeCreate a hardware overlay swap chain for UI elements

Mit der Verwendung der Swapchainskalierung ist der Nachteil verbunden, dass auch die UI herunterskaliert wird und ggf. verschwimmt und schwieriger zu nutzen ist.When using swap chain scaling, there is an inherent disadvantage in that the UI is also scaled down, potentially making it blurry and harder to use. Auf Geräten mit Hardwareunterstützung für Überlagerungsswapchains kann dieses Problem vollständig vermieden werden, indem die UI mit der systemeigenen Auflösung in einer Swapchain gerendert wird, die von den Echtzeitinhalten des Spiels getrennt ist.On devices with hardware support for overlay swap chains, this problem is alleviated entirely by rendering the UI at native resolution in a swap chain that's separate from the real-time game content. Beachten Sie, dass dieses Verfahren nur für CoreWindow-Swapchains gilt und nicht für die XAML-Interoperabilität verwendet werden kann.Note that this technique applies only to CoreWindow swap chains - it cannot be used with XAML interop.

Führen Sie die folgenden Schritte aus, um eine Vordergrund-Swapchain zu erstellen, bei der eine Hardwareüberlagerungsfunktion verwendet wird.Use the following steps to create a foreground swap chain that uses hardware overlay capability. Diese Schritte werden ausgeführt, nachdem wie oben beschrieben zuerst eine Swapchain für die Echtzeitinhalte des Spiels erstellt wurde.These steps are performed after first creating a swap chain for real-time game content as described above.

  1. Ermitteln Sie zuerst, ob Überlagerungen vom DXGI-Adapter unterstützt werden.First, determine whether the DXGI adapter supports overlays. Rufen Sie den DXGI-Ausgabeadapter aus der Swapchain ab:Get the DXGI output adapter from the swap chain:

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

    Überlagerungen werden vom DXGI-Adapter unterstützt, wenn der Ausgabeadapter für SupportsOverlays "True" zurückgibt.The DXGI adapter supports overlays if the output adapter returns True for SupportsOverlays.

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

    Beachten Sie    Wenn überlagert der DXGI-Adapter unterstützt wird, fahren Sie mit dem nächsten Schritt.Note   If the DXGI adapter supports overlays, continue to the next step. Wenn das Gerät Überlagerungen nicht unterstützt, ist das Rendern mit mehreren Swapchains nicht effizient.If the device does not support overlays, rendering with multiple swap chains will not be efficient. Rendern Sie die UI stattdessen mit reduzierter Auflösung in derselben Swapchain wie die Echtzeitinhalte des Spiels.Instead, render the UI at reduced resolution in the same swap chain as real-time game content.

     

  2. Erstellen Sie die Vordergrund-Swapchain mit IDXGIFactory2::CreateSwapChainForCoreWindow.Create the foreground swap chain with IDXGIFactory2::CreateSwapChainForCoreWindow. Die folgenden Optionen müssen festgelegt werden, der DXGI_AUSTAUSCHEN_Kette_DESC1 für angegebene der pDesc Parameter:The following options must be set in the DXGI_SWAP_CHAIN_DESC1 supplied to the pDesc parameter:

     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.
    

    Beachten Sie    legen Sie die DXGI_AUSTAUSCHEN_Kette_FLAG_VORDERGRUND_Ebene erneut alle Zeitpunkt, zu die SwapChain geändert wird.Note   Set the DXGI_SWAP_CHAIN_FLAG_FOREGROUND_LAYER again every time the swap chain is resized.

    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. Erhöhen Sie bei Verwendung von zwei Swapchains die maximale Framelatenz auf 2, damit der DXGI-Adapter genügend Zeit hat, um beide Swapchains gleichzeitig (innerhalb desselben VSync-Intervalls) darzustellen.When two swap chains are being used, increase the maximum frame latency to 2 so that the DXGI adapter has time to present both swap chains simultaneously (within the same VSync interval).

    // 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. Für Vordergrund-Swapchains wird immer prämultipliziertes Alpha verwendet.Foreground swap chains always use premultiplied alpha. Es wird davon ausgegangen, dass die Farbwerte der einzelnen Pixel vor der Darstellung des Frames bereits mit dem Alphawert multipliziert wurden.Each pixel's color values are expected to be already multiplied by the alpha value before the frame is presented. Ein BGRA-Pixel mit 100 % Weiß und einem Alpha von 50 % wird beispielsweise auf (0,5, 0,5, 0,5, 0,5) festgelegt.For example, a 100% white BGRA pixel at 50% alpha is set to (0.5, 0.5, 0.5, 0.5).

    Der alpha premultiplication Schritt kann in der Ausgabe-Fusions Phase ausgeführt werden, durch Anwenden einer app Blend-Status (finden Sie unter ID3D11BlendState) mit der D3D11_ RENDERN_Ziel_BLEND_DESC -Struktur SrcBlend Feld festgelegt, um D3D11_SRC_ALPHA.The alpha premultiplication step can be done in the output-merger stage by applying an app blend state (see ID3D11BlendState) with the D3D11_RENDER_TARGET_BLEND_DESC structure's SrcBlend field set to D3D11_SRC_ALPHA. Es können auch Ressourcen mit prämultiplizierten Alphawerten verwendet werden.Assets with pre-multiplied alpha values can also be used.

    Wenn der Schritt der Alphaprämultiplikation nicht erfolgt, erscheinen Farben für die Vordergrund-Swapchain heller als erwartet.If the alpha premultiplication step is not done, colors on the foreground swap chain will be brighter than expected.

  5. Je nachdem, ob die Vordergrund-Swapchain erstellt wurde, muss die Direct2D-Zeichenoberfläche für UI-Elemente möglicherweise der Vordergrund-Swapchain zugeordnet werden.Depending on whether the foreground swap chain was created, the Direct2D drawing surface for UI elements might need be associated with the foreground swap chain.

    Erstellen von Renderzielansichten:Creating render target views:

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

    Erstellen der Direct2D-Zeichenoberfläche:Creating the Direct2D drawing surface:

    if (m_foregroundSwapChain)
    {
        // Create a Direct2D target bitmap for the 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 a Direct2D target bitmap for the 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());
    
    // 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
            )
        );
    
  6. Stellen Sie die Vordergrund-Swapchain zusammen mit der skalierten Swapchain dar, die für die Echtzeitinhalte des Spiels verwendet wird.Present the foreground swap chain together with the scaled swap chain used for real-time game content. Da die Framelatenz für beide Swapchains auf 2 festgelegt wurde, können beide von DXGI innerhalb desselben VSync-Intervalls dargestellt werden.Since frame latency was set to 2 for both swap chains, DXGI can present them both within the same VSync interval.

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