On 22 May 2012 11:31, Kenneth Graunke <span dir="ltr">&lt;<a href="mailto:kenneth@whitecape.org" target="_blank">kenneth@whitecape.org</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="im">On 05/11/2012 11:03 AM, Paul Berry wrote:<br>
</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div class="h5">
This patch modifies the &quot;blorp&quot; WM program so that it can be run in<br>
MSDISPMODE_PERSAMPLE (which means that every single sample of a<br>
multisampled render target is dispatched to the WM program, not just<br>
every pixel).<br>
<br>
Previously we were using the ugly hack of configuring multisampled<br>
destination surfaces as single-sampled, and generating sample indices<br>
other than zero by swizzling the pixel coordinates in the WM program.<br>
---<br>
  src/mesa/drivers/dri/i965/brw_<u></u>blorp.h        |   12 ++++<br>
  src/mesa/drivers/dri/i965/brw_<u></u>blorp_blit.cpp |   87 +++++++++++++++++++-------<br>
  src/mesa/drivers/dri/i965/<u></u>gen6_blorp.cpp     |    5 +-<br>
  src/mesa/drivers/dri/i965/<u></u>gen7_blorp.cpp     |   10 ++-<br>
  4 files changed, 87 insertions(+), 27 deletions(-)<br>
<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 f14a5c7..b911356 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>
@@ -132,6 +132,12 @@ const unsigned int BRW_BLORP_NUM_PUSH_CONST_REGS =<br>
  struct brw_blorp_prog_data<br>
  {<br>
     unsigned int first_curbe_grf;<br>
+<br>
+   /**<br>
+    * True if the WM program should be run in MSDISPMODE_PERSAMPLE with more<br>
+    * than one sample per pixel.<br>
+    */<br>
+   bool persample_msaa_dispatch;<br>
  };<br>
<br>
  class brw_blorp_params<br>
@@ -218,6 +224,12 @@ struct brw_blorp_blit_prog_key<br>
      * pixels that are outside the destination rectangle.<br>
      */<br>
     bool use_kill;<br>
+<br>
+   /**<br>
+    * True if the WM program should be run in MSDISPMODE_PERSAMPLE with more<br>
+    * than one sample per pixel.<br>
+    */<br>
+   bool persample_msaa_dispatch;<br>
  };<br>
<br>
  class brw_blorp_blit_params : public brw_blorp_params<br>
