From 5124fd87d51b5038653f35b1cb1b9594f9a49067 Mon Sep 17 00:00:00 2001
From: Philip Rebohle <philip.rebohle@tu-dortmund.de>
Date: Wed, 17 Oct 2018 17:22:52 +0200
Subject: [PATCH] [d3d11] Implicitly flush when queueing an event query

Significantly improves GPU utilization in Quake Champions.
---
 src/d3d11/d3d11_context_imm.cpp | 28 +++++++++++++++++++++-------
 src/d3d11/d3d11_context_imm.h   |  5 ++++-
 2 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/src/d3d11/d3d11_context_imm.cpp b/src/d3d11/d3d11_context_imm.cpp
index a09042f7..2e5eb4c9 100644
--- a/src/d3d11/d3d11_context_imm.cpp
+++ b/src/d3d11/d3d11_context_imm.cpp
@@ -48,6 +48,20 @@ namespace dxvk {
   }
   
   
+  void STDMETHODCALLTYPE D3D11ImmediateContext::End(
+          ID3D11Asynchronous*               pAsync) {
+    D3D11DeviceContext::End(pAsync);
+
+    if (pAsync) {
+      D3D11_QUERY_DESC desc;
+      static_cast<D3D11Query*>(pAsync)->GetDesc(&desc);
+      
+      if (desc.Query == D3D11_QUERY_EVENT)
+        FlushImplicit(TRUE);
+    }
+  }
+
+
   HRESULT STDMETHODCALLTYPE D3D11ImmediateContext::GetData(
           ID3D11Asynchronous*               pAsync,
           void*                             pData,
@@ -75,7 +89,7 @@ namespace dxvk {
     // If we're likely going to spin on the asynchronous object,
     // flush the context so that we're keeping the GPU busy
     if (hr == S_FALSE)
-      FlushImplicit();
+      FlushImplicit(FALSE);
     
     return hr;
   }
@@ -116,7 +130,7 @@ namespace dxvk {
     
     // As an optimization, flush everything if the
     // number of pending draw calls is high enough.
-    FlushImplicit();
+    FlushImplicit(FALSE);
     
     // Dispatch command list to the CS thread and
     // restore the immediate context's state
@@ -193,7 +207,7 @@ namespace dxvk {
           UINT                              NumViews,
           ID3D11RenderTargetView* const*    ppRenderTargetViews,
           ID3D11DepthStencilView*           pDepthStencilView) {
-    FlushImplicit();
+    FlushImplicit(FALSE);
     
     D3D11DeviceContext::OMSetRenderTargets(
       NumViews, ppRenderTargetViews, pDepthStencilView);
@@ -208,7 +222,7 @@ namespace dxvk {
           UINT                              NumUAVs,
           ID3D11UnorderedAccessView* const* ppUnorderedAccessViews,
     const UINT*                             pUAVInitialCounts) {
-    FlushImplicit();
+    FlushImplicit(FALSE);
 
     D3D11DeviceContext::OMSetRenderTargetsAndUnorderedAccessViews(
       NumRTVs, ppRenderTargetViews, pDepthStencilView,
@@ -429,7 +443,7 @@ namespace dxvk {
         // We don't have to wait, but misbehaving games may
         // still try to spin on `Map` until the resource is
         // idle, so we should flush pending commands
-        FlushImplicit();
+        FlushImplicit(FALSE);
         return false;
       } else {
         // Make sure pending commands using the resource get
@@ -452,10 +466,10 @@ namespace dxvk {
   }
 
 
-  void D3D11ImmediateContext::FlushImplicit() {
+  void D3D11ImmediateContext::FlushImplicit(BOOL StrongHint) {
     // Flush only if the GPU is about to go idle, in
     // order to keep the number of submissions low.
-    if (m_device->pendingSubmissions() <= MaxPendingSubmits) {
+    if (StrongHint || m_device->pendingSubmissions() <= MaxPendingSubmits) {
       auto now = std::chrono::high_resolution_clock::now();
 
       // Prevent flushing too often in short intervals.
diff --git a/src/d3d11/d3d11_context_imm.h b/src/d3d11/d3d11_context_imm.h
index 90582f97..97852f33 100644
--- a/src/d3d11/d3d11_context_imm.h
+++ b/src/d3d11/d3d11_context_imm.h
@@ -25,6 +25,9 @@ namespace dxvk {
     
     UINT STDMETHODCALLTYPE GetContextFlags();
     
+    void STDMETHODCALLTYPE End(
+            ID3D11Asynchronous*               pAsync);
+
     HRESULT STDMETHODCALLTYPE GetData(
             ID3D11Asynchronous*               pAsync,
             void*                             pData,
@@ -101,7 +104,7 @@ namespace dxvk {
     
     void EmitCsChunk(DxvkCsChunkRef&& chunk);
 
-    void FlushImplicit();
+    void FlushImplicit(BOOL StrongHint);
     
   };