From 58d8ea2d31b372bad6a6986889fc16bb084cc6bb Mon Sep 17 00:00:00 2001 From: Danylo Piliaiev Date: Thu, 16 May 2024 13:50:37 +0200 Subject: [PATCH] [d3d11,d3d9,util] Add a config option for reproducible VK output It ensures that for the same D3D commands the output VK commands don't change between runs. Useful for comparative benchmarking, can negatively affect performance. Signed-off-by: Danylo Piliaiev --- dxvk.conf | 14 ++++++++++++++ src/d3d11/d3d11_context_imm.cpp | 1 + src/d3d11/d3d11_options.cpp | 1 + src/d3d11/d3d11_options.h | 5 +++++ src/d3d9/d3d9_device.cpp | 1 + src/d3d9/d3d9_options.cpp | 1 + src/d3d9/d3d9_options.h | 5 +++++ src/util/util_flush.cpp | 9 +++++++++ src/util/util_flush.h | 4 ++++ 9 files changed, 41 insertions(+) diff --git a/dxvk.conf b/dxvk.conf index 46edbb9c0..3543876a5 100644 --- a/dxvk.conf +++ b/dxvk.conf @@ -312,6 +312,20 @@ # d3d11.exposeDriverCommandLists = True +# Reproducible Command Stream +# +# Ensure that for the same D3D commands the output VK commands +# don't change between runs. Useful for comparative benchmarking, +# can negatively affect performance and can break some games +# that don't use queries correctly. +# +# Supported values: +# - True/False + +# d3d11.reproducibleCommandStream = False +# d3d9.reproducibleCommandStream = False + + # Sets number of pipeline compiler threads. # # If the graphics pipeline library feature is enabled, the given diff --git a/src/d3d11/d3d11_context_imm.cpp b/src/d3d11/d3d11_context_imm.cpp index 466e9a967..aa379d41d 100644 --- a/src/d3d11/d3d11_context_imm.cpp +++ b/src/d3d11/d3d11_context_imm.cpp @@ -19,6 +19,7 @@ namespace dxvk { m_csThread(Device, Device->createContext(DxvkContextType::Primary)), m_maxImplicitDiscardSize(pParent->GetOptions()->maxImplicitDiscardSize), m_submissionFence(new sync::CallbackFence()), + m_flushTracker(pParent->GetOptions()->reproducibleCommandStream), m_multithread(this, false, pParent->GetOptions()->enableContextLock), m_videoContext(this, Device) { EmitCs([ diff --git a/src/d3d11/d3d11_options.cpp b/src/d3d11/d3d11_options.cpp index ddbfe0a9a..c6b41ecb7 100644 --- a/src/d3d11/d3d11_options.cpp +++ b/src/d3d11/d3d11_options.cpp @@ -33,6 +33,7 @@ namespace dxvk { this->maxFrameRate = config.getOption("dxgi.maxFrameRate", 0); this->exposeDriverCommandLists = config.getOption("d3d11.exposeDriverCommandLists", true); this->longMad = config.getOption("d3d11.longMad", false); + this->reproducibleCommandStream = config.getOption("d3d11.reproducibleCommandStream", false); // Clamp LOD bias so that people don't abuse this in unintended ways this->samplerLodBias = dxvk::fclamp(this->samplerLodBias, -2.0f, 1.0f); diff --git a/src/d3d11/d3d11_options.h b/src/d3d11/d3d11_options.h index 5cd548cd5..a5e21e17e 100644 --- a/src/d3d11/d3d11_options.h +++ b/src/d3d11/d3d11_options.h @@ -123,6 +123,11 @@ namespace dxvk { /// Should we make our Mads a FFma or do it the long way with an FMul and an FAdd? bool longMad; + + /// Ensure that for the same D3D commands the output VK commands + /// don't change between runs. Useful for comparative benchmarking, + /// can negatively affect performance. + bool reproducibleCommandStream; }; } \ No newline at end of file diff --git a/src/d3d9/d3d9_device.cpp b/src/d3d9/d3d9_device.cpp index 87d39eeb7..2a4a7b32c 100644 --- a/src/d3d9/d3d9_device.cpp +++ b/src/d3d9/d3d9_device.cpp @@ -56,6 +56,7 @@ namespace dxvk { , m_csThread ( dxvkDevice, dxvkDevice->createContext(DxvkContextType::Primary) ) , m_csChunk ( AllocCsChunk() ) , m_submissionFence (new sync::Fence()) + , m_flushTracker (m_d3d9Options.reproducibleCommandStream) , m_d3d9Interop ( this ) , m_d3d9On12 ( this ) , m_d3d8Bridge ( this ) { diff --git a/src/d3d9/d3d9_options.cpp b/src/d3d9/d3d9_options.cpp index 1845daabd..0884819f1 100644 --- a/src/d3d9/d3d9_options.cpp +++ b/src/d3d9/d3d9_options.cpp @@ -77,6 +77,7 @@ namespace dxvk { this->samplerLodBias = config.getOption ("d3d9.samplerLodBias", 0.0f); this->clampNegativeLodBias = config.getOption ("d3d9.clampNegativeLodBias", false); this->countLosableResources = config.getOption ("d3d9.countLosableResources", true); + this->reproducibleCommandStream = config.getOption ("d3d9.reproducibleCommandStream", false); // Clamp LOD bias so that people don't abuse this in unintended ways this->samplerLodBias = dxvk::fclamp(this->samplerLodBias, -2.0f, 1.0f); diff --git a/src/d3d9/d3d9_options.h b/src/d3d9/d3d9_options.h index 034c85d3a..824ba076c 100644 --- a/src/d3d9/d3d9_options.h +++ b/src/d3d9/d3d9_options.h @@ -155,6 +155,11 @@ namespace dxvk { /// Disable counting losable resources and rejecting calls to Reset() if any are still alive bool countLosableResources; + + /// Ensure that for the same D3D commands the output VK commands + /// don't change between runs. Useful for comparative benchmarking, + /// can negatively affect performance. + bool reproducibleCommandStream; }; } diff --git a/src/util/util_flush.cpp b/src/util/util_flush.cpp index a4d91bd43..c2b1ce6a6 100644 --- a/src/util/util_flush.cpp +++ b/src/util/util_flush.cpp @@ -2,6 +2,12 @@ namespace dxvk { + GpuFlushTracker::GpuFlushTracker( + bool ensureReproducibleHeuristic) + : m_ensureReproducibleHeuristic(ensureReproducibleHeuristic) { + + } + bool GpuFlushTracker::considerFlush( GpuFlushType flushType, uint64_t chunkId, @@ -17,6 +23,9 @@ namespace dxvk { if (!chunkCount) return false; + if (m_ensureReproducibleHeuristic && flushType != GpuFlushType::ExplicitFlush) + return false; + // Take any earlier missed flush with a stronger hint into account, so // that we still flush those as soon as possible. Ignore synchronization // commands since they will either perform a flush or not need it at all. diff --git a/src/util/util_flush.h b/src/util/util_flush.h index 138aa992b..c3e71ebcb 100644 --- a/src/util/util_flush.h +++ b/src/util/util_flush.h @@ -34,6 +34,8 @@ namespace dxvk { public: + GpuFlushTracker(bool ensureReproducibleHeuristic); + /** * \brief Checks whether a context flush should be performed * @@ -61,6 +63,8 @@ namespace dxvk { private: + bool m_ensureReproducibleHeuristic; + GpuFlushType m_lastMissedType = GpuFlushType::ImplicitWeakHint; uint64_t m_lastFlushChunkId = 0ull;