u_blitter: fix cube array check
[mesa.git] / src / gallium / auxiliary / util / u_blitter.c
index 1e373223eafb4a425d02c10cbacc083292a3b8a0..091b6e1b28cc39f36f9029091e8c0ce6dfadd39e 100644 (file)
@@ -27,7 +27,7 @@
 /**
  * @file
  * Blitter utility to facilitate acceleration of the clear, clear_render_target,
- * clear_depth_stencil, and resource_copy_region functions.
+ * clear_depth_stencil, resource_copy_region, and blit functions.
  *
  * @author Marek Olšák
  */
@@ -88,8 +88,7 @@ struct blitter_context_priv
    void *fs_texfetch_stencil_msaa[PIPE_MAX_TEXTURE_TYPES];
 
    /* Blend state. */
-   void *blend_write_color;   /**< blend state with writemask of RGBA */
-   void *blend_keep_color;    /**< blend state with writemask of 0 */
+   void *blend[PIPE_MASK_RGBA+1]; /**< blend state with writemask */
 
    /* Depth stencil alpha state. */
    void *dsa_write_depth_stencil;
@@ -104,11 +103,10 @@ struct blitter_context_priv
    void *velem_state_readbuf;
 
    /* Sampler state. */
-   void *sampler_state;
+   void *sampler_state, *sampler_state_linear;
 
    /* Rasterizer state. */
-   void *rs_state;
-   void *rs_discard_state;
+   void *rs_state, *rs_state_scissor, *rs_discard_state;
 
    /* Viewport state. */
    struct pipe_viewport_state viewport;
@@ -121,15 +119,13 @@ struct blitter_context_priv
    boolean vertex_has_integers;
    boolean has_stream_out;
    boolean has_stencil_export;
-};
-
-static void blitter_draw_rectangle(struct blitter_context *blitter,
-                                   unsigned x, unsigned y,
-                                   unsigned width, unsigned height,
-                                   float depth,
-                                   enum blitter_attrib_type type,
-                                   const union pipe_color_union *attrib);
+   boolean has_texture_multisample;
 
+   /* The Draw module overrides these functions.
+    * Always create the blitter before Draw. */
+   void   (*bind_fs_state)(struct pipe_context *, void *);
+   void   (*delete_fs_state)(struct pipe_context *, void *);
+};
 
 struct blitter_context *util_blitter_create(struct pipe_context *pipe)
 {
@@ -146,7 +142,10 @@ struct blitter_context *util_blitter_create(struct pipe_context *pipe)
       return NULL;
 
    ctx->base.pipe = pipe;
-   ctx->base.draw_rectangle = blitter_draw_rectangle;
+   ctx->base.draw_rectangle = util_blitter_draw_rectangle;
+
+   ctx->bind_fs_state = pipe->bind_fs_state;
+   ctx->delete_fs_state = pipe->delete_fs_state;
 
    /* init state objects for them to be considered invalid */
    ctx->base.saved_blend_state = INVALID_PTR;
@@ -159,7 +158,6 @@ struct blitter_context *util_blitter_create(struct pipe_context *pipe)
    ctx->base.saved_fb_state.nr_cbufs = ~0;
    ctx->base.saved_num_sampler_views = ~0;
    ctx->base.saved_num_sampler_states = ~0;
-   ctx->base.saved_num_vertex_buffers = ~0;
    ctx->base.saved_num_so_targets = ~0;
 
    ctx->has_geometry_shader =
@@ -176,12 +174,16 @@ struct blitter_context *util_blitter_create(struct pipe_context *pipe)
          pipe->screen->get_param(pipe->screen,
                                  PIPE_CAP_SHADER_STENCIL_EXPORT);
 
+   ctx->has_texture_multisample =
+      pipe->screen->get_param(pipe->screen, PIPE_CAP_TEXTURE_MULTISAMPLE);
+
    /* blend state objects */
    memset(&blend, 0, sizeof(blend));
-   ctx->blend_keep_color = pipe->create_blend_state(pipe, &blend);
 
-   blend.rt[0].colormask = PIPE_MASK_RGBA;
-   ctx->blend_write_color = pipe->create_blend_state(pipe, &blend);
+   for (i = 0; i <= PIPE_MASK_RGBA; i++) {
+      blend.rt[0].colormask = i;
+      ctx->blend[i] = pipe->create_blend_state(pipe, &blend);
+   }
 
    /* depth stencil alpha state objects */
    memset(&dsa, 0, sizeof(dsa));
@@ -217,6 +219,10 @@ struct blitter_context *util_blitter_create(struct pipe_context *pipe)
    sampler_state.normalized_coords = 1;
    ctx->sampler_state = pipe->create_sampler_state(pipe, &sampler_state);
 
+   sampler_state.min_img_filter = PIPE_TEX_FILTER_LINEAR;
+   sampler_state.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
+   ctx->sampler_state_linear = pipe->create_sampler_state(pipe, &sampler_state);
+
    /* rasterizer state */
    memset(&rs_state, 0, sizeof(rs_state));
    rs_state.cull_face = PIPE_FACE_NONE;
@@ -225,16 +231,23 @@ struct blitter_context *util_blitter_create(struct pipe_context *pipe)
    rs_state.depth_clip = 1;
    ctx->rs_state = pipe->create_rasterizer_state(pipe, &rs_state);
 
+   rs_state.scissor = 1;
+   ctx->rs_state_scissor = pipe->create_rasterizer_state(pipe, &rs_state);
+
    if (ctx->has_stream_out) {
+      rs_state.scissor = 0;
       rs_state.rasterizer_discard = 1;
       ctx->rs_discard_state = pipe->create_rasterizer_state(pipe, &rs_state);
    }
 
+   ctx->base.vb_slot = 0; /* 0 for now */
+
    /* vertex elements states */
    memset(&velem[0], 0, sizeof(velem[0]) * 2);
    for (i = 0; i < 2; i++) {
       velem[i].src_offset = i * 4 * sizeof(float);
       velem[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
+      velem[i].vertex_buffer_index = ctx->base.vb_slot;
    }
    ctx->velem_state = pipe->create_vertex_elements_state(pipe, 2, &velem[0]);
 
@@ -242,20 +255,25 @@ struct blitter_context *util_blitter_create(struct pipe_context *pipe)
       memset(&velem[0], 0, sizeof(velem[0]) * 2);
       velem[0].src_offset = 0;
       velem[0].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
+      velem[0].vertex_buffer_index = ctx->base.vb_slot;
       velem[1].src_offset = 4 * sizeof(float);
       velem[1].src_format = PIPE_FORMAT_R32G32B32A32_SINT;
+      velem[1].vertex_buffer_index = ctx->base.vb_slot;
       ctx->velem_sint_state = pipe->create_vertex_elements_state(pipe, 2, &velem[0]);
 
       memset(&velem[0], 0, sizeof(velem[0]) * 2);
       velem[0].src_offset = 0;
       velem[0].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
+      velem[0].vertex_buffer_index = ctx->base.vb_slot;
       velem[1].src_offset = 4 * sizeof(float);
       velem[1].src_format = PIPE_FORMAT_R32G32B32A32_UINT;
+      velem[1].vertex_buffer_index = ctx->base.vb_slot;
       ctx->velem_uint_state = pipe->create_vertex_elements_state(pipe, 2, &velem[0]);
    }
 
    if (ctx->has_stream_out) {
       velem[0].src_format = PIPE_FORMAT_R32_UINT;
+      velem[0].vertex_buffer_index = ctx->base.vb_slot;
       ctx->velem_state_readbuf = pipe->create_vertex_elements_state(pipe, 1, &velem[0]);
    }
 
@@ -300,8 +318,9 @@ void util_blitter_destroy(struct blitter_context *blitter)
    struct pipe_context *pipe = blitter->pipe;
    int i;
 
-   pipe->delete_blend_state(pipe, ctx->blend_write_color);
-   pipe->delete_blend_state(pipe, ctx->blend_keep_color);
+   for (i = 0; i <= PIPE_MASK_RGBA; i++) {
+      pipe->delete_blend_state(pipe, ctx->blend[i]);
+   }
    pipe->delete_depth_stencil_alpha_state(pipe, ctx->dsa_keep_depth_stencil);
    pipe->delete_depth_stencil_alpha_state(pipe,
                                           ctx->dsa_write_depth_keep_stencil);
@@ -309,6 +328,7 @@ void util_blitter_destroy(struct blitter_context *blitter)
    pipe->delete_depth_stencil_alpha_state(pipe, ctx->dsa_keep_depth_write_stencil);
 
    pipe->delete_rasterizer_state(pipe, ctx->rs_state);
+   pipe->delete_rasterizer_state(pipe, ctx->rs_state_scissor);
    if (ctx->rs_discard_state)
       pipe->delete_rasterizer_state(pipe, ctx->rs_discard_state);
    pipe->delete_vs_state(pipe, ctx->vs);
@@ -324,27 +344,36 @@ void util_blitter_destroy(struct blitter_context *blitter)
 
    for (i = 0; i < PIPE_MAX_TEXTURE_TYPES; i++) {
       if (ctx->fs_texfetch_col[i])
-         pipe->delete_fs_state(pipe, ctx->fs_texfetch_col[i]);
+         ctx->delete_fs_state(pipe, ctx->fs_texfetch_col[i]);
       if (ctx->fs_texfetch_depth[i])
-         pipe->delete_fs_state(pipe, ctx->fs_texfetch_depth[i]);
+         ctx->delete_fs_state(pipe, ctx->fs_texfetch_depth[i]);
       if (ctx->fs_texfetch_depthstencil[i])
-         pipe->delete_fs_state(pipe, ctx->fs_texfetch_depthstencil[i]);
+         ctx->delete_fs_state(pipe, ctx->fs_texfetch_depthstencil[i]);
       if (ctx->fs_texfetch_stencil[i])
-         pipe->delete_fs_state(pipe, ctx->fs_texfetch_stencil[i]);
+         ctx->delete_fs_state(pipe, ctx->fs_texfetch_stencil[i]);
    }
 
    for (i = 0; i <= PIPE_MAX_COLOR_BUFS; i++) {
       if (ctx->fs_col[i])
-         pipe->delete_fs_state(pipe, ctx->fs_col[i]);
+         ctx->delete_fs_state(pipe, ctx->fs_col[i]);
       if (ctx->fs_col_int[i])
-         pipe->delete_fs_state(pipe, ctx->fs_col_int[i]);
+         ctx->delete_fs_state(pipe, ctx->fs_col_int[i]);
    }
 
    pipe->delete_sampler_state(pipe, ctx->sampler_state);
+   pipe->delete_sampler_state(pipe, ctx->sampler_state_linear);
    u_upload_destroy(ctx->upload);
    FREE(ctx);
 }
 
