From 775b3dfe715859bf0031ad9531938ebaf5670312 Mon Sep 17 00:00:00 2001 From: netborg <137700136+netborg-afps@users.noreply.github.com> Date: Fri, 28 Feb 2025 11:23:02 +0100 Subject: [PATCH] Revert "[dxvk] Remove dxvk.lowLatencyAllowCpuFramesOverlap config variable" This reverts commit c802bdf42e993b467f8fa18b2db52da5841164d1 and makes small adjustments. Until we have a proper synchronization in place between emitting Cs triggered by the app thread, and fetching them from the queue, to measure the CsThread-caused delay, this config option is still useful for running some rare CsThread-limited games. --- src/dxvk/dxvk_options.cpp | 2 ++ src/dxvk/framepacer/dxvk_framepacer.cpp | 1 + src/dxvk/framepacer/dxvk_framepacer.h | 1 + src/dxvk/framepacer/dxvk_framepacer_mode.h | 4 ++++ .../dxvk_framepacer_mode_low_latency.cpp | 19 +++++++++++++++++++ .../dxvk_framepacer_mode_low_latency.h | 11 +++++++++-- 6 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/dxvk/dxvk_options.cpp b/src/dxvk/dxvk_options.cpp index a31778e18..85fc3ec3e 100644 --- a/src/dxvk/dxvk_options.cpp +++ b/src/dxvk/dxvk_options.cpp @@ -20,6 +20,8 @@ namespace dxvk { allowFse = config.getOption ("dxvk.allowFse", false); framePace = config.getOption("dxvk.framePace", ""); lowLatencyOffset = config.getOption ("dxvk.lowLatencyOffset", 0); + lowLatencyAllowCpuFramesOverlap + = config.getOption ("dxvk.lowLatencyAllowCpuFramesOverlap", true); deviceFilter = config.getOption("dxvk.deviceFilter", ""); tilerMode = config.getOption("dxvk.tilerMode", Tristate::Auto); } diff --git a/src/dxvk/framepacer/dxvk_framepacer.cpp b/src/dxvk/framepacer/dxvk_framepacer.cpp index 944476817..3ff8791a9 100644 --- a/src/dxvk/framepacer/dxvk_framepacer.cpp +++ b/src/dxvk/framepacer/dxvk_framepacer.cpp @@ -71,6 +71,7 @@ namespace dxvk { m_mode->signalGpuStart ( firstFrameId-1 ); m_mode->signalRenderFinished ( firstFrameId-1 ); + m_mode->signalCsFinished ( firstFrameId ); } diff --git a/src/dxvk/framepacer/dxvk_framepacer.h b/src/dxvk/framepacer/dxvk_framepacer.h index 2ae4b76e8..0d5befc02 100644 --- a/src/dxvk/framepacer/dxvk_framepacer.h +++ b/src/dxvk/framepacer/dxvk_framepacer.h @@ -53,6 +53,7 @@ namespace dxvk { auto now = high_resolution_clock::now(); LatencyMarkers* m = m_latencyMarkersStorage.getMarkers(frameId); m->csFinished = std::chrono::duration_cast(now - m->start).count(); + m_mode->signalCsFinished( frameId ); } void notifySubmit( uint64_t frameId ) override { diff --git a/src/dxvk/framepacer/dxvk_framepacer_mode.h b/src/dxvk/framepacer/dxvk_framepacer_mode.h index 2109bd57b..98404ee71 100644 --- a/src/dxvk/framepacer/dxvk_framepacer_mode.h +++ b/src/dxvk/framepacer/dxvk_framepacer_mode.h @@ -44,6 +44,9 @@ namespace dxvk { void signalGpuStart( uint64_t frameId ) { if (m_mode) m_fenceGpuStart.signal(frameId); } + void signalCsFinished( uint64_t frameId ) { + if (m_mode) m_fenceCsFinished.signal(frameId); } + void setTargetFrameRate( double frameRate ) { if (!m_fpsLimitEnvOverride && frameRate > 1.0) m_fpsLimitFrametime.store( 1'000'000/frameRate ); @@ -65,6 +68,7 @@ namespace dxvk { sync::Fence m_fenceGpuStart = { sync::Fence(DXGI_MAX_SWAP_CHAIN_BUFFERS) }; sync::Fence m_fenceGpuFinished = { sync::Fence(DXGI_MAX_SWAP_CHAIN_BUFFERS) }; + sync::Fence m_fenceCsFinished = { sync::Fence(DXGI_MAX_SWAP_CHAIN_BUFFERS) }; }; diff --git a/src/dxvk/framepacer/dxvk_framepacer_mode_low_latency.cpp b/src/dxvk/framepacer/dxvk_framepacer_mode_low_latency.cpp index 4af77f051..4e39145b4 100644 --- a/src/dxvk/framepacer/dxvk_framepacer_mode_low_latency.cpp +++ b/src/dxvk/framepacer/dxvk_framepacer_mode_low_latency.cpp @@ -10,6 +10,15 @@ namespace dxvk { } + bool getLowLatencyAllowCpuFramesOverlapFromEnv( bool& allowOverlap ) { + int32_t o; + if (!FramePacerMode::getIntFromEnv("DXVK_LOW_LATENCY_ALLOW_CPU_FRAMES_OVERLAP", &o)) + return false; + allowOverlap = (bool) o; + return true; + } + + int32_t LowLatencyMode::getLowLatencyOffset( const DxvkOptions& options ) { int32_t offset = options.lowLatencyOffset; int32_t o; @@ -21,4 +30,14 @@ namespace dxvk { return offset; } + + bool LowLatencyMode::getLowLatencyAllowCpuFramesOverlap( const DxvkOptions& options ) { + bool allowOverlap = options.lowLatencyAllowCpuFramesOverlap; + bool o; + if (getLowLatencyAllowCpuFramesOverlapFromEnv(o)) + allowOverlap = o; + return allowOverlap; + } + + } diff --git a/src/dxvk/framepacer/dxvk_framepacer_mode_low_latency.h b/src/dxvk/framepacer/dxvk_framepacer_mode_low_latency.h index 24d8ab60e..59d10909e 100644 --- a/src/dxvk/framepacer/dxvk_framepacer_mode_low_latency.h +++ b/src/dxvk/framepacer/dxvk_framepacer_mode_low_latency.h @@ -44,17 +44,21 @@ namespace dxvk { LowLatencyMode(Mode mode, LatencyMarkersStorage* storage, const DxvkOptions& options) : FramePacerMode(mode, storage), - m_lowLatencyOffset(getLowLatencyOffset(options)) { + m_lowLatencyOffset(getLowLatencyOffset(options)), + m_allowCpuFramesOverlap(getLowLatencyAllowCpuFramesOverlap(options)) { Logger::info( str::format("Using lowLatencyOffset: ", m_lowLatencyOffset) ); + Logger::info( str::format("Using lowLatencyAllowCpuFramesOverlap: ", m_allowCpuFramesOverlap) ); } ~LowLatencyMode() {} void startFrame( uint64_t frameId ) override { - using std::chrono::duration_cast; + if (!m_allowCpuFramesOverlap) + m_fenceCsFinished.wait( frameId-1 ); + m_fenceGpuStart.wait( frameId-1 ); time_point now = high_resolution_clock::now(); @@ -227,7 +231,10 @@ namespace dxvk { int32_t getLowLatencyOffset( const DxvkOptions& options ); + bool getLowLatencyAllowCpuFramesOverlap( const DxvkOptions& options ); + const int32_t m_lowLatencyOffset; + const bool m_allowCpuFramesOverlap; Sleep::TimePoint m_lastStart = { high_resolution_clock::now() }; std::array m_props;