[Mesa-dev] [PATCH 29/36] i965/blorp: Only do offset hacks for fake W-tiling and IMS

Jason Ekstrand jason at jlekstrand.net
Thu Jun 30 00:37:48 UTC 2016


Since the dawn of time, blorp has used offsets directly to get at different
mip levels and array slices of surfaces.  This isn't really necessary since
we can just use the base level/layer provided in the surface state.  While
it may have simplified blorp's original design, we haven't been using the
blorp path for surface state on gen8 thanks to render compression and
there's really no good need for it most of the time.  This commit restricts
such surface munging to the cases of fake W-tiling and fake interleaved
multisampling.
---
 src/mesa/drivers/dri/i965/brw_blorp.c        |  74 ++---------
 src/mesa/drivers/dri/i965/brw_blorp.h        |   6 +
 src/mesa/drivers/dri/i965/brw_blorp_blit.cpp | 189 +++++++++++++++++++--------
 3 files changed, 154 insertions(+), 115 deletions(-)

diff --git a/src/mesa/drivers/dri/i965/brw_blorp.c b/src/mesa/drivers/dri/i965/brw_blorp.c
index 4103306..f6833a0 100644
--- a/src/mesa/drivers/dri/i965/brw_blorp.c
+++ b/src/mesa/drivers/dri/i965/brw_blorp.c
@@ -92,7 +92,7 @@ get_image_offset_sa_gen6_stencil(const struct isl_surf *surf,
    *y_offset_sa = y;
 }
 
