On 22 May 2012 09:21, Paul Berry <span dir="ltr">&lt;<a href="mailto:stereotype441@gmail.com" target="_blank">stereotype441@gmail.com</a>&gt;</span> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="HOEnZb"><div class="h5">On 22 May 2012 08:19, Kenneth Graunke <span dir="ltr">&lt;<a href="mailto:kenneth@whitecape.org" target="_blank">kenneth@whitecape.org</a>&gt;</span> wrote:<br></div></div><div class="gmail_quote">
<div><div class="h5"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div>On 05/11/2012 11:03 AM, Paul Berry wrote:<br>
</div></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div>
Starting in Gen7, there are two possible layouts for MSAA surfaces:<br>
<br>
- Interleaved, in which additional samples are accommodated by scaling<br>
   up the width and height of the surface.  This is the only layout<br>
   available in Gen6.  On Gen7 it is used for depth and stencil<br>
   surfaces only.<br>
<br>
- Sliced, in which the surface is stored as a 2D array, with array<br>
   slice n containing all pixel data for sample n.  On Gen7 this layout<br>
   is used for color surfaces.<br>
<br>
The &quot;Sliced&quot; layout has an additional requirement: it must be used in<br>
ARYSPC_LOD0 mode, which means that the surface doesn&#39;t leave any extra<br>
room between array slices for miplevels other than 0.<br>
<br>
This patch modifies the surface allocation functions to use the<br>
correct layout when allocating MSAA surfaces in Gen7, and to set the<br>
array offsets properly when using ARYSPC_LOD0 mode.  It also modifies<br>
the code that populates SURFACE_STATE structures to ensure that<br>
ARYSPC_LOD0 mode is selected in the appropriate circumstances.<br>
---<br>
  src/mesa/drivers/dri/i965/brw_<u></u>blorp.cpp           |    1 +<br>
  src/mesa/drivers/dri/i965/brw_<u></u>blorp.h             |    5 +<br>
  src/mesa/drivers/dri/i965/brw_<u></u>tex_layout.c        |   10 ++-<br>
  src/mesa/drivers/dri/i965/brw_<u></u>wm_surface_state.c  |    3 +-<br>
  src/mesa/drivers/dri/i965/<u></u>gen7_blorp.cpp          |    2 +<br>
  src/mesa/drivers/dri/i965/<u></u>gen7_wm_surface_state.c |   10 ++<br>
  src/mesa/drivers/dri/intel/<u></u>intel_mipmap_tree.c    |  102 ++++++++++++++++-----<br>
  src/mesa/drivers/dri/intel/<u></u>intel_mipmap_tree.h    |   23 +++++-<br>
  src/mesa/drivers/dri/intel/<u></u>intel_tex_image.c      |    3 +-<br>
  src/mesa/drivers/dri/intel/<u></u>intel_tex_validate.c   |    3 +-<br>
  10 files changed, 134 insertions(+), 28 deletions(-)<br>
