[Mesa-dev] [PATCH v2 30/32] intel/isl: Start using miptails

Jason Ekstrand jason at jlekstrand.net
Fri Oct 12 18:47:00 UTC 2018


This commit adds the code for choosing where to start the miptail and
enables miptails by default unless the client driver passes
info->min_miptail_start_level >= info->levels.
---
 src/intel/isl/isl.c | 165 ++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 161 insertions(+), 4 deletions(-)

diff --git a/src/intel/isl/isl.c b/src/intel/isl/isl.c
index 2513d2e73d1..8677f8edcbc 100644
--- a/src/intel/isl/isl.c
+++ b/src/intel/isl/isl.c
@@ -1026,6 +1026,130 @@ isl_get_miptail_level_offset_el(enum isl_tiling tiling,
    }
 }
 
+static uint32_t
+isl_choose_miptail_start_level(const struct isl_device *dev,
+                               const struct isl_surf_init_info *restrict info,
+                               const struct isl_tile_info *tile_info)
+{
+   const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
+
+   if (tile_info->max_miptail_levels == 0)
+      return info->levels;
+
+   assert(isl_tiling_is_std_y(tile_info->tiling));
+
+   if (info->samples > 1) {
+      /* In theory, miptails work for multisampled images, but we don't
+       * support mipmapped multisampling.
+       */
+      assert(info->levels == 1);
+      return info->levels;
+   }
+
+   uint32_t max_miptail_levels = tile_info->max_miptail_levels;
+
+   if (info->dim == ISL_SURF_DIM_3D && fmtl->bpb > 32) {
+      /* On Sky Lake, the render engine does not properly handle the higher
+       * slots in the 3D miptail layout for 64 and 128 bpb formats.
+       * Specifically, any attempt to render into slot 6 or higher may end you
+       * up in the wrong spot.  To work around this issue, we limit the
+       * miptail to 2 levels for Yf and 6 levels for Ys.
+       */
+      if (tile_info->tiling == ISL_TILING_GEN9_Yf) {
+         max_miptail_levels = 2;
+      } else if (tile_info->tiling == ISL_TILING_GEN9_Ys) {
+         max_miptail_levels = 6;
+      }
+   }
+
+   /* Start with the minimum number of levels that will fit in the tile */
+   uint32_t min_miptail_start =
+      info->levels > max_miptail_levels ? info->levels - max_miptail_levels : 0;
+
+   /* Account for the specified minimum */
+   min_miptail_start = MAX(min_miptail_start, info->min_miptail_start_level);
+
+   struct isl_extent3d level0_extent_el = {
+      .w = isl_align_div_npot(info->width, fmtl->bw),
+      .h = isl_align_div_npot(info->height, fmtl->bh),
+      .d = isl_align_div_npot(info->depth, fmtl->bd),
+   };
+
+   /* In the SKL PRM entry for RENDER_SURFACE_STATE::Mip Tail Start LOD, there
+    * is a table of maximum sizes for the first level of the miptail.
+    */
+   struct isl_extent3d miptail_level0_extent_el;
+   if (info->dim == ISL_SURF_DIM_1D) {
+      /* For 1D, it's just 1/4 of the tile width */
+      miptail_level0_extent_el = (struct isl_extent3d) {
+         .w = tile_info->logical_extent_el.w / 4,
+         .h = 1,
+         .d = 1,
+      };
+   } else {
+      /* For 2D and 3D images, it's just the distance from the offset of the
+       * first level to the corner of the tile.
+       */
+      uint32_t level0_x_offset_el, level0_y_offset_el, level0_z_offset_el;
+      isl_get_miptail_level_offset_el(tile_info->tiling, info->dim,
+                                      fmtl->bpb, info->samples,
+                                      0, /* level */
+                                      &level0_x_offset_el,
+                                      &level0_y_offset_el,
+                                      &level0_z_offset_el);
+      miptail_level0_extent_el = (struct isl_extent3d) {
+         .w = tile_info->logical_extent_el.w - level0_x_offset_el,
+         .h = tile_info->logical_extent_el.h - level0_y_offset_el,
+         .d = tile_info->logical_extent_el.d - level0_z_offset_el,
+      };
+   }
+
+   /* For determining whether or not all miplevels past a certain point will
+    * fit, we can just compare the first LOD of the miptail with the minified
+    * first LOD of the surface.  This is not normally valid, however there are
+    * three facts that we have working in our favor:
+    *
+    *  1) All dimensions of the first LOD of the miptail are powers of two
+    *  2) The miptail levels decrease in size by at most a factor of two in
+    *     each dimension at each step.
+    *  3) Each miptail level is non-empty
+    *
+    * For 1D images, (2) above is true only because miptail_level0_extent_el
+    * is chosen such that it starts off only half-filling the available space.
+    * At row 6 in the offset table, the space available drops by a factor of 4
+    * instead of 2.  This is ok because we only choose to fill half of the
+    * available space for the first several levels.
+    *
+    * As an example, suppose that some LOD of the main surface has width W
+    * and it fits in the first LOD of the miptail which has width 2^p.
+    * Then
+    *
+    *                 ciel(W / fmtl->bw) <= 2^p
+    *                      W / fmtl->bw  <= 2^p
+    *                                 W  <= 2^p * fmtl->bw
+    *                     floor(W / 2^k) <= 2^(p - k) * fmtl->bw
+    *    ceil(floor(W / 2^k) / fmtl->bw) <= 2^(p - k)
+    *
+    * for each k <= p.  Since the width decreases by at most one power of
+    * two, we have that the miplevels continue to fit as long as k <= p.
+    * As soon as k > p, we are in the case where the miplevel does not even
+    * fill a whole block and, since all levels of the miptail are
+    * non-empty, a single block will fit.
+    *
+    * This does not hold for 1D textures because they take a drop in size
+    * from 64 to 16 between the 5th and 6th rows of the table and that is a
+    * factor of 4 decrease, not 2.
+    */
+   for (uint32_t s = min_miptail_start; s < info->levels; s++) {
+      if (isl_minify(level0_extent_el.w, s) <= miptail_level0_extent_el.w &&
+          isl_minify(level0_extent_el.h, s) <= miptail_level0_extent_el.h &&
+          isl_minify(level0_extent_el.d, s) <= miptail_level0_extent_el.d)
+         return s;
+   }
+
+   return info->levels;
+}
+
 /**
  * Calculate the pitch between physical array slices, in units of rows of
  * surface elements.
@@ -1136,14 +1260,16 @@ static void
 isl_calc_phys_slice0_extent_sa_gen4_2d(
       const struct isl_device *dev,
       const struct isl_surf_init_info *restrict info,
+      const struct isl_tile_info *tile_info,
       enum isl_msaa_layout msaa_layout,
       const struct isl_extent3d *image_align_sa,
       const struct isl_extent4d *phys_level0_sa,
+      uint32_t miptail_start_level,
       struct isl_extent2d *phys_slice0_sa)
 {
    const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
 
-   if (info->levels == 1) {
+   if (info->levels == 1 && miptail_start_level > 0) {
       /* Do not pad the surface to the image alignment. Instead, pad it only
        * to the pixel format's block alignment.
        *
@@ -1194,6 +1320,17 @@ isl_calc_phys_slice0_extent_sa_gen4_2d(
       } else {
          slice_right_h += h;
       }
+
+      if (l >= miptail_start_level) {
+         assert(l == miptail_start_level);
+         assert(isl_tiling_is_std_y(tile_info->tiling));
+         assert(w == tile_info->logical_extent_el.w * fmtl->bw);
+         assert(h == tile_info->logical_extent_el.h * fmtl->bh);
+         /* If we've gone into the miptail, we're done.  All higher miplevels
+          * will be tucked into the same tile as this one.
+          */
+         break;
+      }
    }
 
    *phys_slice0_sa = (struct isl_extent2d) {
@@ -1211,14 +1348,16 @@ isl_calc_phys_total_extent_el_gen4_2d(
       const struct isl_extent3d *image_align_sa,
       const struct isl_extent4d *phys_level0_sa,
       enum isl_array_pitch_span array_pitch_span,
+      uint32_t miptail_start_level,
       uint32_t *array_pitch_el_rows,
       struct isl_extent4d *phys_total_el)
 {
    const struct isl_format_layout *fmtl = isl_format_get_layout(info->format);
 
    struct isl_extent2d phys_slice0_sa;
-   isl_calc_phys_slice0_extent_sa_gen4_2d(dev, info, msaa_layout,
+   isl_calc_phys_slice0_extent_sa_gen4_2d(dev, info, tile_info, msaa_layout,
                                           image_align_sa, phys_level0_sa,
+                                          miptail_start_level,
                                           &phys_slice0_sa);
    *array_pitch_el_rows =
       isl_calc_array_pitch_el_rows_gen4_2d(dev, info, tile_info,
@@ -1385,6 +1524,7 @@ isl_calc_phys_total_extent_el_gen9_1d(
       const struct isl_tile_info *tile_info,
       const struct isl_extent3d *image_align_sa,
       const struct isl_extent4d *phys_level0_sa,
+      uint32_t miptail_start_level,
       uint32_t *array_pitch_el_rows,
       struct isl_extent4d *phys_total_el)
 {
@@ -1403,6 +1543,16 @@ isl_calc_phys_total_extent_el_gen9_1d(
       uint32_t w = isl_align_npot(W, image_align_sa->w);
 
       slice_w += w;
+
+      if (l >= miptail_start_level) {
+         assert(l == miptail_start_level);
+         assert(isl_tiling_is_std_y(tile_info->tiling));
+         assert(w == tile_info->logical_extent_el.w * fmtl->bw);
+         /* If we've gone into the miptail, we're done.  All higher miplevels
+          * will be tucked into the same tile as this one.
+          */
+         break;
+      }
    }
 
    *array_pitch_el_rows = 1;
@@ -1437,6 +1587,7 @@ isl_calc_phys_total_extent_el(const struct isl_device *dev,
                               const struct isl_extent3d *image_align_sa,
                               const struct isl_extent4d *phys_level0_sa,
                               enum isl_array_pitch_span array_pitch_span,
+                              uint32_t miptail_start_level,
                               uint32_t *array_pitch_el_rows,
                               struct isl_extent4d *phys_total_el)
 {
@@ -1445,6 +1596,7 @@ isl_calc_phys_total_extent_el(const struct isl_device *dev,
       assert(array_pitch_span == ISL_ARRAY_PITCH_SPAN_COMPACT);
       isl_calc_phys_total_extent_el_gen9_1d(dev, info, tile_info,
                                             image_align_sa, phys_level0_sa,
+                                            miptail_start_level,
                                             array_pitch_el_rows,
                                             phys_total_el);
       return;
@@ -1452,6 +1604,7 @@ isl_calc_phys_total_extent_el(const struct isl_device *dev,
       isl_calc_phys_total_extent_el_gen4_2d(dev, info, tile_info, msaa_layout,
                                             image_align_sa, phys_level0_sa,
                                             array_pitch_span,
+                                            miptail_start_level,
                                             array_pitch_el_rows,
                                             phys_total_el);
       return;
@@ -1699,12 +1852,16 @@ isl_surf_init_s(const struct isl_device *dev,
    enum isl_array_pitch_span array_pitch_span =
       isl_choose_array_pitch_span(dev, info, dim_layout, &phys_level0_sa);
 
+   uint32_t miptail_start_level =
+      isl_choose_miptail_start_level(dev, info, &tile_info);
+
    uint32_t array_pitch_el_rows;
    struct isl_extent4d phys_total_el;
    isl_calc_phys_total_extent_el(dev, info, &tile_info,
                                  dim_layout, msaa_layout,
                                  &image_align_sa, &phys_level0_sa,
-                                 array_pitch_span, &array_pitch_el_rows,
+                                 array_pitch_span, miptail_start_level,
+                                 &array_pitch_el_rows,
                                  &phys_total_el);
 
    uint32_t row_pitch_B;
@@ -1821,7 +1978,7 @@ isl_surf_init_s(const struct isl_device *dev,
       .row_pitch_B = row_pitch_B,
       .array_pitch_el_rows = array_pitch_el_rows,
       .array_pitch_span = array_pitch_span,
-      .miptail_start_level = 15,
+      .miptail_start_level = miptail_start_level,
 
       .usage = info->usage,
    };
-- 
2.19.1



More information about the mesa-dev mailing list