From 6e0ac7fa75fbd75471701a5e76ee76a6c2eee252 Mon Sep 17 00:00:00 2001
From: Connor McLaughlin <stenzek@gmail.com>
Date: Sat, 3 Sep 2022 14:55:12 +1000
Subject: [PATCH] HostDisplay: Make GL/D3D timestamp queries slightly less
 rubbish

---
 pcsx2/Frontend/D3D11HostDisplay.cpp  | 21 ++++++++++++++-------
 pcsx2/Frontend/D3D11HostDisplay.h    |  2 +-
 pcsx2/Frontend/OpenGLHostDisplay.cpp |  6 ++----
 pcsx2/Frontend/OpenGLHostDisplay.h   |  2 +-
 4 files changed, 18 insertions(+), 13 deletions(-)

diff --git a/pcsx2/Frontend/D3D11HostDisplay.cpp b/pcsx2/Frontend/D3D11HostDisplay.cpp
index dfbdaebc40..3521889f23 100644
--- a/pcsx2/Frontend/D3D11HostDisplay.cpp
+++ b/pcsx2/Frontend/D3D11HostDisplay.cpp
@@ -677,6 +677,13 @@ bool D3D11HostDisplay::BeginPresent(bool frame_skip)
 		return false;
 	}
 
+	// When using vsync, the time here seems to include the time for the buffer to become available.
+	// This blows our our GPU usage number considerably, so read the timestamp before the final blit
+	// in this configuration. It does reduce accuracy a little, but better than seeing 100% all of
+	// the time, when it's more like a couple of percent.
+	if (m_vsync_mode != VsyncMode::Off && m_gpu_timing_enabled)
+		PopTimestampQuery();
+
 	static constexpr std::array<float, 4> clear_color = {};
 	m_context->ClearRenderTargetView(m_swap_chain_rtv.get(), clear_color.data());
 	m_context->OMSetRenderTargets(1, m_swap_chain_rtv.addressof(), nullptr);
@@ -693,14 +700,15 @@ void D3D11HostDisplay::EndPresent()
 	ImGui::Render();
 	ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
 
-	if (m_gpu_timing_enabled)
+	// See note in BeginPresent() for why it's conditional on vsync-off.
+	const bool vsync_on = m_vsync_mode != VsyncMode::Off;
+	if (!vsync_on && m_gpu_timing_enabled)
 		PopTimestampQuery();
 
-	const UINT vsync_rate = static_cast<UINT>(m_vsync_mode != VsyncMode::Off);
-	if (vsync_rate == 0 && m_using_allow_tearing)
+	if (!vsync_on && m_using_allow_tearing)
 		m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
 	else
-		m_swap_chain->Present(vsync_rate, 0);
+		m_swap_chain->Present(static_cast<UINT>(vsync_on), 0);
 
 	if (m_gpu_timing_enabled)
 		KickTimestampQuery();
@@ -772,8 +780,7 @@ void D3D11HostDisplay::PopTimestampQuery()
 		}
 	}
 
-	// delay ending the current query until we've read back some
-	if (m_timestamp_query_started && m_waiting_timestamp_queries < (NUM_TIMESTAMP_QUERIES - 1))
+	if (m_timestamp_query_started)
 	{
 		m_context->End(m_timestamp_queries[m_write_timestamp_query][2].get());
 		m_context->End(m_timestamp_queries[m_write_timestamp_query][0].get());
@@ -785,7 +792,7 @@ void D3D11HostDisplay::PopTimestampQuery()
 
 void D3D11HostDisplay::KickTimestampQuery()
 {
-	if (m_timestamp_query_started || !m_timestamp_queries[0][0])
+	if (m_timestamp_query_started || !m_timestamp_queries[0][0] || m_waiting_timestamp_queries == NUM_TIMESTAMP_QUERIES)
 		return;
 
 	m_context->Begin(m_timestamp_queries[m_write_timestamp_query][0].get());
diff --git a/pcsx2/Frontend/D3D11HostDisplay.h b/pcsx2/Frontend/D3D11HostDisplay.h
index 9fe660d901..ea3e982658 100644
--- a/pcsx2/Frontend/D3D11HostDisplay.h
+++ b/pcsx2/Frontend/D3D11HostDisplay.h
@@ -75,7 +75,7 @@ public:
 
 protected:
 	static constexpr u32 DISPLAY_CONSTANT_BUFFER_SIZE = 16;
-	static constexpr u8 NUM_TIMESTAMP_QUERIES = 3;
+	static constexpr u8 NUM_TIMESTAMP_QUERIES = 5;
 
 	static AdapterAndModeList GetAdapterAndModeList(IDXGIFactory* dxgi_factory);
 
diff --git a/pcsx2/Frontend/OpenGLHostDisplay.cpp b/pcsx2/Frontend/OpenGLHostDisplay.cpp
index 80bc5cf3de..b37d428cfd 100644
--- a/pcsx2/Frontend/OpenGLHostDisplay.cpp
+++ b/pcsx2/Frontend/OpenGLHostDisplay.cpp
@@ -440,7 +440,6 @@ void OpenGLHostDisplay::PopTimestampQuery()
 
 		GLint available = 0;
 		GetQueryObjectiv(m_timestamp_queries[m_read_timestamp_query], GL_QUERY_RESULT_AVAILABLE, &available);
-		pxAssert(m_read_timestamp_query != m_write_timestamp_query);
 
 		if (!available)
 			break;
@@ -452,8 +451,7 @@ void OpenGLHostDisplay::PopTimestampQuery()
 		m_waiting_timestamp_queries--;
 	}
 
-	// delay ending the current query until we've read back some
-	if (m_timestamp_query_started && m_waiting_timestamp_queries < (NUM_TIMESTAMP_QUERIES - 1))
+	if (m_timestamp_query_started)
 	{
 		const auto EndQuery = gles ? glEndQueryEXT : glEndQuery;
 		EndQuery(GL_TIME_ELAPSED);
@@ -466,7 +464,7 @@ void OpenGLHostDisplay::PopTimestampQuery()
 
 void OpenGLHostDisplay::KickTimestampQuery()
 {
-	if (m_timestamp_query_started)
+	if (m_timestamp_query_started || m_waiting_timestamp_queries == NUM_TIMESTAMP_QUERIES)
 		return;
 
 	const bool gles = m_gl_context->IsGLES();
diff --git a/pcsx2/Frontend/OpenGLHostDisplay.h b/pcsx2/Frontend/OpenGLHostDisplay.h
index c87146b05b..2af6683648 100644
--- a/pcsx2/Frontend/OpenGLHostDisplay.h
+++ b/pcsx2/Frontend/OpenGLHostDisplay.h
@@ -65,7 +65,7 @@ public:
 	float GetAndResetAccumulatedGPUTime() override;
 
 protected:
-	static constexpr u8 NUM_TIMESTAMP_QUERIES = 3;
+	static constexpr u8 NUM_TIMESTAMP_QUERIES = 5;
 
 	const char* GetGLSLVersionString() const;
 	std::string GetGLSLVersionHeader() const;