diff --git a/src/d3d11/d3d11_context_imm.h b/src/d3d11/d3d11_context_imm.h index 6310d9f2..7831cd55 100644 --- a/src/d3d11/d3d11_context_imm.h +++ b/src/d3d11/d3d11_context_imm.h @@ -11,6 +11,7 @@ namespace dxvk { class D3D11CommonTexture; class D3D11ImmediateContext : public D3D11DeviceContext { + friend class D3D11SwapChain; public: D3D11ImmediateContext( diff --git a/src/d3d11/d3d11_swapchain.cpp b/src/d3d11/d3d11_swapchain.cpp index 875bf036..745ffedd 100644 --- a/src/d3d11/d3d11_swapchain.cpp +++ b/src/d3d11/d3d11_swapchain.cpp @@ -181,8 +181,6 @@ namespace dxvk { if (std::exchange(m_dirty, false)) RecreateSwapChain(vsync); - FlushImmediateContext(); - HRESULT hr = S_OK; try { @@ -200,6 +198,16 @@ namespace dxvk { void D3D11SwapChain::PresentImage(UINT SyncInterval) { + Com deviceContext = nullptr; + m_parent->GetImmediateContext(&deviceContext); + + // Flush pending rendering commands before + auto immediateContext = static_cast(deviceContext.ptr()); + immediateContext->Flush(); + + if (!m_device->hasAsyncPresent()) + immediateContext->SynchronizeCsThread(); + // Wait for the sync event so that we respect the maximum frame latency auto syncEvent = m_dxgiDevice->GetFrameSyncEvent(m_desc.BufferCount); syncEvent->wait(); @@ -305,16 +313,41 @@ namespace dxvk { if (i + 1 >= SyncInterval) m_context->queueSignal(syncEvent); + SubmitPresent(immediateContext, sync); + } + } + + + void D3D11SwapChain::SubmitPresent( + D3D11ImmediateContext* pContext, + const vk::PresenterSync& Sync) { + if (m_device->hasAsyncPresent()) { + // Present from CS thread so that we don't + // have to synchronize with it first. + m_presentStatus.result = VK_NOT_READY; + + pContext->EmitCs([this, + cSync = Sync, + cCommandList = m_context->endRecording() + ] (DxvkContext* ctx) { + m_device->submitCommandList(cCommandList, + cSync.acquire, cSync.present); + + m_device->presentImage(m_presenter, + cSync.present, &m_presentStatus); + }); + + pContext->FlushCsChunk(); + } else { + // Safe path, present from calling thread m_device->submitCommandList( m_context->endRecording(), - sync.acquire, sync.present); + Sync.acquire, Sync.present); m_device->presentImage(m_presenter, - sync.present, &m_presentStatus); + Sync.present, &m_presentStatus); - if (m_presentStatus.result != VK_NOT_READY - && m_presentStatus.result != VK_SUCCESS) - RecreateSwapChain(m_vsync); + SynchronizePresent(); } } @@ -412,18 +445,6 @@ namespace dxvk { } - void D3D11SwapChain::FlushImmediateContext() { - Com deviceContext = nullptr; - m_parent->GetImmediateContext(&deviceContext); - - // The presentation code is run from the main rendering thread - // rather than the command stream thread, so we synchronize. - auto immediateContext = static_cast(deviceContext.ptr()); - immediateContext->Flush(); - immediateContext->SynchronizeCsThread(); - } - - void D3D11SwapChain::CreateBackBuffer() { // Explicitly destroy current swap image before // creating a new one to free up resources diff --git a/src/d3d11/d3d11_swapchain.h b/src/d3d11/d3d11_swapchain.h index ffa3d1fb..de42f172 100644 --- a/src/d3d11/d3d11_swapchain.h +++ b/src/d3d11/d3d11_swapchain.h @@ -122,10 +122,12 @@ namespace dxvk { void PresentImage(UINT SyncInterval); + void SubmitPresent( + D3D11ImmediateContext* pContext, + const vk::PresenterSync& Sync); + void SynchronizePresent(); - void FlushImmediateContext(); - void RecreateSwapChain( BOOL Vsync);