r300g: implement fake but compliant fences
authorMarek Olšák <maraeo@gmail.com>
Tue, 25 May 2010 23:23:07 +0000 (01:23 +0200)
committerMarek Olšák <maraeo@gmail.com>
Tue, 25 May 2010 23:23:11 +0000 (01:23 +0200)
src/gallium/drivers/r300/r300_context.c
src/gallium/drivers/r300/r300_context.h
src/gallium/drivers/r300/r300_flush.c
src/gallium/drivers/r300/r300_screen.c

index 505970ffb8a1e315cebe981b8612d91bd55197d4..4721b7d5dc9bf4fa88ae8dedd0b046b26e98a95c 100644 (file)
@@ -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);
+            }
+        }
+    }
+}
index 0933d6b833a19c4482d39bbf5f7aea1c323fb3e5..82183cfcb8b6b980acab88f84fafd487eeffe6ea 100644 (file)
@@ -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)
index f629e57c5a450723c65038167ea1ddbf277707a4..9cda940c85d69b90b05e1d7ba3e2b7e2fb62cbc0 100644 (file)
@@ -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;
     }
 }
 
index ef0255066b798061a30f74924c5c2557e5ba3d1a..4859db523a52e48f0f58af7ed1e03620853dad29 100644 (file)
@@ -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)