Mesa (main): intel/isl: Add more cases to isl_surf_get_uncompressed_surf

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Tue Jul 6 19:42:51 UTC 2021


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

Author: Jason Ekstrand <jason at jlekstrand.net>
Date:   Mon Jun 28 19:03:18 2021 -0500

intel/isl: Add more cases to isl_surf_get_uncompressed_surf

We can actually create array surfaces instead of requiring single-slice
in a few cases.  This does require us to be very careful about our
checks, though.

Reviewed-by: Kenneth Graunke <kenneth at whitecape.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11647>

---

 src/intel/blorp/blorp_blit.c | 10 +++--
 src/intel/isl/isl.c          | 91 +++++++++++++++++++++++++++++++-------------
 src/intel/isl/isl.h          |  2 +-
 src/intel/vulkan/anv_image.c |  8 ++--
 4 files changed, 78 insertions(+), 33 deletions(-)

diff --git a/src/intel/blorp/blorp_blit.c b/src/intel/blorp/blorp_blit.c
index 106cf3169dc..c664bdc412b 100644
--- a/src/intel/blorp/blorp_blit.c
+++ b/src/intel/blorp/blorp_blit.c
@@ -2621,14 +2621,18 @@ blorp_surf_convert_to_uncompressed(const struct isl_device *isl_dev,
    }
 
    uint32_t offset_B;
-   isl_surf_get_uncompressed_surf(isl_dev, &info->surf, &info->view,
-                                  &info->surf, &info->view, &offset_B,
-                                  &info->tile_x_sa, &info->tile_y_sa);
+   ASSERTED bool ok =
+      isl_surf_get_uncompressed_surf(isl_dev, &info->surf, &info->view,
+                                     &info->surf, &info->view, &offset_B,
+                                     &info->tile_x_sa, &info->tile_y_sa);
+   assert(ok);
    info->addr.offset += offset_B;
 
    /* BLORP doesn't use the actual intratile offsets.  Instead, it needs the
     * surface to be a bit bigger and we offset the vertices instead.
     */
+   assert(info->surf.dim == ISL_SURF_DIM_2D);
+   assert(info->surf.logical_level0_px.array_len == 1);
    info->surf.logical_level0_px.w += info->tile_x_sa;
    info->surf.logical_level0_px.h += info->tile_y_sa;
    info->surf.phys_level0_sa.w += info->tile_x_sa;
diff --git a/src/intel/isl/isl.c b/src/intel/isl/isl.c
index 76819b102c2..2e2e79c5659 100644
--- a/src/intel/isl/isl.c
+++ b/src/intel/isl/isl.c
@@ -2827,7 +2827,7 @@ isl_surf_get_image_surf(const struct isl_device *dev,
    assert(ok);
 }
 
