diff --git a/Source/Core/VideoBackends/D3D12/PerfQuery.cpp b/Source/Core/VideoBackends/D3D12/PerfQuery.cpp index f5231aad76..4b2ec079ee 100644 --- a/Source/Core/VideoBackends/D3D12/PerfQuery.cpp +++ b/Source/Core/VideoBackends/D3D12/PerfQuery.cpp @@ -57,6 +57,12 @@ void PerfQuery::EnableQuery(PerfQueryGroup type) PartialFlush(do_resolve, blocking); } + // Ensure all state is applied before beginning the query. + // This is because we can't leave a query open when submitting a command list, and the draw + // call itself may need to execute a command list if we run out of descriptors. Note that + // this assumes that the caller has bound all required state prior to enabling the query. + Renderer::GetInstance()->ApplyState(); + if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP) { ActiveQuery& entry = m_query_buffer[m_query_next_pos]; diff --git a/Source/Core/VideoBackends/D3D12/Renderer.h b/Source/Core/VideoBackends/D3D12/Renderer.h index 60e0000cff..1979833048 100644 --- a/Source/Core/VideoBackends/D3D12/Renderer.h +++ b/Source/Core/VideoBackends/D3D12/Renderer.h @@ -89,6 +89,9 @@ public: void SetVertexBuffer(D3D12_GPU_VIRTUAL_ADDRESS address, u32 stride, u32 size); void SetIndexBuffer(D3D12_GPU_VIRTUAL_ADDRESS address, u32 size, DXGI_FORMAT format); + // Binds all dirty state + bool ApplyState(); + protected: void OnConfigChanged(u32 bits) override; @@ -131,8 +134,6 @@ private: void CheckForSwapChainChanges(); - // Binds all dirty state - bool ApplyState(); void BindFramebuffer(DXFramebuffer* fb); void SetRootSignatures(); void SetDescriptorHeaps(); diff --git a/Source/Core/VideoCommon/PerfQueryBase.h b/Source/Core/VideoCommon/PerfQueryBase.h index 449b86cc1b..de99b215c9 100644 --- a/Source/Core/VideoCommon/PerfQueryBase.h +++ b/Source/Core/VideoCommon/PerfQueryBase.h @@ -31,22 +31,31 @@ class PerfQueryBase public: PerfQueryBase() : m_query_count(0) {} virtual ~PerfQueryBase() {} + // Checks if performance queries are enabled in the gameini configuration. // NOTE: Called from CPU+GPU thread static bool ShouldEmulate(); // Begin querying the specified value for the following host GPU commands + // The call to EnableQuery() should be placed immediately before the draw command, otherwise + // there is a risk of GPU resets if the query is left open and the buffer is submitted during + // resource binding (D3D12/Vulkan). virtual void EnableQuery(PerfQueryGroup type) {} + // Stop querying the specified value for the following host GPU commands virtual void DisableQuery(PerfQueryGroup type) {} + // Reset query counters to zero and drop any pending queries virtual void ResetQuery() {} + // Return the measured value for the specified query type // NOTE: Called from CPU thread virtual u32 GetQueryResult(PerfQueryType type) { return 0; } + // Request the value of any pending queries - causes a pipeline flush and thus should be used // carefully! virtual void FlushResults() {} + // True if there are no further pending query results // NOTE: Called from CPU thread virtual bool IsFlushed() const { return true; }