[Mesa-dev] [PATCH 06/10] radeonsi: implement transfer_map with user_stride
Marek Olšák
maraeo at gmail.com
Wed Apr 25 21:16:27 UTC 2018
From: Nicolai Hähnle <nicolai.haehnle at amd.com>
The stride ends up being aligned by AddrLib in ways that are
inconvenient to express clearly, but basically, a stride that
is aligned to both 64 pixels and 256 bytes will go through
unchanged in practice.
---
src/gallium/drivers/radeonsi/si_texture.c | 35 +++++++++++++++++++----
1 file changed, 29 insertions(+), 6 deletions(-)
diff --git a/src/gallium/drivers/radeonsi/si_texture.c b/src/gallium/drivers/radeonsi/si_texture.c
index 43f1560ec3e..368fb034977 100644
--- a/src/gallium/drivers/radeonsi/si_texture.c
+++ b/src/gallium/drivers/radeonsi/si_texture.c
@@ -170,43 +170,54 @@ static void si_copy_from_staging_texture(struct pipe_context *ctx, struct r600_t
transfer->box.x, transfer->box.y, transfer->box.z,
src, 0, &sbox);
return;
}
sctx->dma_copy(ctx, dst, transfer->level,
transfer->box.x, transfer->box.y, transfer->box.z,
src, 0, &sbox);
}
+static unsigned si_texture_get_stride(struct si_screen *sscreen,
+ struct r600_texture *rtex,
+ unsigned level)
+{
+ if (sscreen->info.chip_class >= GFX9) {
+ return rtex->surface.u.gfx9.surf_pitch * rtex->surface.bpe;
+ } else {
+ return rtex->surface.u.legacy.level[level].nblk_x *
+ rtex->surface.bpe;
+ }
+}
+
static unsigned si_texture_get_offset(struct si_screen *sscreen,
struct r600_texture *rtex, unsigned level,
const struct pipe_box *box,
unsigned *stride,
unsigned *layer_stride)
{
+ *stride = si_texture_get_stride(sscreen, rtex, level);
+
if (sscreen->info.chip_class >= GFX9) {
- *stride = rtex->surface.u.gfx9.surf_pitch * rtex->surface.bpe;
*layer_stride = rtex->surface.u.gfx9.surf_slice_size;
if (!box)
return 0;
/* Each texture is an array of slices. Each slice is an array
* of mipmap levels. */
return box->z * rtex->surface.u.gfx9.surf_slice_size +
rtex->surface.u.gfx9.offset[level] +
(box->y / rtex->surface.blk_h *
rtex->surface.u.gfx9.surf_pitch +
box->x / rtex->surface.blk_w) * rtex->surface.bpe;
} else {
- *stride = rtex->surface.u.legacy.level[level].nblk_x *
- rtex->surface.bpe;
assert((uint64_t)rtex->surface.u.legacy.level[level].slice_size_dw * 4 <= UINT_MAX);
*layer_stride = (uint64_t)rtex->surface.u.legacy.level[level].slice_size_dw * 4;
if (!box)
return rtex->surface.u.legacy.level[level].offset;
/* Each texture is an array of mipmap levels. Each level is
* an array of slices. */
return rtex->surface.u.legacy.level[level].offset +
box->z * (uint64_t)rtex->surface.u.legacy.level[level].slice_size_dw * 4 +
@@ -1686,21 +1697,23 @@ static void *si_texture_transfer_map(struct pipe_context *ctx,
/* Tiled textures need to be converted into a linear texture for CPU
* access. The staging texture is always linear and is placed in GART.
*
* Reading from VRAM or GTT WC is slow, always use the staging
* texture in this case.
*
* Use the staging texture for uploads if the underlying BO
* is busy.
*/
- if (!rtex->surface.is_linear)
+ if (!rtex->surface.is_linear ||
+ (user_stride &&
+ user_stride != si_texture_get_stride(sctx->screen, rtex, level)))
use_staging_texture = true;
else if (usage & PIPE_TRANSFER_READ)
use_staging_texture =
rtex->resource.domains & RADEON_DOMAIN_VRAM ||
rtex->resource.flags & RADEON_FLAG_GTT_WC;
/* Write & linear only: */
else if (si_rings_is_buffer_referenced(sctx, rtex->resource.buf,
RADEON_USAGE_READWRITE) ||
!sctx->ws->buffer_wait(rtex->resource.buf, 0,
RADEON_USAGE_READWRITE)) {
@@ -1778,23 +1791,33 @@ static void *si_texture_transfer_map(struct pipe_context *ctx,
level, box,
&trans->b.b.stride,
&trans->b.b.layer_stride);
}
trans->staging = (struct r600_resource*)staging_depth;
buf = trans->staging;
} else if (use_staging_texture) {
struct pipe_resource resource;
struct r600_texture *staging;
+ struct pipe_box staging_box = *box;
+
+ if (user_stride) {
+ if (user_stride % rtex->surface.bpe != 0)
+ goto fail_trans;
+
+ staging_box.width = user_stride / rtex->surface.bpe;
+ assert(staging_box.width >= box->width);
+ }
+
+ si_init_temp_resource_from_box(&resource, texture, &staging_box, level,
+ SI_RESOURCE_FLAG_TRANSFER);
- si_init_temp_resource_from_box(&resource, texture, box, level,
- SI_RESOURCE_FLAG_TRANSFER);
resource.usage = (usage & PIPE_TRANSFER_READ) ?
PIPE_USAGE_STAGING : PIPE_USAGE_STREAM;
/* Create the temporary texture. */
staging = (struct r600_texture*)ctx->screen->resource_create(ctx->screen, &resource);
if (!staging) {
PRINT_ERR("failed to create temporary texture to hold untiled copy\n");
goto fail_trans;
}
trans->staging = &staging->resource;
--
2.17.0
More information about the mesa-dev
mailing list