<div dir="ltr">On 19 June 2013 19:45, 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 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">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 engine.<br>
Images generated with this patch are free from blocky artifacts and show<br>
big improvement in visual quality.<br>
<br>
Observed no piglit and gles3 regressions.<br>
<br>
V3:<br>
- Algorithm used for filtering assumes a rectangular grid of samples<br>
  roughly corresponding to sample locations.<br>
- Test the boundary conditions on the edges of texture.<br>
<br>
Signed-off-by: Anuj Phogat <<a href="mailto:anuj.phogat@gmail.com" target="_blank">anuj.phogat@gmail.com</a>><br></blockquote><div><br></div><div>Thanks for all your effort on this, Anuj.  I think we have an algorithm that's going to get us good quality.  I have a number of minor comments below, but I think the basic approach is good.<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>
 src/mesa/drivers/dri/i965/brw_blorp.h        |  11 ++<br>
 src/mesa/drivers/dri/i965/brw_blorp_blit.cpp | 257 +++++++++++++++++++++++++--<br>
 2 files changed, 258 insertions(+), 10 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 ffc27cc..0a15b89 100644<br>
--- a/src/mesa/drivers/dri/i965/brw_blorp.h<br>
+++ b/src/mesa/drivers/dri/i965/brw_blorp.h<br>
@@ -319,6 +319,17 @@ 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>
+   /* Source rectangle dimensions. Used to test boundary conditions in shader<br>
+    * program.<br>
+    */<br>
+   float src_x0;<br>
+   float src_y0;<br>
+   float src_x1;<br>
+   float src_y1;<br></blockquote><div><br></div><div>Two comments about this:<br><br></div><div>(1) Rather than clamp to the boundary of the source rectangle, I have a minor preference for clamping to the boundary of the source image.  This is what I've observed in nVidia's blitter, and it's what's implemented in Mesa's meta path for scaled blits.  Also, it would have the benefit of simplifying some of the logic below, since the lower clamp will always be 0.<br>
<br></div><div>(2) We can't put these numbers in the program key, since they're going to change frequently, and changing the program key causes the program to be recompiled.  They need to go in push constants, like we do for the destination rectangle coordinates and the multipliers and offsets.<br>
</div><br> <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
 };<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 8694128..e99c9df 100644<br>
--- a/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp<br>
+++ b/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp<br>
@@ -622,7 +622,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></blockquote><div><br></div><div>Minor nit pick: can we call this function manual_blend_bilinear()?  "linear" is such a generic term that it's hard to guess what it does, but "bilinear" makes it obvious.<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">
    void sample(struct brw_reg dst);<br>
    void texel_fetch(struct brw_reg dst);<br>
    void mcs_fetch();<br>
@@ -676,6 +677,16 @@ private:<br>
     */<br>
    struct brw_reg y_coords[2];<br>
<br>
+   /* X, Y coordinates of the pixel from which we need to fetch the specific<br>
+    *  sample. These are used for multisample scaled blitting.<br>
+    */<br>
+   struct brw_reg x_sample_coords;<br>
+   struct brw_reg y_sample_coords;<br>
+<br>
+   /* Store the values to use to interpolate in x and y directions */<br>
+   struct brw_reg x_lerp;<br>
+   struct brw_reg y_lerp;<br>
+<br></blockquote><div><br></div><div>I had trouble guessing what the "lerp" variables are used for.  How about something like this instead?<br><br></div><div>/* Fractional parts of the x and y coordinates, used as bilinear interpolation coefficients */<br>
</div><div>struct brw_reg x_frac;<br></div><div>struct brw_reg y_frac;<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">
    /* Which element of x_coords and y_coords is currently in use.<br>
     */<br>
    int xy_coord_index;<br>
@@ -814,15 +825,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>
@@ -913,6 +926,18 @@ brw_blorp_blit_program::alloc_regs()<br>
          = retype(brw_vec8_grf(reg, 0), BRW_REGISTER_TYPE_UD);<br>
       reg += 2;<br>
    }<br>
