From fa6c32684ace2ece04db57a2e153c7ccd869bc9b Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sat, 18 Jan 2025 00:23:24 +0100 Subject: [PATCH] [dxvk] Add latency tracker to presenter --- src/dxvk/dxvk_presenter.cpp | 22 ++++++++++++++++++---- src/dxvk/dxvk_presenter.h | 16 +++++++++++----- src/dxvk/dxvk_queue.cpp | 3 ++- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/dxvk/dxvk_presenter.cpp b/src/dxvk/dxvk_presenter.cpp index 096f2ffe2..769d5406f 100644 --- a/src/dxvk/dxvk_presenter.cpp +++ b/src/dxvk/dxvk_presenter.cpp @@ -228,7 +228,10 @@ namespace dxvk { } - void Presenter::signalFrame(VkResult result, uint64_t frameId) { + void Presenter::signalFrame( + VkResult result, + uint64_t frameId, + const Rc& tracker) { if (m_signal == nullptr || !frameId) return; @@ -236,15 +239,19 @@ namespace dxvk { std::lock_guard lock(m_frameMutex); PresenterFrame frame = { }; - frame.result = result; - frame.mode = m_presentMode; - frame.frameId = frameId; + frame.frameId = frameId; + frame.tracker = tracker; + frame.mode = m_presentMode; + frame.result = result; m_frameQueue.push(frame); m_frameCond.notify_one(); } else { m_fpsLimiter.delay(); m_signal->signal(frameId); + + if (tracker) + tracker->notifyGpuPresentEnd(frameId); } m_lastFrameId.store(frameId, std::memory_order_release); @@ -1058,6 +1065,13 @@ namespace dxvk { Logger::err(str::format("Presenter: vkWaitForPresentKHR failed: ", vr)); } + // Signal latency tracker right away to get more accurate + // measurements if the frame rate limiter is enabled. + if (frame.tracker) { + frame.tracker->notifyGpuPresentEnd(frame.frameId); + frame.tracker = nullptr; + } + // Apply FPS limtier here to align it as closely with scanout as we can, // and delay signaling the frame latency event to emulate behaviour of a // low refresh rate display as closely as we can. diff --git a/src/dxvk/dxvk_presenter.h b/src/dxvk/dxvk_presenter.h index 8fe7d9aae..633ca7753 100644 --- a/src/dxvk/dxvk_presenter.h +++ b/src/dxvk/dxvk_presenter.h @@ -18,6 +18,7 @@ #include "dxvk_format.h" #include "dxvk_image.h" +#include "dxvk_latency.h" namespace dxvk { @@ -55,9 +56,10 @@ namespace dxvk { * \brief Queued frame */ struct PresenterFrame { - uint64_t frameId = 0u; - VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR; - VkResult result = VK_NOT_READY; + uint64_t frameId = 0u; + Rc tracker = nullptr; + VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR; + VkResult result = VK_NOT_READY; }; /** @@ -135,9 +137,13 @@ namespace dxvk { * called before GPU work prior to the present submission has * completed in order to maintain consistency. * \param [in] result Presentation result - * \param [in] frameId Frame number + * \param [in] frameId Frame ID + * \param [in] tracker Latency tracker */ - void signalFrame(VkResult result, uint64_t frameId); + void signalFrame( + VkResult result, + uint64_t frameId, + const Rc& tracker); /** * \brief Changes sync interval diff --git a/src/dxvk/dxvk_queue.cpp b/src/dxvk/dxvk_queue.cpp index dcf5f900a..4e3855ba9 100644 --- a/src/dxvk/dxvk_queue.cpp +++ b/src/dxvk/dxvk_queue.cpp @@ -260,7 +260,8 @@ namespace dxvk { // Signal the frame and then immediately destroy the reference. // This is necessary since the front-end may want to explicitly // destroy the presenter object. - entry.present.presenter->signalFrame(entry.result, entry.present.frameId); + entry.present.presenter->signalFrame(entry.result, + entry.present.frameId, entry.latency.tracker); entry.present.presenter = nullptr; }