+void util_blitter_set_texture_multisample(struct blitter_context *blitter,
+                                          boolean supported)
+{
+   struct blitter_context_priv *ctx = (struct blitter_context_priv*)blitter;
+
+   ctx->has_texture_multisample = supported;
+}
+
 static void blitter_set_running_flag(struct blitter_context_priv *ctx)
 {
    if (ctx->base.running) {
@@ -365,7 +394,6 @@ static void blitter_unset_running_flag(struct blitter_context_priv *ctx)
 
 static void blitter_check_saved_vertex_states(struct blitter_context_priv *ctx)
 {
-   assert(ctx->base.saved_num_vertex_buffers != ~0);
    assert(ctx->base.saved_velem_state != INVALID_PTR);
    assert(ctx->base.saved_vs != INVALID_PTR);
    assert(!ctx->has_geometry_shader || ctx->base.saved_gs != INVALID_PTR);
@@ -378,18 +406,10 @@ static void blitter_restore_vertex_states(struct blitter_context_priv *ctx)
    struct pipe_context *pipe = ctx->base.pipe;
    unsigned i;
 
-   /* Vertex buffers. */
-   pipe->set_vertex_buffers(pipe,
-                            ctx->base.saved_num_vertex_buffers,
-                            ctx->base.saved_vertex_buffers);
-
-   for (i = 0; i < ctx->base.saved_num_vertex_buffers; i++) {
-      if (ctx->base.saved_vertex_buffers[i].buffer) {
-         pipe_resource_reference(&ctx->base.saved_vertex_buffers[i].buffer,
-                                 NULL);
-      }
-   }
-   ctx->base.saved_num_vertex_buffers = ~0;
+   /* Vertex buffer. */
+   pipe->set_vertex_buffers(pipe, ctx->base.vb_slot, 1,
+                            &ctx->base.saved_vertex_buffer);
+   pipe_resource_reference(&ctx->base.saved_vertex_buffer.buffer, NULL);
 
    /* Vertex elements. */
    pipe->bind_vertex_elements_state(pipe, ctx->base.saved_velem_state);
@@ -434,7 +454,7 @@ static void blitter_restore_fragment_states(struct blitter_context_priv *ctx)
    struct pipe_context *pipe = ctx->base.pipe;
 
    /* Fragment shader. */
-   pipe->bind_fs_state(pipe, ctx->base.saved_fs);
+   ctx->bind_fs_state(pipe, ctx->base.saved_fs);
    ctx->base.saved_fs = INVALID_PTR;
 
    /* Depth, stencil, alpha. */
@@ -463,6 +483,26 @@ static void blitter_check_saved_fb_state(struct blitter_context_priv *ctx)
    assert(ctx->base.saved_fb_state.nr_cbufs != ~0);
 }
 
+static void blitter_disable_render_cond(struct blitter_context_priv *ctx)
+{
+   struct pipe_context *pipe = ctx->base.pipe;
+
+   if (ctx->base.saved_render_cond_query) {
+      pipe->render_condition(pipe, NULL, 0);
+   }
+}
+
+static void blitter_restore_render_cond(struct blitter_context_priv *ctx)
+{
+   struct pipe_context *pipe = ctx->base.pipe;
+
+   if (ctx->base.saved_render_cond_query) {
+      pipe->render_condition(pipe, ctx->base.saved_render_cond_query,
+                             ctx->base.saved_render_cond_mode);
+      ctx->base.saved_render_cond_query = NULL;
+   }
+}
+
 static void blitter_restore_fb_state(struct blitter_context_priv *ctx)
 {
    struct pipe_context *pipe = ctx->base.pipe;
@@ -500,8 +540,7 @@ static void blitter_restore_textures(struct blitter_context_priv *ctx)
 }
 
 static void blitter_set_rectangle(struct blitter_context_priv *ctx,
-                                  unsigned x1, unsigned y1,
-                                  unsigned x2, unsigned y2,
+                                  int x1, int y1, int x2, int y2,
                                   float depth)
 {
    int i;
@@ -559,8 +598,7 @@ static void blitter_set_clear_color(struct blitter_context_priv *ctx,
 
 static void get_texcoords(struct pipe_sampler_view *src,
                           unsigned src_width0, unsigned src_height0,
-                          unsigned x1, unsigned y1,
-                          unsigned x2, unsigned y2,
+                          int x1, int y1, int x2, int y2,
                           float out[4])
 {
    struct pipe_resource *tex = src->texture;
@@ -574,10 +612,10 @@ static void get_texcoords(struct pipe_sampler_view *src,
       out[2] = x2 / (float)u_minify(src_width0,  level);
       out[3] = y2 / (float)u_minify(src_height0, level);
    } else {
-      out[0] = x1;
-      out[1] = y1;
-      out[2] = x2;
-      out[3] = y2;
+      out[0] = (float) x1;
+      out[1] = (float) y1;
+      out[2] = (float) x2;
+      out[3] = (float) y2;
    }
 }
 
@@ -601,8 +639,7 @@ static void blitter_set_texcoords(struct blitter_context_priv *ctx,
                                   struct pipe_sampler_view *src,
                                   unsigned src_width0, unsigned src_height0,
                                   unsigned layer, unsigned sample,
-                                  unsigned x1, unsigned y1,
-                                  unsigned x2, unsigned y2)
+                                  int x1, int y1, int x2, int y2)
 {
    unsigned i;
    float coord[4];
@@ -610,9 +647,10 @@ static void blitter_set_texcoords(struct blitter_context_priv *ctx,
 
    get_texcoords(src, src_width0, src_height0, x1, y1, x2, y2, coord);
 
-   if (src->texture->target == PIPE_TEXTURE_CUBE) {
+   if (src->texture->target == PIPE_TEXTURE_CUBE ||
+       src->texture->target == PIPE_TEXTURE_CUBE_ARRAY) {
       set_texcoords_in_vertices(coord, &face_coord[0][0], 2);
-      util_map_texcoords2d_onto_cubemap(layer,
+      util_map_texcoords2d_onto_cubemap(layer % 6,
                                         /* pointer, stride in floats */
                                         &face_coord[0][0], 2,
                                         &ctx->vertices[0][1][0], 8);
@@ -633,19 +671,19 @@ static void blitter_set_texcoords(struct blitter_context_priv *ctx,
 
    case PIPE_TEXTURE_1D_ARRAY:
       for (i = 0; i < 4; i++)
-         ctx->vertices[i][1][1] = layer; /*t*/
+         ctx->vertices[i][1][1] = (float) layer; /*t*/
       break;
 
    case PIPE_TEXTURE_2D_ARRAY:
       for (i = 0; i < 4; i++) {
-         ctx->vertices[i][1][2] = layer;  /*r*/
-         ctx->vertices[i][1][3] = sample; /*q*/
+         ctx->vertices[i][1][2] = (float) layer;  /*r*/
+         ctx->vertices[i][1][3] = (float) sample; /*q*/
       }
       break;
 
    case PIPE_TEXTURE_2D:
       for (i = 0; i < 4; i++) {
-         ctx->vertices[i][1][2] = sample; /*r*/
+         ctx->vertices[i][1][2] = (float) sample; /*r*/
       }
       break;
 
@@ -660,9 +698,8 @@ static void blitter_set_dst_dimensions(struct blitter_context_priv *ctx,
    ctx->dst_height = height;
 }
 
-static INLINE
-void *blitter_get_fs_col(struct blitter_context_priv *ctx, unsigned num_cbufs,
-                         boolean int_format)
+static void *blitter_get_fs_col(struct blitter_context_priv *ctx,
+                                unsigned num_cbufs, boolean int_format)
 {
    struct pipe_context *pipe = ctx->base.pipe;
 
@@ -685,32 +722,32 @@ void *blitter_get_fs_col(struct blitter_context_priv *ctx, unsigned num_cbufs,
    }
 }
 
-static INLINE
-void *blitter_get_fs_texfetch_col(struct blitter_context_priv *ctx,
-                                  struct pipe_resource *tex)
+static void *blitter_get_fs_texfetch_col(struct blitter_context_priv *ctx,
+                                         enum pipe_texture_target target,
+                                         unsigned nr_samples)
 {
    struct pipe_context *pipe = ctx->base.pipe;
 
-   assert(tex->target < PIPE_MAX_TEXTURE_TYPES);
+   assert(target < PIPE_MAX_TEXTURE_TYPES);
 
-   if (tex->nr_samples > 1) {
-      void **shader = &ctx->fs_texfetch_col_msaa[tex->target];
+   if (nr_samples > 1) {
+      void **shader = &ctx->fs_texfetch_col_msaa[target];
 
       /* Create the fragment shader on-demand. */
       if (!*shader) {
-         unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(tex->target,
-                                                       tex->nr_samples);
+         unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(target,
+                                                       nr_samples);
 
          *shader = util_make_fs_blit_msaa_color(pipe, tgsi_tex);
       }
 
       return *shader;
    } else {
-      void **shader = &ctx->fs_texfetch_col[tex->target];
+      void **shader = &ctx->fs_texfetch_col[target];
 
       /* Create the fragment shader on-demand. */
       if (!*shader) {
-         unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(tex->target, 0);
+         unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(target, 0);
 
          *shader =
             util_make_fragment_tex_shader(pipe, tgsi_tex,
@@ -723,19 +760,20 @@ void *blitter_get_fs_texfetch_col(struct blitter_context_priv *ctx,
 
 static INLINE
 void *blitter_get_fs_texfetch_depth(struct blitter_context_priv *ctx,
-                                    struct pipe_resource *tex)
+                                    enum pipe_texture_target target,
+                                    unsigned nr_samples)
 {
    struct pipe_context *pipe = ctx->base.pipe;
 
-   assert(tex->target < PIPE_MAX_TEXTURE_TYPES);
+   assert(target < PIPE_MAX_TEXTURE_TYPES);
 
-   if (tex->nr_samples > 1) {
-      void **shader = &ctx->fs_texfetch_depth_msaa[tex->target];
+   if (nr_samples > 1) {
+      void **shader = &ctx->fs_texfetch_depth_msaa[target];
 
       /* Create the fragment shader on-demand. */
       if (!*shader) {
-         unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(tex->target,
-                                                       tex->nr_samples);
+         unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(target,
+                                                       nr_samples);
 
          *shader =
             util_make_fs_blit_msaa_depth(pipe, tgsi_tex);
@@ -743,11 +781,11 @@ void *blitter_get_fs_texfetch_depth(struct blitter_context_priv *ctx,
 
       return *shader;
    } else {
-      void **shader = &ctx->fs_texfetch_depth[tex->target];
+      void **shader = &ctx->fs_texfetch_depth[target];
 
       /* Create the fragment shader on-demand. */
       if (!*shader) {
-         unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(tex->target, 0);
+         unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(target, 0);
 
          *shader =
             util_make_fragment_tex_shader_writedepth(pipe, tgsi_tex,
@@ -760,19 +798,20 @@ void *blitter_get_fs_texfetch_depth(struct blitter_context_priv *ctx,
 
 static INLINE
 void *blitter_get_fs_texfetch_depthstencil(struct blitter_context_priv *ctx,
-                                           struct pipe_resource *tex)
+                                           enum pipe_texture_target target,
+                                           unsigned nr_samples)
 {
    struct pipe_context *pipe = ctx->base.pipe;
 
-   assert(tex->target < PIPE_MAX_TEXTURE_TYPES);
+   assert(target < PIPE_MAX_TEXTURE_TYPES);
 
-   if (tex->nr_samples > 1) {
-      void **shader = &ctx->fs_texfetch_depthstencil_msaa[tex->target];
+   if (nr_samples > 1) {
+      void **shader = &ctx->fs_texfetch_depthstencil_msaa[target];
 
       /* Create the fragment shader on-demand. */
       if (!*shader) {
-         unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(tex->target,
-                                                       tex->nr_samples);
+         unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(target,
+                                                       nr_samples);
 
          *shader =
             util_make_fs_blit_msaa_depthstencil(pipe, tgsi_tex);
@@ -780,11 +819,11 @@ void *blitter_get_fs_texfetch_depthstencil(struct blitter_context_priv *ctx,
 
       return *shader;
    } else {
-      void **shader = &ctx->fs_texfetch_depthstencil[tex->target];
+      void **shader = &ctx->fs_texfetch_depthstencil[target];
 
       /* Create the fragment shader on-demand. */
       if (!*shader) {
-         unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(tex->target, 0);
+         unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(target, 0);
 
          *shader =
             util_make_fragment_tex_shader_writedepthstencil(pipe, tgsi_tex,
@@ -797,19 +836,20 @@ void *blitter_get_fs_texfetch_depthstencil(struct blitter_context_priv *ctx,
 
 static INLINE
 void *blitter_get_fs_texfetch_stencil(struct blitter_context_priv *ctx,
-                                      struct pipe_resource *tex)
+                                      enum pipe_texture_target target,
+                                      unsigned nr_samples)
 {
    struct pipe_context *pipe = ctx->base.pipe;
 
-   assert(tex->target < PIPE_MAX_TEXTURE_TYPES);
+   assert(target < PIPE_MAX_TEXTURE_TYPES);
 
-   if (tex->nr_samples > 1) {
-      void **shader = &ctx->fs_texfetch_stencil_msaa[tex->target];
+   if (nr_samples > 1) {
+      void **shader = &ctx->fs_texfetch_stencil_msaa[target];
 
       /* Create the fragment shader on-demand. */
       if (!*shader) {
-         unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(tex->target,
-                                                       tex->nr_samples);
+         unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(target,
+                                                       nr_samples);
 
          *shader =
             util_make_fs_blit_msaa_stencil(pipe, tgsi_tex);
@@ -817,11 +857,11 @@ void *blitter_get_fs_texfetch_stencil(struct blitter_context_priv *ctx,
 
       return *shader;
    } else {
-      void **shader = &ctx->fs_texfetch_stencil[tex->target];
+      void **shader = &ctx->fs_texfetch_stencil[target];
 
       /* Create the fragment shader on-demand. */
       if (!*shader) {
-         unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(tex->target, 0);
+         unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(target, 0);
 
          *shader =
             util_make_fragment_tex_shader_writestencil(pipe, tgsi_tex,
@@ -832,11 +872,55 @@ void *blitter_get_fs_texfetch_stencil(struct blitter_context_priv *ctx,
    }
 }
 
-static void blitter_set_common_draw_rect_state(struct blitter_context_priv *ctx)
+void util_blitter_cache_all_shaders(struct blitter_context *blitter)
+{
+   struct blitter_context_priv *ctx = (struct blitter_context_priv*)blitter;
+   struct pipe_screen *screen = blitter->pipe->screen;
+   unsigned num_cbufs, i, target, max_samples;
+   boolean has_arraytex, has_cubearraytex;
+
+   num_cbufs = MAX2(screen->get_param(screen,
+                                      PIPE_CAP_MAX_RENDER_TARGETS), 1);
+   max_samples = ctx->has_texture_multisample ? 2 : 1;
+   has_arraytex = screen->get_param(screen,
+                                    PIPE_CAP_MAX_TEXTURE_ARRAY_LAYERS) != 0;
+   has_cubearraytex = screen->get_param(screen,
+                                    PIPE_CAP_CUBE_MAP_ARRAY) != 0;
+
+   for (i = 0; i < num_cbufs; i++) {
+      blitter_get_fs_col(ctx, i, FALSE);
+      blitter_get_fs_col(ctx, i, TRUE);
+   }
+
+   /* It only matters if i <= 1 or > 1. */
+   for (i = 1; i <= max_samples; i++) {
+      for (target = PIPE_TEXTURE_1D; target < PIPE_MAX_TEXTURE_TYPES; target++) {
+         if (!has_arraytex &&
+             (target == PIPE_TEXTURE_1D_ARRAY ||
+              target == PIPE_TEXTURE_2D_ARRAY)) {
+            continue;
+         }
+         if (!has_cubearraytex &&
+             (target == PIPE_TEXTURE_CUBE_ARRAY))
+            continue;
+
+         blitter_get_fs_texfetch_col(ctx, target, i);
+         blitter_get_fs_texfetch_depth(ctx, target, i);
+         if (ctx->has_stencil_export) {
+            blitter_get_fs_texfetch_depthstencil(ctx, target, i);
+            blitter_get_fs_texfetch_stencil(ctx, target, i);
+         }
+      }
+   }
+}
+
+static void blitter_set_common_draw_rect_state(struct blitter_context_priv *ctx,
+                                               boolean scissor)
 {
    struct pipe_context *pipe = ctx->base.pipe;
 
-   pipe->bind_rasterizer_state(pipe, ctx->rs_state);
+   pipe->bind_rasterizer_state(pipe, scissor ? ctx->rs_state_scissor
+                                             : ctx->rs_state);
    pipe->bind_vs_state(pipe, ctx->vs);
    if (ctx->has_geometry_shader)
       pipe->bind_gs_state(pipe, NULL);
@@ -845,9 +929,7 @@ static void blitter_set_common_draw_rect_state(struct blitter_context_priv *ctx)
 }
 
 static void blitter_draw(struct blitter_context_priv *ctx,
-                         unsigned x1, unsigned y1,
-                         unsigned x2, unsigned y2,
-                         float depth)
+                         int x1, int y1, int x2, int y2, float depth)
 {
    struct pipe_resource *buf = NULL;
    unsigned offset = 0;
@@ -857,17 +939,15 @@ static void blitter_draw(struct blitter_context_priv *ctx,
    u_upload_data(ctx->upload, 0, sizeof(ctx->vertices), ctx->vertices,
                  &offset, &buf);
    u_upload_unmap(ctx->upload);
-   util_draw_vertex_buffer(ctx->base.pipe, NULL, buf, offset,
-                           PIPE_PRIM_TRIANGLE_FAN, 4, 2);
+   util_draw_vertex_buffer(ctx->base.pipe, NULL, buf, ctx->base.vb_slot,
+                           offset, PIPE_PRIM_TRIANGLE_FAN, 4, 2);
    pipe_resource_reference(&buf, NULL);
 }
 
-static void blitter_draw_rectangle(struct blitter_context *blitter,
-                                   unsigned x1, unsigned y1,
-                                   unsigned x2, unsigned y2,
-                                   float depth,
-                                   enum blitter_attrib_type type,
-                                   const union pipe_color_union *attrib)
+void util_blitter_draw_rectangle(struct blitter_context *blitter,
+                                 int x1, int y1, int x2, int y2, float depth,
+                                 enum blitter_attrib_type type,
+                                 const union pipe_color_union *attrib)
 {
    struct blitter_context_priv *ctx = (struct blitter_context_priv*)blitter;
 
@@ -904,14 +984,15 @@ static void util_blitter_clear_custom(struct blitter_context *blitter,
    blitter_set_running_flag(ctx);
    blitter_check_saved_vertex_states(ctx);
    blitter_check_saved_fragment_states(ctx);
+   blitter_disable_render_cond(ctx);
 
    /* bind states */
    if (custom_blend) {
       pipe->bind_blend_state(pipe, custom_blend);
    } else if (clear_buffers & PIPE_CLEAR_COLOR) {
-      pipe->bind_blend_state(pipe, ctx->blend_write_color);
+      pipe->bind_blend_state(pipe, ctx->blend[PIPE_MASK_RGBA]);
    } else {
-      pipe->bind_blend_state(pipe, ctx->blend_keep_color);
+      pipe->bind_blend_state(pipe, ctx->blend[0]);
    }
 
    if (custom_dsa) {
@@ -936,16 +1017,17 @@ static void util_blitter_clear_custom(struct blitter_context *blitter,
    } else {
       pipe->bind_vertex_elements_state(pipe, ctx->velem_state);
    }
-   pipe->bind_fs_state(pipe, blitter_get_fs_col(ctx, num_cbufs, int_format));
+   ctx->bind_fs_state(pipe, blitter_get_fs_col(ctx, num_cbufs, int_format));
    pipe->set_sample_mask(pipe, ~0);
 
-   blitter_set_common_draw_rect_state(ctx);
+   blitter_set_common_draw_rect_state(ctx, FALSE);
    blitter_set_dst_dimensions(ctx, width, height);
-   blitter->draw_rectangle(blitter, 0, 0, width, height, depth,
+   blitter->draw_rectangle(blitter, 0, 0, width, height, (float) depth,
                            UTIL_BLITTER_ATTRIB_COLOR, color);
 
    blitter_restore_vertex_states(ctx);
    blitter_restore_fragment_states(ctx);
+   blitter_restore_render_cond(ctx);
    blitter_unset_running_flag(ctx);
 }
 
@@ -962,7 +1044,7 @@ void util_blitter_clear(struct blitter_context *blitter,
                              NULL, NULL);
 }
 
-void util_blitter_clear_depth_custom(struct blitter_context *blitter,
+void util_blitter_custom_clear_depth(struct blitter_context *blitter,
                                      unsigned width, unsigned height,
                                      double depth, void *custom_dsa)
 {
@@ -972,7 +1054,7 @@ void util_blitter_clear_depth_custom(struct blitter_context *blitter,
 }
 
 static
-boolean is_overlap(unsigned dstx, unsigned dsty, unsigned dstz,
+boolean is_overlap(int dstx, int dsty, int dstz,
                   const struct pipe_box *srcbox)
 {
    struct pipe_box src = *srcbox;
@@ -1031,10 +1113,12 @@ void util_blitter_default_src_texture(struct pipe_sampler_view *src_templ,
     src_templ->swizzle_a = PIPE_SWIZZLE_ALPHA;
 }
 
-boolean util_blitter_is_copy_supported(struct blitter_context *blitter,
-                                       const struct pipe_resource *dst,
-                                       const struct pipe_resource *src,
-                                       unsigned mask)
+static boolean is_blit_generic_supported(struct blitter_context *blitter,
+                                         const struct pipe_resource *dst,
+                                         enum pipe_format dst_format,
+                                         const struct pipe_resource *src,
+                                         enum pipe_format src_format,
+                                         unsigned mask)
 {
    struct blitter_context_priv *ctx = (struct blitter_context_priv*)blitter;
    struct pipe_screen *screen = ctx->base.pipe->screen;
@@ -1043,7 +1127,7 @@ boolean util_blitter_is_copy_supported(struct blitter_context *blitter,
       unsigned bind;
       boolean is_stencil;
       const struct util_format_description *desc =
-            util_format_description(dst->format);
+            util_format_description(dst_format);
 
       is_stencil = util_format_has_stencil(desc);
 
@@ -1057,25 +1141,29 @@ boolean util_blitter_is_copy_supported(struct blitter_context *blitter,
       else
          bind = PIPE_BIND_RENDER_TARGET;
 
-      if (!screen->is_format_supported(screen, dst->format, dst->target,
+      if (!screen->is_format_supported(screen, dst_format, dst->target,
                                        dst->nr_samples, bind)) {
          return FALSE;
       }
    }
 
    if (src) {
-      if (!screen->is_format_supported(screen, src->format, src->target,
+      if (src->nr_samples > 1 && !ctx->has_texture_multisample) {
+         return FALSE;
+      }
+
+      if (!screen->is_format_supported(screen, src_format, src->target,
                                  src->nr_samples, PIPE_BIND_SAMPLER_VIEW)) {
          return FALSE;
       }
 
       /* Check stencil sampler support for stencil copy. */
-      if (util_format_has_stencil(util_format_description(src->format))) {
+      if (util_format_has_stencil(util_format_description(src_format))) {
          enum pipe_format stencil_format =
-               util_format_stencil_only(src->format);
+               util_format_stencil_only(src_format);
          assert(stencil_format != PIPE_FORMAT_NONE);
 
-         if (stencil_format != src->format &&
+         if (stencil_format != src_format &&
              !screen->is_format_supported(screen, stencil_format, src->target,
                                  src->nr_samples, PIPE_BIND_SAMPLER_VIEW)) {
             return FALSE;
@@ -1086,13 +1174,32 @@ boolean util_blitter_is_copy_supported(struct blitter_context *blitter,
    return TRUE;
 }
 
+boolean util_blitter_is_copy_supported(struct blitter_context *blitter,
+                                       const struct pipe_resource *dst,
+                                       const struct pipe_resource *src,
+                                       unsigned mask)
+{
+   return is_blit_generic_supported(blitter, dst, dst->format,
+                                    src, src->format, mask);
+}
+
+boolean util_blitter_is_blit_supported(struct blitter_context *blitter,
+                                      const struct pipe_blit_info *info)
+{
+   return is_blit_generic_supported(blitter,
+                                    info->dst.resource, info->dst.format,
+                                    info->src.resource, info->src.format,
+                                    info->mask);
+}
+
 void util_blitter_copy_texture(struct blitter_context *blitter,
                                struct pipe_resource *dst,
-                               unsigned dst_level, unsigned dst_sample_mask,
+                               unsigned dst_level,
                                unsigned dstx, unsigned dsty, unsigned dstz,
                                struct pipe_resource *src,
-                               unsigned src_level, unsigned src_sample,
-                               const struct pipe_box *srcbox)
+                               unsigned src_level,
+                               const struct pipe_box *srcbox, unsigned mask,
+                               boolean copy_all_samples)
 {
    struct blitter_context_priv *ctx = (struct blitter_context_priv*)blitter;
    struct pipe_context *pipe = ctx->base.pipe;
@@ -1111,44 +1218,53 @@ void util_blitter_copy_texture(struct blitter_context *blitter,
    src_view = pipe->create_sampler_view(pipe, src, &src_templ);
 
    /* Copy. */
-   util_blitter_copy_texture_view(blitter, dst_view, dst_sample_mask, dstx,
-                                 dsty, src_view, src_sample, srcbox,
-                                 src->width0, src->height0, PIPE_MASK_RGBAZS);
+   util_blitter_blit_generic(blitter, dst_view, dstx, dsty,
+                             abs(srcbox->width), abs(srcbox->height),
+                             src_view, srcbox, src->width0, src->height0,
+                             mask, PIPE_TEX_FILTER_NEAREST, NULL,
+                             copy_all_samples);
 
    pipe_surface_reference(&dst_view, NULL);
    pipe_sampler_view_reference(&src_view, NULL);
 }
 
-void util_blitter_copy_texture_view(struct blitter_context *blitter,
-                                    struct pipe_surface *dst,
-                                    unsigned dst_sample_mask,
-                                    unsigned dstx, unsigned dsty,
-                                    struct pipe_sampler_view *src,
-                                    unsigned src_sample,
-                                    const struct pipe_box *srcbox,
-                                    unsigned src_width0, unsigned src_height0,
-                                    unsigned mask)
+void util_blitter_blit_generic(struct blitter_context *blitter,
+                               struct pipe_surface *dst,
+                               int dstx, int dsty,
+                               unsigned dst_width, unsigned dst_height,
+                               struct pipe_sampler_view *src,
+                               const struct pipe_box *srcbox,
+                               unsigned src_width0, unsigned src_height0,
+                               unsigned mask, unsigned filter,
+                               const struct pipe_scissor_state *scissor,
+                               boolean copy_all_samples)
 {
    struct blitter_context_priv *ctx = (struct blitter_context_priv*)blitter;
    struct pipe_context *pipe = ctx->base.pipe;
    struct pipe_framebuffer_state fb_state;
    enum pipe_texture_target src_target = src->texture->target;
-   int abs_width = abs(srcbox->width);
-   int abs_height = abs(srcbox->height);
-   boolean blit_stencil, blit_depth;
+   boolean has_depth, has_stencil, has_color;
+   boolean blit_stencil, blit_depth, blit_color;
+   void *sampler_state;
    const struct util_format_description *src_desc =
          util_format_description(src->format);
-
-   blit_depth = util_format_has_depth(src_desc) && (mask & PIPE_MASK_Z);
-   blit_stencil = util_format_has_stencil(src_desc) && (mask & PIPE_MASK_S);
-
-   /* If you want a fallback for stencil copies,
-    * use util_blitter_copy_texture. */
-   if (blit_stencil && !ctx->has_stencil_export) {
-      blit_stencil = FALSE;
-
-      if (!blit_depth)
-         return;
+   const struct util_format_description *dst_desc =
+         util_format_description(dst->format);
+
+   has_color = src_desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS &&
+               dst_desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS;
+   has_depth = util_format_has_depth(src_desc) &&
+               util_format_has_depth(dst_desc);
+   has_stencil = util_format_has_stencil(src_desc) &&
+                 util_format_has_stencil(dst_desc);
+
+   blit_color = has_color && (mask & PIPE_MASK_RGBA);
+   blit_depth = has_depth && (mask & PIPE_MASK_Z);
+   blit_stencil = has_stencil && (mask & PIPE_MASK_S) &&
+                  ctx->has_stencil_export;
+
+   if (!blit_stencil && !blit_depth && !blit_color) {
+      return;
    }
 
    /* Sanity checks. */
@@ -1165,49 +1281,65 @@ void util_blitter_copy_texture_view(struct blitter_context *blitter,
    blitter_check_saved_fragment_states(ctx);
    blitter_check_saved_textures(ctx);
    blitter_check_saved_fb_state(ctx);
+   blitter_disable_render_cond(ctx);
 
    /* Initialize framebuffer state. */
    fb_state.width = dst->width;
    fb_state.height = dst->height;
 
    if (blit_depth || blit_stencil) {
-      pipe->bind_blend_state(pipe, ctx->blend_keep_color);
+      pipe->bind_blend_state(pipe, ctx->blend[0]);
 
       if (blit_depth && blit_stencil) {
          pipe->bind_depth_stencil_alpha_state(pipe,
                                               ctx->dsa_write_depth_stencil);
-         pipe->bind_fs_state(pipe,
-               blitter_get_fs_texfetch_depthstencil(ctx, src->texture));
+         ctx->bind_fs_state(pipe,
+               blitter_get_fs_texfetch_depthstencil(ctx, src->texture->target,
+                                                    src->texture->nr_samples));
       } else if (blit_depth) {
          pipe->bind_depth_stencil_alpha_state(pipe,
                                               ctx->dsa_write_depth_keep_stencil);
-         pipe->bind_fs_state(pipe,
-               blitter_get_fs_texfetch_depth(ctx, src->texture));
+         ctx->bind_fs_state(pipe,
+               blitter_get_fs_texfetch_depth(ctx, src->texture->target,
+                                             src->texture->nr_samples));
       } else { /* is_stencil */
          pipe->bind_depth_stencil_alpha_state(pipe,
                                               ctx->dsa_keep_depth_write_stencil);
-         pipe->bind_fs_state(pipe,
-               blitter_get_fs_texfetch_stencil(ctx, src->texture));
+         ctx->bind_fs_state(pipe,
+               blitter_get_fs_texfetch_stencil(ctx, src->texture->target,
+                                               src->texture->nr_samples));
       }
 
       fb_state.nr_cbufs = 0;
       fb_state.zsbuf = dst;
    } else {
-      pipe->bind_blend_state(pipe, ctx->blend_write_color);
+      pipe->bind_blend_state(pipe, ctx->blend[mask & PIPE_MASK_RGBA]);
       pipe->bind_depth_stencil_alpha_state(pipe, ctx->dsa_keep_depth_stencil);
-      pipe->bind_fs_state(pipe,
-            blitter_get_fs_texfetch_col(ctx, src->texture));
+      ctx->bind_fs_state(pipe,
+            blitter_get_fs_texfetch_col(ctx, src->texture->target,
+                                        src->texture->nr_samples));
 
       fb_state.nr_cbufs = 1;
       fb_state.cbufs[0] = dst;
       fb_state.zsbuf = 0;
    }
 
+   /* Set the linear filter only for scaled color non-MSAA blits. */
+   if (filter == PIPE_TEX_FILTER_LINEAR &&
+       !blit_depth && !blit_stencil &&
+       src->texture->nr_samples <= 1 &&
+       (dst_width != abs(srcbox->width) || dst_height != abs(srcbox->height))) {
+      sampler_state = ctx->sampler_state_linear;
+   } else {
+      sampler_state = ctx->sampler_state;
+   }
+
+   /* Set samplers. */
    if (blit_depth && blit_stencil) {
       /* Setup two samplers, one for depth and the other one for stencil. */
       struct pipe_sampler_view templ;
       struct pipe_sampler_view *views[2];
-      void *samplers[2] = {ctx->sampler_state, ctx->sampler_state};
+      void *samplers[2] = {sampler_state, sampler_state};
 
       templ = *src;
       templ.format = util_format_stencil_only(templ.format);
@@ -1220,16 +1352,34 @@ void util_blitter_copy_texture_view(struct blitter_context *blitter,
       pipe->bind_fragment_sampler_states(pipe, 2, samplers);
 
       pipe_sampler_view_reference(&views[1], NULL);
+   } else if (blit_stencil) {
+      /* Set a stencil-only sampler view for it not to sample depth instead. */
+      struct pipe_sampler_view templ;
+      struct pipe_sampler_view *view;
+
+      templ = *src;
+      templ.format = util_format_stencil_only(templ.format);
+      assert(templ.format != PIPE_FORMAT_NONE);
+
+      view = pipe->create_sampler_view(pipe, src->texture, &templ);
+
+      pipe->set_fragment_sampler_views(pipe, 1, &view);
+      pipe->bind_fragment_sampler_states(pipe, 1, &sampler_state);
+
+      pipe_sampler_view_reference(&view, NULL);
    } else {
       pipe->set_fragment_sampler_views(pipe, 1, &src);
-      pipe->bind_fragment_sampler_states(pipe, 1, &ctx->sampler_state);
+      pipe->bind_fragment_sampler_states(pipe, 1, &sampler_state);
    }
 
    pipe->bind_vertex_elements_state(pipe, ctx->velem_state);
    pipe->set_framebuffer_state(pipe, &fb_state);
-   pipe->set_sample_mask(pipe, dst_sample_mask);
 
-   blitter_set_common_draw_rect_state(ctx);
+   if (scissor) {
+      pipe->set_scissor_state(pipe, scissor);
+   }
+
+   blitter_set_common_draw_rect_state(ctx, scissor != NULL);
    blitter_set_dst_dimensions(ctx, dst->width, dst->height);
 
    if ((src_target == PIPE_TEXTURE_1D ||
@@ -1248,24 +1398,82 @@ void util_blitter_copy_texture_view(struct blitter_context *blitter,
                     srcbox->x+srcbox->width, srcbox->y+srcbox->height, coord.f);
 
       /* Draw. */
-      blitter->draw_rectangle(blitter, dstx, dsty, dstx+abs_width, dsty+abs_height, 0,
+      pipe->set_sample_mask(pipe, ~0);
+      blitter->draw_rectangle(blitter, dstx, dsty,
+                              dstx+dst_width, dsty+dst_height, 0,
                               UTIL_BLITTER_ATTRIB_TEXCOORD, &coord);
    } else {
       /* Draw the quad with the generic codepath. */
-      blitter_set_texcoords(ctx, src, src_width0, src_height0, srcbox->z,
-                            src_sample,
-                            srcbox->x, srcbox->y,
-                            srcbox->x + srcbox->width, srcbox->y + srcbox->height);
-      blitter_draw(ctx, dstx, dsty, dstx+abs_width, dsty+abs_height, 0);
+      if (copy_all_samples &&
+          src->texture->nr_samples == dst->texture->nr_samples &&
+          dst->texture->nr_samples > 1) {
+         /* MSAA copy. */
+         unsigned i, max_sample = MAX2(dst->texture->nr_samples, 1) - 1;
+
+         for (i = 0; i <= max_sample; i++) {
+            pipe->set_sample_mask(pipe, 1 << i);
+            blitter_set_texcoords(ctx, src, src_width0, src_height0, srcbox->z,
+                                  i, srcbox->x, srcbox->y,
+                                  srcbox->x + srcbox->width,
+                                  srcbox->y + srcbox->height);
+            blitter_draw(ctx, dstx, dsty,
+                         dstx+dst_width, dsty+dst_height, 0);
+         }
+      } else {
+         pipe->set_sample_mask(pipe, ~0);
+         blitter_set_texcoords(ctx, src, src_width0, src_height0, srcbox->z, 0,
+                               srcbox->x, srcbox->y,
+                               srcbox->x + srcbox->width,
+                               srcbox->y + srcbox->height);
+         blitter_draw(ctx, dstx, dsty, dstx+dst_width, dsty+dst_height, 0);
+      }
    }
 
    blitter_restore_vertex_states(ctx);
    blitter_restore_fragment_states(ctx);
    blitter_restore_textures(ctx);
    blitter_restore_fb_state(ctx);
+   if (scissor) {
+      pipe->set_scissor_state(pipe, &ctx->base.saved_scissor);
+   }
+   blitter_restore_render_cond(ctx);
    blitter_unset_running_flag(ctx);
 }
 
+void
+util_blitter_blit(struct blitter_context *blitter,
+                 const struct pipe_blit_info *info)
+{
+   struct pipe_resource *dst = info->dst.resource;
+   struct pipe_resource *src = info->src.resource;
+   struct blitter_context_priv *ctx = (struct blitter_context_priv*)blitter;
+   struct pipe_context *pipe = ctx->base.pipe;
+   struct pipe_surface *dst_view, dst_templ;
+   struct pipe_sampler_view src_templ, *src_view;
+
+   /* Initialize the surface. */
+   util_blitter_default_dst_texture(&dst_templ, dst, info->dst.level,
+                                    info->dst.box.z, &info->src.box);
+   dst_templ.format = info->dst.format;
+   dst_view = pipe->create_surface(pipe, dst, &dst_templ);
+
+   /* Initialize the sampler view. */
+   util_blitter_default_src_texture(&src_templ, src, info->src.level);
+   src_templ.format = info->src.format;
+   src_view = pipe->create_sampler_view(pipe, src, &src_templ);
+
+   /* Copy. */
+   util_blitter_blit_generic(blitter, dst_view,
+                             info->dst.box.x, info->dst.box.y,
+                             info->dst.box.width, info->dst.box.height,
+                             src_view, &info->src.box, src->width0, src->height0,
+                             info->mask, info->filter,
+                             info->scissor_enable ? &info->scissor : NULL, TRUE);
+
+   pipe_surface_reference(&dst_view, NULL);
+   pipe_sampler_view_reference(&src_view, NULL);
+}
+
 /* Clear a region of a color surface to a constant value. */
 void util_blitter_clear_render_target(struct blitter_context *blitter,
                                       struct pipe_surface *dstsurf,
@@ -1286,11 +1494,12 @@ void util_blitter_clear_render_target(struct blitter_context *blitter,
    blitter_check_saved_vertex_states(ctx);
    blitter_check_saved_fragment_states(ctx);
    blitter_check_saved_fb_state(ctx);
+   blitter_disable_render_cond(ctx);
 
    /* bind states */
-   pipe->bind_blend_state(pipe, ctx->blend_write_color);
+   pipe->bind_blend_state(pipe, ctx->blend[PIPE_MASK_RGBA]);
    pipe->bind_depth_stencil_alpha_state(pipe, ctx->dsa_keep_depth_stencil);
-   pipe->bind_fs_state(pipe, blitter_get_fs_col(ctx, 1, FALSE));
+   ctx->bind_fs_state(pipe, blitter_get_fs_col(ctx, 1, FALSE));
    pipe->bind_vertex_elements_state(pipe, ctx->velem_state);
 
    /* set a framebuffer state */
@@ -1302,7 +1511,7 @@ void util_blitter_clear_render_target(struct blitter_context *blitter,
    pipe->set_framebuffer_state(pipe, &fb_state);
    pipe->set_sample_mask(pipe, ~0);
 
-   blitter_set_common_draw_rect_state(ctx);
+   blitter_set_common_draw_rect_state(ctx, FALSE);
    blitter_set_dst_dimensions(ctx, dstsurf->width, dstsurf->height);
    blitter->draw_rectangle(blitter, dstx, dsty, dstx+width, dsty+height, 0,
                            UTIL_BLITTER_ATTRIB_COLOR, color);
@@ -1310,6 +1519,7 @@ void util_blitter_clear_render_target(struct blitter_context *blitter,
    blitter_restore_vertex_states(ctx);
    blitter_restore_fragment_states(ctx);
    blitter_restore_fb_state(ctx);
+   blitter_restore_render_cond(ctx);
    blitter_unset_running_flag(ctx);
 }
 
@@ -1336,9 +1546,10 @@ void util_blitter_clear_depth_stencil(struct blitter_context *blitter,
    blitter_check_saved_vertex_states(ctx);
    blitter_check_saved_fragment_states(ctx);
    blitter_check_saved_fb_state(ctx);
+   blitter_disable_render_cond(ctx);
 
    /* bind states */
-   pipe->bind_blend_state(pipe, ctx->blend_keep_color);
+   pipe->bind_blend_state(pipe, ctx->blend[0]);
    if ((clear_flags & PIPE_CLEAR_DEPTHSTENCIL) == PIPE_CLEAR_DEPTHSTENCIL) {
       sr.ref_value[0] = stencil & 0xff;
       pipe->bind_depth_stencil_alpha_state(pipe, ctx->dsa_write_depth_stencil);
@@ -1356,7 +1567,7 @@ void util_blitter_clear_depth_stencil(struct blitter_context *blitter,
       /* hmm that should be illegal probably, or make it a no-op somewhere */
       pipe->bind_depth_stencil_alpha_state(pipe, ctx->dsa_keep_depth_stencil);
 
-   pipe->bind_fs_state(pipe, blitter_get_fs_col(ctx, 0, FALSE));
+   ctx->bind_fs_state(pipe, blitter_get_fs_col(ctx, 0, FALSE));
    pipe->bind_vertex_elements_state(pipe, ctx->velem_state);
 
    /* set a framebuffer state */
@@ -1368,14 +1579,16 @@ void util_blitter_clear_depth_stencil(struct blitter_context *blitter,
    pipe->set_framebuffer_state(pipe, &fb_state);
    pipe->set_sample_mask(pipe, ~0);
 
-   blitter_set_common_draw_rect_state(ctx);
+   blitter_set_common_draw_rect_state(ctx, FALSE);
    blitter_set_dst_dimensions(ctx, dstsurf->width, dstsurf->height);
-   blitter->draw_rectangle(blitter, dstx, dsty, dstx+width, dsty+height, depth,
+   blitter->draw_rectangle(blitter, dstx, dsty, dstx+width, dsty+height,
+                           (float) depth,
                            UTIL_BLITTER_ATTRIB_NONE, NULL);
 
    blitter_restore_vertex_states(ctx);
    blitter_restore_fragment_states(ctx);
    blitter_restore_fb_state(ctx);
+   blitter_restore_render_cond(ctx);
    blitter_unset_running_flag(ctx);
 }
 
@@ -1399,11 +1612,13 @@ void util_blitter_custom_depth_stencil(struct blitter_context *blitter,
    blitter_check_saved_vertex_states(ctx);
    blitter_check_saved_fragment_states(ctx);
    blitter_check_saved_fb_state(ctx);
+   blitter_disable_render_cond(ctx);
 
    /* bind states */
-   pipe->bind_blend_state(pipe, ctx->blend_write_color);
+   pipe->bind_blend_state(pipe, cbsurf ? ctx->blend[PIPE_MASK_RGBA] :
+                                         ctx->blend[0]);
    pipe->bind_depth_stencil_alpha_state(pipe, dsa_stage);
-   pipe->bind_fs_state(pipe, blitter_get_fs_col(ctx, 0, FALSE));
+   ctx->bind_fs_state(pipe, blitter_get_fs_col(ctx, 0, FALSE));
    pipe->bind_vertex_elements_state(pipe, ctx->velem_state);
 
    /* set a framebuffer state */
@@ -1421,7 +1636,7 @@ void util_blitter_custom_depth_stencil(struct blitter_context *blitter,
    pipe->set_framebuffer_state(pipe, &fb_state);
    pipe->set_sample_mask(pipe, sample_mask);
 
-   blitter_set_common_draw_rect_state(ctx);
+   blitter_set_common_draw_rect_state(ctx, FALSE);
    blitter_set_dst_dimensions(ctx, zsurf->width, zsurf->height);
    blitter->draw_rectangle(blitter, 0, 0, zsurf->width, zsurf->height, depth,
                            UTIL_BLITTER_ATTRIB_NONE, NULL);
@@ -1429,6 +1644,7 @@ void util_blitter_custom_depth_stencil(struct blitter_context *blitter,
    blitter_restore_vertex_states(ctx);
    blitter_restore_fragment_states(ctx);
    blitter_restore_fb_state(ctx);
+   blitter_restore_render_cond(ctx);
    blitter_unset_running_flag(ctx);
 }
 
@@ -1470,12 +1686,13 @@ void util_blitter_copy_buffer(struct blitter_context *blitter,
 
    blitter_set_running_flag(ctx);
    blitter_check_saved_vertex_states(ctx);
+   blitter_disable_render_cond(ctx);
 
    vb.buffer = src;
    vb.buffer_offset = srcx;
    vb.stride = 4;
 
-   pipe->set_vertex_buffers(pipe, 1, &vb);
+   pipe->set_vertex_buffers(pipe, ctx->base.vb_slot, 1, &vb);
    pipe->bind_vertex_elements_state(pipe, ctx->velem_state_readbuf);
    pipe->bind_vs_state(pipe, ctx->vs_pos_only);
    if (ctx->has_geometry_shader)
@@ -1488,6 +1705,260 @@ void util_blitter_copy_buffer(struct blitter_context *blitter,
    util_draw_arrays(pipe, PIPE_PRIM_POINTS, 0, size / 4);
 
    blitter_restore_vertex_states(ctx);
+   blitter_restore_render_cond(ctx);
    blitter_unset_running_flag(ctx);
    pipe_so_target_reference(&so_target, NULL);
 }
+
+/* probably radeon specific */
+void util_blitter_custom_resolve_color(struct blitter_context *blitter,
+                                      struct pipe_resource *dst,
+                                      unsigned dst_level,
+                                      unsigned dst_layer,
+                                      struct pipe_resource *src,
+                                      unsigned src_layer,
+                                      unsigned sample_mask,
+                                      void *custom_blend,
+                                       enum pipe_format format)
+{
+   struct blitter_context_priv *ctx = (struct blitter_context_priv*)blitter;
+   struct pipe_context *pipe = ctx->base.pipe;
+   struct pipe_framebuffer_state fb_state;
+   struct pipe_surface *srcsurf, *dstsurf, surf_tmpl;
+
+   blitter_set_running_flag(ctx);
+   blitter_check_saved_vertex_states(ctx);
+   blitter_check_saved_fragment_states(ctx);
+   blitter_disable_render_cond(ctx);
+
+   /* bind states */
+   pipe->bind_blend_state(pipe, custom_blend);
+   pipe->bind_depth_stencil_alpha_state(pipe, ctx->dsa_keep_depth_stencil);
+   pipe->bind_vertex_elements_state(pipe, ctx->velem_state);
+   ctx->bind_fs_state(pipe, blitter_get_fs_col(ctx, 1, FALSE));
+   pipe->set_sample_mask(pipe, sample_mask);
+
+   memset(&surf_tmpl, 0, sizeof(surf_tmpl));
+   surf_tmpl.format = format;
+   surf_tmpl.u.tex.level = dst_level;
+   surf_tmpl.u.tex.first_layer = dst_layer;
+   surf_tmpl.u.tex.last_layer = dst_layer;
+   surf_tmpl.usage = PIPE_BIND_RENDER_TARGET;
+
+   dstsurf = pipe->create_surface(pipe, dst, &surf_tmpl);
+
+   surf_tmpl.u.tex.level = 0;
+   surf_tmpl.u.tex.first_layer = src_layer;
+   surf_tmpl.u.tex.last_layer = src_layer;
+
+   srcsurf = pipe->create_surface(pipe, src, &surf_tmpl);
+
+   /* set a framebuffer state */
+   fb_state.width = src->width0;
+   fb_state.height = src->height0;
+   fb_state.nr_cbufs = 2;
+   fb_state.cbufs[0] = srcsurf;
+   fb_state.cbufs[1] = dstsurf;
+   fb_state.zsbuf = NULL;
+   pipe->set_framebuffer_state(pipe, &fb_state);
+
+   blitter_set_common_draw_rect_state(ctx, FALSE);
+   blitter_set_dst_dimensions(ctx, src->width0, src->height0);
+   blitter->draw_rectangle(blitter, 0, 0, src->width0, src->height0,
+                           0, 0, NULL);
+   blitter_restore_fb_state(ctx);
+   blitter_restore_vertex_states(ctx);
+   blitter_restore_fragment_states(ctx);
+   blitter_restore_render_cond(ctx);
+   blitter_unset_running_flag(ctx);
+
+   pipe_surface_reference(&srcsurf, NULL);
+   pipe_surface_reference(&dstsurf, NULL);
+}
+
+void util_blitter_custom_color(struct blitter_context *blitter,
+                               struct pipe_surface *dstsurf,
+                               void *custom_blend)
+{
+   struct blitter_context_priv *ctx = (struct blitter_context_priv*)blitter;
+   struct pipe_context *pipe = ctx->base.pipe;
+   struct pipe_framebuffer_state fb_state;
+
+   assert(dstsurf->texture);
+   if (!dstsurf->texture)
+      return;
+
+   /* check the saved state */
+   blitter_set_running_flag(ctx);
+   blitter_check_saved_vertex_states(ctx);
+   blitter_check_saved_fragment_states(ctx);
+   blitter_check_saved_fb_state(ctx);
+   blitter_disable_render_cond(ctx);
+
+   /* bind states */
+   pipe->bind_blend_state(pipe, custom_blend);
+   pipe->bind_depth_stencil_alpha_state(pipe, ctx->dsa_keep_depth_stencil);
+   ctx->bind_fs_state(pipe, blitter_get_fs_col(ctx, 1, FALSE));
+   pipe->bind_vertex_elements_state(pipe, ctx->velem_state);
+   pipe->set_sample_mask(pipe, (1ull << MAX2(1, dstsurf->texture->nr_samples)) - 1);
+
+   /* set a framebuffer state */
+   fb_state.width = dstsurf->width;
+   fb_state.height = dstsurf->height;
+   fb_state.nr_cbufs = 1;
+   fb_state.cbufs[0] = dstsurf;
+   fb_state.zsbuf = 0;
+   pipe->set_framebuffer_state(pipe, &fb_state);
+   pipe->set_sample_mask(pipe, ~0);
+
+   blitter_set_common_draw_rect_state(ctx, FALSE);
+   blitter_set_dst_dimensions(ctx, dstsurf->width, dstsurf->height);
+   blitter->draw_rectangle(blitter, 0, 0, dstsurf->width, dstsurf->height,
+                           0, 0, NULL);
+
+   blitter_restore_vertex_states(ctx);
+   blitter_restore_fragment_states(ctx);
+   blitter_restore_fb_state(ctx);
+   blitter_restore_render_cond(ctx);
+   blitter_unset_running_flag(ctx);
+}
+
+/* Return whether this is an RGBA, Z, S, or combined ZS format.
+ */
+static unsigned get_format_mask(enum pipe_format format)
+{
+   const struct util_format_description *desc = util_format_description(format);
+
+   assert(desc);
+
+   if (util_format_has_depth(desc)) {
+      if (util_format_has_stencil(desc)) {
+         return PIPE_MASK_ZS;
+      } else {
+         return PIPE_MASK_Z;
+      }
+   } else {
+      if (util_format_has_stencil(desc)) {
+         return PIPE_MASK_S;
+      } else {
+         return PIPE_MASK_RGBA;
+      }
+   }
+}
+
+/* Return if the box is totally inside the resource.
+ */
+static boolean is_box_inside_resource(const struct pipe_resource *res,
+                                      const struct pipe_box *box,
+                                      unsigned level)
+{
+   unsigned width = 1, height = 1, depth = 1;
+
+   switch (res->target) {
+   case PIPE_BUFFER:
+      width = res->width0;
+      height = 1;
+      depth = 1;
+      break;
+   case PIPE_TEXTURE_1D:
+      width = u_minify(res->width0, level);
+      height = 1;
+      depth = 1;
+      break;
+   case PIPE_TEXTURE_2D:
+   case PIPE_TEXTURE_RECT:
+      width = u_minify(res->width0, level);
+      height = u_minify(res->height0, level);
+      depth = 1;
+      break;
+   case PIPE_TEXTURE_3D:
+      width = u_minify(res->width0, level);
+      height = u_minify(res->height0, level);
+      depth = u_minify(res->depth0, level);
+      break;
+   case PIPE_TEXTURE_CUBE:
+      width = u_minify(res->width0, level);
+      height = u_minify(res->height0, level);
+      depth = 6;
+      break;
+   case PIPE_TEXTURE_1D_ARRAY:
+      width = u_minify(res->width0, level);
+      height = 1;
+      depth = res->array_size;
+      break;
+   case PIPE_TEXTURE_2D_ARRAY:
+      width = u_minify(res->width0, level);
+      height = u_minify(res->height0, level);
+      depth = res->array_size;
+      break;
+   case PIPE_MAX_TEXTURE_TYPES:;
+   }
+
+   return box->x >= 0 &&
+          box->x + box->width <= (int) width &&
+          box->y >= 0 &&
+          box->y + box->height <= (int) height &&
+          box->z >= 0 &&
+          box->z + box->depth <= (int) depth;
+}
+
+static unsigned get_sample_count(const struct pipe_resource *res)
+{
+   return res->nr_samples ? res->nr_samples : 1;
+}
+
+boolean util_try_blit_via_copy_region(struct pipe_context *ctx,
+                                      const struct pipe_blit_info *blit)
+{
+   unsigned mask = get_format_mask(blit->dst.format);
+
+   /* No format conversions. */
+   if (blit->src.resource->format != blit->src.format ||
+       blit->dst.resource->format != blit->dst.format ||
+       !util_is_format_compatible(
+          util_format_description(blit->src.resource->format),
+          util_format_description(blit->dst.resource->format))) {
+      return FALSE;
+   }
+
+   /* No masks, no filtering, no scissor. */
+   if ((blit->mask & mask) != mask ||
+       blit->filter != PIPE_TEX_FILTER_NEAREST ||
+       blit->scissor_enable) {
+      return FALSE;
+   }
+
+   /* No flipping. */
+   if (blit->src.box.width < 0 ||
+       blit->src.box.height < 0 ||
+       blit->src.box.depth < 0) {
+      return FALSE;
+   }
+
+   /* No scaling. */
+   if (blit->src.box.width != blit->dst.box.width ||
+       blit->src.box.height != blit->dst.box.height ||
+       blit->src.box.depth != blit->dst.box.depth) {
+      return FALSE;
+   }
+
+   /* No out-of-bounds access. */
+   if (!is_box_inside_resource(blit->src.resource, &blit->src.box,
+                               blit->src.level) ||
+       !is_box_inside_resource(blit->dst.resource, &blit->dst.box,
+                               blit->dst.level)) {
+      return FALSE;
+   }
+
+   /* Sample counts must match. */
+   if (get_sample_count(blit->src.resource) !=
+       get_sample_count(blit->dst.resource)) {
+      return FALSE;
+   }
+
+   ctx->resource_copy_region(ctx, blit->dst.resource, blit->dst.level,
+                             blit->dst.box.x, blit->dst.box.y, blit->dst.box.z,
+                             blit->src.resource, blit->src.level,
+                             &blit->src.box);
+   return TRUE;
+}