+<br>
+   if (key->blit_scaled && key->blend) {<br>
+      this->x_sample_coords = brw_vec8_grf(reg, 0);<br>
+      reg += 2;<br>
+      this->y_sample_coords = brw_vec8_grf(reg, 0);<br>
+      reg += 2;<br>
+      this->x_lerp = brw_vec8_grf(reg, 0);<br>
+      reg += 2;<br>
+      this->y_lerp = brw_vec8_grf(reg, 0);<br>
+      reg += 2;<br>
+   }<br>
+<br>
    this->xy_coord_index = 0;<br>
    this->sample_index<br>
       = retype(brw_vec8_grf(reg, 0), BRW_REGISTER_TYPE_UD);<br>
@@ -1368,11 +1393,82 @@ 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>
-   /* Round the float coordinates down to nearest integer by moving to<br>
-    * UD registers.<br>
-    */<br>
-   brw_MOV(&func, Xp, X_f);<br>
-   brw_MOV(&func, Yp, Y_f);<br>
+   if (key->blit_scaled && key->blend) {<br>
+      float x_scale = 2.0;<br>
+      float y_scale = key->src_samples / 2.0;<br></blockquote><div><br></div><div>It would be nice to have a comment above x_scale and y_scale explaining that they are the scale factor between the pixel grid and the grid of samples that we're texturing from.<br>
<br></div><div>Also, I'd recommend moving them to someplace more global (either the class definition or the program key) so that they can be accessed from manual_blend_linear().<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">

+      /* Translate coordinates to lay out the samples in a rectangular  grid<br>
+       * roughly corresponding to sample locations. <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>
+      brw_ADD(&func, X_f, X_f, brw_imm_f(-0.25));<br>
+      brw_ADD(&func, Y_f, Y_f, brw_imm_f(-1.0 / key->src_samples));<br>
+      brw_MUL(&func, X_f, X_f, brw_imm_f(x_scale));<br>
+      brw_MUL(&func, Y_f, Y_f, brw_imm_f(y_scale));<br></blockquote><div><br></div><div>The additive constants -0.25 and -1.0/key->src_samples are a bit difficult to understand.  I believe this is equivalent, and would be easier to follow:<br>
<br></div><div>/* Translate coordinates to lay out the samples in a rectangular grid<br></div><div> * roughly corresponding to sample locations.<br> */<br></div><div>brw_MUL(&func, X_f, X_f, brw_imm_f(x_scale));<br></div>
<div>brw_MUL(&func, Y_f, Y_f, brw_imm_f(y_scale));<br><br></div><div>/* Adjust coordinates so that integers represent pixel centers rather<br> * than pixel edges.<br> */<br></div><div>brw_ADD(&func, X_f, X_f, brw_imm_f(-0.5));<br>
</div><div>brw_ADD(&func, Y_f, Y_f, brw_imm_f(-0.5));<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>
+      /* Test boundary conditions to properly handle the sampling of texels on<br>
+       * texture edges.<br>
+       */<br>
+      brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_L,<br>
+              X_f, brw_imm_f(2.0  * key->src_x0));<br>
+      brw_IF(&func, BRW_EXECUTE_16);<br>
+      {<br>
+         /* Left Edge in X */<br>
+         brw_MOV(&func, x_lerp, brw_imm_f(1.0));<br>
+      }<br>
+      brw_ELSE(&func);<br>
+      {<br>
+         brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_GE,<br>
+                 X_f, brw_imm_f(2.0 * (key->src_x1 - 0.50)));<br>
+         brw_IF(&func, BRW_EXECUTE_16);<br>
+         {<br>
+            /* Right Edge in X */<br>
+            brw_MOV(&func, x_lerp, brw_imm_f(0.0));<br>
+         }<br>
+         brw_ELSE(&func);<br>
+         {<br>
+            /* Store the fractional part to be used as color interpolator */<br>
+            brw_FRC(&func, x_lerp, X_f);<br>
+         }<br>
+         brw_ENDIF(&func);<br>
+      }<br>
+      brw_ENDIF(&func); <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>
+      brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_L,<br>
+              Y_f, brw_imm_f((y_scale) * key->src_y0));<br>
+      brw_IF(&func, BRW_EXECUTE_16);<br>
+      {<br>
+         /* Bottom Edge in Y */<br>
+         brw_MOV(&func, y_lerp, brw_imm_f(1.0));<br>
+      }<br>
+      brw_ELSE(&func);<br>
+      {<br>
+         brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_GE, Y_f,<br>
+                 brw_imm_f((y_scale) * (key->src_y1 - 1 / y_scale)));<br>
+         brw_IF(&func, BRW_EXECUTE_16);<br>
+         {<br>
+            /* Top Edge in Y */<br>
+            brw_MOV(&func, y_lerp, brw_imm_f(0.0));<br>
+         }<br>
+         brw_ELSE(&func);<br>
+         {<br>
+            /* Store the fractional part to be used as color interpolator */<br>
+            brw_FRC(&func, y_lerp, Y_f);<br>
+         }<br>
+         brw_ENDIF(&func);<br>
+      }<br>
+      brw_ENDIF(&func);<br></blockquote><div><br></div><div>A few thoughts on the above conditional logic:<br><br></div><div>(1) I think the math would be easier to follow if the following expressions were changed to equivalent forms:<br>
<br>"2.0 * key->src_x0" => "x_scale * key->src_x0"<br></div><div>"2.0 * (key->src_x1 - 0.50)" => "x_scale * key->src_x1 - 1.0"<br></div><div>"(y_scale) * (key->src_y1 - 1 / y_scale)" => "y_scale * key->src_y1 - 1.0"<br>
<br></div><div>This will also help in the future when we want to support hardware with 16x MSAA, because in that case we'll want x_scale = y_scale = 4.<br></div><div><br></div><div>(2) Effectively what this code is doing is clamping the x and y coordinates to the boundary of the source rectangle.  But since it's accomplishing the clamping by adjusting x_lerp to 0.0 or 1.0, can only clamp things that aren't too far outside the source rectangle to begin with (i.e. no more than 1.0 outside the boundary).  I *think* that will work, but it seems like an unnecessary risk (and an unnecessary source of confusion).  Why not just clamp X_f to the range [x_scale * key->src_x0, x_scale * key->src_x1 - 1.0] (and similar for Y_f), and then afterward compute x_lerp = FRC(X_f)?  That way there will be no doubt that the coordinate is properly in range.<br>
<br></div><div>(3) You can probably save a lot of instructions if you use conditional moves to do the clamping, e.g.<br><br></div><div>brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_L, X_f, brw_imm_f(x_scale * key->src_x0));<br>
</div><div>brw_MOV(&func, X_f, brw_imm_f(x_scale * key->src_x0));<br></div><div>brw_set_predicate_control(&func, BRW_PREDICATE_NONE);<br></div><div>...etc.<br> <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>
+     /* Round the float coordinates down to nearest integer */<br>
+     brw_RNDD(&func, Xp_f, X_f);<br>
+     brw_RNDD(&func, Yp_f, Y_f);<br>
+     brw_MUL(&func, X_f, Xp_f, brw_imm_f(0.5));<br>
+     brw_MUL(&func, Y_f, Yp_f, brw_imm_f(1 / y_scale));<br>
+   } else {<br>
+      /* Round the float coordinates down to nearest integer by moving to<br>
+       * UD registers.<br>
+       */<br>
+      brw_MOV(&func, Xp, X_f);<br>
+      brw_MOV(&func, Yp, Y_f);<br>
+   }<br>
    SWAP_XY_AND_XPYP();<br>
    brw_set_compression_control(&func, BRW_COMPRESSION_NONE);<br>
 }<br>
