<div dir="ltr">On 4 June 2013 18:20, Anuj Phogat <span dir="ltr"><<a href="mailto:anuj.phogat@gmail.com" target="_blank">anuj.phogat@gmail.com</a>></span> wrote:<br><div class="gmail_extra"><div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
Current implementation of ext_framebuffer_multisample_blit_scaled in<br>
i965/blorp uses nearest filtering for multisample scaled blits. Using<br>
nearest filtering produces blocky artifacts and negates the benefits<br>
of MSAA. That is the reason why extension was not enabled on i965.<br>
<br>
This patch implements the bilinear filtering of samples in blorp<br>
engine. Images generated with this patch are free from blocky<br>
artifacts and show big improvement in visual quality.<br></blockquote><div><br></div><div>This is definitely a quality improvement over our previous implementation.  I still have some concerns about whether we want this to be our final answer, though.  In particular, it seems to me that to avoid blocky artifacts, sampling at coordinates (x, y) should produce nearly the same result as sampling at (x+dx, y+dy), where |dx| and |dy| are much less than 1.  Normal bilinear filtering has this property.  But the algorithm in this patch doesn't, since for example sampling at (0.99999, 1.5) of a 4x MSAA surface gets you a blend of samples 1 and 3 from (0, 1), and sampling at (1.00000, 1.5) gets you a blend of samples 0 and 2 from (1, 1).<br>
<br>I'm hoping you, Ian, and I can find a time to discuss it in person tomorrow.  It seems like this sort of algorithm design really benefits from a whiteboard.<br><br></div><div>The comments that follow assume we decide to stick with the algorithm as is.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
Observed no piglit and gles3 regressions.<br>
---<br>
 src/mesa/drivers/dri/i965/brw_blorp.h        |   3 +<br>
 src/mesa/drivers/dri/i965/brw_blorp_blit.cpp | 157 ++++++++++++++++++++++++++-<br>
 2 files changed, 155 insertions(+), 5 deletions(-)<br>
<br>
diff --git a/src/mesa/drivers/dri/i965/brw_blorp.h b/src/mesa/drivers/dri/i965/brw_blorp.h<br>
index 51b23db..a40324b 100644<br>
--- a/src/mesa/drivers/dri/i965/brw_blorp.h<br>
+++ b/src/mesa/drivers/dri/i965/brw_blorp.h<br>
@@ -305,6 +305,9 @@ struct brw_blorp_blit_prog_key<br>
     * than one sample per pixel.<br>
     */<br>
    bool persample_msaa_dispatch;<br>
+<br>
+   /* True for scaled blitting. */<br>
+   bool blit_scaled;<br>
 };<br>
<br>
 class brw_blorp_blit_params : public brw_blorp_params<br>
diff --git a/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp b/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp<br>
index a6b2bbf..46aa6d4 100644<br>
--- a/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp<br>
+++ b/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp<br>
@@ -619,7 +619,8 @@ private:<br>
    void kill_if_outside_dst_rect();<br>
    void translate_dst_to_src();<br>
    void single_to_blend();<br>
-   void manual_blend(unsigned num_samples);<br>
+   void manual_blend_average(unsigned num_samples);<br>
+   void manual_blend_linear(unsigned num_samples);<br>
    void sample(struct brw_reg dst);<br>
    void texel_fetch(struct brw_reg dst);<br>
    void mcs_fetch();<br>
@@ -630,7 +631,7 @@ private:<br>
    /**<br>
     * Base-2 logarithm of the maximum number of samples that can be blended.<br>
     */<br>
-   static const unsigned LOG2_MAX_BLEND_SAMPLES = 3;<br>
+   static const unsigned LOG2_MAX_BLEND_SAMPLES = 7;<br></blockquote><div><br></div>This is misleading now, since it looks like it's saying that the maximum number of samples that can be blended is 2^7 == 128.  What's really happening is that you're adding an algorithm that requires n temporary storage locations (where n is the number of samples), whereas the old algorithm required only log2(n)+1 temporary storage locations.  Let's just rip this constant out and declare texture_data to have size 8.<br>
 <br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
    void *mem_ctx;<br>
    struct brw_context *brw;<br>
