Module: Mesa
Branch: main
Commit: 4f047c9583a0ef3dc23017c3eb37d01aaf1d61dd
URL:    
http://cgit.freedesktop.org/mesa/mesa/commit/?id=4f047c9583a0ef3dc23017c3eb37d01aaf1d61dd

Author: David Rosca <[email protected]>
Date:   Sun Jul 30 12:39:15 2023 +0200

radeonsi: Copy all planes with multi-plane staging textures

Multi-plane format textures are allocated as a single buffer
for all planes, so when mapping first plane it will map
all planes.
However, when staging texture is used, only the first
plane will be available.

When asked to map first plane of multi-plane texture,
create a staging texture with matching multi-plane format
and copy all planes on map/unmap.

Reviewed-by: Marek Olšák <[email protected]>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24389>

---

 src/gallium/drivers/radeonsi/si_pipe.h    |  1 +
 src/gallium/drivers/radeonsi/si_texture.c | 62 ++++++++++++++++++++++++++++---
 2 files changed, 58 insertions(+), 5 deletions(-)

diff --git a/src/gallium/drivers/radeonsi/si_pipe.h 
b/src/gallium/drivers/radeonsi/si_pipe.h
index 389716854f9..154ab2bf138 100644
--- a/src/gallium/drivers/radeonsi/si_pipe.h
+++ b/src/gallium/drivers/radeonsi/si_pipe.h
@@ -383,6 +383,7 @@ struct si_texture {
    unsigned num_level0_transfers;
    unsigned plane_index; /* other planes are different pipe_resources */
    unsigned num_planes;
+   enum pipe_format multi_plane_format;
 
    /* Depth buffer compression and fast clear. */
    float depth_clear_value[RADEON_SURF_MAX_LEVELS];
diff --git a/src/gallium/drivers/radeonsi/si_texture.c 
b/src/gallium/drivers/radeonsi/si_texture.c
index a5f33dc928e..f3c5c307192 100644
--- a/src/gallium/drivers/radeonsi/si_texture.c
+++ b/src/gallium/drivers/radeonsi/si_texture.c
@@ -65,6 +65,44 @@ static void si_copy_region_with_blit(struct pipe_context 
*pipe, struct pipe_reso
    }
 }
 
+/* Copy all planes of multi-plane texture */
+static bool si_copy_multi_plane_texture(struct pipe_context *ctx, struct 
pipe_resource *dst,
+                                        unsigned dst_level, unsigned dstx, 
unsigned dsty, unsigned dstz,
+                                        struct pipe_resource *src, unsigned 
src_level,
+                                        const struct pipe_box *src_box)
+{
+   unsigned i;
+   struct si_texture *src_tex = (struct si_texture *)src;
+   struct si_texture *dst_tex = (struct si_texture *)dst;
+   struct pipe_box sbox;
+   const struct util_format_description *desc;
+
+   if (src_tex->multi_plane_format == PIPE_FORMAT_NONE || src_tex->plane_index 
!= 0)
+      return false;
+
+   assert(src_tex->multi_plane_format == dst_tex->multi_plane_format);
+   assert(dst_tex->plane_index == 0 && src_tex->num_planes == 
dst_tex->num_planes);
+
+   sbox = *src_box;
+   desc = util_format_description(src_tex->multi_plane_format);
+
+   for (i = 0; i < src_tex->num_planes; ++i) {
+      if (!src || !dst)
+         break;
+      si_resource_copy_region(ctx, dst, dst_level, dstx, dsty, dstz, src, 
src_level, &sbox);
+      src = src->next;
+      dst = dst->next;
+      if (i == 0) {
+         dstx /= desc->block.width;
+         dsty /= desc->block.height;
+         sbox.width /= desc->block.width;
+         sbox.height /= desc->block.height;
+      }
+   }
+
+   return true;
+}
+
 /* Copy from a full GPU texture to a transfer's staging one. */
 static void si_copy_to_staging_texture(struct pipe_context *ctx, struct 
si_transfer *stransfer)
 {
@@ -79,6 +117,9 @@ static void si_copy_to_staging_texture(struct pipe_context 
*ctx, struct si_trans
       return;
    }
 
+   if (si_copy_multi_plane_texture(ctx, dst, 0, 0, 0, 0, src, src_level, 
&transfer->box))
+      return;
+
    si_resource_copy_region(ctx, dst, 0, 0, 0, 0, src, src_level, 
&transfer->box);
 }
 
@@ -101,6 +142,10 @@ static void si_copy_from_staging_texture(struct 
pipe_context *ctx, struct si_tra
       return;
    }
 
+   if (si_copy_multi_plane_texture(ctx, dst, transfer->level, transfer->box.x, 
transfer->box.y,
+                                   transfer->box.z, src, 0, &sbox))
+      return;
+
    if (util_format_is_compressed(dst->format)) {
       sbox.width = util_format_get_nblocksx(dst->format, sbox.width);
       sbox.height = util_format_get_nblocksx(dst->format, sbox.height);
@@ -1331,6 +1376,9 @@ si_texture_create_with_modifier(struct pipe_screen 
*screen,
          si_set_tex_bo_metadata(sscreen, tex);
    }
 
+   if (num_planes >= 2)
+      plane0->multi_plane_format = templ->format;
+
    return (struct pipe_resource *)plane0;
 }
 
@@ -1753,8 +1801,12 @@ static void si_init_temp_resource_from_box(struct 
pipe_resource *res, struct pip
                                            const struct pipe_box *box, 
unsigned level,
                                            unsigned usage, unsigned flags)
 {
+   struct si_texture *tex = (struct si_texture *)orig;
+   enum pipe_format orig_format = tex->multi_plane_format != PIPE_FORMAT_NONE ?
+      tex->multi_plane_format : orig->format;
+
    memset(res, 0, sizeof(*res));
-   res->format = orig->format;
+   res->format = orig_format;
    res->width0 = box->width;
    res->height0 = box->height;
    res->depth0 = 1;
@@ -1762,11 +1814,11 @@ static void si_init_temp_resource_from_box(struct 
pipe_resource *res, struct pip
    res->usage = usage;
    res->flags = flags;
 
-   if (flags & SI_RESOURCE_FLAG_FORCE_LINEAR && 
util_format_is_compressed(orig->format)) {
+   if (flags & SI_RESOURCE_FLAG_FORCE_LINEAR && 
util_format_is_compressed(orig_format)) {
       /* Transfer resources are allocated with linear tiling, which is
        * not supported for compressed formats.
        */
-      unsigned blocksize = util_format_get_blocksize(orig->format);
+      unsigned blocksize = util_format_get_blocksize(orig_format);
 
       if (blocksize == 8) {
          res->format = PIPE_FORMAT_R16G16B16A16_UINT;
@@ -1775,8 +1827,8 @@ static void si_init_temp_resource_from_box(struct 
pipe_resource *res, struct pip
          res->format = PIPE_FORMAT_R32G32B32A32_UINT;
       }
 
-      res->width0 = util_format_get_nblocksx(orig->format, box->width);
-      res->height0 = util_format_get_nblocksy(orig->format, box->height);
+      res->width0 = util_format_get_nblocksx(orig_format, box->width);
+      res->height0 = util_format_get_nblocksy(orig_format, box->height);
    }
 
    /* We must set the correct texture target and dimensions for a 3D box. */

Reply via email to