@@ -1418,7 +1514,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>
@@ -1523,6 +1619,135 @@ 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>
+   if (key->tex_layout == INTEL_MSAA_LAYOUT_CMS)<br>
+      mcs_fetch();<br></blockquote><div><br></div><div>This won't work.  The MCS value we fetch has to match up with the pixel that we're sampling from.  Since this function samples from different pixels in each iteration of the "for" loop below, the call to mcs_fetch() needs to go inside the loop, and it needs to happen after storing the coordinates in X and Y.<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>
+   /* We do this computation by performing the following operations:<br>
+    *<br>
+    * In case of 4x, 8x MSAA:<br>
+    * - Compute the pixel coordinates and sample numbers (a, b, c, d)<br>
+    *   which are later used for interpolation<br>
+    * - linearly interpolate samples a and b in X<br>
+    * - linearly interpolate samples c and d in X<br>
+    * - linearly interpolate the results of last two operations in Y<br>
+    *<br>
+    *   result = lrp(lrp(a + b) + lrp(c + d))<br>
+    */<br>
+   struct brw_reg Xp_f = retype(Xp, BRW_REGISTER_TYPE_F);<br>
+   struct brw_reg Yp_f = retype(Yp, BRW_REGISTER_TYPE_F);<br>
+   struct brw_reg t1_f = retype(t1, BRW_REGISTER_TYPE_F);<br>
+   struct brw_reg t2_f = retype(t2, BRW_REGISTER_TYPE_F);<br>
+<br>
+   for (unsigned i = 0; i < 4; ++i) {<br>
+      assert(i < ARRAY_SIZE(texture_data));<br>
+      s_is_zero = false;<br>
+<br>
+      /* Compute pixel coordinates */<br>
+      brw_ADD(&func, vec16(x_sample_coords), Xp_f,<br>
+              brw_imm_f((float)(i & 0x1) * 0.5));<br>
+      brw_ADD(&func, vec16(y_sample_coords), Yp_f,<br>
+              brw_imm_f((float)(i & 0x2) * (1.0 / num_samples)));<br>
+      brw_MOV(&func, vec16(X), x_sample_coords);<br>
+      brw_MOV(&func, vec16(Y), y_sample_coords);<br>
+<br>
+      /* Compute sample index. In case of 4x MSAA, sample index is<br>
+       * equal to sample number.<br>
+       */<br></blockquote><div><br></div><div>This comment should explain what you mean by "sample index" vs "sample number".<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">

+      brw_FRC(&func, vec16(t1_f), x_sample_coords);<br>
+      brw_FRC(&func, vec16(t2_f), y_sample_coords);<br>
+      brw_MUL(&func, vec16(t1_f), t1_f, brw_imm_f(2.0));<br>
+      brw_MUL(&func, vec16(t2_f), t2_f, brw_imm_f(num_samples));<br></blockquote><div><br></div><div>How about this instead?  It's a little more future proof and it clarifies that what we're doing is computing our position within the grid of samples corresponding to a single pixel:<br>
<br></div><div>brw_MUL(&func, vec16(t1_f), t1_f, brw_imm_f(x_scale));<br>brw_MUL(&func, vec16(t2_f), t2_f, brw_imm_f(x_scale * y_scale));<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">

+      brw_ADD(&func, vec16(t1_f), t1_f, t2_f);<br>
+      brw_MOV(&func, vec16(S), t1_f);<br>
+<br>
+      if (num_samples == 8) {<br>
+         /* Map the sample index to a sample number */<br>
+         brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_L,<br>
+                 S, brw_imm_d(4));<br>
+         brw_IF(&func, BRW_EXECUTE_16);<br>
+         {<br>
+            brw_MOV(&func, vec16(t2), brw_imm_d(5));<br>
+            brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_EQ,<br>
+                    S, brw_imm_d(1));<br>
+            brw_MOV(&func, vec16(t2), brw_imm_d(2));<br>
+            brw_set_predicate_control(&func, BRW_PREDICATE_NONE);<br>
+            brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_EQ,<br>
+                    S, brw_imm_d(2));<br>
+            brw_MOV(&func, vec16(t2), brw_imm_d(4));<br>
+            brw_set_predicate_control(&func, BRW_PREDICATE_NONE);<br>
+            brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_EQ,<br>
+                    S, brw_imm_d(3));<br>
+            brw_MOV(&func, vec16(t2), brw_imm_d(6));<br>
+            brw_set_predicate_control(&func, BRW_PREDICATE_NONE);<br>
+         }<br>
+         brw_ELSE(&func);<br>
+         {<br>
+            brw_MOV(&func, vec16(t2), brw_imm_d(0));<br>
+            brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_EQ,<br>
+                    S, brw_imm_d(5));<br>
+            brw_MOV(&func, vec16(t2), brw_imm_d(3));<br>
+            brw_set_predicate_control(&func, BRW_PREDICATE_NONE);<br>
+            brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_EQ,<br>
+                    S, brw_imm_d(6));<br>
+            brw_MOV(&func, vec16(t2), brw_imm_d(7));<br>
+            brw_set_predicate_control(&func, BRW_PREDICATE_NONE);<br>
+            brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_EQ,<br>
+                    S, brw_imm_d(7));<br>
+            brw_MOV(&func, vec16(t2), brw_imm_d(1));<br>
+            brw_set_predicate_control(&func, BRW_PREDICATE_NONE);<br>
+         }<br>
+         brw_ENDIF(&func);<br>
+         brw_MOV(&func, vec16(S), t2);<br></blockquote><div><br></div><div>This seems like a lot of work to accomplish what is effectively a lookup table.  If this winds up becoming a performance bottleneck, you might want to consider passing the table in via a push constant, and using indirect addressing to convert sample index to sample number. <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>
+      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></blockquote><div><br></div><div>We can't do this optimization for scaled multisample blits, because it relies on the assumption that all the samples we're blending together belong to the same pixel.  I'd recommend just pulling this code out.<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>
+#define SAMPLE(x, y) offset(texture_data[x], y)<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_lerp, 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_lerp, k & 1),<br>
+              vec8(SAMPLE(2, k)),<br>
+              vec8(SAMPLE(0, k)));<br>
+   brw_set_access_mode(&func, BRW_ALIGN_1);<br></blockquote><div><br></div><div>I'm confused why we need loops from 0 to 7 here.  It looks like you're trying to interpolate each component of the SIMD8 register separately.  That shouldn't be necessary.<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">
+#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>
@@ -1535,7 +1760,8 @@ brw_blorp_blit_program::sample(struct brw_reg dst)<br>
       SAMPLER_MESSAGE_ARG_V_FLOAT<br>
    };<br>
<br>
-   texture_lookup(dst, GEN5_SAMPLER_MESSAGE_SAMPLE, args, ARRAY_SIZE(args));<br>
+   texture_lookup(dst, GEN5_SAMPLER_MESSAGE_SAMPLE, args,<br>
+                  ARRAY_SIZE(args));<br>
 }<br>
<br>
 /**<br>
@@ -1872,6 +2098,17 @@ 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>
+   /* Source rectangle dimensions */<br>
+   wm_prog_key.src_x0 = src_x0;<br>
+   wm_prog_key.src_y0 = src_y0;<br>
+   wm_prog_key.src_x1 = src_x1;<br>
+   wm_prog_key.src_y1 = src_y1;<br>
+<br>
    /* The render path must be configured to use the same number of samples as<br>
     * the destination buffer.<br>
     */<br>
<span><font color="#888888">--<br>
1.8.1.4<br>
<br>
</font></span></blockquote></div><br></div></div>