diff options
author | Marek Olšák <[email protected]> | 2013-02-27 23:50:15 +0100 |
---|---|---|
committer | Marek Olšák <[email protected]> | 2013-03-01 13:46:32 +0100 |
commit | 89e2898e9ecfcf93c337b99542b06892a8e30cbe (patch) | |
tree | cc04229ada84b24ff72eeb2969f2a1a8723fe7e6 /src/gallium/drivers/r600/r600_buffer.c | |
parent | 44f37261fc34763003314245a811cfd21ce6fc87 (diff) |
r600g: always map uninitialized buffer range as unsynchronized
Any driver can implement this simple and efficient optimization.
Team Fortress 2 hits it always. The DISCARD_RANGE codepath is not even used
with TF2 anymore, so we avoid a ton of useless buffer copies.
Tested-by: Andreas Boll <[email protected]>
NOTE: This is a candidate for the 9.1 branch.
Diffstat (limited to 'src/gallium/drivers/r600/r600_buffer.c')
-rw-r--r-- | src/gallium/drivers/r600/r600_buffer.c | 17 |
1 files changed, 17 insertions, 0 deletions
diff --git a/src/gallium/drivers/r600/r600_buffer.c b/src/gallium/drivers/r600/r600_buffer.c index 3267c37cc6d..7574cd6c889 100644 --- a/src/gallium/drivers/r600/r600_buffer.c +++ b/src/gallium/drivers/r600/r600_buffer.c @@ -34,6 +34,7 @@ static void r600_buffer_destroy(struct pipe_screen *screen, { struct r600_resource *rbuffer = r600_resource(buf); + util_range_destroy(&rbuffer->valid_buffer_range); pb_reference(&rbuffer->buf, NULL); FREE(rbuffer); } @@ -98,6 +99,14 @@ static void *r600_buffer_transfer_map(struct pipe_context *ctx, assert(box->x + box->width <= resource->width0); + /* See if the buffer range being mapped has never been initialized, + * in which case it can be mapped unsynchronized. */ + if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED) && + usage & PIPE_TRANSFER_WRITE && + !util_ranges_intersect(&rbuffer->valid_buffer_range, box->x, box->x + box->width)) { + usage |= PIPE_TRANSFER_UNSYNCHRONIZED; + } + if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE && !(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) { assert(usage & PIPE_TRANSFER_WRITE); @@ -180,6 +189,7 @@ static void r600_buffer_transfer_unmap(struct pipe_context *pipe, { struct r600_context *rctx = (struct r600_context*)pipe; struct r600_transfer *rtransfer = (struct r600_transfer*)transfer; + struct r600_resource *rbuffer = r600_resource(transfer->resource); if (rtransfer->staging) { struct pipe_resource *dst, *src; @@ -205,6 +215,11 @@ static void r600_buffer_transfer_unmap(struct pipe_context *pipe, } pipe_resource_reference((struct pipe_resource**)&rtransfer->staging, NULL); } + + if (transfer->usage & PIPE_TRANSFER_WRITE) { + util_range_add(&rbuffer->valid_buffer_range, transfer->box.x, + transfer->box.x + transfer->box.width); + } util_slab_free(&rctx->pool_transfers, transfer); } @@ -261,6 +276,7 @@ bool r600_init_resource(struct r600_screen *rscreen, res->cs_buf = rscreen->ws->buffer_get_cs_handle(res->buf); res->domains = domains; + util_range_set_empty(&res->valid_buffer_range); return true; } @@ -277,6 +293,7 @@ struct pipe_resource *r600_buffer_create(struct pipe_screen *screen, pipe_reference_init(&rbuffer->b.b.reference, 1); rbuffer->b.b.screen = screen; rbuffer->b.vtbl = &r600_buffer_vtbl; + util_range_init(&rbuffer->valid_buffer_range); if (!r600_init_resource(rscreen, rbuffer, templ->width0, alignment, TRUE, templ->usage)) { FREE(rbuffer); |