diff --git a/src/gallium/drivers/r600/r600_pipe.c b/src/gallium/drivers/r600/r600_pipe.c index 43d6fea66d0..008a0b90d10 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_pipe_context *ctx) rscreen->fences.data[fence->index] = 0; r600_context_emit_fence(&ctx->ctx, 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(&ctx->ctx.screen->screen, PIPE_BIND_CUSTOM, + PIPE_USAGE_STAGING, 1); + /* Add the fence as a dummy relocation. */ + r600_context_bo_reloc(&ctx->ctx, fence->sleep_bo, RADEON_USAGE_READWRITE); + out: pipe_mutex_unlock(rscreen->fences.mutex); return fence; @@ -568,6 +577,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); } @@ -601,6 +611,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 @@ -610,11 +631,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 015d5e0b2aa..5e622100a1b 100644 --- a/src/gallium/drivers/r600/r600_pipe.h +++ b/src/gallium/drivers/r600/r600_pipe.h @@ -172,6 +172,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; };