[Mesa-dev] [PATCH 3/5] r600g: use a buffer in GTT as intermediate on texture up and downloads

Keith Whitwell keithw at vmware.com
Tue Nov 2 12:40:12 PDT 2010


Generalize the existing tiled_buffer path in texture transfers for use
in some non-tiled up and downloads.

Use a staging buffer, which the winsys will restrict to GTT memory.

GTT buffers have the major advantage when they are mapped, they are
cachable, which is a very nice property for downloads, usually the CPU
will want to do look at the data it downloaded.
---
 src/gallium/drivers/r600/r600_resource.h |    2 +-
 src/gallium/drivers/r600/r600_texture.c  |   85 ++++++++++++++++++++++--------
 2 files changed, 64 insertions(+), 23 deletions(-)

diff --git a/src/gallium/drivers/r600/r600_resource.h b/src/gallium/drivers/r600/r600_resource.h
index d152285..d24d5a1 100644
--- a/src/gallium/drivers/r600/r600_resource.h
+++ b/src/gallium/drivers/r600/r600_resource.h
@@ -35,7 +35,7 @@ struct r600_transfer {
 	/* Buffer transfer. */
 	struct pipe_transfer		*buffer_transfer;
 	unsigned			offset;
-	struct pipe_resource		*linear_texture;
+	struct pipe_resource		*staging_texture;
 };
 
 /* This gets further specialized into either buffer or texture
diff --git a/src/gallium/drivers/r600/r600_texture.c b/src/gallium/drivers/r600/r600_texture.c
index 9a52cfa..8fbe4a0 100644
--- a/src/gallium/drivers/r600/r600_texture.c
+++ b/src/gallium/drivers/r600/r600_texture.c
@@ -40,8 +40,8 @@
 
 extern struct u_resource_vtbl r600_texture_vtbl;
 
-/* Copy from a tiled texture to a detiled one. */
-static void r600_copy_from_tiled_texture(struct pipe_context *ctx, struct r600_transfer *rtransfer)
+/* Copy from a full GPU texture to a transfer's staging one. */
+static void r600_copy_to_staging_texture(struct pipe_context *ctx, struct r600_transfer *rtransfer)
 {
 	struct pipe_transfer *transfer = (struct pipe_transfer*)rtransfer;
 	struct pipe_resource *texture = transfer->resource;
@@ -49,15 +49,15 @@ static void r600_copy_from_tiled_texture(struct pipe_context *ctx, struct r600_t
 
 	subdst.face = 0;
 	subdst.level = 0;
-	ctx->resource_copy_region(ctx, rtransfer->linear_texture,
+	ctx->resource_copy_region(ctx, rtransfer->staging_texture,
 				subdst, 0, 0, 0, texture, transfer->sr,
 				transfer->box.x, transfer->box.y, transfer->box.z,
 				transfer->box.width, transfer->box.height);
 }
 
 
-/* Copy from a detiled texture to a tiled one. */
-static void r600_copy_into_tiled_texture(struct pipe_context *ctx, struct r600_transfer *rtransfer)
+/* Copy from a transfer's staging texture to a full GPU one. */
+static void r600_copy_from_staging_texture(struct pipe_context *ctx, struct r600_transfer *rtransfer)
 {
 	struct pipe_transfer *transfer = (struct pipe_transfer*)rtransfer;
 	struct pipe_resource *texture = transfer->resource;
@@ -67,7 +67,7 @@ static void r600_copy_into_tiled_texture(struct pipe_context *ctx, struct r600_t
 	subsrc.level = 0;
 	ctx->resource_copy_region(ctx, texture, transfer->sr,
 				  transfer->box.x, transfer->box.y, transfer->box.z,
-				  rtransfer->linear_texture, subsrc,
+				  rtransfer->staging_texture, subsrc,
 				  0, 0, 0,
 				  transfer->box.width, transfer->box.height);
 
@@ -435,10 +435,20 @@ int r600_texture_depth_flush(struct pipe_context *ctx,
 	}
 
 out:
+	/* XXX: only do this if the depth texture has actually changed:
+	 */
 	r600_blit_uncompress_depth_ptr(ctx, rtex);
 	return 0;
 }
 
+/* Needs adjustment for pixelformat:
+ */
+static INLINE unsigned u_box_volume( const struct pipe_box *box )
+{
+        return box->width * box->depth * box->height;
+};
+
+
 struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx,
 						struct pipe_resource *texture,
 						struct pipe_subresource sr,
@@ -449,6 +459,35 @@ struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx,
 	struct pipe_resource resource;
 	struct r600_transfer *trans;
 	int r;
+	boolean use_staging_texture = FALSE;
+	boolean discard = FALSE;
+
+	if (!(usage & PIPE_TRANSFER_READ) && (usage & PIPE_TRANSFER_DISCARD))
+		discard = TRUE;
+
+	/* We cannot map a tiled texture directly because the data is
+	 * in a different order, therefore we do detiling using a blit.
+	 *
+	 * Also, use a temporary in GTT memory for read transfers, as
+	 * the CPU is much happier reading out of cached system memory
+	 * than uncached VRAM.
+	 */
+	if (rtex->tiled)
+		use_staging_texture = TRUE;
+
+        if (usage & PIPE_TRANSFER_READ &&
+            u_box_volume(box) > 1024)
+                use_staging_texture = TRUE;
+
+        /* XXX: Use a staging texture for uploads if the underlying BO
+         * is busy.  No interface for checking that currently? so do
+         * it eagerly whenever the transfer doesn't require a readback
+         * and might block.
+         */
+        if ((usage & PIPE_TRANSFER_WRITE) &&
+            discard &&
+            !(usage & (PIPE_TRANSFER_DONTBLOCK | PIPE_TRANSFER_UNSYNCHRONIZED)))
+                use_staging_texture = TRUE;
 
 	trans = CALLOC_STRUCT(r600_transfer);
 	if (trans == NULL)
@@ -458,6 +497,10 @@ struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx,
 	trans->transfer.usage = usage;
 	trans->transfer.box = *box;
 	if (rtex->depth) {
+                /* XXX: only readback the rectangle which is being mapped?
+                 */
+                /* XXX: when discard is true, no need to read back from depth texture
+                 */
 		r = r600_texture_depth_flush(ctx, texture);
 		if (r < 0) {
 			R600_ERR("failed to create temporary texture to hold untiled copy\n");
@@ -465,7 +508,7 @@ struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx,
 			FREE(trans);
 			return NULL;
 		}
-	} else if (rtex->tiled) {
+	} else if (use_staging_texture) {
 		resource.target = PIPE_TEXTURE_2D;
 		resource.format = texture->format;
 		resource.width0 = box->width;
@@ -473,7 +516,7 @@ struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx,
 		resource.depth0 = 1;
 		resource.last_level = 0;
 		resource.nr_samples = 0;
-		resource.usage = PIPE_USAGE_DYNAMIC;
+		resource.usage = PIPE_USAGE_STAGING;
 		resource.bind = 0;
 		resource.flags = R600_RESOURCE_FLAG_TRANSFER;
 		/* For texture reading, the temporary (detiled) texture is used as
@@ -487,8 +530,8 @@ struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx,
 			resource.bind |= PIPE_BIND_SAMPLER_VIEW;
 		}
 		/* Create the temporary texture. */
-		trans->linear_texture = ctx->screen->resource_create(ctx->screen, &resource);
-		if (trans->linear_texture == NULL) {
+		trans->staging_texture = ctx->screen->resource_create(ctx->screen, &resource);
+		if (trans->staging_texture == NULL) {
 			R600_ERR("failed to create temporary texture to hold untiled copy\n");
 			pipe_resource_reference(&trans->transfer.resource, NULL);
 			FREE(trans);
@@ -496,11 +539,9 @@ struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx,
 		}
 
 		trans->transfer.stride =
-		  ((struct r600_resource_texture *)trans->linear_texture)->pitch_in_bytes[0];
-		if (usage & PIPE_TRANSFER_READ) {
-			/* We cannot map a tiled texture directly because the data is
-			 * in a different order, therefore we do detiling using a blit. */
-			r600_copy_from_tiled_texture(ctx, trans);
+                        ((struct r600_resource_texture *)trans->staging_texture)->pitch_in_bytes[0];
+		if (!discard) {
+			r600_copy_to_staging_texture(ctx, trans);
 			/* Always referenced in the blit. */
 			ctx->flush(ctx, 0, NULL);
 		}
@@ -517,11 +558,11 @@ void r600_texture_transfer_destroy(struct pipe_context *ctx,
 	struct r600_transfer *rtransfer = (struct r600_transfer*)transfer;
 	struct r600_resource_texture *rtex = (struct r600_resource_texture*)transfer->resource;
 
-	if (rtransfer->linear_texture) {
+	if (rtransfer->staging_texture) {
 		if (transfer->usage & PIPE_TRANSFER_WRITE) {
-			r600_copy_into_tiled_texture(ctx, rtransfer);
+			r600_copy_from_staging_texture(ctx, rtransfer);
 		}
-		pipe_resource_reference(&rtransfer->linear_texture, NULL);
+		pipe_resource_reference(&rtransfer->staging_texture, NULL);
 	}
 	if (rtex->flushed_depth_texture) {
 		pipe_resource_reference((struct pipe_resource **)&rtex->flushed_depth_texture, NULL);
@@ -541,8 +582,8 @@ void* r600_texture_transfer_map(struct pipe_context *ctx,
 	unsigned usage = 0;
 	char *map;
 
-	if (rtransfer->linear_texture) {
-		bo = ((struct r600_resource *)rtransfer->linear_texture)->bo;
+	if (rtransfer->staging_texture) {
+		bo = ((struct r600_resource *)rtransfer->staging_texture)->bo;
 	} else {
 		struct r600_resource_texture *rtex = (struct r600_resource_texture*)transfer->resource;
 
@@ -593,8 +634,8 @@ void r600_texture_transfer_unmap(struct pipe_context *ctx,
 	struct radeon *radeon = (struct radeon *)ctx->screen->winsys;
 	struct r600_bo *bo;
 
-	if (rtransfer->linear_texture) {
-		bo = ((struct r600_resource *)rtransfer->linear_texture)->bo;
+	if (rtransfer->staging_texture) {
+		bo = ((struct r600_resource *)rtransfer->staging_texture)->bo;
 	} else {
 		struct r600_resource_texture *rtex = (struct r600_resource_texture*)transfer->resource;
 
-- 
1.7.1



More information about the mesa-dev mailing list