---
 src/gallium/drivers/r600/r600_blit.c   |    8 +--
 src/gallium/drivers/r600/r600_buffer.c |   65 +++++++++++++++++++++++++++-----
 src/gallium/drivers/r600/r600_pipe.c   |    2 +-
 src/gallium/drivers/r600/r600_pipe.h   |    3 +
 4 files changed, 62 insertions(+), 16 deletions(-)

diff --git a/src/gallium/drivers/r600/r600_blit.c 
b/src/gallium/drivers/r600/r600_blit.c
index 0d9618d..6c740ce 100644
--- a/src/gallium/drivers/r600/r600_blit.c
+++ b/src/gallium/drivers/r600/r600_blit.c
@@ -246,11 +246,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 733d707..0e7b948 100644
--- a/src/gallium/drivers/r600/r600_buffer.c
+++ b/src/gallium/drivers/r600/r600_buffer.c
@@ -53,22 +53,30 @@ 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;
 }
 
+/* XXX this isn't reliable yet; there are no piglit regressions,
+ * but some apps may lock up (tested on evergreen). I guess streamout is 
buggy. */
+DEBUG_GET_ONCE_BOOL_OPTION(transfer_nowait, "R600_TRANSFER_NOWAIT", FALSE);
+
 static void *r600_buffer_transfer_map(struct pipe_context *pipe,
                                      struct pipe_transfer *transfer)
 {
@@ -79,6 +87,30 @@ static void *r600_buffer_transfer_map(struct pipe_context 
*pipe,
        if (rbuffer->b.user_ptr)
                return (uint8_t*)rbuffer->b.user_ptr + transfer->box.x;
 
+       /* At least one of the DISCARD flags and none of {READ, DONTBLOCK, 
UNSYNCHRONIZED} must be present.
+        * The buffer range must be aligned to 4. */
+       if ((transfer->usage & (PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE | 
PIPE_TRANSFER_DISCARD_RANGE)) &&
+           !(transfer->usage & (PIPE_TRANSFER_READ | PIPE_TRANSFER_DONTBLOCK | 
PIPE_TRANSFER_UNSYNCHRONIZED)) &&
+           debug_get_option_transfer_nowait() &&
+           rctx->screen->info.r600_has_streamout &&
+           transfer->box.x % 4 == 0 && transfer->box.width % 4 == 0) {
+               /* When mapping for read, we only need to check if the GPU is 
writing to it. */
+               enum radeon_bo_usage rusage = transfer->usage & 
PIPE_TRANSFER_WRITE ?
+                               RADEON_USAGE_READWRITE : RADEON_USAGE_WRITE;
+
+               /* Check if mapping this buffer would cause waiting for the 
GPU. */
+               if (rctx->ws->cs_is_buffer_referenced(rctx->cs, 
rbuffer->cs_buf, rusage) ||
+                   rctx->ws->buffer_is_busy(rbuffer->buf, rusage)) {
+                       /* 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->buf, 
rctx->cs, PIPE_TRANSFER_WRITE);
+               }
+       }
+
        data = rctx->ws->buffer_map(rbuffer->buf, rctx->cs, transfer->usage);
        if (!data)
                return NULL;
@@ -91,11 +123,24 @@ static void r600_buffer_transfer_unmap(struct pipe_context 
*pipe,
 {
        struct r600_resource *rbuffer = r600_resource(transfer->resource);
        struct r600_context *rctx = (struct r600_context*)pipe;
+       struct r600_transfer *rtransfer = (struct r600_transfer*)transfer;
 
        if (rbuffer->b.user_ptr)
                return;
 
-       rctx->ws->buffer_unmap(rbuffer->buf);
+       if (rtransfer->staging) {
+               struct pipe_box box;
+               u_box_1d(0, transfer->box.width, &box);
+
+               rctx->ws->buffer_unmap(rtransfer->staging->buf);
+
+               /* Copy the staging buffer into the original one. */
+               r600_copy_buffer(pipe, transfer->resource, transfer->box.x,
+                                &rtransfer->staging->b.b.b, &box);
+               pipe_resource_reference((struct 
pipe_resource**)&rtransfer->staging, NULL);
+       } else {
+               rctx->ws->buffer_unmap(rbuffer->buf);
+       }
 }
 
 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 db1bf0e..97c2511 100644
--- a/src/gallium/drivers/r600/r600_pipe.c
+++ b/src/gallium/drivers/r600/r600_pipe.c
@@ -235,7 +235,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);
 
        r600_update_num_contexts(rscreen, 1);
diff --git a/src/gallium/drivers/r600/r600_pipe.h 
b/src/gallium/drivers/r600/r600_pipe.h
index 08441d1..f70a4eb 100644
--- a/src/gallium/drivers/r600/r600_pipe.h
+++ b/src/gallium/drivers/r600/r600_pipe.h
@@ -399,6 +399,9 @@ boolean evergreen_is_format_supported(struct pipe_screen 
*screen,
 void evergreen_set_rasterizer_discard(struct pipe_context *ctx, boolean 
discard);
 
 /* 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);
 void r600_blit_push_depth(struct pipe_context *ctx, struct 
r600_resource_texture *texture);
-- 
1.7.5.4

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

Reply via email to