Mesa (master): amd/common: Add support for modifiers.

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Nov 13 03:44:46 UTC 2020


Module: Mesa
Branch: master
Commit: 0833dd7d124bfd94161bff15e5b4293987920fce
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=0833dd7d124bfd94161bff15e5b4293987920fce

Author: Bas Nieuwenhuizen <bas at basnieuwenhuizen.nl>
Date:   Tue Oct  8 10:21:30 2019 +0200

amd/common: Add support for modifiers.

Reviewed-by: Marek Olšák <marek.olsak at amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6176>

---

 src/amd/common/ac_surface.c               | 452 ++++++++++++++++++++++++++----
 src/amd/common/ac_surface.h               |  33 +++
 src/amd/vulkan/radv_image.c               |   6 +-
 src/gallium/drivers/radeonsi/si_texture.c |   2 +
 4 files changed, 437 insertions(+), 56 deletions(-)

diff --git a/src/amd/common/ac_surface.c b/src/amd/common/ac_surface.c
index 9eddd3cb7c2..6218fbea3f3 100644
--- a/src/amd/common/ac_surface.c
+++ b/src/amd/common/ac_surface.c
@@ -32,11 +32,13 @@
 #include "addrlib/src/amdgpu_asic_addr.h"
 #include "amd_family.h"
 #include "drm-uapi/amdgpu_drm.h"
+#include "drm-uapi/drm_fourcc.h"
 #include "sid.h"
 #include "util/hash_table.h"
 #include "util/macros.h"
 #include "util/simple_mtx.h"
 #include "util/u_atomic.h"
+#include "util/format/u_format.h"
 #include "util/u_math.h"
 #include "util/u_memory.h"
 
@@ -326,6 +328,259 @@ static uint32_t *ac_compute_dcc_retile_map(struct ac_addrlib *addrlib,
    return dcc_retile_map;
 }
 
