Mesa (master): r300g: implement fake but compliant fences

Marek Olšák mareko at kemper.freedesktop.org
Tue May 25 23:36:19 UTC 2010


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

Author: Marek Olšák <maraeo at gmail.com>
Date:   Wed May 26 01:23:07 2010 +0200

r300g: implement fake but compliant fences

---

 src/gallium/drivers/r300/r300_context.c |   26 +++++++++++++++++++++
 src/gallium/drivers/r300/r300_context.h |   17 +++++++++++++
 src/gallium/drivers/r300/r300_flush.c   |   38 ++++--------------------------
 src/gallium/drivers/r300/r300_screen.c  |   17 ++++++++++++-
 4 files changed, 63 insertions(+), 35 deletions(-)

diff --git a/src/gallium/drivers/r300/r300_context.c b/src/gallium/drivers/r300/r300_context.c
index 505970f..4721b7d 100644
--- a/src/gallium/drivers/r300/r300_context.c
+++ b/src/gallium/drivers/r300/r300_context.c
@@ -235,3 +235,29 @@ struct pipe_context* r300_create_context(struct pipe_screen* screen,
     FREE(r300);
     return NULL;
 }
+
+void r300_finish(struct r300_context *r300)
+{
+    struct pipe_framebuffer_state *fb;
+    unsigned i;
+
+    /* This is a preliminary implementation of glFinish.
+     *
+     * The ideal implementation should use something like EmitIrqLocked and
+     * WaitIrq, or better, real fences.
+     */
+    if (r300->fb_state.state) {
+        fb = r300->fb_state.state;
+
+        for (i = 0; i < fb->nr_cbufs; i++) {
+            if (fb->cbufs[i]->texture) {
+                r300->rws->buffer_wait(r300->rws,
+                    r300_texture(fb->cbufs[i]->texture)->buffer);
+            }
+            if (fb->zsbuf) {
+                r300->rws->buffer_wait(r300->rws,
+                    r300_texture(fb->zsbuf->texture)->buffer);
+            }
+        }
+    }
+}
diff --git a/src/gallium/drivers/r300/r300_context.h b/src/gallium/drivers/r300/r300_context.h
index 0933d6b..82183cf 100644
--- a/src/gallium/drivers/r300/r300_context.h
+++ b/src/gallium/drivers/r300/r300_context.h
@@ -252,6 +252,22 @@ struct r300_query {
     struct r300_query* next;
 };
 
+/* Fence object.
+ *
+ * This is a fake fence. Instead of syncing with the fence, we sync
+ * with the context, which is inefficient but compliant.
+ *
+ * This is not a subclass of pipe_fence_handle because pipe_fence_handle is
+ * never actually fully defined. So, rather than have it as a member, and do
+ * subclass-style casting, we treat pipe_query as an opaque, and just
+ * trust that our state tracker does not ever mess up query objects.
+ */
+struct r300_fence {
+    struct pipe_reference reference;
+    struct r300_context *ctx;
+    boolean signalled;
+};
+
 struct r300_texture {
     /* Parent class */
     struct u_resource b;
@@ -474,6 +490,7 @@ void r300_init_render_functions(struct r300_context *r300);
 void r300_init_state_functions(struct r300_context* r300);
 void r300_init_resource_functions(struct r300_context* r300);
 
+void r300_finish(struct r300_context *r300);
 void r500_dump_rs_block(struct r300_rs_block *rs);
 
 static INLINE boolean CTX_DBG_ON(struct r300_context * ctx, unsigned flags)
diff --git a/src/gallium/drivers/r300/r300_flush.c b/src/gallium/drivers/r300/r300_flush.c
index f629e57..9cda940 100644
--- a/src/gallium/drivers/r300/r300_flush.c
+++ b/src/gallium/drivers/r300/r300_flush.c
@@ -37,8 +37,7 @@ static void r300_flush(struct pipe_context* pipe,
     struct r300_context *r300 = r300_context(pipe);
     struct r300_query *query;
     struct r300_atom *atom;
-    struct pipe_framebuffer_state *fb;
-    unsigned i;
+    struct r300_fence **rfence = (struct r300_fence**)fence;
 
     CS_LOCALS(r300);
     (void) cs_count;
@@ -75,37 +74,10 @@ static void r300_flush(struct pipe_context* pipe,
         query->flushed = TRUE;
     }
 
-    /* XXX
-     *
-     * This is a preliminary implementation of glFinish. Note that st/mesa
-     * uses a non-null fence when glFinish is called and then waits for
-     * the fence. Instead of returning the actual fence, we do the sync
-     * directly.
-     *
-     * The ideal implementation should use something like EmitIrqLocked and
-     * WaitIrq, or better, real fences.
-     *
-     * This feature degrades performance to the level of r300c for games that
-     * use glFinish a lot, even openarena does. Ideally we wouldn't need
-     * glFinish at all if we had proper throttling in swapbuffers so that
-     * the CPU wouldn't outrun the GPU by several frames, so this is basically
-     * a temporary fix for the input lag. Once swap&sync works with DRI2,
-     * I'll be happy to remove this code.
-     *
-     * - M. */
-    if (fence && r300->fb_state.state) {
-        fb = r300->fb_state.state;
-
-        for (i = 0; i < fb->nr_cbufs; i++) {
-            if (fb->cbufs[i]->texture) {
-                r300->rws->buffer_wait(r300->rws,
-                    r300_texture(fb->cbufs[i]->texture)->buffer);
-            }
-            if (fb->zsbuf) {
-                r300->rws->buffer_wait(r300->rws,
-                    r300_texture(fb->zsbuf->texture)->buffer);
-            }
-        }
+    /* Create a new fence. */
+    if (rfence) {
+        *rfence = CALLOC_STRUCT(r300_fence);
+        (*rfence)->ctx = r300;
     }
 }
 
diff --git a/src/gallium/drivers/r300/r300_screen.c b/src/gallium/drivers/r300/r300_screen.c
index ef02550..4859db5 100644
--- a/src/gallium/drivers/r300/r300_screen.c
+++ b/src/gallium/drivers/r300/r300_screen.c
@@ -319,20 +319,33 @@ static void r300_fence_reference(struct pipe_screen *screen,
                                  struct pipe_fence_handle **ptr,
                                  struct pipe_fence_handle *fence)
 {
+    struct r300_fence **oldf = (struct r300_fence**)ptr;
+    struct r300_fence *newf = (struct r300_fence*)fence;
+
+    if (pipe_reference(&(*oldf)->reference, &newf->reference))
+        FREE(*oldf);
+
+    *ptr = fence;
 }
 
 static int r300_fence_signalled(struct pipe_screen *screen,
                                 struct pipe_fence_handle *fence,
                                 unsigned flags)
 {
-    return 0;
+    struct r300_fence *rfence = (struct r300_fence*)fence;
+
+    return rfence->signalled ? 0 : 1; /* 0 == success */
 }
 
 static int r300_fence_finish(struct pipe_screen *screen,
                              struct pipe_fence_handle *fence,
                              unsigned flags)
 {
-    return 0;
+    struct r300_fence *rfence = (struct r300_fence*)fence;
+
+    r300_finish(rfence->ctx);
+    rfence->signalled = TRUE;
+    return 0; /* 0 == success */
 }
 
 struct pipe_screen* r300_create_screen(struct r300_winsys_screen *rws)




More information about the mesa-commit mailing list