From 99c65bac341f808279a8a847158ace4f058aa72e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Sun, 26 Feb 2012 20:37:43 +0100 Subject: [PATCH] r600g: implement wait-free buffer transfer for DISCARD_RANGE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alex Deucher Reviewed-by: Christian König --- src/gallium/drivers/r600/r600_blit.c | 8 ++-- src/gallium/drivers/r600/r600_buffer.c | 53 +++++++++++++++++++++----- src/gallium/drivers/r600/r600_pipe.c | 2 +- src/gallium/drivers/r600/r600_pipe.h | 3 ++ 4 files changed, 50 insertions(+), 16 deletions(-) diff --git a/src/gallium/drivers/r600/r600_blit.c b/src/gallium/drivers/r600/r600_blit.c index 829d979d2e4..8cdfae8b3f0 100644 --- a/src/gallium/drivers/r600/r600_blit.c +++ b/src/gallium/drivers/r600/r600_blit.c @@ -259,11 +259,9 @@ static void r600_clear_depth_stencil(struct pipe_context *ctx, r600_blitter_end(ctx); } -static void r600_copy_buffer(struct pipe_context *ctx, - struct pipe_resource *dst, - unsigned dstx, - struct pipe_resource *src, - const struct pipe_box *src_box) +void r600_copy_buffer(struct pipe_context *ctx, struct + pipe_resource *dst, unsigned dstx, + struct pipe_resource *src, const struct pipe_box *src_box) { struct r600_context *rctx = (struct r600_context*)ctx; diff --git a/src/gallium/drivers/r600/r600_buffer.c b/src/gallium/drivers/r600/r600_buffer.c index 165427eddf4..27dddcc1cf7 100644 --- a/src/gallium/drivers/r600/r600_buffer.c +++ b/src/gallium/drivers/r600/r600_buffer.c @@ -44,20 +44,24 @@ static struct pipe_transfer *r600_get_transfer(struct pipe_context *ctx, const struct pipe_box *box) { struct r600_context *rctx = (struct r600_context*)ctx; - struct pipe_transfer *transfer = util_slab_alloc(&rctx->pool_transfers); + struct r600_transfer *transfer = util_slab_alloc(&rctx->pool_transfers); - transfer->resource = resource; - transfer->level = level; - transfer->usage = usage; - transfer->box = *box; - transfer->stride = 0; - transfer->layer_stride = 0; - transfer->data = NULL; + assert(box->x + box->width <= resource->width0); + + transfer->transfer.resource = resource; + transfer->transfer.level = level; + transfer->transfer.usage = usage; + transfer->transfer.box = *box; + transfer->transfer.stride = 0; + transfer->transfer.layer_stride = 0; + transfer->transfer.data = NULL; + transfer->staging = NULL; + transfer->offset = 0; /* Note strides are zero, this is ok for buffers, but not for * textures 2d & higher at least. */ - return transfer; + return &transfer->transfer; } static void r600_set_constants_dirty_if_bound(struct r600_context *rctx, @@ -126,6 +130,25 @@ static void *r600_buffer_transfer_map(struct pipe_context *pipe, r600_set_constants_dirty_if_bound(rctx, &rctx->ps_constbuf_state, rbuffer); } } + else if ((transfer->usage & PIPE_TRANSFER_DISCARD_RANGE) && + !(transfer->usage & PIPE_TRANSFER_UNSYNCHRONIZED) && + rctx->screen->has_streamout && + /* The buffer range must be aligned to 4. */ + transfer->box.x % 4 == 0 && transfer->box.width % 4 == 0) { + assert(transfer->usage & PIPE_TRANSFER_WRITE); + + /* Check if mapping this buffer would cause waiting for the GPU. */ + if (rctx->ws->cs_is_buffer_referenced(rctx->cs, rbuffer->cs_buf, RADEON_USAGE_READWRITE) || + rctx->ws->buffer_is_busy(rbuffer->buf, RADEON_USAGE_READWRITE)) { + /* Do a wait-free write-only transfer using a temporary buffer. */ + struct r600_transfer *rtransfer = (struct r600_transfer*)transfer; + + rtransfer->staging = (struct r600_resource*) + pipe_buffer_create(pipe->screen, PIPE_BIND_VERTEX_BUFFER, + PIPE_USAGE_STAGING, transfer->box.width); + return rctx->ws->buffer_map(rtransfer->staging->cs_buf, rctx->cs, PIPE_TRANSFER_WRITE); + } + } data = rctx->ws->buffer_map(rbuffer->cs_buf, rctx->cs, transfer->usage); if (!data) @@ -137,7 +160,17 @@ static void *r600_buffer_transfer_map(struct pipe_context *pipe, static void r600_buffer_transfer_unmap(struct pipe_context *pipe, struct pipe_transfer *transfer) { - /* no-op */ + struct r600_transfer *rtransfer = (struct r600_transfer*)transfer; + + if (rtransfer->staging) { + struct pipe_box box; + u_box_1d(0, transfer->box.width, &box); + + /* Copy the staging buffer into the original one. */ + r600_copy_buffer(pipe, transfer->resource, transfer->box.x, + &rtransfer->staging->b.b, &box); + pipe_resource_reference((struct pipe_resource**)&rtransfer->staging, NULL); + } } static void r600_transfer_destroy(struct pipe_context *ctx, diff --git a/src/gallium/drivers/r600/r600_pipe.c b/src/gallium/drivers/r600/r600_pipe.c index 2a102621183..52725fc5c67 100644 --- a/src/gallium/drivers/r600/r600_pipe.c +++ b/src/gallium/drivers/r600/r600_pipe.c @@ -197,7 +197,7 @@ static struct pipe_context *r600_create_context(struct pipe_screen *screen, void return NULL; util_slab_create(&rctx->pool_transfers, - sizeof(struct pipe_transfer), 64, + sizeof(struct r600_transfer), 64, UTIL_SLAB_SINGLETHREADED); rctx->context.screen = screen; diff --git a/src/gallium/drivers/r600/r600_pipe.h b/src/gallium/drivers/r600/r600_pipe.h index 2f16ff6e51c..7fdf2f8c444 100644 --- a/src/gallium/drivers/r600/r600_pipe.h +++ b/src/gallium/drivers/r600/r600_pipe.h @@ -456,6 +456,9 @@ void evergreen_cb(struct r600_context *rctx, struct r600_pipe_state *rstate, void evergreen_update_dual_export_state(struct r600_context * rctx); /* r600_blit.c */ +void r600_copy_buffer(struct pipe_context *ctx, struct + pipe_resource *dst, unsigned dstx, + struct pipe_resource *src, const struct pipe_box *src_box); void r600_init_blit_functions(struct r600_context *rctx); void r600_blit_uncompress_depth(struct pipe_context *ctx, struct r600_resource_texture *texture,