-void
+bool
 isl_surf_get_uncompressed_surf(const struct isl_device *dev,
                                const struct isl_surf *surf,
                                const struct isl_view *view,
@@ -2839,6 +2839,7 @@ isl_surf_get_uncompressed_surf(const struct isl_device *dev,
 {
    const struct isl_format_layout *fmtl =
       isl_format_get_layout(surf->format);
+   const enum isl_format view_format = view->format;
 
    assert(fmtl->bw > 1 || fmtl->bh > 1 || fmtl->bd > 1);
    assert(isl_format_is_compressed(surf->format));
@@ -2854,46 +2855,84 @@ isl_surf_get_uncompressed_surf(const struct isl_device *dev,
    const uint32_t ucompr_width = isl_align_div_npot(view_width, fmtl->bw);
    const uint32_t ucompr_height = isl_align_div_npot(view_height, fmtl->bh);
 
-   /* Due to hardware restrictions with intratile offsets, we can only
-    * handle a single slice.
-    */
-   assert(view->array_len == 1);
+   /* If we ever enable 3D block formats, we'll need to re-think this */
+   assert(fmtl->bd == 1);
+
+   uint32_t x_offset_sa = 0, y_offset_sa = 0;
+   if (view->array_len > 1) {
+      /* The Skylake PRM Vol. 2d, "RENDER_SURFACE_STATE::X Offset" says:
+       *
+       *    "If Surface Array is enabled, this field must be zero."
+       *
+       * The PRMs for other hardware have similar text.  This is also tricky
+       * to handle with things like BLORP's SW offsetting because the
+       * increased surface size required for the offset may result in an image
+       * height greater than qpitch.
+       */
+      if (view->base_level > 0)
+         return false;
+
+      /* On Haswell and earlier, RENDER_SURFACE_STATE doesn't have a QPitch
+       * field; it only has "array pitch span" which means the QPitch is
+       * automatically calculated.  Since we're smashing the surface format
+       * (block formats are subtly different) and the number of miplevels,
+       * that calculation will get thrown off.  This means we can't do arrays
+       * even at LOD0
+       *
+       * On Broadwell, we do have a QPitch field which we can control.
+       * However, HALIGN and VALIGN are specified in pixels and are
+       * hard-coded to align to exactly the block size of the compressed
+       * texture.  This means that, when reinterpreted as a non-compressed
+       * the QPitch may be anything but the HW requires it to be properly
+       * aligned.
+       */
+      if (ISL_GFX_VER(dev) < 9)
+         return false;
+
+      *ucompr_surf = *surf;
+      ucompr_surf->levels = 1;
 
-   uint32_t x_offset_sa, y_offset_sa;
-   isl_surf_get_image_surf(dev, surf,
-                           view->base_level,
-                           surf->dim == ISL_SURF_DIM_3D ?
-                              0 : view->base_array_layer,
-                           surf->dim == ISL_SURF_DIM_3D ?
-                              view->base_array_layer : 0,
-                           ucompr_surf,
-                           offset_B, &x_offset_sa, &y_offset_sa);
+      /* The view remains the same */
+      *ucompr_view = *view;
+   } else {
+      /* If only one array slice is requested, directly offset to that slice.
+       * We could, in theory, still use arrays in some cases but BLORP isn't
+       * prepared for this and everyone who calls this function should be
+       * prepared to handle an X/Y offset.
+       */
+      isl_surf_get_image_surf(dev, surf,
+                              view->base_level,
+                              surf->dim == ISL_SURF_DIM_3D ?
+                                 0 : view->base_array_layer,
+                              surf->dim == ISL_SURF_DIM_3D ?
+                                 view->base_array_layer : 0,
+                              ucompr_surf,
+                              offset_B, &x_offset_sa, &y_offset_sa);
+
+      /* The newly created image represents the one subimage we're
+       * referencing with this view so it only has one array slice and
+       * miplevel.
+       */
+      *ucompr_view = *view;
+      ucompr_view->base_array_layer = 0;
+      ucompr_view->base_level = 0;
+   }
 
-   ucompr_surf->format = view->format;
+   ucompr_surf->format = view_format;
 
    /* We're making an uncompressed view here.  The image dimensions
     * need to be scaled down by the block size.
     */
    assert(ucompr_surf->logical_level0_px.width == view_width);
    assert(ucompr_surf->logical_level0_px.height == view_height);
-   assert(ucompr_surf->logical_level0_px.depth == 1);
-   assert(ucompr_surf->logical_level0_px.array_len = 1);
    ucompr_surf->logical_level0_px.width = ucompr_width;
    ucompr_surf->logical_level0_px.height = ucompr_height;
-
-   assert(ucompr_surf->phys_level0_sa.depth == 1);
-   assert(ucompr_surf->phys_level0_sa.array_len == 1);
    ucompr_surf->phys_level0_sa = isl_surf_get_phys_level0_el(surf);
 
    *x_offset_el = isl_assert_div(x_offset_sa, fmtl->bw);
    *y_offset_el = isl_assert_div(y_offset_sa, fmtl->bh);
 
-   /* The newly created image represents the one subimage we're referencing
-    * with this view so it only has one array slice and miplevel.
-    */
-   *ucompr_view = *view;
-   ucompr_view->base_array_layer = 0;
-   ucompr_view->base_level = 0;
+   return true;
 }
 
 void
diff --git a/src/intel/isl/isl.h b/src/intel/isl/isl.h
index 95943b12450..e1c9743791a 100644
--- a/src/intel/isl/isl.h
+++ b/src/intel/isl/isl.h
@@ -2664,7 +2664,7 @@ isl_surf_get_image_surf(const struct isl_device *dev,
  * It is safe to call this function with surf == uncompressed_surf and
  * view == uncompressed_view.
  */
-void
+bool MUST_CHECK
 isl_surf_get_uncompressed_surf(const struct isl_device *dev,
                                const struct isl_surf *surf,
                                const struct isl_view *view,
diff --git a/src/intel/vulkan/anv_image.c b/src/intel/vulkan/anv_image.c
index 876848cc454..386241fd8f5 100644
--- a/src/intel/vulkan/anv_image.c
+++ b/src/intel/vulkan/anv_image.c
@@ -2570,9 +2570,11 @@ anv_image_fill_surface_state(struct anv_device *device,
          assert(view.levels == 1);
          assert(view.array_len == 1);
 
-         isl_surf_get_uncompressed_surf(&device->isl_dev, isl_surf, &view,
-                                        &tmp_surf, &view,
-                                        &offset_B, &tile_x_sa, &tile_y_sa);
+         ASSERTED bool ok =
+            isl_surf_get_uncompressed_surf(&device->isl_dev, isl_surf, &view,
+                                           &tmp_surf, &view,
+                                           &offset_B, &tile_x_sa, &tile_y_sa);
+         assert(ok);
          isl_surf = &tmp_surf;
 
          if (device->info.ver <= 8) {



More information about the mesa-commit mailing list