diff --git a/src/mesa/drivers/dri/i965/<u></u>brw_blorp_blit.cpp b/src/mesa/drivers/dri/i965/<u></u>brw_blorp_blit.cpp<br>
index e985fad..07e9dd7 100644<br>
--- a/src/mesa/drivers/dri/i965/<u></u>brw_blorp_blit.cpp<br>
+++ b/src/mesa/drivers/dri/i965/<u></u>brw_blorp_blit.cpp<br>
@@ -437,13 +437,14 @@ brw_blorp_blit_program::<u></u>compile(struct brw_context *brw,<br>
                                  GLuint *program_size)<br>
  {<br>
     /* Sanity checks */<br>
-   if (key-&gt;dst_tiled_w) {<br>
-      /* If the destination image is W tiled, then dst_samples must be 0.<br>
-       * Otherwise, after conversion between W and Y tiling, there&#39;s no<br></div></div>
+   if (key-&gt;dst_tiled_w&amp;&amp;  key-&gt;rt_samples&gt;  0) {<div><div class="h5"><br>
+      /* If the destination image is W tiled and multisampled, then the thread<br>
+       * must be dispatched once per sample, not once per pixel.  This is<br>
+       * necessary because after conversion between W and Y tiling, there&#39;s no<br>
         * guarantee that all samples corresponding to a single pixel will still<br>
         * be together.<br>
         */<br>
-      assert(key-&gt;rt_samples == 0);<br>
+      assert(key-&gt;persample_msaa_<u></u>dispatch);<br>
     }<br>
<br>
     if (key-&gt;blend) {<br>
@@ -459,6 +460,17 @@ brw_blorp_blit_program::<u></u>compile(struct brw_context *brw,<br>
        assert(key-&gt;tex_samples&gt;  0);<br>
     }<br>
<br>
+   if (key-&gt;persample_msaa_dispatch) {<br>
+      /* It only makes sense to do persample dispatch if the render target is<br>
+       * configured as multisampled.<br>
+       */<br>
+      assert(key-&gt;rt_samples&gt;  0);<br>
+   }<br>
+<br>
+   /* Set up prog_data */<br>
+   memset(&amp;prog_data, 0, sizeof(prog_data));<br>
+   prog_data.persample_msaa_<u></u>dispatch = key-&gt;persample_msaa_dispatch;<br>
+<br>
     brw_set_compression_control(&amp;<u></u>func, BRW_COMPRESSION_NONE);<br>
<br>
     alloc_regs();<br>
@@ -658,11 +670,29 @@ brw_blorp_blit_program::<u></u>compute_frag_coords()<br>
      */<br>
     brw_ADD(&amp;func, Y, stride(suboffset(R1, 5), 2, 4, 0), brw_imm_v(0x11001100));<br>
<br>
-   /* Since we always run the WM in a mode that causes a single fragment<br>
-    * dispatch per pixel, it&#39;s not meaningful to compute a sample value.  Just<br>
-    * set it to 0.<br>
-    */<br>
-   s_is_zero = true;<br>
+   if (key-&gt;persample_msaa_dispatch) {<br>
+      /* The WM will be run in MSDISPMODE_PERSAMPLE with num_samples&gt;  0.<br>
+       * Therefore, subspan 0 will represent sample 0, subspan 1 will<br>
+       * represent sample 1, and so on.<br>
+       *<br>
+       * So we need to populate S with the sequence (0, 0, 0, 0, 1, 1, 1, 1,<br>
+       * 2, 2, 2, 2, 3, 3, 3, 3).  The easiest way to do this is to populate a<br>
+       * temporary variable with the sequence (0, 1, 2, 3), and then copy from<br>
+       * it using vstride=1, width=4, hstride=0.<br>
+       *<br>
+       * TODO: implement appropriate calculation for Gen7.<br>
+       */<br>
</div></div></blockquote>
<br>
I think you mean:<br>
<br>
TODO: implement the necessary calculation for 8x multisampling.<br></blockquote><div><br>You&#39;re right.  Good catch.<br> </div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

<br>
Otherwise,<br>
Reviewed-by: Kenneth Graunke &lt;<a href="mailto:kenneth@whitecape.org" target="_blank">kenneth@whitecape.org</a>&gt;<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="im">
+      brw_MOV(&amp;func, t1, brw_imm_v(0x3210));<br>
+      brw_MOV(&amp;func, S, stride(t1, 1, 4, 0));<br>
+      s_is_zero = false;<br>
+   } else {<br>
+      /* Either the destination surface is single-sampled, or the WM will be<br>
+       * run in MSDISPMODE_PERPIXEL (which causes a single fragment dispatch<br>
+       * per pixel).  In either case, it&#39;s not meaningful to compute a sample<br>
+       * value.  Just set it to 0.<br>
+       */<br>
+      s_is_zero = true;<br>
+   }<br>
  }<br>
<br>
  /**<br>
@@ -1065,22 +1095,23 @@ brw_blorp_blit_params::brw_<u></u>blorp_blit_params(struct intel_mipmap_tree *src_mt,<br>
     use_wm_prog = true;<br>
     memset(&amp;wm_prog_key, 0, sizeof(wm_prog_key));<br>
<br>
-   if (dst.map_stencil_as_y_tiled) {<br>
-      /* If the destination surface is a W-tiled stencil buffer that we&#39;re<br>
-       * mapping as Y tiled, then we need to set up the surface state as<br>
-       * single-sampled, because the memory layout of related samples doesn&#39;t<br>
-       * match between W and Y tiling.<br></div>
+   if (dst.map_stencil_as_y_tiled&amp;&amp;  dst.num_samples&gt;  0) {<div class="im"><br>
+      /* If the destination surface is a W-tiled multisampled stencil buffer<br>
+       * that we&#39;re mapping as Y tiled, then we need to arrange for the WM<br>
+       * program to run once per sample rather than once per pixel, because<br>
+       * the memory layout of related samples doesn&#39;t match between W and Y<br>
+       * tiling.<br>
         */<br>
-      dst.num_samples = 0;<br>
+      wm_prog_key.persample_msaa_<u></u>dispatch = true;<br>
     }<br>
