intel/isl: Implement correct tile size calculations for Ys/Yf
authorJason Ekstrand <jason.ekstrand@intel.com>
Thu, 22 Feb 2018 00:04:32 +0000 (16:04 -0800)
committerMarge Bot <emma+marge@anholt.net>
Fri, 1 Sep 2023 23:22:17 +0000 (23:22 +0000)
The tile size calculations use a clever bit of math to make them short
and simple.  We add unit tests to assert that they identically match the
tables in the PRM.

Reviewed-by: Topi Pohjolainen <topi.pohjolainen@intel.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Reviewed-by: Nanley Chery <nanley.g.chery@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/23620>

src/intel/isl/isl.c
src/intel/isl/isl_gfx12.c
src/intel/isl/isl_gfx9.c
src/intel/isl/meson.build
src/intel/isl/tests/isl_tile_std_y_test.c [new file with mode: 0644]

index 3055857..3857d39 100644 (file)
@@ -507,13 +507,67 @@ isl_tiling_get_info(enum isl_tiling tiling,
    case ISL_TILING_ICL_Ys: {
       bool is_Ys = tiling == ISL_TILING_SKL_Ys ||
                    tiling == ISL_TILING_ICL_Ys;
+      assert(format_bpb >= 8);
 
-      assert(bs > 0);
-      unsigned width = 1 << (6 + (ffs(bs) / 2) + (2 * is_Ys));
-      unsigned height = 1 << (6 - (ffs(bs) / 2) + (2 * is_Ys));
+      switch (dim) {
+      case ISL_SURF_DIM_2D:
+         /* See the BSpec Memory Data Formats » Common Surface Formats »
+          * Surface Layout and Tiling [SKL+] » 2D Surfaces SKL+ » 2D/CUBE
+          * Alignment Requirement [SKL+]
+          *
+          * Or, look in the SKL PRM under Memory Views > Common Surface
+          * Formats > Surface Layout and Tiling > 2D Surfaces > 2D/CUBE
+          * Alignment Requirements.
+          */
+         logical_el = (struct isl_extent4d) {
+            .w = 1 << (6 - ((ffs(format_bpb) - 4) / 2) + (2 * is_Ys)),
+            .h = 1 << (6 - ((ffs(format_bpb) - 3) / 2) + (2 * is_Ys)),
+            .d = 1,
+            .a = 1,
+         };
+
+         if (samples > 1 && tiling != ISL_TILING_SKL_Yf) {
+            /* SKL PRMs, Volume 5: Memory Views, 2D/CUBE Alignment
+             * Requirement:
+             *
+             *    "For MSFMT_MSS type multi-sampled TileYS surfaces, the
+             *     alignments given above must be divided by the appropriate
+             *     value from the table below."
+             *
+             * The formulas below reproduce those values.
+             */
+            if (msaa_layout == ISL_MSAA_LAYOUT_ARRAY) {
+               logical_el.w >>= (ffs(samples) - 0) / 2;
+               logical_el.h >>= (ffs(samples) - 1) / 2;
+               logical_el.a = samples;
+            }
+         }
+         break;
+
+      case ISL_SURF_DIM_3D:
+         /* See the BSpec Memory Data Formats » Common Surface Formats »
+          * Surface Layout and Tiling [SKL+] » 3D Surfaces SKL+ » 3D Alignment
+          * Requirements [SKL+]
+          *
+          * Or, look in the SKL PRM under Memory Views > Common Surface
+          * Formats > Surface Layout and Tiling > 3D Surfaces > 3D Alignment
+          * Requirements.
+          */
+         logical_el = (struct isl_extent4d) {
+            .w = 1 << (4 - ((ffs(format_bpb) - 2) / 3) + (2 * is_Ys)),
+            .h = 1 << (4 - ((ffs(format_bpb) - 4) / 3) + (1 * is_Ys)),
+            .d = 1 << (4 - ((ffs(format_bpb) - 3) / 3) + (1 * is_Ys)),
+            .a = 1,
+         };
+         break;
+      default:
+         unreachable("Invalid dimension");
+      }
+
+      uint32_t tile_size_B = is_Ys ? (1 << 16) : (1 << 12);
 
-      logical_el = isl_extent4d(width / bs, height, 1, 1);
-      phys_B = isl_extent2d(width, height);
+      phys_B.w = logical_el.width * bs;
+      phys_B.h = tile_size_B / phys_B.w;
       break;
    }
    case ISL_TILING_64:
index 215e901..ec4325d 100644 (file)
@@ -220,7 +220,29 @@ isl_gfx12_choose_image_alignment_el(const struct isl_device *dev,
       return;
    }
 
-   if (isl_surf_usage_is_depth(info->usage)) {
+   if (isl_tiling_is_std_y(tiling)) {
+      /* From RENDER_SURFACE_STATE::SurfaceHorizontalAlignment,
+       *
+       *   This field is ignored for Tile64 surface formats because horizontal
+       *   alignment is always to the start of the next tile in that case.
+       *
+       * From RENDER_SURFACE_STATE::SurfaceQPitch,
+       *
+       *   Because MSAA is only supported for Tile64, QPitch must also be
+       *   programmed to an aligned tile boundary for MSAA surfaces.
+       *
+       * Images in this surface must be tile-aligned.  The table on the Bspec
+       * page, "2D/CUBE Alignment Requirement", shows that the vertical
+       * alignment is also a tile height for non-MSAA as well.
+       */
+      struct isl_tile_info tile_info;
+      isl_tiling_get_info(tiling, info->dim, msaa_layout, fmtl->bpb,
+                          info->samples, &tile_info);
+
+      *image_align_el = isl_extent3d(tile_info.logical_extent_el.w,
+                                     tile_info.logical_extent_el.h,
+                                     1);
+   } else if (isl_surf_usage_is_depth(info->usage)) {
       /* The alignment parameters for depth buffers are summarized in the
        * following table:
        *
index 4c22f60..75db0fd 100644 (file)
 #include "isl_gfx9.h"
 #include "isl_priv.h"
 
-/**
- * Calculate the surface's subimage alignment, in units of surface samples,
- * for the standard tiling formats Yf and Ys.
- */
-static void
-gfx9_calc_std_image_alignment_sa(const struct isl_device *dev,
-                                 const struct isl_surf_init_info *restrict info,
-                                 enum isl_tiling tiling,
-                                 enum isl_msaa_layout msaa_layout,
-                                 struct isl_extent3d *align_sa)
-{
-   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
-
-   assert(isl_tiling_is_std_y(tiling));
-
-   const uint32_t bpb = fmtl->bpb;
-   const uint32_t is_Ys = tiling == ISL_TILING_SKL_Ys ||
-                          tiling == ISL_TILING_ICL_Ys;
-
-   switch (info->dim) {
-   case ISL_SURF_DIM_1D:
-      /* See the Skylake BSpec > Memory Views > Common Surface Formats > Surface
-       * Layout and Tiling > 1D Surfaces > 1D Alignment Requirements.
-       */
-      *align_sa = (struct isl_extent3d) {
-         .w = 1 << (12 - (ffs(bpb) - 4) + (4 * is_Ys)),
-         .h = 1,
-         .d = 1,
-      };
-      return;
-   case ISL_SURF_DIM_2D:
-      /* See the Skylake BSpec > Memory Views > Common Surface Formats >
-       * Surface Layout and Tiling > 2D Surfaces > 2D/CUBE Alignment
-       * Requirements.
-       */
-      *align_sa = (struct isl_extent3d) {
-         .w = 1 << (6 - ((ffs(bpb) - 4) / 2) + (4 * is_Ys)),
-         .h = 1 << (6 - ((ffs(bpb) - 3) / 2) + (4 * is_Ys)),
-         .d = 1,
-      };
-
-      if (is_Ys) {
-         /* FINISHME(chadv): I don't trust this code. Untested. */
-         isl_finishme("%s:%s: [SKL+] multisample TileYs", __FILE__, __func__);
-
-         switch (msaa_layout) {
-         case ISL_MSAA_LAYOUT_NONE:
-         case ISL_MSAA_LAYOUT_INTERLEAVED:
-            break;
-         case ISL_MSAA_LAYOUT_ARRAY:
-            align_sa->w >>= (ffs(info->samples) - 0) / 2;
-            align_sa->h >>= (ffs(info->samples) - 1) / 2;
-            break;
-         }
-      }
-      return;
-
-   case ISL_SURF_DIM_3D:
-      /* See the Skylake BSpec > Memory Views > Common Surface Formats > Surface
-       * Layout and Tiling > 1D Surfaces > 1D Alignment Requirements.
-       */
-      *align_sa = (struct isl_extent3d) {
-         .w = 1 << (4 - ((ffs(bpb) - 2) / 3) + (4 * is_Ys)),
-         .h = 1 << (4 - ((ffs(bpb) - 4) / 3) + (2 * is_Ys)),
-         .d = 1 << (4 - ((ffs(bpb) - 3) / 3) + (2 * is_Ys)),
-      };
-      return;
-   }
-
-   unreachable("bad isl_surface_type");
-}
-
 void
 isl_gfx9_choose_image_alignment_el(const struct isl_device *dev,
                                    const struct isl_surf_init_info *restrict info,
@@ -167,11 +95,15 @@ isl_gfx9_choose_image_alignment_el(const struct isl_device *dev,
     */
 
    if (isl_tiling_is_std_y(tiling)) {
-      struct isl_extent3d image_align_sa;
-      gfx9_calc_std_image_alignment_sa(dev, info, tiling, msaa_layout,
-                                     &image_align_sa);
-
-      *image_align_el = isl_extent3d_sa_to_el(info->format, image_align_sa);
+      /* Ys and Yf tiled images are aligned to the tile size */
+      struct isl_tile_info tile_info;
+      isl_tiling_get_info(tiling, info->dim, msaa_layout,
+                          fmtl->bpb, info->samples, &tile_info);
+      *image_align_el = (struct isl_extent3d) {
+         .w = tile_info.logical_extent_el.w,
+         .h = tile_info.logical_extent_el.h,
+         .d = tile_info.logical_extent_el.d,
+      };
       return;
    }
 
index c3816bd..682392b 100644 (file)
@@ -186,4 +186,16 @@ if with_tests
     suite : ['intel'],
     protocol : 'gtest',
   )
+
+  test(
+    'isl_tile_std_y',
+    executable(
+      'isl_tile_std_y_test',
+      'tests/isl_tile_std_y_test.c',
+      dependencies : dep_m,
+      include_directories : [inc_include, inc_src, inc_gallium, inc_intel],
+      link_with : [libisl, libintel_dev],
+    ),
+    suite : ['intel'],
+  )
 endif
diff --git a/src/intel/isl/tests/isl_tile_std_y_test.c b/src/intel/isl/tests/isl_tile_std_y_test.c
new file mode 100644 (file)
index 0000000..83bd647
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2018 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "isl/isl.h"
+
+// An asssert that works regardless of NDEBUG.
+#define t_assert(cond) \
+   do { \
+      if (!(cond)) { \
+         fprintf(stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
+         abort(); \
+      } \
+   } while (0)
+
+static void
+assert_tile_size(enum isl_tiling tiling, enum isl_surf_dim dim,
+                 enum isl_msaa_layout msaa_layout,
+                 uint32_t bpb, uint32_t samples,
+                 uint32_t w, uint32_t h, uint32_t d, uint32_t a)
+{
+   struct isl_tile_info tile_info;
+   isl_tiling_get_info(tiling, dim, msaa_layout, bpb, samples, &tile_info);
+
+   /* Sanity */
+   t_assert(tile_info.tiling == tiling);
+   t_assert(tile_info.format_bpb == bpb);
+
+   t_assert(tile_info.logical_extent_el.w == w);
+   t_assert(tile_info.logical_extent_el.h == h);
+   t_assert(tile_info.logical_extent_el.d == d);
+   t_assert(tile_info.logical_extent_el.a == a);
+
+   bool is_Ys = tiling == ISL_TILING_SKL_Ys ||
+                tiling == ISL_TILING_ICL_Ys;
+   uint32_t tile_size = is_Ys ? 64 * 1024 : 4 * 1024;
+
+   assert(tile_size == tile_info.phys_extent_B.w *
+                       tile_info.phys_extent_B.h);
+
+   assert(tile_size == tile_info.logical_extent_el.w *
+                       tile_info.logical_extent_el.h *
+                       tile_info.logical_extent_el.d *
+                       tile_info.logical_extent_el.a *
+                       bpb / 8);
+}
+
+static void
+assert_2d_tile_size(enum isl_tiling tiling, uint32_t bpb,
+                    uint32_t halign, uint32_t valign)
+{
+#define ASSERT_2D(tiling, bpb, samples, w, h, a) \
+   assert_tile_size(tiling, ISL_SURF_DIM_2D, ISL_MSAA_LAYOUT_ARRAY, \
+                    bpb, samples, w, h, 1, a)
+
+   /* Single sampled */
+   ASSERT_2D(tiling, bpb, 1, halign, valign, 1);
+
+   /* Multisampled */
+   if (tiling == ISL_TILING_SKL_Yf) {
+      ASSERT_2D(tiling, bpb,  2, halign, valign, 1);
+      ASSERT_2D(tiling, bpb,  4, halign, valign, 1);
+      ASSERT_2D(tiling, bpb,  8, halign, valign, 1);
+      ASSERT_2D(tiling, bpb, 16, halign, valign, 1);
+   } else {
+      /* For gfx9 Ys and for both Yf and Ys on gfx11, we have to divide the
+       * size by the number of samples.
+       */
+      ASSERT_2D(tiling, bpb,  2, halign / 2, valign / 1,  2);
+      ASSERT_2D(tiling, bpb,  4, halign / 2, valign / 2,  4);
+      ASSERT_2D(tiling, bpb,  8, halign / 4, valign / 2,  8);
+      ASSERT_2D(tiling, bpb, 16, halign / 4, valign / 4, 16);
+   }
+
+#undef ASSERT_2D
+}
+
+static void
+test_2d_tile_dimensions()
+{
+   assert_2d_tile_size(ISL_TILING_SKL_Ys,  128,  64,  64);
+   assert_2d_tile_size(ISL_TILING_SKL_Ys,   64, 128,  64);
+   assert_2d_tile_size(ISL_TILING_SKL_Ys,   32, 128, 128);
+   assert_2d_tile_size(ISL_TILING_SKL_Ys,   16, 256, 128);
+   assert_2d_tile_size(ISL_TILING_SKL_Ys,    8, 256, 256);
+
+   assert_2d_tile_size(ISL_TILING_SKL_Yf,  128,  16,  16);
+   assert_2d_tile_size(ISL_TILING_SKL_Yf,   64,  32,  16);
+   assert_2d_tile_size(ISL_TILING_SKL_Yf,   32,  32,  32);
+   assert_2d_tile_size(ISL_TILING_SKL_Yf,   16,  64,  32);
+   assert_2d_tile_size(ISL_TILING_SKL_Yf,    8,  64,  64);
+
+   assert_2d_tile_size(ISL_TILING_ICL_Ys, 128,  64,  64);
+   assert_2d_tile_size(ISL_TILING_ICL_Ys,  64, 128,  64);
+   assert_2d_tile_size(ISL_TILING_ICL_Ys,  32, 128, 128);
+   assert_2d_tile_size(ISL_TILING_ICL_Ys,  16, 256, 128);
+   assert_2d_tile_size(ISL_TILING_ICL_Ys,   8, 256, 256);
+
+   assert_2d_tile_size(ISL_TILING_ICL_Yf, 128,  16,  16);
+   assert_2d_tile_size(ISL_TILING_ICL_Yf,  64,  32,  16);
+   assert_2d_tile_size(ISL_TILING_ICL_Yf,  32,  32,  32);
+   assert_2d_tile_size(ISL_TILING_ICL_Yf,  16,  64,  32);
+   assert_2d_tile_size(ISL_TILING_ICL_Yf,   8,  64,  64);
+}
+
+static void
+test_3d_tile_dimensions()
+{
+#define ASSERT_3D(tiling, bpb, halign, valign, dalign) \
+   assert_tile_size(tiling, ISL_SURF_DIM_3D, ISL_MSAA_LAYOUT_ARRAY, \
+                    bpb, 1, halign, valign, dalign, 1)
+
+   ASSERT_3D(ISL_TILING_SKL_Ys, 128, 16, 16, 16);
+   ASSERT_3D(ISL_TILING_SKL_Ys,  64, 32, 16, 16);
+   ASSERT_3D(ISL_TILING_SKL_Ys,  32, 32, 32, 16);
+   ASSERT_3D(ISL_TILING_SKL_Ys,  16, 32, 32, 32);
+   ASSERT_3D(ISL_TILING_SKL_Ys,   8, 64, 32, 32);
+
+   ASSERT_3D(ISL_TILING_SKL_Yf, 128,  4,  8,  8);
+   ASSERT_3D(ISL_TILING_SKL_Yf,  64,  8,  8,  8);
+   ASSERT_3D(ISL_TILING_SKL_Yf,  32,  8, 16,  8);
+   ASSERT_3D(ISL_TILING_SKL_Yf,  16,  8, 16, 16);
+   ASSERT_3D(ISL_TILING_SKL_Yf,   8, 16, 16, 16);
+
+   ASSERT_3D(ISL_TILING_ICL_Ys, 128, 16, 16, 16);
+   ASSERT_3D(ISL_TILING_ICL_Ys,  64, 32, 16, 16);
+   ASSERT_3D(ISL_TILING_ICL_Ys,  32, 32, 32, 16);
+   ASSERT_3D(ISL_TILING_ICL_Ys,  16, 32, 32, 32);
+   ASSERT_3D(ISL_TILING_ICL_Ys,   8, 64, 32, 32);
+
+   ASSERT_3D(ISL_TILING_ICL_Yf, 128,  4,  8,  8);
+   ASSERT_3D(ISL_TILING_ICL_Yf,  64,  8,  8,  8);
+   ASSERT_3D(ISL_TILING_ICL_Yf,  32,  8, 16,  8);
+   ASSERT_3D(ISL_TILING_ICL_Yf,  16,  8, 16, 16);
+   ASSERT_3D(ISL_TILING_ICL_Yf,   8, 16, 16, 16);
+
+#undef ASSERT_3D
+}
+
+int main(void)
+{
+   test_2d_tile_dimensions();
+   test_3d_tile_dimensions();
+
+   return 0;
+}