@@ -673,6 +674,9 @@ private:<br>
     */<br>
    struct brw_reg y_coords[2];<br>
<br>
+   struct brw_reg x_coord_fract;<br>
+   struct brw_reg y_coord_fract;<br>
+<br>
    /* Which element of x_coords and y_coords is currently in use.<br>
     */<br>
    int xy_coord_index;<br>
@@ -811,15 +815,17 @@ brw_blorp_blit_program::compile(struct brw_context *brw,<br>
     * that we want to texture from.  Exception: if we are blending, then S is<br>
     * irrelevant, because we are going to fetch all samples.<br>
     */<br>
-   if (key->blend) {<br>
+   if (key->blend && !key->blit_scaled) {<br>
       if (brw->intel.gen == 6) {<br>
          /* Gen6 hardware an automatically blend using the SAMPLE message */<br>
          single_to_blend();<br>
          sample(texture_data[0]);<br>
       } else {<br>
          /* Gen7+ hardware doesn't automaticaly blend. */<br>
-         manual_blend(key->src_samples);<br>
+         manual_blend_average(key->src_samples);<br>
       }<br>
+   } else if(key->blend && key->blit_scaled) {<br>
+      manual_blend_linear(key->src_samples);<br>
    } else {<br>
       /* We aren't blending, which means we just want to fetch a single sample<br>
        * from the source surface.  The address that we want to fetch from is<br>
@@ -910,6 +916,13 @@ brw_blorp_blit_program::alloc_regs()<br>
          = retype(brw_vec8_grf(reg, 0), BRW_REGISTER_TYPE_UD);<br>
       reg += 2;<br>
    }<br>
+   this->x_coord_fract<br>
+      = vec8(retype(brw_vec8_grf(reg, 0), BRW_REGISTER_TYPE_F));<br>
+   reg += 2;<br>
+   this->y_coord_fract<br>
+      = vec8(retype(brw_vec8_grf(reg, 0), BRW_REGISTER_TYPE_F));<br>
+   reg += 2;<br>
+<br>
    this->xy_coord_index = 0;<br>
    this->sample_index<br>
       = retype(brw_vec8_grf(reg, 0), BRW_REGISTER_TYPE_UD);<br>
@@ -1365,6 +1378,10 @@ brw_blorp_blit_program::translate_dst_to_src()<br>
    brw_MUL(&func, Y_f, Yp_f, y_transform.multiplier);<br>
    brw_ADD(&func, X_f, X_f, x_transform.offset);<br>
    brw_ADD(&func, Y_f, Y_f, y_transform.offset);<br>
+   if (key->blit_scaled && key->blend) {<br>
+      brw_FRC(&func, x_coord_fract, X_f);<br>
+      brw_FRC(&func, y_coord_fract, Y_f);<br>
+   }<br>
    /* Round the float coordinates down to nearest integer by moving to<br>
     * UD registers.<br>
     */<br>
@@ -1415,7 +1432,7 @@ inline int count_trailing_one_bits(unsigned value)<br>
<br>
<br>
 void<br>
-brw_blorp_blit_program::manual_blend(unsigned num_samples)<br>
+brw_blorp_blit_program::manual_blend_average(unsigned num_samples)<br>
 {<br>
    if (key->tex_layout == INTEL_MSAA_LAYOUT_CMS)<br>
       mcs_fetch();<br>
@@ -1520,6 +1537,131 @@ brw_blorp_blit_program::manual_blend(unsigned num_samples)<br>
       brw_ENDIF(&func);<br>
 }<br>
<br>
+void<br>
+brw_blorp_blit_program::manual_blend_linear(unsigned num_samples)<br>
+{  <br></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+   if (key->tex_layout == INTEL_MSAA_LAYOUT_CMS)<br>
+      mcs_fetch();<br>
+<br>
+   /* e.g. for 4x MSAA:<br>
+    *   result = lrp(lrp(sample[0] + sample[1]) + lrp(sample[2] + sample[3]))<br>
+    *<br>
+    * We do this computation by performing the following operations:<br>
+    *<br>
+    * In case of 4x MSAA:<br>
+    * - Compute samples 0 to 3<br>
+    * - linearly interpolate samples 0 and 1 in X<br>
+    * - linearly interpolate samples 2 and 3 in X<br>
+    * - linearly interpolate the results of last two operations in Y <br></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+    *<br>
+    * In case of 8x MSAA, we take the average of two samples in each quarter<br>
+    * of the pixel to generate 4 sample values. These 4 sample values are used<br>
+    * in a way similar to 4x MSAA:<br>
+    * - Compute samples 0 to 7<br>
+    * - Compute avearge of samples 0 and 7 and leave the result in sample 0<br>
+    * - Compute average of samples 1 and 3 and leave the result in sample 1<br>
+    * - Compute average of samples 2 and 6 and leave the result in sample 2<br>
+    * - Compute average of samples 4 and 5 and leave the result in sample 3<br>
+    * - linearly interpolate samples 0 and 1 in X<br>
+    * - linearly interpolate samples 2 and 3 in X<br>
+    * - linearly interpolate the results of last two operations in Y<br>
+    *<br>
+    */<br>
+   for (unsigned i = 0; i < num_samples; ++i) {<br>
+      assert(i < ARRAY_SIZE(texture_data));<br>
+      if (i == 0) {<br>
+         s_is_zero = true;<br>
+      } else {<br>
+         s_is_zero = false;<br>
+         brw_MOV(&func, vec16(S), brw_imm_ud(i));<br>
+      }<br>
+      texel_fetch(texture_data[i]);<br>
+<br>
+      if (i == 0 && key->tex_layout == INTEL_MSAA_LAYOUT_CMS) {<br>
+         /* The Ivy Bridge PRM, Vol4 Part1 p27 (Multisample Control Surface)<br>
+          * suggests an optimization:<br>
+          *<br>
+          *     "A simple optimization with probable large return in<br>
+          *     performance is to compare the MCS value to zero (indicating<br>
+          *     all samples are on sample slice 0), and sample only from<br>
+          *     sample slice 0 using ld2dss if MCS is zero."<br>
+          *<br>
+          * Note that in the case where the MCS value is zero, sampling from<br>
+          * sample slice 0 using ld2dss and sampling from sample 0 using<br>
+          * ld2dms are equivalent (since all samples are on sample slice 0).<br>
+          * Since we have already sampled from sample 0, all we need to do is<br>
+          * skip the remaining fetches and averaging if MCS is zero.<br>
+          */<br>
+         brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_NZ,<br>
+                 mcs_data, brw_imm_ud(0));<br>
+         brw_IF(&func, BRW_EXECUTE_16);<br>
+      }<br>
+   }<br>
+<br>
+#define SAMPLE(x, y) offset(texture_data[x], y)<br>
+#define COMBINE(brw_op, dst, src0, src1)\<br>
+   for (int k = 0; k < 4; ++k)\<br>
+      brw_op(&func, dst, src0, src1);<br>
+<br>
+   if (num_samples == 8) {<br>
+      COMBINE(brw_ADD, SAMPLE(0, 2*k),<br>
+              vec8(SAMPLE(0, 2*k)),<br>
+              vec8(SAMPLE(7, 2*k)));<br>
+      COMBINE(brw_MUL, SAMPLE(0, 2*k),<br>
+              vec8(SAMPLE(0, 2*k)),<br>
+              brw_imm_f(0.5));<br>
+      COMBINE(brw_ADD, SAMPLE(1, 2*k),<br>
+              vec8(SAMPLE(1, 2*k)),<br>
+              vec8(SAMPLE(3, 2*k)));<br>
+      COMBINE(brw_MUL, SAMPLE(1, 2*k),<br>
+              vec8(SAMPLE(1, 2*k)),<br>
+              brw_imm_f(0.5));<br>
+      COMBINE(brw_ADD, SAMPLE(2, 2*k),<br>
+              vec8(SAMPLE(2, 2*k)),<br>
+              vec8(SAMPLE(6, 2*k)));<br>
+      COMBINE(brw_MUL, SAMPLE(2, 2*k),<br>
+              vec8(SAMPLE(2, 2*k)),<br>
+              brw_imm_f(0.5));<br>
+      COMBINE(brw_ADD, SAMPLE(3, 2*k),<br>
+              vec8(SAMPLE(4, 2*k)),<br>
+              vec8(SAMPLE(5, 2*k)));<br>
+      COMBINE(brw_MUL, SAMPLE(3, 2*k),<br>
+              vec8(SAMPLE(3, 2*k)),<br>
+              brw_imm_f(0.5));<br></blockquote><div><br></div><div>It would be faster to drop the MUL(..., 0.5) parts and just multiply by 0.5 at the end.<br></div> <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

+<br>
+      /* Shuffle sample registers stored in texture_data array to match with<br>
+       * the layout of samples in 4x MSAA.<br>
+       */<br>
+      t1 = texture_data[0];<br>
+      t2 = texture_data[1];<br>
+      texture_data[0] = texture_data[3];<br>
+      texture_data[1] = texture_data[2];<br>
+      texture_data[2] = t1;<br>
+      texture_data[3] = t2;<br></blockquote><div><br></div><div>I see what you're doing, and I see why it will work, but it makes me feel really jittery to see the texture_data array get modified like this--the array is supposed to get initialized by alloc_regs() and stay constant thereafter.  I believe we can get the equivalent effect by carefully rewriting the code above to this:<br>
<br>      COMBINE(brw_ADD, SAMPLE(3, 2*k),<br>              vec8(SAMPLE(1, 2*k)),<br>              vec8(SAMPLE(3, 2*k)));<br>      COMBINE(brw_ADD, SAMPLE(1, 2*k),<br>              vec8(SAMPLE(2, 2*k)),<br>              vec8(SAMPLE(6, 2*k)));<br>
      COMBINE(brw_ADD, SAMPLE(2, 2*k),<br>              vec8(SAMPLE(0, 2*k)),<br>              vec8(SAMPLE(7, 2*k)));<br>      COMBINE(brw_ADD, SAMPLE(0, 2*k),<br>              vec8(SAMPLE(4, 2*k)),<br>              vec8(SAMPLE(5, 2*k)));<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+   }<br>
+<br>
+   brw_set_access_mode(&func, BRW_ALIGN_16);<br>
+   for (int index = 3; index > 0; ) {<br>
+      for (int k = 0; k < 8; ++k)<br>
+         brw_LRP(&func,<br>
+                 vec8(SAMPLE(index - 1, k)),<br>
+                 offset(x_coord_fract, k & 1),<br>
+                 SAMPLE(index, k),<br>
+                 SAMPLE(index - 1, k));<br>
+      index -= 2;<br>
+   }<br>
+   for (int k = 0; k < 8; ++k)<br>
+      brw_LRP(&func,<br>
+              vec8(SAMPLE(0, k)),<br>
+              offset(y_coord_fract, k & 1),<br>
+              vec8(SAMPLE(2, k)),<br>
+              vec8(SAMPLE(0, k)));<br>
+   brw_set_access_mode(&func, BRW_ALIGN_1);<br>
+#undef SAMPLE<br>
+   if (key->tex_layout == INTEL_MSAA_LAYOUT_CMS)<br>
+      brw_ENDIF(&func);<br>
+}<br>
+<br>
 /**<br>
  * Emit code to look up a value in the texture using the SAMPLE message (which<br>
  * does blending of MSAA surfaces).<br>
@@ -1869,6 +2011,11 @@ brw_blorp_blit_params::brw_blorp_blit_params(struct brw_context *brw,<br>
       wm_prog_key.persample_msaa_dispatch = true;<br>
    }<br>
<br>
+   /* Scaled blitting or not. */<br>
+   wm_prog_key.blit_scaled =<br>
+      ((dst_x1 - dst_x0) == (src_x1 - src_x0) &&<br>
+       (dst_y1 - dst_y0) == (src_y1 - src_y0)) ? false : true;<br>
+<br>
    /* The render path must be configured to use the same number of samples as<br>
     * the destination buffer.<br>
     */<br>
<span class=""><font color="#888888">--<br>
1.8.1.4<br>
<br>
</font></span></blockquote></div><br></div></div>