-static void
+void
 blorp_get_image_offset_sa(struct isl_device *dev, const struct isl_surf *surf,
                           uint32_t level, uint32_t layer,
                           uint32_t *x_offset_sa,
@@ -102,60 +102,11 @@ blorp_get_image_offset_sa(struct isl_device *dev, const struct isl_surf *surf,
       get_image_offset_sa_gen6_stencil(surf, level, layer,
                                        x_offset_sa, y_offset_sa);
    } else {
-      /* Using base_array_layer for Z in 3-D surfaces is a bit abusive, but it
-       * will go away soon enough.
-       */
-      uint32_t z = 0;
-      if (surf->dim == ISL_SURF_DIM_3D) {
-         z = layer;
-         layer = 0;
-      }
-
-      isl_surf_get_image_offset_sa(surf, level, layer, z,
+      isl_surf_get_image_offset_sa(surf, level, layer, 0,
                                    x_offset_sa, y_offset_sa);
    }
 }
 
-static void
-surf_apply_level_layer_offsets(struct isl_device *dev, struct isl_surf *surf,
-                               struct isl_view *view, uint32_t *byte_offset,
-                               uint32_t *tile_x_sa, uint32_t *tile_y_sa)
-{
-   /* This only makes sense for a single level and array slice */
-   assert(view->levels == 1 && view->array_len == 1);
-
-   uint32_t x_offset_sa, y_offset_sa;
-   blorp_get_image_offset_sa(dev, surf, view->base_level,
-                             view->base_array_layer,
-                             &x_offset_sa, &y_offset_sa);
-
-   isl_tiling_get_intratile_offset_sa(dev, surf->tiling, view->format,
-                                      surf->row_pitch, x_offset_sa, y_offset_sa,
-                                      byte_offset, tile_x_sa, tile_y_sa);
-
-   /* Now that that's done, we have a very bare 2-D surface */
-   surf->dim = ISL_SURF_DIM_2D;
-   surf->dim_layout = ISL_DIM_LAYOUT_GEN4_2D;
-
-   surf->logical_level0_px.width =
-      minify(surf->logical_level0_px.width, view->base_level);
-   surf->logical_level0_px.height =
-      minify(surf->logical_level0_px.height, view->base_level);
-   surf->logical_level0_px.depth = 1;
-   surf->logical_level0_px.array_len = 1;
-   surf->levels = 1;
-
-   /* Alignment doesn't matter since we have 1 miplevel and 1 array slice so
-    * just pick something that works for everybody.
-    */
-   surf->image_alignment_el = isl_extent3d(4, 4, 1);
-
-   /* TODO: surf->physcal_level0_extent_sa? */
-
-   view->base_level = 0;
-   view->base_array_layer = 0;
-}
-
 void
 brw_blorp_surface_info_init(struct brw_context *brw,
                             struct brw_blorp_surface_info *info,
@@ -193,8 +144,6 @@ brw_blorp_surface_info_init(struct brw_context *brw,
       .format = ISL_FORMAT_UNSUPPORTED, /* Set later */
       .base_level = level,
       .levels = 1,
-      .base_array_layer = layer / layer_multiplier,
-      .array_len = 1,
       .channel_select = {
          ISL_CHANNEL_SELECT_RED,
          ISL_CHANNEL_SELECT_GREEN,
@@ -203,12 +152,21 @@ brw_blorp_surface_info_init(struct brw_context *brw,
       },
    };
 
-   if (brw->gen >= 8 && !is_render_target && info->surf.dim == ISL_SURF_DIM_3D) {
-      /* On gen8+ we use actual 3-D textures so we need to pass the layer
-       * through to the sampler.
+   if (!is_render_target &&
+       (info->surf.dim == ISL_SURF_DIM_3D ||
+        info->surf.msaa_layout == ISL_MSAA_LAYOUT_ARRAY)) {
+      /* 3-D textures don't support base_array layer and neither do 2-D
+       * multisampled textures on IVB so we need to pass it through the
+       * sampler in those cases.  These are also two cases where we are
+       * guaranteed that we won't be doing any funny surface hacks.
        */
+      info->view.base_array_layer = 0;
+      info->view.array_len = MAX2(info->surf.logical_level0_px.depth,
+                                  info->surf.logical_level0_px.array_len);
       info->z_offset = layer / layer_multiplier;
    } else {
+      info->view.base_array_layer = layer / layer_multiplier;
+      info->view.array_len = 1;
       info->z_offset = 0;
    }
 
@@ -254,10 +212,6 @@ brw_blorp_surface_info_init(struct brw_context *brw,
       break;
    }
    }
-
-   surf_apply_level_layer_offsets(&brw->isl_dev, &info->surf, &info->view,
-                                  &info->bo_offset,
-                                  &info->tile_x_sa, &info->tile_y_sa);
 }
 
 
diff --git a/src/mesa/drivers/dri/i965/brw_blorp.h b/src/mesa/drivers/dri/i965/brw_blorp.h
index 3beb10e..d280494 100644
--- a/src/mesa/drivers/dri/i965/brw_blorp.h
+++ b/src/mesa/drivers/dri/i965/brw_blorp.h
@@ -310,6 +310,12 @@ brw_blorp_compile_nir_shader(struct brw_context *brw, struct nir_shader *nir,
                              struct brw_blorp_prog_data *prog_data,
                              unsigned *program_size);
 
+void
+blorp_get_image_offset_sa(struct isl_device *dev, const struct isl_surf *surf,
+                          uint32_t level, uint32_t layer,
+                          uint32_t *x_offset_sa,
+                          uint32_t *y_offset_sa);
+
 uint32_t
 brw_blorp_emit_surface_state(struct brw_context *brw,
                              const struct brw_blorp_surface_info *surface,
diff --git a/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp b/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp
index 7b2dd53..b5f254a 100644
--- a/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp
+++ b/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp
@@ -1583,6 +1583,116 @@ swizzle_to_scs(GLenum swizzle)
    return (enum isl_channel_select)((swizzle + 4) & 7);
 }
 
+static void
+surf_convert_to_single_slice(struct brw_context *brw,
+                             struct brw_blorp_surface_info *info)
+{
+   /* This only makes sense for a single level and array slice */
+   assert(info->view.levels == 1 && info->view.array_len == 1);
+
+   /* Just bail if we have nothing to do. */
+   if (info->surf.dim == ISL_SURF_DIM_2D &&
+       info->view.base_level == 0 && info->view.base_array_layer == 0 &&
+       info->surf.levels == 0 && info->surf.logical_level0_px.array_len == 0)
+      return;
+
+   uint32_t x_offset_sa, y_offset_sa;
+   blorp_get_image_offset_sa(&brw->isl_dev, &info->surf, info->view.base_level,
+                             info->view.base_array_layer,
+                             &x_offset_sa, &y_offset_sa);
+
+   isl_tiling_get_intratile_offset_sa(&brw->isl_dev, info->surf.tiling,
+                                      info->view.format, info->surf.row_pitch,
+                                      x_offset_sa, y_offset_sa,
+                                      &info->bo_offset,
+                                      &info->tile_x_sa, &info->tile_y_sa);
+
+   /* TODO: Once this file gets converted to C, we shouls just use designated
+    * initializers.
+    */
+   struct isl_surf_init_info init_info = isl_surf_init_info();
+
+   init_info.dim = ISL_SURF_DIM_2D;
+   init_info.format = ISL_FORMAT_R8_UINT;
+   init_info.width =
+      minify(info->surf.logical_level0_px.width, info->view.base_level);
+   init_info.height =
+      minify(info->surf.logical_level0_px.height, info->view.base_level);
+   init_info.depth = 1;
+   init_info.levels = 1;
+   init_info.array_len = 1;
+   init_info.samples = info->surf.samples;
+   init_info.min_pitch = info->surf.row_pitch;
+   init_info.usage = info->surf.usage;
+   init_info.tiling_flags = 1 << info->surf.tiling;
+
+   isl_surf_init_s(&brw->isl_dev, &info->surf, &init_info);
+   assert(info->surf.row_pitch == init_info.min_pitch);
+
+   /* The view is also different now. */
+   info->view.base_level = 0;
+   info->view.levels = 1;
+   info->view.base_array_layer = 0;
+   info->view.array_len = 1;
+}
+
+static void
+surf_fake_interleaved_msaa(struct brw_context *brw,
+                           struct brw_blorp_surface_info *info)
+{
+   assert(info->surf.msaa_layout == ISL_MSAA_LAYOUT_INTERLEAVED);
+
+   /* First, we need to convert it to a simple 1-level 1-layer 2-D surface */
+   surf_convert_to_single_slice(brw, info);
+
+   info->surf.logical_level0_px = info->surf.phys_level0_sa;
+   info->surf.samples = 1;
+   info->surf.msaa_layout = ISL_MSAA_LAYOUT_NONE;
+}
+
+static void
+surf_retile_w_to_y(struct brw_context *brw,
+                   struct brw_blorp_surface_info *info)
+{
+   assert(info->surf.tiling == ISL_TILING_W);
+
+   /* First, we need to convert it to a simple 1-level 1-layer 2-D surface */
+   surf_convert_to_single_slice(brw, info);
+
+   /* On gen7+, we don't have interleaved multisampling for color render
+    * targets so we have to fake it.
+    *
+    * TODO: Are we sure we don't also need to fake it on gen6?
+    */
+   if (brw->gen > 6 && info->surf.msaa_layout == ISL_MSAA_LAYOUT_INTERLEAVED) {
+      info->surf.logical_level0_px = info->surf.phys_level0_sa;
+      info->surf.samples = 1;
+      info->surf.msaa_layout = ISL_MSAA_LAYOUT_NONE;
+   }
+
+   if (brw->gen == 6) {
+      /* Gen6 stencil buffers have a very large alignment coming in from the
+       * miptree.  It's out-of-bounds for what the surface state can handle.
+       * Since we have a single layer and level, it doesn't really matter as
+       * long as we don't pass a bogus value into isl_surf_fill_state().
+       */
+      info->surf.image_alignment_el = isl_extent3d(4, 2, 1);
+   }
+
+   /* Now that we've converted everything to a simple 2-D surface with only
+    * one miplevel, we can go about retiling it.
+    */
+   const unsigned x_align = 8, y_align = info->surf.samples != 0 ? 8 : 4;
+   info->surf.tiling = ISL_TILING_Y0;
+   info->surf.row_pitch *= 2;
+   info->surf.logical_level0_px.width =
+      ALIGN(info->surf.logical_level0_px.width, x_align) * 2;
+   info->surf.logical_level0_px.height =
+      ALIGN(info->surf.logical_level0_px.height, y_align) / 2;
+   info->tile_x_sa *= 2;
+   info->tile_y_sa /= 2;
+}
+
 /**
  * Note: if the src (or dst) is a 2D multisample array texture on Gen7+ using
  * INTEL_MSAA_LAYOUT_UMS or INTEL_MSAA_LAYOUT_CMS, src_layer (dst_layer) is
@@ -1775,9 +1885,13 @@ brw_blorp_blit_miptrees(struct brw_context *brw,
    brw_blorp_setup_coord_transform(&params.wm_push_consts.y_transform,
                                    src_y0, src_y1, dst_y0, dst_y1, mirror_y);
 
+   /* For some texture types, we need to pass the layer through the sampler. */
    params.wm_push_consts.src_z = params.src.z_offset;
 
-   if (brw->gen > 6 && dst_mt->msaa_layout == INTEL_MSAA_LAYOUT_IMS) {
+   if (brw->gen > 6 &&
+       params.dst.surf.msaa_layout == ISL_MSAA_LAYOUT_INTERLEAVED) {
+      assert(params.dst.surf.samples > 1);
+
       /* We must expand the rectangle we send through the rendering pipeline,
        * to account for the fact that we are mapping the destination region as
        * single-sampled when it is in fact multisampled.  We must also align
@@ -1790,72 +1904,41 @@ brw_blorp_blit_miptrees(struct brw_context *brw,
        * If it's UMS, then we have no choice but to set up the rendering
        * pipeline as multisampled.
        */
-      assert(params.dst.surf.msaa_layout = ISL_MSAA_LAYOUT_INTERLEAVED);
       switch (params.dst.surf.samples) {
       case 2:
          params.x0 = ROUND_DOWN_TO(params.x0 * 2, 4);
          params.y0 = ROUND_DOWN_TO(params.y0, 4);
          params.x1 = ALIGN(params.x1 * 2, 4);
          params.y1 = ALIGN(params.y1, 4);
-         params.dst.surf.logical_level0_px.width *= 2;
          break;
       case 4:
          params.x0 = ROUND_DOWN_TO(params.x0 * 2, 4);
          params.y0 = ROUND_DOWN_TO(params.y0 * 2, 4);
          params.x1 = ALIGN(params.x1 * 2, 4);
          params.y1 = ALIGN(params.y1 * 2, 4);
-         params.dst.surf.logical_level0_px.width *= 2;
-         params.dst.surf.logical_level0_px.height *= 2;
          break;
       case 8:
          params.x0 = ROUND_DOWN_TO(params.x0 * 4, 8);
          params.y0 = ROUND_DOWN_TO(params.y0 * 2, 4);
          params.x1 = ALIGN(params.x1 * 4, 8);
          params.y1 = ALIGN(params.y1 * 2, 4);
-         params.dst.surf.logical_level0_px.width *= 4;
-         params.dst.surf.logical_level0_px.height *= 2;
          break;
       case 16:
          params.x0 = ROUND_DOWN_TO(params.x0 * 4, 8);
          params.y0 = ROUND_DOWN_TO(params.y0 * 4, 8);
          params.x1 = ALIGN(params.x1 * 4, 8);
          params.y1 = ALIGN(params.y1 * 4, 8);
-         params.dst.surf.logical_level0_px.width *= 4;
-         params.dst.surf.logical_level0_px.height *= 4;
          break;
       default:
          unreachable("Unrecognized sample count in brw_blorp_blit_params ctor");
       }
 
-      /* Gen7's rendering hardware only supports the IMS layout for depth and
-       * stencil render targets.  Blorp always maps its destination surface as
-       * a color render target (even if it's actually a depth or stencil
-       * buffer).  So if the destination is IMS, we'll have to map it as a
-       * single-sampled texture and interleave the samples ourselves.
-       */
-      params.dst.surf.samples = 1;
-      params.dst.surf.msaa_layout = ISL_MSAA_LAYOUT_NONE;
+      surf_fake_interleaved_msaa(brw, &params.dst);
 
       wm_prog_key.use_kill = true;
    }
 
    if (params.dst.surf.tiling == ISL_TILING_W) {
-      /* We need to fake W-tiling with Y-tiling */
-      params.dst.surf.tiling = ISL_TILING_Y0;
-      params.dst.surf.row_pitch *= 2;
-
-      wm_prog_key.dst_tiled_w = true;
-
-      if (params.dst.surf.samples > 1) {
-         /* If the destination surface is a W-tiled multisampled stencil
-          * buffer that we're mapping as Y tiled, then we need to arrange for
-          * the WM program to run once per sample rather than once per pixel,
-          * because the memory layout of related samples doesn't match between
-          * W and Y tiling.
-          */
-         wm_prog_key.persample_msaa_dispatch = true;
-      }
-
       /* We must modify the rectangle we send through the rendering pipeline
        * (and the size and x/y offset of the destination surface), to account
        * for the fact that we are mapping it as Y-tiled when it is in fact
@@ -1907,40 +1990,36 @@ brw_blorp_blit_miptrees(struct brw_context *brw,
       params.y0 = ROUND_DOWN_TO(params.y0, y_align) / 2;
       params.x1 = ALIGN(params.x1, x_align) * 2;
       params.y1 = ALIGN(params.y1, y_align) / 2;
-      params.dst.surf.logical_level0_px.width =
-         ALIGN(params.dst.surf.logical_level0_px.width, x_align) * 2;
-      params.dst.surf.logical_level0_px.height =
-         ALIGN(params.dst.surf.logical_level0_px.height, y_align) / 2;
-      params.dst.tile_x_sa *= 2;
-      params.dst.tile_y_sa /= 2;
+
+      /* Retile the surface to Y-tiled */
+      surf_retile_w_to_y(brw, &params.dst);
+
+      wm_prog_key.dst_tiled_w = true;
       wm_prog_key.use_kill = true;
+
+      if (params.dst.surf.samples > 1) {
+         /* If the destination surface is a W-tiled multisampled stencil
+          * buffer that we're mapping as Y tiled, then we need to arrange for
+          * the WM program to run once per sample rather than once per pixel,
+          * because the memory layout of related samples doesn't match between
+          * W and Y tiling.
+          */
+         wm_prog_key.persample_msaa_dispatch = true;
+      }
    }
 
    if (brw->gen < 8 && params.src.surf.tiling == ISL_TILING_W) {
       /* On Haswell and earlier, we have to fake W-tiled sources as Y-tiled.
        * Broadwell adds support for sampling from stencil.
-       */
-      params.src.surf.tiling = ISL_TILING_Y0;
-      params.src.surf.row_pitch *= 2;
-
-      wm_prog_key.src_tiled_w = true;
-
-      /* We must modify the size and x/y offset of the source surface to
-       * account for the fact that we are mapping it as Y-tiled when it is in
-       * fact W tiled.
        *
        * See the comments above concerning x/y offset alignment for the
        * destination surface.
        *
        * TODO: what if this makes the texture size too large?
        */
-      const unsigned x_align = 8, y_align = params.src.surf.samples != 0 ? 8 : 4;
-      params.src.surf.logical_level0_px.width =
-         ALIGN(params.src.surf.logical_level0_px.width, x_align) * 2;
-      params.src.surf.logical_level0_px.height =
-         ALIGN(params.src.surf.logical_level0_px.height, y_align) / 2;
-      params.src.tile_x_sa *= 2;
-      params.src.tile_y_sa /= 2;
+      surf_retile_w_to_y(brw, &params.src);
+
+      wm_prog_key.src_tiled_w = true;
    }
 
    /* tex_samples and rt_samples are the sample counts that are set up in
-- 
2.5.0.400.gff86faf



More information about the mesa-dev mailing list