Not
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Lär dig hur du skapar skalbara växlingskedjor för snabbare återgivning på mobila enheter och använder växlingskedjor för överlägg (när det är tillgängligt) för att öka den visuella kvaliteten.
Växlingskedjor i DirectX 11.2
Med Direct3D 11.2 kan du skapa UWP-appar (Universal Windows Platform) med växlingskedjor som skalas upp från icke-inbyggda (reducerade) upplösningar, vilket möjliggör snabbare fyllningshastigheter. Direct3D 11.2 innehåller även API:er för rendering med maskinvaruöverlägg så att du kan presentera ett användargränssnitt i en annan växlingskedja (swapchain) med ursprunglig upplösning. Detta gör att ditt spel kan rendera användargränssnittet med full nativ upplösning samtidigt som du behåller en hög framerate, vilket möjliggör bästa möjliga utnyttjande av mobila enheter och skärmar med hög DPI (till exempel 3840 × 2160). Den här artikeln beskriver hur du använder överlappande växlingskedjor.
Direct3D 11.2 introducerar också en ny funktion för minskad latens med flipmodell-växlingskedjor. Se Minska svarstiden med DXGI 1.3-växlingskedjor.
Använd swapkedjeskalning
När ditt spel körs på maskinvara på lägre nivå – eller maskinvara som är optimerad för energibesparingar – kan det vara fördelaktigt att rendera spelinnehåll i realtid med en lägre upplösning än vad bildskärmen har inbyggd kapacitet för. För att göra detta måste växlingskedjan som används för rendering av spelinnehåll vara mindre än den inbyggda upplösningen, eller så måste en underregion i byteskedjan användas.
Skapa först en swap-kedja på fullständig ursprunglig upplösning.
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) );Välj sedan en underregion i växlingskedjan för att skala upp genom att ställa in källstorleken på en reducerad upplösning.
Exemplet DX Foreground Swap Chains beräknar en reducerad storlek baserat på en procentandel:
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 ) );Skapa en vyport som matchar underregionen för växlingskedjan.
// 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);Om Direct2D används måste rotationstransformeringen justeras för att kompensera för källregionen.
Skapa en byteskedja för maskinvaruöverlägg för UI-element
När du använder växlingskedjans skalning finns det en inneboende nackdel eftersom användargränssnittet också skalas ned, vilket kan göra det suddigt och svårare att använda. På enheter med maskinvarustöd för överläggsväxlingskedjor lindras det här problemet helt genom att användargränssnittet återges med inbyggd upplösning i en växlingskedja som är skild från realtidsspelinnehållet. Observera att den här tekniken endast gäller för CoreWindow-växlingskedjor – den kan inte användas med XAML-interop.
Använd följande steg för att skapa en förgrundsväxlingskedja som använder maskinvaruöverläggsfunktioner. De här stegen utförs efter att du först har skapat en växlingskedja för spelinnehåll i realtid enligt beskrivningen ovan.
Bestäm först om DXGI-adaptern stöder överlägg. Hämta DXGI-utgångsadaptern från swapkedjan:
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) );Om output-adaptern returnerar Sann för SupportsOverlays, stöder DXGI-adaptern överlägg.
m_overlaySupportExists = dxgiOutput2->SupportsOverlays() ? true : false;Obs Om DXGI-adaptern stöder överlägg fortsätter du till nästa steg. Om enheten inte stöder överlägg blir återgivningen med flera växlingskedjor inte effektiv. Rendera i stället användargränssnittet med reducerad upplösning i samma växlingskedja som realtidsspelinnehåll.
Skapa förgrundsväxlingskedjan med IDXGIFactory2::CreateSwapChainForCoreWindow. Följande alternativ måste anges i DXGI_SWAP_CHAIN_DESC1 som tillhandahålls till parametern pDesc:
- Ange flaggan DXGI_SWAP_CHAIN_FLAG_FOREGROUND_LAYER för växlingskedjan för att beteckna en förgrundsväxlingskedja.
- Använd flaggan DXGI_ALPHA_MODE_PREMULTIPLIED alfaläge. Växlingskedjor för förgrund är alltid premultiplicerade.
- Ange DXGI_SCALING_NONE . Förgrundsväxlingskedjor körs alltid med inbyggd upplösning.
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.Obs Ange DXGI_SWAP_CHAIN_FLAG_FOREGROUND_LAYER igen varje gång swap-kedjan ändras i storlek.
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. );När två växlingskedjor används ökar du den maximala bildrutefördröjningen till 2 så att DXGI-adaptern har tid att presentera båda växlingskedjorna samtidigt (inom samma VSync-intervall).
// 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 ) ); }Förgrundswap-kedjor använder alltid förmultipliserad alfa. Varje pixels färgvärden förväntas redan multipliceras med alfavärdet innan ramen visas. Till exempel är en 100% vit BGRA-pixel vid 50% alfa inställd på (0,5, 0,5, 0,5, 0,5).
Alfapremultiplication-steget kan utföras i utdatasammanslagningsfasen genom att tillämpa ett appblandningstillstånd (se ID3D11BlendState) med D3D11_RENDER_TARGET_BLEND_DESC-strukturensSrcBlend-fält inställt på D3D11_SRC_ALPHA. Tillgångar med förmultiplicerade alfa-värden kan också användas.
Om alfapremultiplication-steget inte är klart blir färgerna i förgrundsväxlingskedjan ljusare än förväntat.
Beroende på om förgrundsväxlingskedjan har skapats kan Direct2D-ritytan för gränssnittselementen behöva associeras med förgrundsväxlingskedjan.
Skapa återgivningsmålvyer:
// 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 ) ); }Att skapa Direct2D-ritytan:
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 ) );Presentera förgrundsväxlingskedjan tillsammans med den skalbara växlingskedja som används för spelinnehåll i realtid. Eftersom bildrutefördröjningen har angetts till 2 för båda växlingskedjorna kan DXGI presentera dem båda inom samma VSync-intervall.
// 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); } }