From 0d018451fd5027140e8a9b86cf9cc0329c8a158e Mon Sep 17 00:00:00 2001 From: netborg <137700136+netborg-afps@users.noreply.github.com> Date: Fri, 28 Feb 2025 08:05:46 +0100 Subject: [PATCH] [dxvk] Optimize flush heuristic for low-latency Possibly can be optimized more, but just changing these numbers already had a huge effect, especially for games having a small number of submissions to begin with. --- src/dxvk/framepacer/dxvk_framepacer.cpp | 5 +++++ src/dxvk/framepacer/dxvk_framepacer.h | 2 +- src/util/util_flush.cpp | 16 ++++++++-------- src/util/util_flush.h | 5 +++++ 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/dxvk/framepacer/dxvk_framepacer.cpp b/src/dxvk/framepacer/dxvk_framepacer.cpp index a71b2d31d..944476817 100644 --- a/src/dxvk/framepacer/dxvk_framepacer.cpp +++ b/src/dxvk/framepacer/dxvk_framepacer.cpp @@ -2,6 +2,7 @@ #include "dxvk_framepacer_mode_low_latency.h" #include "dxvk_framepacer_mode_min_latency.h" #include "dxvk_options.h" +#include "../../util/util_flush.h" #include "../../util/util_env.h" #include "../../util/log/log.h" @@ -40,11 +41,15 @@ namespace dxvk { case FramePacerMode::LOW_LATENCY: Logger::info( "Frame pace: low-latency" ); + GpuFlushTracker::m_minPendingSubmissions = 1; + GpuFlushTracker::m_minChunkCount = 1; m_mode = std::make_unique(mode, &m_latencyMarkersStorage, options); break; case FramePacerMode::MIN_LATENCY: Logger::info( "Frame pace: min-latency" ); + GpuFlushTracker::m_minPendingSubmissions = 1; + GpuFlushTracker::m_minChunkCount = 1; m_mode = std::make_unique(mode, &m_latencyMarkersStorage); break; } diff --git a/src/dxvk/framepacer/dxvk_framepacer.h b/src/dxvk/framepacer/dxvk_framepacer.h index 38d740d1a..2ae4b76e8 100644 --- a/src/dxvk/framepacer/dxvk_framepacer.h +++ b/src/dxvk/framepacer/dxvk_framepacer.h @@ -136,7 +136,7 @@ namespace dxvk { // not implemented methods - void notifyCpuPresentBegin( uint64_t frameId) override { } + void notifyCpuPresentBegin( uint64_t frameId ) override { } void notifyCpuPresentEnd( uint64_t frameId ) override { } void notifyQueuePresentEnd( uint64_t frameId, VkResult status) override { } void notifyGpuExecutionBegin( uint64_t frameId ) override { } diff --git a/src/util/util_flush.cpp b/src/util/util_flush.cpp index 17d266901..4a2cd854b 100644 --- a/src/util/util_flush.cpp +++ b/src/util/util_flush.cpp @@ -2,6 +2,10 @@ namespace dxvk { + std::atomic GpuFlushTracker::m_minPendingSubmissions = { 2 }; + std::atomic GpuFlushTracker::m_minChunkCount = { 3 }; + std::atomic GpuFlushTracker::m_maxChunkCount = { 20 }; + GpuFlushTracker::GpuFlushTracker(GpuFlushType maxType) : m_maxType(maxType) { @@ -11,10 +15,6 @@ namespace dxvk { GpuFlushType flushType, uint64_t chunkId, uint32_t lastCompleteSubmissionId) { - constexpr uint32_t minPendingSubmissions = 2; - - constexpr uint32_t minChunkCount = 3u; - constexpr uint32_t maxChunkCount = 20u; // Do not flush if there is nothing to flush uint32_t chunkCount = uint32_t(chunkId - m_lastFlushChunkId); @@ -42,14 +42,14 @@ namespace dxvk { case GpuFlushType::ImplicitStrongHint: { // Flush aggressively with a strong hint to reduce readback latency. - return chunkCount >= minChunkCount; + return chunkCount >= m_minChunkCount; } case GpuFlushType::ImplicitMediumHint: case GpuFlushType::ImplicitWeakHint: { // Aim for a higher number of chunks per submission with // a weak hint in order to avoid submitting too often. - if (chunkCount < 2 * minChunkCount) + if (chunkCount < 2 * m_minChunkCount) return false; // Actual heuristic is shared with synchronization commands @@ -60,13 +60,13 @@ namespace dxvk { // required if the application is spinning on a query or resource. uint32_t pendingSubmissions = uint32_t(m_lastFlushSubmissionId - lastCompleteSubmissionId); - if (pendingSubmissions < minPendingSubmissions) + if (pendingSubmissions < m_minPendingSubmissions) return true; // Use the number of pending submissions to decide whether to flush. Other // than ignoring the minimum chunk count condition, we should treat this // the same as weak hints to avoid unnecessary synchronization. - uint32_t threshold = std::min(maxChunkCount, pendingSubmissions * minChunkCount); + uint32_t threshold = std::min(m_maxChunkCount.load(), pendingSubmissions * m_minChunkCount.load()); return chunkCount >= threshold; } } diff --git a/src/util/util_flush.h b/src/util/util_flush.h index 5d593649d..8673f404f 100644 --- a/src/util/util_flush.h +++ b/src/util/util_flush.h @@ -3,6 +3,7 @@ #include #include #include +#include namespace dxvk { @@ -64,6 +65,10 @@ namespace dxvk { uint64_t chunkId, uint64_t submissionId); + static std::atomic m_minPendingSubmissions; + static std::atomic m_minChunkCount; + static std::atomic m_maxChunkCount; + private: GpuFlushType m_maxType = GpuFlushType::ImplicitWeakHint;