i965/gs: Add a case to brwNewProgram() for geometry shaders.
[mesa.git] / src / mesa / drivers / dri / i965 / brw_blorp_blit.cpp
index 61403454d497ca4f62800ab2e87029126c451807..f07d39f9bb9866071ad1377fd9aa11e9e98a9600 100644 (file)
@@ -124,7 +124,7 @@ find_miptree(GLbitfield buffer_bit, struct intel_renderbuffer *irb)
 }
 
 void
-brw_blorp_blit_miptrees(struct intel_context *intel,
+brw_blorp_blit_miptrees(struct brw_context *brw,
                         struct intel_mipmap_tree *src_mt,
                         unsigned src_level, unsigned src_layer,
                         struct intel_mipmap_tree *dst_mt,
@@ -133,7 +133,7 @@ brw_blorp_blit_miptrees(struct intel_context *intel,
                         float src_x1, float src_y1,
                         float dst_x0, float dst_y0,
                         float dst_x1, float dst_y1,
-                        bool mirror_x, bool mirror_y)
+                        GLenum filter, bool mirror_x, bool mirror_y)
 {
    /* Get ready to blit.  This includes depth resolving the src and dst
     * buffers if necessary.  Note: it's not necessary to do a color resolve on
@@ -141,9 +141,9 @@ brw_blorp_blit_miptrees(struct intel_context *intel,
     * to destination color buffers, and the standard render path is
     * fast-color-aware.
     */
-   intel_miptree_resolve_color(intel, src_mt);
-   intel_miptree_slice_resolve_depth(intel, src_mt, src_level, src_layer);
-   intel_miptree_slice_resolve_depth(intel, dst_mt, dst_level, dst_layer);
+   intel_miptree_resolve_color(brw, src_mt);
+   intel_miptree_slice_resolve_depth(brw, src_mt, src_level, src_layer);
+   intel_miptree_slice_resolve_depth(brw, dst_mt, dst_level, dst_layer);
 
    DBG("%s from %s mt %p %d %d (%f,%f) (%f,%f)"
        "to %s mt %p %d %d (%f,%f) (%f,%f) (flip %d,%d)\n",
@@ -154,38 +154,38 @@ brw_blorp_blit_miptrees(struct intel_context *intel,
        dst_level, dst_layer, dst_x0, dst_y0, dst_x1, dst_y1,
        mirror_x, mirror_y);
 
-   brw_blorp_blit_params params(brw_context(&intel->ctx),
+   brw_blorp_blit_params params(brw,
                                 src_mt, src_level, src_layer,
                                 dst_mt, dst_level, dst_layer,
                                 src_x0, src_y0,
                                 src_x1, src_y1,
                                 dst_x0, dst_y0,
                                 dst_x1, dst_y1,
-                                mirror_x, mirror_y);
-   brw_blorp_exec(intel, &params);
+                                filter, mirror_x, mirror_y);
+   brw_blorp_exec(brw, &params);
 
    intel_miptree_slice_set_needs_hiz_resolve(dst_mt, dst_level, dst_layer);
 }
 
 static void
-do_blorp_blit(struct intel_context *intel, GLbitfield buffer_bit,
+do_blorp_blit(struct brw_context *brw, GLbitfield buffer_bit,
               struct intel_renderbuffer *src_irb,
               struct intel_renderbuffer *dst_irb,
               GLfloat srcX0, GLfloat srcY0, GLfloat srcX1, GLfloat srcY1,
               GLfloat dstX0, GLfloat dstY0, GLfloat dstX1, GLfloat dstY1,
-              bool mirror_x, bool mirror_y)
+              GLenum filter, bool mirror_x, bool mirror_y)
 {
    /* Find source/dst miptrees */
    struct intel_mipmap_tree *src_mt = find_miptree(buffer_bit, src_irb);
    struct intel_mipmap_tree *dst_mt = find_miptree(buffer_bit, dst_irb);
 
    /* Do the blit */
-   brw_blorp_blit_miptrees(intel,
+   brw_blorp_blit_miptrees(brw,
                            src_mt, src_irb->mt_level, src_irb->mt_layer,
                            dst_mt, dst_irb->mt_level, dst_irb->mt_layer,
                            srcX0, srcY0, srcX1, srcY1,
                            dstX0, dstY0, dstX1, dstY1,
-                           mirror_x, mirror_y);
+                           filter, mirror_x, mirror_y);
 
    intel_renderbuffer_set_needs_downsample(dst_irb);
 }
@@ -223,17 +223,17 @@ formats_match(GLbitfield buffer_bit, struct intel_renderbuffer *src_irb,
 }
 
 static bool
-try_blorp_blit(struct intel_context *intel,
+try_blorp_blit(struct brw_context *brw,
                GLfloat srcX0, GLfloat srcY0, GLfloat srcX1, GLfloat srcY1,
                GLfloat dstX0, GLfloat dstY0, GLfloat dstX1, GLfloat dstY1,
                GLenum filter, GLbitfield buffer_bit)
 {
-   struct gl_context *ctx = &intel->ctx;
+   struct gl_context *ctx = &brw->ctx;
 
    /* Sync up the state of window system buffers.  We need to do this before
     * we go looking for the buffers.
     */
-   intel_prepare_render(intel);
+   intel_prepare_render(brw);
 
    const struct gl_framebuffer *read_fb = ctx->ReadBuffer;
    const struct gl_framebuffer *draw_fb = ctx->DrawBuffer;
@@ -245,14 +245,6 @@ try_blorp_blit(struct intel_context *intel,
    fixup_mirroring(mirror_y, srcY0, srcY1);
    fixup_mirroring(mirror_y, dstY0, dstY1);
 
-   /* Linear filtering is not yet implemented in blorp engine. So, fallback
-    * to other blit paths.
-    */
-   if ((srcX1 - srcX0 != dstX1 - dstX0 ||
-        srcY1 - srcY0 != dstY1 - dstY0) &&
-       filter == GL_LINEAR)
-      return false;
-
    /* If the destination rectangle needs to be clipped or scissored, do so.
     */
    if (!(clip_or_scissor(mirror_x, srcX0, srcX1, dstX0, dstX1,
@@ -302,9 +294,9 @@ try_blorp_blit(struct intel_context *intel,
       for (unsigned i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; ++i) {
          dst_irb = intel_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[i]);
         if (dst_irb)
-            do_blorp_blit(intel, buffer_bit, src_irb, dst_irb, srcX0, srcY0,
+            do_blorp_blit(brw, buffer_bit, src_irb, dst_irb, srcX0, srcY0,
                           srcX1, srcY1, dstX0, dstY0, dstX1, dstY1,
-                          mirror_x, mirror_y);
+                          filter, mirror_x, mirror_y);
       }
       break;
    case GL_DEPTH_BUFFER_BIT:
@@ -314,9 +306,9 @@ try_blorp_blit(struct intel_context *intel,
          intel_renderbuffer(draw_fb->Attachment[BUFFER_DEPTH].Renderbuffer);
       if (!formats_match(buffer_bit, src_irb, dst_irb))
          return false;
-      do_blorp_blit(intel, buffer_bit, src_irb, dst_irb, srcX0, srcY0,
+      do_blorp_blit(brw, buffer_bit, src_irb, dst_irb, srcX0, srcY0,
                     srcX1, srcY1, dstX0, dstY0, dstX1, dstY1,
-                    mirror_x, mirror_y);
+                    filter, mirror_x, mirror_y);
       break;
    case GL_STENCIL_BUFFER_BIT:
       src_irb =
@@ -325,9 +317,9 @@ try_blorp_blit(struct intel_context *intel,
          intel_renderbuffer(draw_fb->Attachment[BUFFER_STENCIL].Renderbuffer);
       if (!formats_match(buffer_bit, src_irb, dst_irb))
          return false;
-      do_blorp_blit(intel, buffer_bit, src_irb, dst_irb, srcX0, srcY0,
+      do_blorp_blit(brw, buffer_bit, src_irb, dst_irb, srcX0, srcY0,
                     srcX1, srcY1, dstX0, dstY0, dstX1, dstY1,
-                    mirror_x, mirror_y);
+                    filter, mirror_x, mirror_y);
       break;
    default:
       assert(false);
@@ -337,7 +329,7 @@ try_blorp_blit(struct intel_context *intel,
 }
 
 bool
-brw_blorp_copytexsubimage(struct intel_context *intel,
+brw_blorp_copytexsubimage(struct brw_context *brw,
                           struct gl_renderbuffer *src_rb,
                           struct gl_texture_image *dst_image,
                           int slice,
@@ -345,20 +337,20 @@ brw_blorp_copytexsubimage(struct intel_context *intel,
                           int dstX0, int dstY0,
                           int width, int height)
 {
-   struct gl_context *ctx = &intel->ctx;
+   struct gl_context *ctx = &brw->ctx;
    struct intel_renderbuffer *src_irb = intel_renderbuffer(src_rb);
    struct intel_texture_image *intel_image = intel_texture_image(dst_image);
 
    /* Sync up the state of window system buffers.  We need to do this before
     * we go looking at the src renderbuffer's miptree.
     */
-   intel_prepare_render(intel);
+   intel_prepare_render(brw);
 
    struct intel_mipmap_tree *src_mt = src_irb->mt;
    struct intel_mipmap_tree *dst_mt = intel_image->mt;
 
    /* BLORP is not supported before Gen6. */
-   if (intel->gen < 6)
+   if (brw->gen < 6)
       return false;
 
    if (!color_formats_match(src_mt->format, dst_mt->format)) {
@@ -391,12 +383,12 @@ brw_blorp_copytexsubimage(struct intel_context *intel,
       mirror_y = true;
    }
 
-   brw_blorp_blit_miptrees(intel,
+   brw_blorp_blit_miptrees(brw,
                            src_mt, src_irb->mt_level, src_irb->mt_layer,
                            dst_mt, dst_image->Level, dst_image->Face + slice,
                            srcX0, srcY0, srcX1, srcY1,
                            dstX0, dstY0, dstX1, dstY1,
-                           false, mirror_y);
+                           GL_NEAREST, false, mirror_y);
 
    /* If we're copying to a packed depth stencil texture and the source
     * framebuffer has separate stencil, we need to also copy the stencil data
@@ -414,13 +406,13 @@ brw_blorp_copytexsubimage(struct intel_context *intel,
          dst_mt = dst_mt->stencil_mt;
 
       if (src_mt != dst_mt) {
-         brw_blorp_blit_miptrees(intel,
+         brw_blorp_blit_miptrees(brw,
                                  src_mt, src_irb->mt_level, src_irb->mt_layer,
                                  dst_mt, dst_image->Level,
                                  dst_image->Face + slice,
                                  srcX0, srcY0, srcX1, srcY1,
                                  dstX0, dstY0, dstX1, dstY1,
-                                 false, mirror_y);
+                                 GL_NEAREST, false, mirror_y);
       }
    }
 
@@ -429,13 +421,13 @@ brw_blorp_copytexsubimage(struct intel_context *intel,
 
 
 GLbitfield
-brw_blorp_framebuffer(struct intel_context *intel,
+brw_blorp_framebuffer(struct brw_context *brw,
                       GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
                       GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
                       GLbitfield mask, GLenum filter)
 {
    /* BLORP is not supported before Gen6. */
-   if (intel->gen < 6)
+   if (brw->gen < 6)
       return mask;
 
    static GLbitfield buffer_bits[] = {
@@ -446,7 +438,7 @@ brw_blorp_framebuffer(struct intel_context *intel,
 
    for (unsigned int i = 0; i < ARRAY_SIZE(buffer_bits); ++i) {
       if ((mask & buffer_bits[i]) &&
-       try_blorp_blit(intel,
+       try_blorp_blit(brw,
                       srcX0, srcY0, srcX1, srcY1,
                       dstX0, dstY0, dstX1, dstY1,
                       filter, buffer_bits[i])) {
@@ -631,8 +623,12 @@ private:
    void decode_msaa(unsigned num_samples, intel_msaa_layout layout);
    void kill_if_outside_dst_rect();
    void translate_dst_to_src();
+   void clamp_tex_coords(struct brw_reg regX, struct brw_reg regY,
+                         struct brw_reg clampX0, struct brw_reg clampY0,
+                         struct brw_reg clampX1, struct brw_reg clampY1);
    void single_to_blend();
-   void manual_blend(unsigned num_samples);
+   void manual_blend_average(unsigned num_samples);
+   void manual_blend_bilinear(unsigned num_samples);
    void sample(struct brw_reg dst);
    void texel_fetch(struct brw_reg dst);
    void mcs_fetch();
@@ -661,6 +657,9 @@ private:
    struct brw_reg dst_x1;
    struct brw_reg dst_y0;
    struct brw_reg dst_y1;
+   /* Top right coordinates of the rectangular grid used for scaled blitting */
+   struct brw_reg rect_grid_x1;
+   struct brw_reg rect_grid_y1;
    struct {
       struct brw_reg multiplier;
       struct brw_reg offset;
@@ -686,6 +685,16 @@ private:
     */
    struct brw_reg y_coords[2];
 
+   /* X, Y coordinates of the pixel from which we need to fetch the specific
+    *  sample. These are used for multisample scaled blitting.
+    */
+   struct brw_reg x_sample_coords;
+   struct brw_reg y_sample_coords;
+
+   /* Fractional parts of the x and y coordinates, used as bilinear interpolation coefficients */
+   struct brw_reg x_frac;
+   struct brw_reg y_frac;
+
    /* Which element of x_coords and y_coords is currently in use.
     */
    int xy_coord_index;
@@ -824,15 +833,17 @@ brw_blorp_blit_program::compile(struct brw_context *brw,
     * that we want to texture from.  Exception: if we are blending, then S is
     * irrelevant, because we are going to fetch all samples.
     */
-   if (key->blend) {
-      if (brw->intel.gen == 6) {
+   if (key->blend && !key->blit_scaled) {
+      if (brw->gen == 6) {
          /* Gen6 hardware an automatically blend using the SAMPLE message */
          single_to_blend();
          sample(texture_data[0]);
       } else {
          /* Gen7+ hardware doesn't automaticaly blend. */
-         manual_blend(key->src_samples);
+         manual_blend_average(key->src_samples);
       }
+   } else if(key->blend && key->blit_scaled) {
+      manual_blend_bilinear(key->src_samples);
    } else {
       /* We aren't blending, which means we just want to fetch a single sample
        * from the source surface.  The address that we want to fetch from is
@@ -844,9 +855,10 @@ brw_blorp_blit_program::compile(struct brw_context *brw,
        * the same as the configuration of the texture, then we need to adjust
        * the coordinates to compensate for the difference.
        */
-      if (tex_tiled_w != key->src_tiled_w ||
-          key->tex_samples != key->src_samples ||
-          key->tex_layout != key->src_layout) {
+      if ((tex_tiled_w != key->src_tiled_w ||
+           key->tex_samples != key->src_samples ||
+           key->tex_layout != key->src_layout) &&
+          !key->bilinear_filter) {
          encode_msaa(key->src_samples, key->src_layout);
          /* Now (X, Y, S) = detile(src_tiling, offset) */
          translate_tiling(key->src_tiled_w, tex_tiled_w);
@@ -854,15 +866,20 @@ brw_blorp_blit_program::compile(struct brw_context *brw,
          decode_msaa(key->tex_samples, key->tex_layout);
       }
 
-      /* Now (X, Y, S) = decode_msaa(tex_samples, detile(tex_tiling, offset)).
-       *
-       * In other words: X, Y, and S now contain values which, when passed to
-       * the texturing unit, will cause data to be read from the correct
-       * memory location.  So we can fetch the texel now.
-       */
-      if (key->tex_layout == INTEL_MSAA_LAYOUT_CMS)
-         mcs_fetch();
-      texel_fetch(texture_data[0]);
+      if (key->bilinear_filter) {
+         sample(texture_data[0]);
+      }
+      else {
+         /* Now (X, Y, S) = decode_msaa(tex_samples, detile(tex_tiling, offset)).
+          *
+          * In other words: X, Y, and S now contain values which, when passed to
+          * the texturing unit, will cause data to be read from the correct
+          * memory location.  So we can fetch the texel now.
+          */
+         if (key->tex_layout == INTEL_MSAA_LAYOUT_CMS)
+            mcs_fetch();
+         texel_fetch(texture_data[0]);
+      }
    }
 
    /* Finally, write the fetched (or blended) value to the render target and
@@ -884,12 +901,16 @@ brw_blorp_blit_program::alloc_push_const_regs(int base_reg)
 #define CONST_LOC(name) offsetof(brw_blorp_wm_push_constants, name)
 #define ALLOC_REG(name) \
    this->name = \
-      brw_vec1_reg(BRW_GENERAL_REGISTER_FILE, base_reg, CONST_LOC(name) / 4)
+      brw_vec1_reg(BRW_GENERAL_REGISTER_FILE, \
+                   base_reg + CONST_LOC(name) / 32, \
+                   (CONST_LOC(name) % 32) / 4)
 
    ALLOC_REG(dst_x0);
    ALLOC_REG(dst_x1);
    ALLOC_REG(dst_y0);
    ALLOC_REG(dst_y1);
+   ALLOC_REG(rect_grid_x1);
+   ALLOC_REG(rect_grid_y1);
    ALLOC_REG(x_transform.multiplier);
    ALLOC_REG(x_transform.offset);
    ALLOC_REG(y_transform.multiplier);
@@ -923,6 +944,18 @@ brw_blorp_blit_program::alloc_regs()
          = retype(brw_vec8_grf(reg, 0), BRW_REGISTER_TYPE_UD);
       reg += 2;
    }
+
+   if (key->blit_scaled && key->blend) {
+      this->x_sample_coords = brw_vec8_grf(reg, 0);
+      reg += 2;
+      this->y_sample_coords = brw_vec8_grf(reg, 0);
+      reg += 2;
+      this->x_frac = brw_vec8_grf(reg, 0);
+      reg += 2;
+      this->y_frac = brw_vec8_grf(reg, 0);
+      reg += 2;
+   }
+
    this->xy_coord_index = 0;
    this->sample_index
       = retype(brw_vec8_grf(reg, 0), BRW_REGISTER_TYPE_UD);
@@ -1357,6 +1390,10 @@ brw_blorp_blit_program::kill_if_outside_dst_rect()
    brw_pop_insn_state(&func);
 }
 
+#define X_f retype(X, BRW_REGISTER_TYPE_F)
+#define Y_f retype(Y, BRW_REGISTER_TYPE_F)
+#define Xp_f retype(Xp, BRW_REGISTER_TYPE_F)
+#define Yp_f retype(Yp, BRW_REGISTER_TYPE_F)
 /**
  * Emit code to translate from destination (X, Y) coordinates to source (X, Y)
  * coordinates.
@@ -1364,11 +1401,6 @@ brw_blorp_blit_program::kill_if_outside_dst_rect()
 void
 brw_blorp_blit_program::translate_dst_to_src()
 {
-   struct brw_reg X_f = retype(X, BRW_REGISTER_TYPE_F);
-   struct brw_reg Y_f = retype(Y, BRW_REGISTER_TYPE_F);
-   struct brw_reg Xp_f = retype(Xp, BRW_REGISTER_TYPE_F);
-   struct brw_reg Yp_f = retype(Yp, BRW_REGISTER_TYPE_F);
-
    brw_set_compression_control(&func, BRW_COMPRESSION_COMPRESSED);
    /* Move the UD coordinates to float registers. */
    brw_MOV(&func, Xp_f, X);
@@ -1378,15 +1410,77 @@ brw_blorp_blit_program::translate_dst_to_src()
    brw_MUL(&func, Y_f, Yp_f, y_transform.multiplier);
    brw_ADD(&func, X_f, X_f, x_transform.offset);
    brw_ADD(&func, Y_f, Y_f, y_transform.offset);
-   /* Round the float coordinates down to nearest integer by moving to
-    * UD registers.
-    */
-   brw_MOV(&func, Xp, X_f);
-   brw_MOV(&func, Yp, Y_f);
-   SWAP_XY_AND_XPYP();
+   if (key->blit_scaled && key->blend) {
+      /* Translate coordinates to lay out the samples in a rectangular  grid
+       * roughly corresponding to sample locations.
+       */
+      brw_MUL(&func, X_f, X_f, brw_imm_f(key->x_scale));
+      brw_MUL(&func, Y_f, Y_f, brw_imm_f(key->y_scale));
+     /* Adjust coordinates so that integers represent pixel centers rather
+      * than pixel edges.
+      */
+      brw_ADD(&func, X_f, X_f, brw_imm_f(-0.5));
+      brw_ADD(&func, Y_f, Y_f, brw_imm_f(-0.5));
+
+      /* Clamp the X, Y texture coordinates to properly handle the sampling of
+       *  texels on texture edges.
+       */
+      clamp_tex_coords(X_f, Y_f,
+                       brw_imm_f(0.0), brw_imm_f(0.0),
+                       rect_grid_x1, rect_grid_y1);
+
+      /* Store the fractional parts to be used as bilinear interpolation
+       *  coefficients.
+      */
+      brw_FRC(&func, x_frac, X_f);
+      brw_FRC(&func, y_frac, Y_f);
+
+      /* Round the float coordinates down to nearest integer */
+      brw_RNDD(&func, Xp_f, X_f);
+      brw_RNDD(&func, Yp_f, Y_f);
+      brw_MUL(&func, X_f, Xp_f, brw_imm_f(1 / key->x_scale));
+      brw_MUL(&func, Y_f, Yp_f, brw_imm_f(1 / key->y_scale));
+      SWAP_XY_AND_XPYP();
+   } else if (!key->bilinear_filter) {
+      /* Round the float coordinates down to nearest integer by moving to
+       * UD registers.
+       */
+      brw_MOV(&func, Xp, X_f);
+      brw_MOV(&func, Yp, Y_f);
+      SWAP_XY_AND_XPYP();
+   }
    brw_set_compression_control(&func, BRW_COMPRESSION_NONE);
 }
 
+void
+brw_blorp_blit_program::clamp_tex_coords(struct brw_reg regX,
+                                         struct brw_reg regY,
+                                         struct brw_reg clampX0,
+                                         struct brw_reg clampY0,
+                                         struct brw_reg clampX1,
+                                         struct brw_reg clampY1)
+{
+   brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_L, regX, clampX0);
+   brw_MOV(&func, regX, clampX0);
+   brw_set_predicate_control(&func, BRW_PREDICATE_NONE);
+
+   brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_G, regX, clampX1);
+   brw_MOV(&func, regX, clampX1);
+   brw_set_predicate_control(&func, BRW_PREDICATE_NONE);
+
+   brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_L, regY, clampY0);
+   brw_MOV(&func, regY, clampY0);
+   brw_set_predicate_control(&func, BRW_PREDICATE_NONE);
+
+   brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_G, regY, clampY1);
+   brw_MOV(&func, regY, clampY1);
+   brw_set_predicate_control(&func, BRW_PREDICATE_NONE);
+}
+#undef X_f
+#undef Y_f
+#undef Xp_f
+#undef Yp_f
+
 /**
  * Emit code to transform the X and Y coordinates as needed for blending
  * together the different samples in an MSAA texture.
@@ -1428,7 +1522,7 @@ inline int count_trailing_one_bits(unsigned value)
 
 
 void
-brw_blorp_blit_program::manual_blend(unsigned num_samples)
+brw_blorp_blit_program::manual_blend_average(unsigned num_samples)
 {
    if (key->tex_layout == INTEL_MSAA_LAYOUT_CMS)
       mcs_fetch();
@@ -1533,6 +1627,143 @@ brw_blorp_blit_program::manual_blend(unsigned num_samples)
       brw_ENDIF(&func);
 }
 
+void
+brw_blorp_blit_program::manual_blend_bilinear(unsigned num_samples)
+{
+   /* We do this computation by performing the following operations:
+    *
+    * In case of 4x, 8x MSAA:
+    * - Compute the pixel coordinates and sample numbers (a, b, c, d)
+    *   which are later used for interpolation
+    * - linearly interpolate samples a and b in X
+    * - linearly interpolate samples c and d in X
+    * - linearly interpolate the results of last two operations in Y
+    *
+    *   result = lrp(lrp(a + b) + lrp(c + d))
+    */
+   struct brw_reg Xp_f = retype(Xp, BRW_REGISTER_TYPE_F);
+   struct brw_reg Yp_f = retype(Yp, BRW_REGISTER_TYPE_F);
+   struct brw_reg t1_f = retype(t1, BRW_REGISTER_TYPE_F);
+   struct brw_reg t2_f = retype(t2, BRW_REGISTER_TYPE_F);
+
+   for (unsigned i = 0; i < 4; ++i) {
+      assert(i < ARRAY_SIZE(texture_data));
+      s_is_zero = false;
+
+      /* Compute pixel coordinates */
+      brw_ADD(&func, vec16(x_sample_coords), Xp_f,
+              brw_imm_f((float)(i & 0x1) * (1.0 / key->x_scale)));
+      brw_ADD(&func, vec16(y_sample_coords), Yp_f,
+              brw_imm_f((float)((i >> 1) & 0x1) * (1.0 / key->y_scale)));
+      brw_MOV(&func, vec16(X), x_sample_coords);
+      brw_MOV(&func, vec16(Y), y_sample_coords);
+
+      /* The MCS value we fetch has to match up with the pixel that we're
+       * sampling from. Since we sample from different pixels in each
+       * iteration of this "for" loop, the call to mcs_fetch() should be
+       * here inside the loop after computing the pixel coordinates.
+       */
+      if (key->tex_layout == INTEL_MSAA_LAYOUT_CMS)
+         mcs_fetch();
+
+     /* Compute sample index and map the sample index to a sample number.
+      * Sample index layout shows the numbering of slots in a rectangular
+      * grid of samples with in a pixel. Sample number layout shows the
+      * rectangular grid of samples roughly corresponding to the real sample
+      * locations with in a pixel.
+      * In case of 4x MSAA, layout of sample indices matches the layout of
+      * sample numbers:
+      *           ---------
+      *           | 0 | 1 |
+      *           ---------
+      *           | 2 | 3 |
+      *           ---------
+      *
+      * In case of 8x MSAA the two layouts don't match.
+      * sample index layout :  ---------    sample number layout :  ---------
+      *                        | 0 | 1 |                            | 5 | 2 |
+      *                        ---------                            ---------
+      *                        | 2 | 3 |                            | 4 | 6 |
+      *                        ---------                            ---------
+      *                        | 4 | 5 |                            | 0 | 3 |
+      *                        ---------                            ---------
+      *                        | 6 | 7 |                            | 7 | 1 |
+      *                        ---------                            ---------
+      */
+      brw_FRC(&func, vec16(t1_f), x_sample_coords);
+      brw_FRC(&func, vec16(t2_f), y_sample_coords);
+      brw_MUL(&func, vec16(t1_f), t1_f, brw_imm_f(key->x_scale));
+      brw_MUL(&func, vec16(t2_f), t2_f, brw_imm_f(key->x_scale * key->y_scale));
+      brw_ADD(&func, vec16(t1_f), t1_f, t2_f);
+      brw_MOV(&func, vec16(S), t1_f);
+
+      if (num_samples == 8) {
+         /* Map the sample index to a sample number */
+         brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_L,
+                 S, brw_imm_d(4));
+         brw_IF(&func, BRW_EXECUTE_16);
+         {
+            brw_MOV(&func, vec16(t2), brw_imm_d(5));
+            brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_EQ,
+                    S, brw_imm_d(1));
+            brw_MOV(&func, vec16(t2), brw_imm_d(2));
+            brw_set_predicate_control(&func, BRW_PREDICATE_NONE);
+            brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_EQ,
+                    S, brw_imm_d(2));
+            brw_MOV(&func, vec16(t2), brw_imm_d(4));
+            brw_set_predicate_control(&func, BRW_PREDICATE_NONE);
+            brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_EQ,
+                    S, brw_imm_d(3));
+            brw_MOV(&func, vec16(t2), brw_imm_d(6));
+            brw_set_predicate_control(&func, BRW_PREDICATE_NONE);
+         }
+         brw_ELSE(&func);
+         {
+            brw_MOV(&func, vec16(t2), brw_imm_d(0));
+            brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_EQ,
+                    S, brw_imm_d(5));
+            brw_MOV(&func, vec16(t2), brw_imm_d(3));
+            brw_set_predicate_control(&func, BRW_PREDICATE_NONE);
+            brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_EQ,
+                    S, brw_imm_d(6));
+            brw_MOV(&func, vec16(t2), brw_imm_d(7));
+            brw_set_predicate_control(&func, BRW_PREDICATE_NONE);
+            brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_EQ,
+                    S, brw_imm_d(7));
+            brw_MOV(&func, vec16(t2), brw_imm_d(1));
+            brw_set_predicate_control(&func, BRW_PREDICATE_NONE);
+         }
+         brw_ENDIF(&func);
+         brw_MOV(&func, vec16(S), t2);
+      }
+      texel_fetch(texture_data[i]);
+   }
+
+#define SAMPLE(x, y) offset(texture_data[x], y)
+   brw_set_access_mode(&func, BRW_ALIGN_16);
+   for (int index = 3; index > 0; ) {
+      /* Since we're doing SIMD16, 4 color channels fits in to 8 registers.
+       * Counter value of 8 in 'for' loop below is used to interpolate all
+       * the color components.
+       */
+      for (int k = 0; k < 8; ++k)
+         brw_LRP(&func,
+                 vec8(SAMPLE(index - 1, k)),
+                 offset(x_frac, k & 1),
+                 SAMPLE(index, k),
+                 SAMPLE(index - 1, k));
+      index -= 2;
+   }
+   for (int k = 0; k < 8; ++k)
+      brw_LRP(&func,
+              vec8(SAMPLE(0, k)),
+              offset(y_frac, k & 1),
+              vec8(SAMPLE(2, k)),
+              vec8(SAMPLE(0, k)));
+   brw_set_access_mode(&func, BRW_ALIGN_1);
+#undef SAMPLE
+}
+
 /**
  * Emit code to look up a value in the texture using the SAMPLE message (which
  * does blending of MSAA surfaces).
@@ -1545,7 +1776,8 @@ brw_blorp_blit_program::sample(struct brw_reg dst)
       SAMPLER_MESSAGE_ARG_V_FLOAT
    };
 
-   texture_lookup(dst, GEN5_SAMPLER_MESSAGE_SAMPLE, args, ARRAY_SIZE(args));
+   texture_lookup(dst, GEN5_SAMPLER_MESSAGE_SAMPLE, args,
+                  ARRAY_SIZE(args));
 }
 
 /**
@@ -1579,7 +1811,7 @@ brw_blorp_blit_program::texel_fetch(struct brw_reg dst)
       SAMPLER_MESSAGE_ARG_V_INT
    };
 
-   switch (brw->intel.gen) {
+   switch (brw->gen) {
    case 6:
       texture_lookup(dst, GEN5_SAMPLER_MESSAGE_SAMPLE_LD, gen6_args,
                      s_is_zero ? 2 : 5);
@@ -1640,10 +1872,18 @@ brw_blorp_blit_program::texture_lookup(struct brw_reg dst,
    for (int arg = 0; arg < num_args; ++arg) {
       switch (args[arg]) {
       case SAMPLER_MESSAGE_ARG_U_FLOAT:
-         brw_MOV(&func, retype(mrf, BRW_REGISTER_TYPE_F), X);
+         if (key->bilinear_filter)
+            brw_MOV(&func, retype(mrf, BRW_REGISTER_TYPE_F),
+                    retype(X, BRW_REGISTER_TYPE_F));
+         else
+            brw_MOV(&func, retype(mrf, BRW_REGISTER_TYPE_F), X);
          break;
       case SAMPLER_MESSAGE_ARG_V_FLOAT:
-         brw_MOV(&func, retype(mrf, BRW_REGISTER_TYPE_F), Y);
+         if (key->bilinear_filter)
+            brw_MOV(&func, retype(mrf, BRW_REGISTER_TYPE_F),
+                    retype(Y, BRW_REGISTER_TYPE_F));
+         else
+            brw_MOV(&func, retype(mrf, BRW_REGISTER_TYPE_F), Y);
          break;
       case SAMPLER_MESSAGE_ARG_U_INT:
          brw_MOV(&func, mrf, X);
@@ -1800,7 +2040,7 @@ compute_msaa_layout_for_pipeline(struct brw_context *brw, unsigned num_samples,
    }
 
    /* Prior to Gen7, all MSAA surfaces use IMS layout. */
-   if (brw->intel.gen == 6) {
+   if (brw->gen == 6) {
       assert(true_layout == INTEL_MSAA_LAYOUT_IMS);
    }
 
@@ -1817,12 +2057,33 @@ brw_blorp_blit_params::brw_blorp_blit_params(struct brw_context *brw,
                                              GLfloat src_x1, GLfloat src_y1,
                                              GLfloat dst_x0, GLfloat dst_y0,
                                              GLfloat dst_x1, GLfloat dst_y1,
+                                             GLenum filter,
                                              bool mirror_x, bool mirror_y)
 {
+   struct gl_context *ctx = &brw->ctx;
+   const struct gl_framebuffer *read_fb = ctx->ReadBuffer;
+
    src.set(brw, src_mt, src_level, src_layer);
    dst.set(brw, dst_mt, dst_level, dst_layer);
 
-   src.brw_surfaceformat = dst.brw_surfaceformat;
+   /* Even though we do multisample resolves at the time of the blit, OpenGL
+    * specification defines them as if they happen at the time of rendering,
+    * which means that the type of averaging we do during the resolve should
+    * only depend on the source format; the destination format should be
+    * ignored. But, specification doesn't seem to be strict about it.
+    *
+    * It has been observed that mulitisample resolves produce slightly better
+    * looking images when averaging is done using destination format. NVIDIA's
+    * proprietary OpenGL driver also follow this approach. So, we choose to
+    * follow it in our driver.
+    *
+    * Following if-else block takes care of this exception made for
+    * multisampled resolves.
+    */
+   if (src.num_samples > 1)
+      src.brw_surfaceformat = dst.brw_surfaceformat;
+   else
+      dst.brw_surfaceformat = src.brw_surfaceformat;
 
    use_wm_prog = true;
    memset(&wm_prog_key, 0, sizeof(wm_prog_key));
@@ -1852,7 +2113,7 @@ brw_blorp_blit_params::brw_blorp_blit_params(struct brw_context *brw,
       break;
    }
 
-   if (brw->intel.gen > 6) {
+   if (brw->gen > 6) {
       /* 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
@@ -1882,6 +2143,20 @@ brw_blorp_blit_params::brw_blorp_blit_params(struct brw_context *brw,
       wm_prog_key.persample_msaa_dispatch = true;
    }
 
+   /* Scaled blitting or not. */
+   wm_prog_key.blit_scaled =
+      ((dst_x1 - dst_x0) == (src_x1 - src_x0) &&
+       (dst_y1 - dst_y0) == (src_y1 - src_y0)) ? false : true;
+
+   /* Scaling factors used for bilinear filtering in multisample scaled
+    * blits.
+    */
+   wm_prog_key.x_scale = 2.0;
+   wm_prog_key.y_scale = src_mt->num_samples / 2.0;
+
+   if (filter == GL_LINEAR)
+      wm_prog_key.bilinear_filter = true;
+
    /* The render path must be configured to use the same number of samples as
     * the destination buffer.
     */
@@ -1925,6 +2200,9 @@ brw_blorp_blit_params::brw_blorp_blit_params(struct brw_context *brw,
    y0 = wm_push_consts.dst_y0 = dst_y0;
    x1 = wm_push_consts.dst_x1 = dst_x1;
    y1 = wm_push_consts.dst_y1 = dst_y1;
+   wm_push_consts.rect_grid_x1 = read_fb->Width * wm_prog_key.x_scale - 1.0;
+   wm_push_consts.rect_grid_y1 = read_fb->Height * wm_prog_key.y_scale - 1.0;
+
    wm_push_consts.x_transform.setup(src_x0, src_x1, dst_x0, dst_x1, mirror_x);
    wm_push_consts.y_transform.setup(src_y0, src_y1, dst_y0, dst_y1, mirror_y);
 
@@ -2043,7 +2321,7 @@ uint32_t
 brw_blorp_blit_params::get_wm_prog(struct brw_context *brw,
                                    brw_blorp_prog_data **prog_data) const
 {
-   uint32_t prog_offset;
+   uint32_t prog_offset = 0;
    if (!brw_search_cache(&brw->cache, BRW_BLORP_BLIT_PROG,
                          &this->wm_prog_key, sizeof(this->wm_prog_key),
                          &prog_offset, prog_data)) {