<br></div>
-   if (src_mt-&gt;num_samples&gt;  0&amp;&amp;  dst_mt-&gt;num_samples&gt;  0) {<br>
+   if (src.num_samples&gt;  0&amp;&amp;  dst.num_samples&gt;  0) {<div class="im"><br>
        /* We are blitting from a multisample buffer to a multisample buffer, so<br>
         * we must preserve samples within a pixel.  This means we have to<br>
-       * configure the render target as single-sampled, so that the WM program<br>
-       * generate each sample separately.<br>
+       * arrange for the WM program to run once per sample rather than once<br>
+       * per pixel.<br>
         */<br>
-      dst.num_samples = 0;<br>
+      wm_prog_key.persample_msaa_<u></u>dispatch = true;<br>
     }<br>
<br>
     /* The render path must be configured to use the same number of samples as<br>
@@ -1138,12 +1169,22 @@ brw_blorp_blit_params::brw_<u></u>blorp_blit_params(struct intel_mipmap_tree *src_mt,<br>
         * dimensions 64x64.  We must also align it to a multiple of the tile<br>
         * size, because the differences between W and Y tiling formats will<br>
         * mean that pixels are scrambled within the tile.<br>
+       *<br>
+       * Note: if the destination surface configured as an MSAA surface, then<br>
+       * the effective tile size we need to align it to is smaller, because<br>
+       * each pixel covers a 2x2 or a 4x2 block of samples.<br>
+       *<br>
         * TODO: what if this makes the coordinates too large?<br>
         */<br></div>
-      x0 = (x0 * 2)&amp;  ~127;<br>
-      y0 = (y0 / 2)&amp;  ~31;<div class="im"><br>
-      x1 = ALIGN(x1 * 2, 128);<br>
-      y1 = ALIGN(y1 / 2, 32);<br>
+      unsigned x_align = 64, y_align = 64;<br>
+      if (dst_mt-&gt;num_samples&gt;  0) {<br>
+         x_align /= (dst_mt-&gt;num_samples == 4 ? 2 : 4);<br>
+         y_align /= 2;<br>
+      }<br></div>
+      x0 = (x0&amp;  ~(x_align - 1)) * 2;<br>
+      y0 = (y0&amp;  ~(y_align - 1)) / 2;<div class="im"><br>
+      x1 = ALIGN(x1, x_align) * 2;<br>
+      y1 = ALIGN(y1, y_align) / 2;<br>
        wm_prog_key.use_kill = true;<br>
     }<br>
  }<br>
diff --git a/src/mesa/drivers/dri/i965/<u></u>gen6_blorp.cpp b/src/mesa/drivers/dri/i965/<u></u>gen6_blorp.cpp<br>
index 8eed9dc..85a8ee6 100644<br>
--- a/src/mesa/drivers/dri/i965/<u></u>gen6_blorp.cpp<br>
+++ b/src/mesa/drivers/dri/i965/<u></u>gen6_blorp.cpp<br>
@@ -742,7 +742,10 @@ gen6_blorp_emit_wm_config(<u></u>struct brw_context *brw,<br>
<br>
     if (params-&gt;num_samples&gt;  0) {<br>
        dw6 |= GEN6_WM_MSRAST_ON_PATTERN;<br>
-      dw6 |= GEN6_WM_MSDISPMODE_PERPIXEL;<br></div>
+      if (prog_data&amp;&amp;  prog_data-&gt;persample_msaa_<u></u>dispatch)<div class="im"><br>
+         dw6 |= GEN6_WM_MSDISPMODE_PERSAMPLE;<br>
+      else<br>
+         dw6 |= GEN6_WM_MSDISPMODE_PERPIXEL;<br>
     } else {<br>
        dw6 |= GEN6_WM_MSRAST_OFF_PIXEL;<br>
        dw6 |= GEN6_WM_MSDISPMODE_PERSAMPLE;<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 fbb94df..e5b27dd 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>
@@ -399,7 +399,8 @@ gen7_blorp_emit_sf_config(<u></u>struct brw_context *brw,<br>
   */<br>
  static void<br>
  gen7_blorp_emit_wm_config(<u></u>struct brw_context *brw,<br>
-                          const brw_blorp_params *params)<br>
+                          const brw_blorp_params *params,<br>
+                          brw_blorp_prog_data *prog_data)<br>
  {<br></div>
     struct intel_context *intel =&amp;brw-&gt;intel;<div class="im"><br>
<br>
@@ -431,7 +432,10 @@ gen7_blorp_emit_wm_config(<u></u>struct brw_context *brw,<br>
<br>
        if (params-&gt;num_samples&gt;  0) {<br>
           dw1 |= GEN7_WM_MSRAST_ON_PATTERN;<br>
-         dw2 |= GEN7_WM_MSDISPMODE_PERPIXEL;<br></div>
+         if (prog_data&amp;&amp;  prog_data-&gt;persample_msaa_<u></u>dispatch)<div class="im"><br>
+            dw2 |= GEN7_WM_MSDISPMODE_PERSAMPLE;<br>
+         else<br>
+            dw2 |= GEN7_WM_MSDISPMODE_PERPIXEL;<br>
        } else {<br>
           dw1 |= GEN7_WM_MSRAST_OFF_PIXEL;<br>
           dw2 |= GEN7_WM_MSDISPMODE_PERSAMPLE;<br>
@@ -757,7 +761,7 @@ gen7_blorp_exec(struct intel_context *intel,<br>
     gen7_blorp_emit_streamout_<u></u>disable(brw, params);<br>
     gen6_blorp_emit_clip_disable(<u></u>brw, params);<br>
     gen7_blorp_emit_sf_config(brw, params);<br>
-   gen7_blorp_emit_wm_config(brw, params);<br>
+   gen7_blorp_emit_wm_config(brw, params, prog_data);<br>
     if (params-&gt;use_wm_prog) {<br>
        gen7_blorp_emit_binding_table_<u></u>pointers_ps(brw, params,<br>
                                                  wm_bind_bo_offset);<br>
</div></blockquote>
<br>
</blockquote></div><br>