Mesa (master): st/nine: Optimize EndScene

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Sat Mar 13 21:39:03 UTC 2021


Module: Mesa
Branch: master
Commit: 634adfa253d3fbb3d6dfd9508658076ed56c7b95
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=634adfa253d3fbb3d6dfd9508658076ed56c7b95

Author: Axel Davy <davyaxel0 at gmail.com>
Date:   Fri Mar  5 18:23:08 2021 +0100

st/nine: Optimize EndScene

So far we did nothing on EndScene, but the API
doc says it flushes the GPU command queue.
The doc implies one can optimize CPU usage
by calling EndScene long before Present() is called.

Implementing the flush behaviour gives me +15-20%
on the CPU limited Halo. On the other hand, do limit
the flush to only once per frame.
3DMark03/3Mark05 get a 2% perf hit with the patch,
but 5% if I allow more flushes.

Signed-off-by: Axel Davy <davyaxel0 at gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/9451>

---

 src/gallium/frontends/nine/device9.c    | 13 +++++++++++++
 src/gallium/frontends/nine/device9.h    |  1 +
 src/gallium/frontends/nine/nine_state.c | 17 +++++++++++++++++
 src/gallium/frontends/nine/nine_state.h |  7 +++++++
 src/gallium/frontends/nine/swapchain9.c |  1 +
 5 files changed, 39 insertions(+)

diff --git a/src/gallium/frontends/nine/device9.c b/src/gallium/frontends/nine/device9.c
index 9b44b9827b7..2de8d50ef68 100644
--- a/src/gallium/frontends/nine/device9.c
+++ b/src/gallium/frontends/nine/device9.c
@@ -2035,6 +2035,19 @@ NineDevice9_EndScene( struct NineDevice9 *This )
     DBG("This=%p\n", This);
     user_assert(This->in_scene, D3DERR_INVALIDCALL);
     This->in_scene = FALSE;
+    This->end_scene_since_present++;
+    /* EndScene() is supposed to flush the GPU commands.
+     * The idea is to flush ahead of the Present() call.
+     * (Apps could take advantage of this by inserting CPU
+     * work between EndScene() and Present()).
+     * Most apps will have one EndScene per frame.
+     * Some will have 2 or 3.
+     * Some bad behaving apps do a lot of them.
+     * As flushing has a cost, do it only once. */
+    if (This->end_scene_since_present <= 1) {
+        nine_context_pipe_flush(This);
+        nine_csmt_flush(This);
+    }
     return D3D_OK;
 }
 
diff --git a/src/gallium/frontends/nine/device9.h b/src/gallium/frontends/nine/device9.h
index 974251f3fe9..876728e0105 100644
--- a/src/gallium/frontends/nine/device9.h
+++ b/src/gallium/frontends/nine/device9.h
@@ -90,6 +90,7 @@ struct NineDevice9
 
     boolean is_recording;
     boolean in_scene;
+    unsigned end_scene_since_present;
 
     uint16_t vs_const_size;
     uint16_t ps_const_size;
diff --git a/src/gallium/frontends/nine/nine_state.c b/src/gallium/frontends/nine/nine_state.c
index 6f57b19e1aa..0d1f670e946 100644
--- a/src/gallium/frontends/nine/nine_state.c
+++ b/src/gallium/frontends/nine/nine_state.c
@@ -211,6 +211,16 @@ nine_csmt_process( struct NineDevice9 *device )
     nine_csmt_wait_processed(ctx);
 }
 
+void
+nine_csmt_flush( struct NineDevice9* device )
+{
+    if (!device->csmt_active)
+        return;
+
+    nine_queue_flush(device->csmt_ctx->pool);
+}
+
+
 /* Destroys a CSMT context.
  * Waits for the worker thread to terminate.
  */
@@ -2648,6 +2658,13 @@ nine_context_get_query_result(struct NineDevice9 *device, struct pipe_query *que
     return ret;
 }
 
+CSMT_ITEM_NO_WAIT(nine_context_pipe_flush)
+{
+    struct nine_context *context = &device->context;
+
+    context->pipe->flush(context->pipe, NULL, PIPE_FLUSH_ASYNC);
+}
+
 /* State defaults */
 
 static const DWORD nine_render_state_defaults[NINED3DRS_LAST + 1] =
diff --git a/src/gallium/frontends/nine/nine_state.h b/src/gallium/frontends/nine/nine_state.h
index cc76bef3418..d42bfbfefc9 100644
--- a/src/gallium/frontends/nine/nine_state.h
+++ b/src/gallium/frontends/nine/nine_state.h
@@ -604,6 +604,9 @@ nine_context_get_query_result(struct NineDevice9 *device, struct pipe_query *que
                               unsigned *counter, boolean flush, boolean wait,
                               union pipe_query_result *result);
 
+void
+nine_context_pipe_flush(struct NineDevice9 *device);
+
 void nine_state_restore_non_cso(struct NineDevice9 *device);
 void nine_state_set_defaults(struct NineDevice9 *, const D3DCAPS9 *,
                              boolean is_reset);
@@ -648,9 +651,13 @@ nine_csmt_create( struct NineDevice9 *This );
 void
 nine_csmt_destroy( struct NineDevice9 *This, struct csmt_context *ctx );
 
+/* Flushes and waits everything is executed */
 void
 nine_csmt_process( struct NineDevice9 *This );
 
+/* Flushes and doesn't wait */
+void
+nine_csmt_flush( struct NineDevice9 *This );
 
 /* Get the pipe_context (should not be called from the worker thread).
  * All the work in the worker thread is finished before returning. */
diff --git a/src/gallium/frontends/nine/swapchain9.c b/src/gallium/frontends/nine/swapchain9.c
index 39784738895..44aa75a949b 100644
--- a/src/gallium/frontends/nine/swapchain9.c
+++ b/src/gallium/frontends/nine/swapchain9.c
@@ -930,6 +930,7 @@ bypass_rendering:
         if (FAILED(hr)) { UNTESTED(3);return hr; }
     }
 
+    This->base.device->end_scene_since_present = 0;
     return D3D_OK;
 }
 



More information about the mesa-commit mailing list