+bool ac_modifier_has_dcc(uint64_t modifier)
+{
+   return IS_AMD_FMT_MOD(modifier) && AMD_FMT_MOD_GET(DCC, modifier);
+}
+
+bool ac_modifier_has_dcc_retile(uint64_t modifier)
+{
+   return IS_AMD_FMT_MOD(modifier) && AMD_FMT_MOD_GET(DCC_RETILE, modifier);
+}
+
+static
+AddrSwizzleMode ac_modifier_gfx9_swizzle_mode(uint64_t modifier)
+{
+   if (modifier == DRM_FORMAT_MOD_LINEAR)
+      return ADDR_SW_LINEAR;
+
+   return AMD_FMT_MOD_GET(TILE, modifier);
+}
+static void
+ac_modifier_fill_dcc_params(uint64_t modifier, struct radeon_surf *surf,
+             ADDR2_COMPUTE_SURFACE_INFO_INPUT *surf_info)
+{
+   assert(ac_modifier_has_dcc(modifier));
+
+   surf_info->flags.metaRbUnaligned = 0;
+   if (AMD_FMT_MOD_GET(DCC_RETILE, modifier)) {
+      surf_info->flags.metaPipeUnaligned = 0;
+   } else {
+      surf_info->flags.metaPipeUnaligned = !AMD_FMT_MOD_GET(DCC_PIPE_ALIGN, modifier);
+   }
+
+   surf->u.gfx9.dcc.independent_64B_blocks = AMD_FMT_MOD_GET(DCC_INDEPENDENT_64B, modifier);
+   surf->u.gfx9.dcc.independent_128B_blocks = AMD_FMT_MOD_GET(DCC_INDEPENDENT_128B, modifier);
+   surf->u.gfx9.dcc.max_compressed_block_size = AMD_FMT_MOD_GET(DCC_MAX_COMPRESSED_BLOCK, modifier);
+}
+
+bool ac_is_modifier_supported(const struct radeon_info *info,
+                              const struct ac_modifier_options *options,
+                              enum pipe_format format,
+                              uint64_t modifier)
+{
+
+   if (util_format_is_compressed(format) ||
+       util_format_is_depth_or_stencil(format) ||
+       util_format_get_blocksize(format) > 8)
+      return false;
+
+   if (info->chip_class < GFX9)
+      return false;
+
+   if(modifier == DRM_FORMAT_MOD_LINEAR)
+      return true;
+
+   if (util_format_get_num_planes(format) > 1)
+      return false;
+
+   uint32_t allowed_swizzles = 0xFFFFFFFF;
+   switch(info->chip_class) {
+   case GFX9:
+      allowed_swizzles = ac_modifier_has_dcc(modifier) ? 0x06000000 : 0x06660660;
+      break;
+   case GFX10:
+   case GFX10_3:
+      allowed_swizzles = ac_modifier_has_dcc(modifier) ? 0x08000000 : 0x0E660660;
+      break;
+   default:
+      return false;
+   }
+
+   if (!((1u << ac_modifier_gfx9_swizzle_mode(modifier)) & allowed_swizzles))
+      return false;
+
+   if (ac_modifier_has_dcc(modifier)) {
+      if (!info->has_graphics)
+         return false;
+
+      if (!options->dcc)
+         return false;
+
+      if (ac_modifier_has_dcc_retile(modifier) && !options->dcc_retile)
+         return false;
+   }
+
+   return true;
+}
+
+bool ac_get_supported_modifiers(const struct radeon_info *info,
+                                const struct ac_modifier_options *options,
+                                enum pipe_format format,
+                                unsigned *mod_count,
+                                uint64_t *mods)
+{
+   unsigned current_mod = 0;
+
+#define ADD_MOD(name)                                                   \
+   if (ac_is_modifier_supported(info, options, format, (name))) {  \
+      if (mods && current_mod < *mod_count)                  \
+         mods[current_mod] = (name);                    \
+      ++current_mod;                                         \
+   }
+
+   /* The modifiers have to be added in descending order of estimated
+    * performance. The drivers will prefer modifiers that come earlier
+    * in the list. */
+   switch (info->chip_class) {
+   case GFX9: {
+      unsigned pipe_xor_bits = MIN2(G_0098F8_NUM_PIPES(info->gb_addr_config) +
+                                    G_0098F8_NUM_SHADER_ENGINES_GFX9(info->gb_addr_config), 8);
+      unsigned bank_xor_bits =  MIN2(G_0098F8_NUM_BANKS(info->gb_addr_config), 8 - pipe_xor_bits);
+      unsigned pipes = G_0098F8_NUM_PIPES(info->gb_addr_config);
+      unsigned rb = G_0098F8_NUM_RB_PER_SE(info->gb_addr_config) +
+                    G_0098F8_NUM_SHADER_ENGINES_GFX9(info->gb_addr_config);
+
+      uint64_t common_dcc = AMD_FMT_MOD_SET(DCC, 1) |
+                            AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
+                            AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
+                            AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, info->has_dcc_constant_encode) |
+                            AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
+                            AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
+                            AMD_FMT_MOD_SET(RB, rb);
+
+      ADD_MOD(AMD_FMT_MOD |
+              AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D_X) |
+              AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
+              AMD_FMT_MOD_SET(DCC_PIPE_ALIGN, 1) |
+              common_dcc |
+              AMD_FMT_MOD_SET(PIPE, pipes))
+
+      ADD_MOD(AMD_FMT_MOD |
+              AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
+              AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
+              AMD_FMT_MOD_SET(DCC_PIPE_ALIGN, 1) |
+              common_dcc |
+              AMD_FMT_MOD_SET(PIPE, pipes))
+
+      if (util_format_get_blocksize(format) == 4) {
+         if (info->num_render_backends == 1) {
+            ADD_MOD(AMD_FMT_MOD |
+                    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
+                    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
+                    common_dcc);
+         }
+
+
+         ADD_MOD(AMD_FMT_MOD |
+                 AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
+                 AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
+                 AMD_FMT_MOD_SET(DCC_RETILE, 1) |
+                 common_dcc |
+                 AMD_FMT_MOD_SET(PIPE, pipes))
+      }
+
+
+      ADD_MOD(AMD_FMT_MOD |
+              AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D_X) |
+              AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
+              AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
+              AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits));
+
+      ADD_MOD(AMD_FMT_MOD |
+              AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
+              AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
+              AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
+              AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits));
+
+      ADD_MOD(AMD_FMT_MOD |
+              AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) |
+              AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
+
+      ADD_MOD(AMD_FMT_MOD |
+              AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) |
+              AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
+
+      ADD_MOD(DRM_FORMAT_MOD_LINEAR)
+      break;
+   }
+   case GFX10:
+   case GFX10_3: {
+      bool rbplus = info->chip_class >= GFX10_3;
+      unsigned pipe_xor_bits = G_0098F8_NUM_PIPES(info->gb_addr_config);
+      unsigned pkrs = rbplus ? G_0098F8_NUM_PKRS(info->gb_addr_config) : 0;
+
+      unsigned version = rbplus ? AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS : AMD_FMT_MOD_TILE_VER_GFX10;
+      uint64_t common_dcc = AMD_FMT_MOD_SET(TILE_VERSION, version) |
+                            AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
+                            AMD_FMT_MOD_SET(DCC, 1) |
+                            AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
+                            AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
+                            AMD_FMT_MOD_SET(PACKERS, pkrs);
+
+      ADD_MOD(AMD_FMT_MOD | common_dcc |
+              AMD_FMT_MOD_SET(DCC_PIPE_ALIGN, 1) |
+              AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
+              AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_128B))
+
+      if (info->family == CHIP_NAVI12 || info->family == CHIP_NAVI14 || info->chip_class >= GFX10_3) {
+         bool independent_128b = info->chip_class >= GFX10_3;
+
+         if (info->num_render_backends == 1) {
+            ADD_MOD(AMD_FMT_MOD | common_dcc |
+                    AMD_FMT_MOD_SET(DCC_PIPE_ALIGN, 1) |
+                    AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
+                    AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, independent_128b) |
+                    AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B))
+         }
+
+         ADD_MOD(AMD_FMT_MOD | common_dcc |
+                 AMD_FMT_MOD_SET(DCC_RETILE, 1) |
+                 AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
+                 AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, independent_128b) |
+                 AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B))
+      }
+
+      ADD_MOD(AMD_FMT_MOD |
+              AMD_FMT_MOD_SET(TILE_VERSION, version) |
+              AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
+              AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
+              AMD_FMT_MOD_SET(PACKERS, pkrs))
+
+      ADD_MOD(AMD_FMT_MOD |
+              AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
+              AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
+              AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits))
+
+      if (util_format_get_blocksize(format) != 4) {
+         ADD_MOD(AMD_FMT_MOD |
+                 AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) |
+                 AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
+      }
+
+      ADD_MOD(AMD_FMT_MOD |
+              AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) |
+              AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
+
+      ADD_MOD(DRM_FORMAT_MOD_LINEAR)
+      break;
+   }
+   default:
+      break;
+   }
+
+#undef ADD_MOD
+
+   if (!mods) {
+      *mod_count = current_mod;
+      return true;
+   }
+
+   bool complete = current_mod <= *mod_count;
+   *mod_count = MIN2(*mod_count, current_mod);
+   return complete;
+}
+
 static void *ADDR_API allocSysMem(const ADDR_ALLOCSYSMEM_INPUT *pInput)
 {
    return malloc(pInput->sizeInBytes);
@@ -695,6 +950,13 @@ static bool get_display_flag(const struct ac_surf_config *config, const struct r
    unsigned num_channels = config->info.num_channels;
    unsigned bpe = surf->bpe;
 
+   /* With modifiers the kernel is in charge of whether it is displayable.
+    * We need to ensure at least 32 pixels pitch alignment, but this is
+    * always the case when the blocksize >= 4K.
+    */
+   if (surf->modifier != DRM_FORMAT_MOD_INVALID)
+      return false;
+
    if (!config->is_3d && !config->is_cube && !(surf->flags & RADEON_SURF_Z_OR_SBUFFER) &&
        surf->flags & RADEON_SURF_SCANOUT && config->info.samples <= 1 && surf->blk_w <= 2 &&
        surf->blk_h == 1) {
@@ -1497,7 +1759,9 @@ static int gfx9_compute_miptree(struct ac_addrlib *addrlib, const struct radeon_
           is_dcc_supported_by_CB(info, in->swizzleMode) &&
           (!in->flags.display ||
            is_dcc_supported_by_DCN(info, config, surf, !in->flags.metaRbUnaligned,
-                                   !in->flags.metaPipeUnaligned))) {
+                                   !in->flags.metaPipeUnaligned)) &&
+          (surf->modifier == DRM_FORMAT_MOD_INVALID ||
+           ac_modifier_has_dcc(surf->modifier))) {
          ADDR2_COMPUTE_DCCINFO_INPUT din = {0};
          ADDR2_COMPUTE_DCCINFO_OUTPUT dout = {0};
          ADDR2_META_MIP_INFO meta_mip_info[RADEON_SURF_MAX_LEVELS] = {0};
@@ -1579,7 +1843,8 @@ static int gfx9_compute_miptree(struct ac_addrlib *addrlib, const struct radeon_
          surf->u.gfx9.dcc_pitch_max = dout.pitch - 1;
 
          /* Compute displayable DCC. */
-         if (in->flags.display && surf->num_dcc_levels && info->use_display_dcc_with_retile_blit) {
+         if (((in->flags.display && info->use_display_dcc_with_retile_blit) ||
+              ac_modifier_has_dcc_retile(surf->modifier)) && surf->num_dcc_levels) {
             /* Compute displayable DCC info. */
             din.dccKeyFlags.pipeAligned = 0;
             din.dccKeyFlags.rbAligned = 0;
@@ -1866,72 +2131,86 @@ static int gfx9_compute_surface(struct ac_addrlib *addrlib, const struct radeon_
    AddrSurfInfoIn.flags.metaPipeUnaligned = 0;
    AddrSurfInfoIn.flags.metaRbUnaligned = 0;
 
-   /* Optimal values for the L2 cache. */
-   if (info->chip_class == GFX9) {
-      surf->u.gfx9.dcc.independent_64B_blocks = 1;
-      surf->u.gfx9.dcc.independent_128B_blocks = 0;
-      surf->u.gfx9.dcc.max_compressed_block_size = V_028C78_MAX_BLOCK_SIZE_64B;
-   } else if (info->chip_class >= GFX10) {
-      surf->u.gfx9.dcc.independent_64B_blocks = 0;
-      surf->u.gfx9.dcc.independent_128B_blocks = 1;
-      surf->u.gfx9.dcc.max_compressed_block_size = V_028C78_MAX_BLOCK_SIZE_128B;
-   }
-
-   if (AddrSurfInfoIn.flags.display) {
-      /* The display hardware can only read DCC with RB_ALIGNED=0 and
-       * PIPE_ALIGNED=0. PIPE_ALIGNED really means L2CACHE_ALIGNED.
-       *
-       * The CB block requires RB_ALIGNED=1 except 1 RB chips.
-       * PIPE_ALIGNED is optional, but PIPE_ALIGNED=0 requires L2 flushes
-       * after rendering, so PIPE_ALIGNED=1 is recommended.
-       */
-      if (info->use_display_dcc_unaligned) {
-         AddrSurfInfoIn.flags.metaPipeUnaligned = 1;
-         AddrSurfInfoIn.flags.metaRbUnaligned = 1;
+   if (ac_modifier_has_dcc(surf->modifier)) {
+      ac_modifier_fill_dcc_params(surf->modifier, surf, &AddrSurfInfoIn);
+   } else {
+      /* Optimal values for the L2 cache. */
+      if (info->chip_class == GFX9) {
+         surf->u.gfx9.dcc.independent_64B_blocks = 1;
+         surf->u.gfx9.dcc.independent_128B_blocks = 0;
+         surf->u.gfx9.dcc.max_compressed_block_size = V_028C78_MAX_BLOCK_SIZE_64B;
+      } else if (info->chip_class >= GFX10) {
+         surf->u.gfx9.dcc.independent_64B_blocks = 0;
+         surf->u.gfx9.dcc.independent_128B_blocks = 1;
+         surf->u.gfx9.dcc.max_compressed_block_size = V_028C78_MAX_BLOCK_SIZE_128B;
       }
 
-      /* Adjust DCC settings to meet DCN requirements. */
-      if (info->use_display_dcc_unaligned || info->use_display_dcc_with_retile_blit) {
-         /* Only Navi12/14 support independent 64B blocks in L2,
-          * but without DCC image stores.
+      if (AddrSurfInfoIn.flags.display) {
+         /* The display hardware can only read DCC with RB_ALIGNED=0 and
+          * PIPE_ALIGNED=0. PIPE_ALIGNED really means L2CACHE_ALIGNED.
+          *
+          * The CB block requires RB_ALIGNED=1 except 1 RB chips.
+          * PIPE_ALIGNED is optional, but PIPE_ALIGNED=0 requires L2 flushes
+          * after rendering, so PIPE_ALIGNED=1 is recommended.
           */
-         if (info->family == CHIP_NAVI12 || info->family == CHIP_NAVI14) {
-            surf->u.gfx9.dcc.independent_64B_blocks = 1;
-            surf->u.gfx9.dcc.independent_128B_blocks = 0;
-            surf->u.gfx9.dcc.max_compressed_block_size = V_028C78_MAX_BLOCK_SIZE_64B;
+         if (info->use_display_dcc_unaligned) {
+            AddrSurfInfoIn.flags.metaPipeUnaligned = 1;
+            AddrSurfInfoIn.flags.metaRbUnaligned = 1;
          }
 
-         if (info->chip_class >= GFX10_3) {
-            surf->u.gfx9.dcc.independent_64B_blocks = 1;
-            surf->u.gfx9.dcc.independent_128B_blocks = 1;
-            surf->u.gfx9.dcc.max_compressed_block_size = V_028C78_MAX_BLOCK_SIZE_64B;
+         /* Adjust DCC settings to meet DCN requirements. */
+         if (info->use_display_dcc_unaligned || info->use_display_dcc_with_retile_blit) {
+            /* Only Navi12/14 support independent 64B blocks in L2,
+             * but without DCC image stores.
+             */
+            if (info->family == CHIP_NAVI12 || info->family == CHIP_NAVI14) {
+               surf->u.gfx9.dcc.independent_64B_blocks = 1;
+               surf->u.gfx9.dcc.independent_128B_blocks = 0;
+               surf->u.gfx9.dcc.max_compressed_block_size = V_028C78_MAX_BLOCK_SIZE_64B;
+            }
+
+            if (info->chip_class >= GFX10_3) {
+               surf->u.gfx9.dcc.independent_64B_blocks = 1;
+               surf->u.gfx9.dcc.independent_128B_blocks = 1;
+               surf->u.gfx9.dcc.max_compressed_block_size = V_028C78_MAX_BLOCK_SIZE_64B;
+            }
          }
       }
    }
 
-   switch (mode) {
-   case RADEON_SURF_MODE_LINEAR_ALIGNED:
-      assert(config->info.samples <= 1);
-      assert(!(surf->flags & RADEON_SURF_Z_OR_SBUFFER));
-      AddrSurfInfoIn.swizzleMode = ADDR_SW_LINEAR;
-      break;
+   if (surf->modifier == DRM_FORMAT_MOD_INVALID) {
+      switch (mode) {
+      case RADEON_SURF_MODE_LINEAR_ALIGNED:
+         assert(config->info.samples <= 1);
+         assert(!(surf->flags & RADEON_SURF_Z_OR_SBUFFER));
+         AddrSurfInfoIn.swizzleMode = ADDR_SW_LINEAR;
+         break;
 
-   case RADEON_SURF_MODE_1D:
-   case RADEON_SURF_MODE_2D:
-      if (surf->flags & RADEON_SURF_IMPORTED ||
-          (info->chip_class >= GFX10 && surf->flags & RADEON_SURF_FORCE_SWIZZLE_MODE)) {
-         AddrSurfInfoIn.swizzleMode = surf->u.gfx9.surf.swizzle_mode;
+      case RADEON_SURF_MODE_1D:
+      case RADEON_SURF_MODE_2D:
+         if (surf->flags & RADEON_SURF_IMPORTED ||
+             (info->chip_class >= GFX10 && surf->flags & RADEON_SURF_FORCE_SWIZZLE_MODE)) {
+            AddrSurfInfoIn.swizzleMode = surf->u.gfx9.surf.swizzle_mode;
+            break;
+         }
+
+         r = gfx9_get_preferred_swizzle_mode(addrlib->handle, surf, &AddrSurfInfoIn, false,
+                                             &AddrSurfInfoIn.swizzleMode);
+         if (r)
+            return r;
          break;
+
+      default:
+         assert(0);
       }
+   } else {
+      /* We have a valid and required modifier here. */
 
-      r = gfx9_get_preferred_swizzle_mode(addrlib->handle, surf, &AddrSurfInfoIn, false,
-                                          &AddrSurfInfoIn.swizzleMode);
-      if (r)
-         return r;
-      break;
+      assert(!compressed);
+      assert(!ac_modifier_has_dcc(surf->modifier) ||
+             !(surf->flags & RADEON_SURF_DISABLE_DCC));
 
-   default:
-      assert(0);
+      AddrSurfInfoIn.swizzleMode = ac_modifier_gfx9_swizzle_mode(surf->modifier);
    }
 
    surf->u.gfx9.resource_type = AddrSurfInfoIn.resourceType;
@@ -2013,7 +2292,9 @@ static int gfx9_compute_surface(struct ac_addrlib *addrlib, const struct radeon_
        AddrSurfInfoIn.flags.color && !surf->is_linear &&
        surf->surf_alignment >= 64 * 1024 && /* 64KB tiling */
        !(surf->flags & (RADEON_SURF_DISABLE_DCC | RADEON_SURF_FORCE_SWIZZLE_MODE |
-                        RADEON_SURF_FORCE_MICRO_TILE_MODE))) {
+                        RADEON_SURF_FORCE_MICRO_TILE_MODE)) &&
+       (surf->modifier == DRM_FORMAT_MOD_INVALID ||
+        ac_modifier_has_dcc(surf->modifier))) {
       /* Validate that DCC is enabled if DCN can do it. */
       if ((info->use_display_dcc_unaligned || info->use_display_dcc_with_retile_blit) &&
           AddrSurfInfoIn.flags.display && surf->bpe == 4) {
@@ -2316,6 +2597,9 @@ bool ac_surface_set_umd_metadata(const struct radeon_info *info, struct radeon_s
    uint32_t *desc = &metadata[2];
    uint64_t offset;
 
+   if (surf->modifier != DRM_FORMAT_MOD_INVALID)
+      return true;
+
    if (info->chip_class >= GFX9)
       offset = surf->u.gfx9.surf_offset;
    else
@@ -2492,3 +2776,61 @@ void ac_surface_override_offset_stride(const struct radeon_info *info, struct ra
    if (surf->display_dcc_offset)
       surf->display_dcc_offset += offset;
 }
+
+unsigned ac_surface_get_nplanes(const struct radeon_surf *surf)
+{
+   if (surf->modifier == DRM_FORMAT_MOD_INVALID)
+      return 1;
+   else if (surf->display_dcc_offset)
+      return 3;
+   else if (surf->dcc_offset)
+      return 2;
+   else
+      return 1;
+}
+
+uint64_t ac_surface_get_plane_offset(enum chip_class chip_class,
+                                    const struct radeon_surf *surf,
+                                    unsigned plane, unsigned layer)
+{
+   switch (plane) {
+   case 0:
+      if (chip_class >= GFX9) {
+         return surf->u.gfx9.surf_offset +
+                layer * surf->u.gfx9.surf_slice_size;
+      } else {
+         return surf->u.legacy.level[0].offset +
+                layer * (uint64_t)surf->u.legacy.level[0].slice_size_dw * 4;
+      }
+   case 1:
+      assert(!layer);
+      return surf->display_dcc_offset ?
+             surf->display_dcc_offset : surf->dcc_offset;
+   case 2:
+      assert(!layer);
+      return surf->dcc_offset;
+   default:
+      unreachable("Invalid plane index");
+   }
+}
+
+uint64_t ac_surface_get_plane_stride(enum chip_class chip_class,
+                                    const struct radeon_surf *surf,
+                                    unsigned plane)
+{
+   switch (plane) {
+   case 0:
+      if (chip_class >= GFX9) {
+         return surf->u.gfx9.surf_pitch * surf->bpe;
+      } else {
+         return surf->u.legacy.level[0].nblk_x * surf->bpe;
+      }
+   case 1:
+      return 1 + (surf->display_dcc_offset ?
+             surf->u.gfx9.display_dcc_pitch_max : surf->u.gfx9.dcc_pitch_max);
+   case 2:
+      return surf->u.gfx9.dcc_pitch_max + 1;
+   default:
+      unreachable("Invalid plane index");
+   }
+}
diff --git a/src/amd/common/ac_surface.h b/src/amd/common/ac_surface.h
index 630f626500f..ef959eae2c3 100644
--- a/src/amd/common/ac_surface.h
+++ b/src/amd/common/ac_surface.h
@@ -27,6 +27,7 @@
 #define AC_SURFACE_H
 
 #include "amd_family.h"
+#include "util/format/u_format.h"
 
 #include <stdbool.h>
 #include <stdint.h>
@@ -207,6 +208,12 @@ struct radeon_surf {
    unsigned micro_tile_mode : 3;
    uint32_t flags;
 
+    /*
+     * DRM format modifier. Set to DRM_FORMAT_MOD_INVALID to have addrlib
+     * select tiling parameters instead.
+     */
+    uint64_t modifier;
+
    /* These are return values. Some of them can be set by the caller, but
     * they will be treated as hints (e.g. bankw, bankh) and might be
     * changed by the calculator.
@@ -313,6 +320,32 @@ void ac_surface_get_umd_metadata(const struct radeon_info *info, struct radeon_s
 void ac_surface_override_offset_stride(const struct radeon_info *info, struct radeon_surf *surf,
                                        unsigned num_mipmap_levels, uint64_t offset, unsigned pitch);
 
+
+struct ac_modifier_options {
+	bool dcc; /* Whether to allow DCC. */
+	bool dcc_retile; /* Whether to allow use of a DCC retile map. */
+};
+
+bool ac_is_modifier_supported(const struct radeon_info *info,
+                              const struct ac_modifier_options *options,
+                              enum pipe_format format,
+                              uint64_t modifier);
+bool ac_get_supported_modifiers(const struct radeon_info *info,
+                                const struct ac_modifier_options *options,
+                                enum pipe_format format,
+                                unsigned *mod_count,
+                                uint64_t *mods);
+bool ac_modifier_has_dcc(uint64_t modifier);
+bool ac_modifier_has_dcc_retile(uint64_t modifier);
+
+unsigned ac_surface_get_nplanes(const struct radeon_surf *surf);
+uint64_t ac_surface_get_plane_offset(enum chip_class chip_class,
+                                     const struct radeon_surf *surf,
+                                     unsigned plane, unsigned layer);
+uint64_t ac_surface_get_plane_stride(enum chip_class chip_class,
+                                     const struct radeon_surf *surf,
+                                     unsigned plane);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/amd/vulkan/radv_image.c b/src/amd/vulkan/radv_image.c
index 429c3d68467..ab70e1b5b5d 100644
--- a/src/amd/vulkan/radv_image.c
+++ b/src/amd/vulkan/radv_image.c
@@ -25,6 +25,8 @@
  * IN THE SOFTWARE.
  */
 
+#include <libdrm/drm_fourcc.h>
+
 #include "radv_debug.h"
 #include "radv_private.h"
 #include "vk_format.h"
@@ -452,7 +454,6 @@ radv_get_surface_flags(struct radv_device *device,
 	is_depth = vk_format_has_depth(desc);
 	is_stencil = vk_format_has_stencil(desc);
 
-
 	flags = RADEON_SURF_SET(array_mode, MODE);
 
 	switch (pCreateInfo->imageType){
@@ -1317,9 +1318,11 @@ radv_image_reset_layout(struct radv_image *image)
 		VkFormat format = vk_format_get_plane_format(image->vk_format, i);
 
 		uint32_t flags = image->planes[i].surface.flags;
+		uint64_t modifier = image->planes[i].surface.modifier;
 		memset(image->planes + i, 0, sizeof(image->planes[i]));
 
 		image->planes[i].surface.flags = flags;
+		image->planes[i].surface.modifier = modifier;
 		image->planes[i].surface.blk_w = vk_format_get_blockwidth(format);
 		image->planes[i].surface.blk_h = vk_format_get_blockheight(format);
 		image->planes[i].surface.bpe = vk_format_get_blocksize(vk_format_depth_only(format));
@@ -1474,6 +1477,7 @@ radv_image_create(VkDevice _device,
 	for (unsigned plane = 0; plane < image->plane_count; ++plane) {
 		image->planes[plane].surface.flags =
 			radv_get_surface_flags(device, image, plane, pCreateInfo, format);
+		image->planes[plane].surface.modifier = DRM_FORMAT_MOD_INVALID;
 	}
 
 	bool delay_layout = external_info &&
diff --git a/src/gallium/drivers/radeonsi/si_texture.c b/src/gallium/drivers/radeonsi/si_texture.c
index 3fea3b2eebd..794ba1ae0f6 100644
--- a/src/gallium/drivers/radeonsi/si_texture.c
+++ b/src/gallium/drivers/radeonsi/si_texture.c
@@ -316,6 +316,8 @@ static int si_init_surface(struct si_screen *sscreen, struct radeon_surf *surfac
          surface->u.gfx9.surf.swizzle_mode = ADDR_SW_64KB_R_X;
    }
 
+   surface->modifier = DRM_FORMAT_MOD_INVALID;
+
    r = sscreen->ws->surface_init(sscreen->ws, ptex, flags, bpe, array_mode, surface);
    if (r) {
       return r;



More information about the mesa-commit mailing list