radeonsi: implement per-level DCC and CMASK fast clears for gfx10+
authorMarek Olšák <marek.olsak@amd.com>
Sat, 20 Mar 2021 00:47:48 +0000 (20:47 -0400)
committerMarge Bot <eric+marge@anholt.net>
Tue, 13 Apr 2021 03:17:42 +0000 (03:17 +0000)
Fast clears are only used for level 0. This enables clearing level 0
of CMASK and DCC on gfx10+ when there are multiple mipmap levels.
vi_dcc_clear_level can also clear any level now.

Mipmapped array textures are still cleared slowly.

Acked-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10003>

src/gallium/drivers/radeonsi/si_clear.c

index 04eb4b8..fd8d0d9 100644 (file)
@@ -279,8 +279,32 @@ bool vi_dcc_get_clear_info(struct si_context *sctx, struct si_texture *tex, unsi
       dcc_offset = tex->surface.meta_offset;
    }
 
-   if (sctx->chip_class >= GFX9) {
-      /* Mipmap level clears aren't implemented. */
+   if (sctx->chip_class >= GFX10) {
+      /* 4x and 8x MSAA needs a sophisticated compute shader for
+       * the clear. */
+      if (tex->buffer.b.b.nr_storage_samples >= 4)
+         return false;
+
+      unsigned num_layers = util_num_layers(&tex->buffer.b.b, level);
+
+      if (num_layers == 1) {
+         /* Clear a specific level. */
+         dcc_offset += tex->surface.u.gfx9.meta_levels[level].offset;
+         clear_size = tex->surface.u.gfx9.meta_levels[level].size;
+      } else if (tex->buffer.b.b.last_level == 0) {
+         /* Clear all layers having only 1 level. */
+         clear_size = tex->surface.meta_size;
+      } else {
+         /* Clearing DCC with both multiple levels and multiple layers is not
+          * implemented.
+          */
+         return false;
+      }
+   } else if (sctx->chip_class == GFX9) {
+      /* TODO: Implement DCC fast clear for level 0 of mipmapped textures. Mipmapped
+       * DCC has to clear a rectangular area of DCC for level 0 (because the whole miptree
+       * is organized in a 2D plane).
+       */
       if (tex->buffer.b.b.last_level > 0)
          return false;
 
@@ -445,15 +469,6 @@ static void si_do_fast_color_clear(struct si_context *sctx, unsigned *buffers,
          continue;
 
       struct si_texture *tex = (struct si_texture *)fb->cbufs[i]->texture;
-
-      /* TODO: GFX9: Implement DCC fast clear for level 0 of
-       * mipmapped textures. Mipmapped DCC has to clear a rectangular
-       * area of DCC for level 0 (because the whole miptree is
-       * organized in a 2D plane).
-       */
-      if (sctx->chip_class >= GFX9 && tex->buffer.b.b.last_level > 0)
-         continue;
-
       unsigned num_layers = util_num_layers(&tex->buffer.b.b, level);
 
       /* the clear is allowed if all layers are bound */
@@ -584,14 +599,58 @@ static void si_do_fast_color_clear(struct si_context *sctx, unsigned *buffers,
          if (tex->buffer.flags & RADEON_FLAG_ENCRYPTED)
             continue;
 
-         /* ensure CMASK is enabled */
-         if (!si_alloc_separate_cmask(sctx->screen, tex))
-            continue;
+         uint64_t cmask_offset = 0;
+         unsigned clear_size = 0;
+
+         if (sctx->chip_class >= GFX10) {
+            assert(level == 0);
+
+            /* Clearing CMASK with both multiple levels and multiple layers is not
+             * implemented.
+             */
+            if (num_layers > 1 && tex->buffer.b.b.last_level > 0)
+               continue;
+
+            if (!si_alloc_separate_cmask(sctx->screen, tex))
+               continue;
+
+            if (num_layers == 1) {
+               /* Clear level 0. */
+               cmask_offset = tex->surface.cmask_offset + tex->surface.u.gfx9.color.cmask_level0.offset;
+               clear_size = tex->surface.u.gfx9.color.cmask_level0.size;
+            } else if (tex->buffer.b.b.last_level == 0) {
+               /* Clear all layers having only 1 level. */
+               cmask_offset = tex->surface.cmask_offset;
+               clear_size = tex->surface.cmask_size;
+            } else {
+               assert(0); /* this is prevented above */
+            }
+         } else if (sctx->chip_class == GFX9) {
+            /* TODO: Implement CMASK fast clear for level 0 of mipmapped textures. Mipmapped
+             * CMASK has to clear a rectangular area of CMASK for level 0 (because the whole
+             * miptree is organized in a 2D plane).
+             */
+            if (tex->buffer.b.b.last_level > 0)
+               continue;
+
+            if (!si_alloc_separate_cmask(sctx->screen, tex))
+               continue;
+
+            cmask_offset = tex->surface.cmask_offset;
+            clear_size = tex->surface.cmask_size;
+         } else {
+            if (!si_alloc_separate_cmask(sctx->screen, tex))
+               continue;
+
+            /* GFX6-8: This only covers mipmap level 0. */
+            cmask_offset = tex->surface.cmask_offset;
+            clear_size = tex->surface.cmask_size;
+         }
 
          /* Do the fast clear. */
          assert(num_clears < ARRAY_SIZE(info));
          si_init_buffer_clear(&info[num_clears++], &tex->cmask_buffer->b.b,
-                              tex->surface.cmask_offset, tex->surface.cmask_size, 0);
+                              cmask_offset, clear_size, 0);
          clear_types |= SI_CLEAR_TYPE_CMASK;
          eliminate_needed = true;
       }