From 93269aa330b1521e70700ae62c47477a700e6f24 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Fri, 17 Jan 2025 22:21:55 +0100 Subject: [PATCH] [d3d11] Implement latency tracking --- src/d3d11/d3d11_context_imm.cpp | 8 +++-- src/d3d11/d3d11_context_imm.h | 3 +- src/d3d11/d3d11_swapchain.cpp | 59 +++++++++++++++++++++++++++++++-- src/d3d11/d3d11_swapchain.h | 6 ++++ 4 files changed, 70 insertions(+), 6 deletions(-) diff --git a/src/d3d11/d3d11_context_imm.cpp b/src/d3d11/d3d11_context_imm.cpp index a4d46d3b3..4c7e6db0e 100644 --- a/src/d3d11/d3d11_context_imm.cpp +++ b/src/d3d11/d3d11_context_imm.cpp @@ -861,11 +861,15 @@ namespace dxvk { } - void D3D11ImmediateContext::EndFrame() { + void D3D11ImmediateContext::EndFrame( + Rc LatencyTracker) { D3D10DeviceLock lock = LockContext(); - EmitCs([] (DxvkContext* ctx) { + EmitCs([ + cTracker = std::move(LatencyTracker) + ] (DxvkContext* ctx) { ctx->endFrame(); + ctx->endLatencyTracking(cTracker); }); } diff --git a/src/d3d11/d3d11_context_imm.h b/src/d3d11/d3d11_context_imm.h index 68958043b..b9f8748eb 100644 --- a/src/d3d11/d3d11_context_imm.h +++ b/src/d3d11/d3d11_context_imm.h @@ -169,7 +169,8 @@ namespace dxvk { void SynchronizeDevice(); - void EndFrame(); + void EndFrame( + Rc LatencyTracker); bool WaitForResource( const DxvkPagedResource& Resource, diff --git a/src/d3d11/d3d11_swapchain.cpp b/src/d3d11/d3d11_swapchain.cpp index ee60e5da7..33f75669b 100644 --- a/src/d3d11/d3d11_swapchain.cpp +++ b/src/d3d11/d3d11_swapchain.cpp @@ -2,6 +2,8 @@ #include "d3d11_device.h" #include "d3d11_swapchain.h" +#include "../dxvk/dxvk_latency_builtin.h" + #include "../util/util_win32_compat.h" namespace dxvk { @@ -80,6 +82,7 @@ namespace dxvk { m_presenter->destroyResources(); DestroyFrameLatencyEvent(); + DestroyLatencyTracker(); } @@ -279,6 +282,18 @@ namespace dxvk { // applications using the semaphore may deadlock. This works because // we do not increment the frame ID in those situations. SyncFrameLatency(); + + // Ignore latency stuff if presentation failed + DxvkLatencyStats latencyStats = { }; + + if (hr == S_OK && m_latency) { + latencyStats = m_latency->getStatistics(m_frameId); + m_latency->sleepAndBeginFrame(m_frameId + 1, std::abs(m_targetFrameRate)); + } + + if (m_latencyHud) + m_latencyHud->accumulateStats(latencyStats); + return hr; } @@ -364,17 +379,23 @@ namespace dxvk { auto immediateContext = m_parent->GetContext(); auto immediateContextLock = immediateContext->LockContext(); - immediateContext->EndFrame(); + immediateContext->EndFrame(m_latency); immediateContext->Flush(); m_presenter->setSyncInterval(SyncInterval); // Presentation semaphores and WSI swap chain image + if (m_latency) + m_latency->notifyCpuPresentBegin(m_frameId + 1u); + PresenterSync sync; Rc backBuffer; VkResult status = m_presenter->acquireNextImage(sync, backBuffer); + if (status != VK_SUCCESS && m_latency) + m_latency->discardTimings(); + if (status < 0) return E_FAIL; @@ -402,6 +423,7 @@ namespace dxvk { cSwapImage = GetBackBufferView(), cSync = sync, cPresenter = m_presenter, + cLatency = m_latency, cColorSpace = m_colorSpace, cFrameId = m_frameId ] (DxvkContext* ctx) { @@ -425,13 +447,27 @@ namespace dxvk { ctx->synchronizeWsi(cSync); ctx->flushCommandList(nullptr); - cDevice->presentImage(cPresenter, cFrameId, nullptr, 0, nullptr); + cDevice->presentImage(cPresenter, cFrameId, cLatency, cFrameId, nullptr); }); if (m_backBuffers.size() > 1u) RotateBackBuffers(immediateContext); immediateContext->FlushCsChunk(); + + if (m_latency) { + m_latency->notifyCpuPresentEnd(m_frameId); + + immediateContext->SynchronizeCsThread(DxvkCsThread::SynchronizeAll); + + immediateContext->EmitCs([ + cLatency = m_latency, + cFrameId = m_frameId + ] (DxvkContext* ctx) { + ctx->beginLatencyTracking(cLatency, cFrameId + 1u); + }); + } + return S_OK; } @@ -479,6 +515,8 @@ namespace dxvk { m_presenter->setSurfaceFormat(GetSurfaceFormat(m_desc.Format)); m_presenter->setSurfaceExtent({ m_desc.Width, m_desc.Height }); m_presenter->setFrameRateLimit(m_targetFrameRate, GetActualFrameLatency()); + + m_latency = m_device->createLatencyTracker(m_presenter); } @@ -555,9 +593,13 @@ namespace dxvk { void D3D11SwapChain::CreateBlitter() { Rc hud = hud::Hud::createHud(m_device); - if (hud) + if (hud) { hud->addItem("api", 1, GetApiName()); + if (m_latency) + m_latencyHud = hud->addItem("latency", 4); + } + m_blitter = new DxvkSwapchainBlitter(m_device, std::move(hud)); } @@ -567,6 +609,17 @@ namespace dxvk { } + void D3D11SwapChain::DestroyLatencyTracker() { + // Need to make sure the context stops using + // the tracker for submissions + m_parent->GetContext()->InjectCs([ + cLatency = m_latency + ] (DxvkContext* ctx) { + ctx->endLatencyTracking(cLatency); + }); + } + + void D3D11SwapChain::SyncFrameLatency() { // Wait for the sync event so that we respect the maximum frame latency m_frameLatencySignal->wait(m_frameId - GetActualFrameLatency()); diff --git a/src/d3d11/d3d11_swapchain.h b/src/d3d11/d3d11_swapchain.h index 0de695270..cb51182d0 100644 --- a/src/d3d11/d3d11_swapchain.h +++ b/src/d3d11/d3d11_swapchain.h @@ -4,6 +4,7 @@ #include "../dxvk/hud/dxvk_hud.h" +#include "../dxvk/dxvk_latency.h" #include "../dxvk/dxvk_swapchain_blitter.h" #include "../util/sync/sync_signal.h" @@ -107,6 +108,7 @@ namespace dxvk { Rc m_presenter; Rc m_blitter; + Rc m_latency; small_vector, 4> m_backBuffers; @@ -123,6 +125,8 @@ namespace dxvk { dxvk::mutex m_frameStatisticsLock; DXGI_VK_FRAME_STATISTICS m_frameStatistics = { }; + Rc m_latencyHud; + Rc GetBackBufferView(); HRESULT PresentImage(UINT SyncInterval); @@ -139,6 +143,8 @@ namespace dxvk { void DestroyFrameLatencyEvent(); + void DestroyLatencyTracker(); + void SyncFrameLatency(); uint32_t GetActualFrameLatency();