From: Nicolai Hähnle <nicolai.haeh...@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

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

Reply via email to