r300g is able to sleep until a fence completes rather than busywait because
it creates a special buffer object and relocation that stays busy until the
CS containing the fence is finished.

Copy the idea into r600g, and use it to sleep if the user asked for an
infinite wait, falling back to busywaiting if the user provided a timeout.

Signed-off-by: Simon Farnsworth <simon.farnswo...@onelan.co.uk>
---
This is now ready to apply. We might also want to backport it to the 8.0
branch, as without this or an equivalent, a GPU reset can result in
applications busywaiting forever.

v4: Rebase against master - cleanups to r600g had stopped it applying.

    At Marek's suggestion, move the sleep BO into r600_pipe.c, instead of
r600_hw_context.c

v3: At Dave Airlie's suggestion on dri-devel, make use of the BO to give us
a fighting chance of recovering after a GPU reset.

We know that the fence will never be signalled by hardware if the dummy BO
has gone idle - we use that information to escape the loop. This might be a
useful addition to the 8.0 branch.

v2: Address Michel's review comments.

The fake bo is now unconditional, and is unreferenced when the fence is
moved to the fence pool by fence_reference. This entailed shifting to
r600_resource, which cleaned the code up a little to boot.

 src/gallium/drivers/r600/r600_pipe.c |   25 +++++++++++++++++++++++--
 src/gallium/drivers/r600/r600_pipe.h |    1 +
 2 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/src/gallium/drivers/r600/r600_pipe.c 
b/src/gallium/drivers/r600/r600_pipe.c
index bfb01f5..7d2dd20 100644
--- a/src/gallium/drivers/r600/r600_pipe.c
+++ b/src/gallium/drivers/r600/r600_pipe.c
@@ -47,6 +47,7 @@
 #include "r600_resource.h"
 #include "r600_shader.h"
 #include "r600_pipe.h"
+#include "r600_hw_context_priv.h"
 
 /*
  * pipe_context
@@ -116,6 +117,14 @@ static struct r600_fence *r600_create_fence(struct 
r600_context *rctx)
 
        rscreen->fences.data[fence->index] = 0;
        r600_context_emit_fence(rctx, rscreen->fences.bo, fence->index, 1);
+
+       /* Create a dummy BO so that fence_finish without a timeout can sleep 
waiting for completion */
+       fence->sleep_bo = (struct r600_resource*)
+                       pipe_buffer_create(&rctx->screen->screen, 
PIPE_BIND_CUSTOM,
+                                          PIPE_USAGE_STAGING, 1);
+       /* Add the fence as a dummy relocation. */
+       r600_context_bo_reloc(rctx, fence->sleep_bo, RADEON_USAGE_READWRITE);
+
 out:
        pipe_mutex_unlock(rscreen->fences.mutex);
        return fence;
@@ -584,6 +593,7 @@ static void r600_fence_reference(struct pipe_screen 
*pscreen,
        if (pipe_reference(&(*oldf)->reference, &newf->reference)) {
                struct r600_screen *rscreen = (struct r600_screen *)pscreen;
                pipe_mutex_lock(rscreen->fences.mutex);
+               pipe_resource_reference((struct 
pipe_resource**)&(*oldf)->sleep_bo, NULL);
                LIST_ADDTAIL(&(*oldf)->head, &rscreen->fences.pool);
                pipe_mutex_unlock(rscreen->fences.mutex);
        }
@@ -617,6 +627,17 @@ static boolean r600_fence_finish(struct pipe_screen 
*pscreen,
        }
 
        while (rscreen->fences.data[rfence->index] == 0) {
+               /* Special-case infinite timeout - wait for the dummy BO to 
become idle */
+               if (timeout == PIPE_TIMEOUT_INFINITE) {
+                       rscreen->ws->buffer_wait(rfence->sleep_bo->buf, 
RADEON_USAGE_READWRITE);
+                       break;
+               }
+
+               /* The dummy BO will be busy until the CS including the fence 
has completed, or
+                * the GPU is reset. Don't bother continuing to spin when the 
BO is idle. */
+               if (!rscreen->ws->buffer_is_busy(rfence->sleep_bo->buf, 
RADEON_USAGE_READWRITE))
+                       break;
+
                if (++spins % 256)
                        continue;
 #ifdef PIPE_OS_UNIX
@@ -626,11 +647,11 @@ static boolean r600_fence_finish(struct pipe_screen 
*pscreen,
 #endif
                if (timeout != PIPE_TIMEOUT_INFINITE &&
                    os_time_get() - start_time >= timeout) {
-                       return FALSE;
+                       break;
                }
        }
 
-       return TRUE;
+       return rscreen->fences.data[rfence->index] != 0;
 }
 
 static int r600_interpret_tiling(struct r600_screen *rscreen, uint32_t 
tiling_config)
diff --git a/src/gallium/drivers/r600/r600_pipe.h 
b/src/gallium/drivers/r600/r600_pipe.h
index f130617..d8e396a 100644
--- a/src/gallium/drivers/r600/r600_pipe.h
+++ b/src/gallium/drivers/r600/r600_pipe.h
@@ -204,6 +204,7 @@ struct r600_textures_info {
 struct r600_fence {
        struct pipe_reference           reference;
        unsigned                        index; /* in the shared bo */
+       struct r600_resource            *sleep_bo;
        struct list_head                head;
 };
 
-- 
1.7.7.6

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to