From 2c072c8f72647a3b32e9855f7635b37ba399f5be Mon Sep 17 00:00:00 2001 From: =?utf8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Wed, 26 May 2010 01:23:07 +0200 Subject: [PATCH] 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 505970ffb8a..4721b7d5dc9 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 0933d6b833a..82183cfcb8b 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 f629e57c5a4..9cda940c85d 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 ef0255066b7..4859db523a5 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) -- 2.30.2