<br>
diff --git a/src/mesa/drivers/dri/i965/<u></u>brw_blorp.cpp b/src/mesa/drivers/dri/i965/<u></u>brw_blorp.cpp<br>
index f6aff44..84f92b4 100644<br>
--- a/src/mesa/drivers/dri/i965/<u></u>brw_blorp.cpp<br>
+++ b/src/mesa/drivers/dri/i965/<u></u>brw_blorp.cpp<br>
@@ -58,6 +58,7 @@ brw_blorp_surface_info::set(<u></u>struct intel_mipmap_tree *mt,<br>
  {<br>
     brw_blorp_mip_info::set(mt, level, layer);<br>
     this-&gt;num_samples = mt-&gt;num_samples;<br>
+   this-&gt;array_spacing_lod0 = mt-&gt;array_spacing_lod0;<br>
<br>
     if (mt-&gt;format == MESA_FORMAT_S8) {<br>
        /* The miptree is a W-tiled stencil buffer.  Surface states can&#39;t be set<br>
diff --git a/src/mesa/drivers/dri/i965/<u></u>brw_blorp.h b/src/mesa/drivers/dri/i965/<u></u>brw_blorp.h<br>
index 8dabf2c..3e37081 100644<br>
--- a/src/mesa/drivers/dri/i965/<u></u>brw_blorp.h<br>
+++ b/src/mesa/drivers/dri/i965/<u></u>brw_blorp.h<br>
@@ -99,6 +99,11 @@ public:<br>
     bool map_stencil_as_y_tiled;<br>
<br>
     unsigned num_samples;<br>
+<br>
+   /* Setting this flag indicates that the surface should be set up in<br>
+    * ARYSPC_LOD0 mode.  Ignored prior to Gen7.<br>
+    */<br>
+   bool array_spacing_lod0;<br>
  };<br>
<br>
<br>
diff --git a/src/mesa/drivers/dri/i965/<u></u>brw_tex_layout.c b/src/mesa/drivers/dri/i965/<u></u>brw_tex_layout.c<br>
index 8bf1d3d..f742131 100644<br>
--- a/src/mesa/drivers/dri/i965/<u></u>brw_tex_layout.c<br>
+++ b/src/mesa/drivers/dri/i965/<u></u>brw_tex_layout.c<br>
@@ -49,7 +49,10 @@ brw_miptree_layout_texture_<u></u>array(struct intel_context *intel,<br>
<br>
     h0 = ALIGN(mt-&gt;height0, mt-&gt;align_h);<br>
     h1 = ALIGN(minify(mt-&gt;height0), mt-&gt;align_h);<br>
-   qpitch = (h0 + h1 + (intel-&gt;gen&gt;= 7 ? 12 : 11) * mt-&gt;align_h);<br>
+   if (mt-&gt;array_spacing_lod0)<br>
+      qpitch = h0;<br>
+   else<br>
+      qpitch = (h0 + h1 + (intel-&gt;gen&gt;= 7 ? 12 : 11) * mt-&gt;align_h);<br>
     if (mt-&gt;compressed)<br>
        qpitch /= 4;<br>
<br>
@@ -165,7 +168,10 @@ brw_miptree_layout(struct intel_context *intel, struct intel_mipmap_tree *mt)<br>
        break;<br>
<br>
     default:<br>
-      i945_miptree_layout_2d(mt);<br></div></div>
+      if (mt-&gt;num_samples&gt;  0&amp;&amp;  !mt-&gt;msaa_is_interleaved)<div><div><br>
+         brw_miptree_layout_texture_<u></u>array(intel, mt);<br>
+      else<br>
+         i945_miptree_layout_2d(mt);<br>
        break;<br>
     }<br>
     DBG(&quot;%s: %dx%dx%d\n&quot;, __FUNCTION__,<br>
diff --git a/src/mesa/drivers/dri/i965/<u></u>brw_wm_surface_state.c b/src/mesa/drivers/dri/i965/<u></u>brw_wm_surface_state.c<br>
index 849da85..6e745cf 100644<br>
--- a/src/mesa/drivers/dri/i965/<u></u>brw_wm_surface_state.c<br>
+++ b/src/mesa/drivers/dri/i965/<u></u>brw_wm_surface_state.c<br>
@@ -955,7 +955,8 @@ brw_update_renderbuffer_<u></u>surface(struct brw_context *brw,<br>
                                       intel_image-&gt;base.Base.Level,<br>
                                       width, height, depth,<br>
                                       true,<br>
-                                       0 /* num_samples */);<br>
+                                       0 /* num_samples */,<br>
+                                       false /* msaa_is_interleaved */);<br>
<br>
         intel_miptree_copy_teximage(<u></u>intel, intel_image, new_mt);<br>
         intel_miptree_reference(&amp;irb-&gt;<u></u>mt, intel_image-&gt;mt);<br>
diff --git a/src/mesa/drivers/dri/i965/<u></u>gen7_blorp.cpp b/src/mesa/drivers/dri/i965/<u></u>gen7_blorp.cpp<br>
index 3775eec..dfc2272 100644<br>
--- a/src/mesa/drivers/dri/i965/<u></u>gen7_blorp.cpp<br>
+++ b/src/mesa/drivers/dri/i965/<u></u>gen7_blorp.cpp<br>
@@ -149,6 +149,8 @@ gen7_blorp_emit_surface_state(<u></u>struct brw_context *brw,<br>
<br>
     surf-&gt;ss0.surface_format = format;<br>
     surf-&gt;ss0.surface_type = BRW_SURFACE_2D;<br>
+   surf-&gt;ss0.surface_array_<u></u>spacing = surface-&gt;array_spacing_lod0 ?<br>
+      GEN7_SURFACE_ARYSPC_LOD0 : GEN7_SURFACE_ARYSPC_FULL;<br>
<br>
     /* reloc */<br>
     surf-&gt;ss1.base_addr = region-&gt;bo-&gt;offset; /* No tile offsets needed */<br>
diff --git a/src/mesa/drivers/dri/i965/<u></u>gen7_wm_surface_state.c b/src/mesa/drivers/dri/i965/<u></u>gen7_wm_surface_state.c<br>
index 5aa62bd..9a01ddf 100644<br>
--- a/src/mesa/drivers/dri/i965/<u></u>gen7_wm_surface_state.c<br>
+++ b/src/mesa/drivers/dri/i965/<u></u>gen7_wm_surface_state.c<br>
@@ -142,6 +142,10 @@ gen7_update_texture_surface(<u></u>struct gl_context *ctx, GLuint unit)<br>
        return;<br>
     }<br>
<br>
+   /* We don&#39;t support MSAA for textures. */<br>
+   assert(!mt-&gt;array_spacing_<u></u>lod0);<br>
+   assert(mt-&gt;num_samples == 0);<br>
+<br>
     intel_miptree_get_dimensions_<u></u>for_image(firstImage,&amp;width,&amp;<u></u>height,&amp;depth);<br>
<br>
     surf = brw_state_batch(brw, AUB_TRACE_SURFACE_STATE,<br>
@@ -296,6 +300,9 @@ gen7_update_renderbuffer_<u></u>surface(struct brw_context *brw,<br></div></div>
                          sizeof(*surf), 32,&amp;brw-&gt;wm.surf_offset[unit])<u></u>;<div><div><br>
     memset(surf, 0, sizeof(*surf));<br>
<br>
+   /* Render targets can&#39;t use MSAA interleaved layout */<br>
+   assert(!irb-&gt;mt-&gt;msaa_is_<u></u>interleaved);<br>
+<br>
     if (irb-&gt;mt-&gt;align_h == 4)<br>
        surf-&gt;ss0.vertical_alignment = 1;<br>
     if (irb-&gt;mt-&gt;align_w == 8)<br>
@@ -324,6 +331,9 @@ gen7_update_renderbuffer_<u></u>surface(struct brw_context *brw,<br>
     }<br>
<br>
     surf-&gt;ss0.surface_type = BRW_SURFACE_2D;<br>
+   surf-&gt;ss0.surface_array_<u></u>spacing = irb-&gt;mt-&gt;array_spacing_lod0 ?<br>
+      GEN7_SURFACE_ARYSPC_LOD0 : GEN7_SURFACE_ARYSPC_FULL;<br>
+<br>
     /* reloc */<br>
     surf-&gt;ss1.base_addr = intel_renderbuffer_tile_<u></u>offsets(irb,&amp;tile_x,&amp;tile_y);<br>
     surf-&gt;ss1.base_addr += region-&gt;bo-&gt;offset; /* reloc */<br>
diff --git a/src/mesa/drivers/dri/intel/<u></u>intel_mipmap_tree.c b/src/mesa/drivers/dri/intel/<u></u>intel_mipmap_tree.c<br>
index 36d7b77..4132351 100644<br>
--- a/src/mesa/drivers/dri/intel/<u></u>intel_mipmap_tree.c<br>
+++ b/src/mesa/drivers/dri/intel/<u></u>intel_mipmap_tree.c<br>
@@ -73,7 +73,8 @@ intel_miptree_create_internal(<u></u>struct intel_context *intel,<br>
                              GLuint height0,<br>
                              GLuint depth0,<br>
                              bool for_region,<br>
-                              GLuint num_samples)<br>
+                              GLuint num_samples,<br>
+                              bool msaa_is_interleaved)<br>
  {<br>
     struct intel_mipmap_tree *mt = calloc(sizeof(*mt), 1);<br>
     int compress_byte = 0;<br>
@@ -95,8 +96,14 @@ intel_miptree_create_internal(<u></u>struct intel_context *intel,<br>
     mt-&gt;cpp = compress_byte ? compress_byte : _mesa_get_format_bytes(mt-&gt;<u></u>format);<br>
     mt-&gt;num_samples = num_samples;<br>
     mt-&gt;compressed = compress_byte ? 1 : 0;<br>
+   mt-&gt;msaa_is_interleaved = msaa_is_interleaved;<br>
     mt-&gt;refcount = 1;<br>
<br>
+   /* array_spacing_lod0 is only used for non-interleaved MSAA surfaces.<br>
+    * TODO: can we use it elsewhere?<br>
+    */<br></div></div>
+   mt-&gt;array_spacing_lod0 = num_samples&gt;  0&amp;&amp;  !msaa_is_interleaved;<div><div><br>
+<br>
     if (target == GL_TEXTURE_CUBE_MAP) {<br>
        assert(depth0 == 1);<br>
        mt-&gt;depth0 = 6;<br>
@@ -109,6 +116,8 @@ intel_miptree_create_internal(<u></u>struct intel_context *intel,<br>
         (intel-&gt;must_use_separate_<u></u>stencil ||<br>
        (intel-&gt;has_separate_stencil&amp;&amp;<br>
        intel-&gt;vtbl.is_hiz_depth_<u></u>format(intel, format)))) {<br>
+      /* MSAA stencil surfaces are always interleaved. */<br>
+      bool msaa_is_interleaved = num_samples&gt;  0;<br>
        mt-&gt;stencil_mt = intel_miptree_create(intel,<br>
                                              mt-&gt;target,<br>
                                              MESA_FORMAT_S8,<br>
@@ -118,7 +127,8 @@ intel_miptree_create_internal(<u></u>struct intel_context *intel,<br>
                                              mt-&gt;height0,<br>
                                              mt-&gt;depth0,<br>
                                              true,<br>
-                                            num_samples);<br>
+                                            num_samples,<br>
+                                            msaa_is_interleaved);<br>
        if (!mt-&gt;stencil_mt) {<br>
         intel_miptree_release(&amp;mt);<br>
         return NULL;<br>
@@ -165,7 +175,8 @@ intel_miptree_create(struct intel_context *intel,<br>
                     GLuint height0,<br>
                     GLuint depth0,<br>
                     bool expect_accelerated_upload,<br>
-                     GLuint num_samples)<br>
+                     GLuint num_samples,<br>
+                     bool msaa_is_interleaved)<br>
  {<br>
     struct intel_mipmap_tree *mt;<br>
     uint32_t tiling = I915_TILING_NONE;<br>
@@ -207,7 +218,7 @@ intel_miptree_create(struct intel_context *intel,<br>
     mt = intel_miptree_create_internal(<u></u>intel, target, format,<br>
                                      first_level, last_level, width0,<br>
                                      height0, depth0,<br>
-                                     false, num_samples);<br>
+                                     false, num_samples, msaa_is_interleaved);<br>
     /*<br>
      * pitch == 0 || height == 0  indicates the null texture<br>
      */<br>
@@ -243,7 +254,8 @@ intel_miptree_create_for_<u></u>region(struct intel_context *intel,<br>
     mt = intel_miptree_create_internal(<u></u>intel, target, format,<br>
                                      0, 0,<br>
                                      region-&gt;width, region-&gt;height, 1,<br>
-                                     true, 0 /* num_samples */);<br>
+                                     true, 0 /* num_samples */,<br>
+                                      false /* msaa_is_interleaved */);<br>
     if (!mt)<br>
        return mt;<br>
<br>
@@ -252,6 +264,31 @@ intel_miptree_create_for_<u></u>region(struct intel_context *intel,<br>
     return mt;<br>
  }<br>
<br>
+/**<br>
+ * Determine whether the MSAA surface being created should use an interleaved<br>
+ * layout or a sliced layout, based on the chip generation and the surface<br>
+ * type.<br>
+ */<br>
+static bool<br>
+msaa_format_is_interleaved(<u></u>struct intel_context *intel, gl_format format)<br>
+{<br>
+   /* Prior to Gen7, all surfaces used interleaved layout. */<br>
+   if (intel-&gt;gen&lt;  7)<br>
+      return true;<br>
+<br>
+   /* In Gen7, interleaved layout is only used for depth and stencil<br>
+    * buffers.<br>
+    */<br>
+   switch (_mesa_get_format_base_format(<u></u>format)) {<br>
+   case GL_DEPTH_COMPONENT:<br>
+   case GL_STENCIL_INDEX:<br>
+   case GL_DEPTH_STENCIL:<br>
+      return true;<br>
+   default:<br>
+      return false;<br>
+   }<br>
+}<br>
+<br>
  struct intel_mipmap_tree*<br>
  intel_miptree_create_for_<u></u>renderbuffer(struct intel_context *intel,<br>
                                        gl_format format,<br>
@@ -260,25 +297,43 @@ intel_miptree_create_for_<u></u>renderbuffer(struct intel_context *intel,<br>
                                        uint32_t num_samples)<br>
  {<br>
     struct intel_mipmap_tree *mt;<br>
-<br>
-   /* Adjust width/height for MSAA.  Note: since samples are interleaved in a<br>
-    * complex pattern that repeats for every 2x2 block of pixels, we need to<br>
-    * expand the width and height to even numbers before the width/height<br>
-    * adjustment, otherwise some of the samples in the last row and column<br>
-    * will fall outside the boundary of the texture.<br>
-    */<br>
-   if (num_samples&gt;  4) {<br>
-      num_samples = 8;<br>
-      width = ALIGN(width, 2) * 4;<br>
-      height = ALIGN(height, 2) * 2;<br>
-   } else if (num_samples&gt;  0) {<br>
-      num_samples = 4;<br>
-      width = ALIGN(width, 2) * 2;<br>
-      height = ALIGN(height, 2) * 2;<br>
+   uint32_t depth = 1;<br>
+   bool msaa_is_interleaved = false;<br>
+<br>
+   if (num_samples&gt;  0) {<br>
+      /* Adjust width/height/depth for MSAA */<br>
+      msaa_is_interleaved = msaa_format_is_interleaved(<u></u>intel, format);<br>
+      if (msaa_is_interleaved) {<br>
+         /* Note: since samples are interleaved in a complex pattern that<br>
+          * repeats for every 2x2 block of pixels, we need to expand the width<br>
+          * and height to even numbers before the width/height adjustment,<br>
+          * otherwise some of the samples in the last row and column will fall<br>
+          * outside the boundary of the texture.<br>
+          */<br>
+         switch (num_samples) {<br>
+         case 4:<br>
+            width = ALIGN(width, 2) * 2;<br>
+            height = ALIGN(height, 2) * 2;<br>
+            break;<br>
+         case 8:<br>
+            width = ALIGN(width, 2) * 4;<br>
+            height = ALIGN(height, 2) * 2;<br>
+            break;<br>
+         default:<br>
+            /* num_samples should already have been quantized to 0, 4, or<br>
+             * 8.<br>
+             */<br>
+            assert(false);<br>
+         }<br>
+      } else {<br>
+         /* Non-interleaved */<br>
+         depth = num_samples;<br>
+      }<br>
     }<br>
<br>
     mt = intel_miptree_create(intel, GL_TEXTURE_2D, format, 0, 0,<br>
-                            width, height, 1, true, num_samples);<br>
+                            width, height, depth, true, num_samples,<br>
+                             msaa_is_interleaved);<br>
<br>
     return mt;<br>
  }<br>
@@ -552,6 +607,8 @@ intel_miptree_alloc_hiz(struct intel_context *intel,<br>
                          GLuint num_samples)<br>
  {<br>
     assert(mt-&gt;hiz_mt == NULL);<br>
+   /* MSAA HiZ surfaces are always interleaved. */<br>
+   bool msaa_is_interleaved = num_samples&gt;  0;<br>
     mt-&gt;hiz_mt = intel_miptree_create(intel,<br>
                                       mt-&gt;target,<br>
                                       MESA_FORMAT_X8_Z24,<br>
@@ -561,7 +618,8 @@ intel_miptree_alloc_hiz(struct intel_context *intel,<br>
                                       mt-&gt;height0,<br>
                                       mt-&gt;depth0,<br>
                                       true,<br>
-                                     num_samples);<br>
+                                     num_samples,<br>
+                                     msaa_is_interleaved);<br>
<br>
     if (!mt-&gt;hiz_mt)<br>
        return false;<br>
diff --git a/src/mesa/drivers/dri/intel/<u></u>intel_mipmap_tree.h b/src/mesa/drivers/dri/intel/<u></u>intel_mipmap_tree.h<br>
index ca1666d..3883d2b 100644<br>
--- a/src/mesa/drivers/dri/intel/<u></u>intel_mipmap_tree.h<br>
+++ b/src/mesa/drivers/dri/intel/<u></u>intel_mipmap_tree.h<br>
@@ -172,6 +172,26 @@ struct intel_mipmap_tree<br>
     GLuint num_samples;<br>
     bool compressed;<br>
<br>
+   /**<br>
+    * For 1D array, 2D array, cube, and 2D multisampled surfaces on Gen7: true<br>
+    * if the surface only contains LOD 0, and hence no space is for LOD&#39;s<br>
+    * other than 0 in between array slices.<br>
+    *<br>
+    * Corresponds to the surface_array_spacing bit in gen7_surface_state.<br>
+    */<br>
+   bool array_spacing_lod0;<br>
</div></div></blockquote>
<br>
It seems like we ought to use ARYSPC_LOD0 mode for all non-mipmapped renderbuffers and textures...it should save memory.  If we did that, I think we could probably just use mt-&gt;first_level != mt-&gt;last_level rather than adding a new flag.<br>


<br>
Then again, I haven&#39;t thought through all the ramifications of that: I know there&#39;s some period of time where the user has defined LOD0, and you&#39;re not sure whether they&#39;re going to defined LOD1, 2, 3 too or just not do mipmapping.  It would suck to allocate something in ARYSPC_LOD0/non-mipmap-capable mode and then have to redo it.  But maybe we have to redo it already?<br>

</blockquote></div></div><div><br>I think you&#39;re right that we have to redo it anyhow, because even without using ARYSPC_LOD0, if we speculatively allocate a texture that just has LOD0, then we haven&#39;t reserved enough memory for the other mip levels of the last array slice.<br>

<br>Your suggestion seems reasonable.  The only thing I can think of that might get in the way is if there are restrictions in the bspec requiring us to disable ARYSPC_LOD0 at certain times.  I&#39;ll try to dig through the bspec today and check that.<br>
</div></div></blockquote><div><br>We discussed this further in person yesterday, and decided that it would be better to wait and do it as a future optimization, on the grounds that changing the layout of every non-mipmapped array texture is a little more risk than we want to incur in the middle of this patch series.  I&#39;ve added it to a list of items to revisit once the bulk of MSAA is complete.<br>
<br>I also seem to recall that you found a subtlety about ARYSPC_LOD0 in the bspec yesterday that we&#39;ll need to keep in mind when we do revisit this topic.  Do you remember what that was?  I&#39;ve forgotten the details.<br>
</div></div>