svga: Rework the blit and resource_copy_region functionality v3
authorThomas Hellstrom <thellstrom@vmware.com>
Tue, 11 Apr 2017 13:18:04 +0000 (15:18 +0200)
committerThomas Hellstrom <thellstrom@vmware.com>
Fri, 16 Jun 2017 06:40:26 +0000 (08:40 +0200)
This work was initially trigged by the fact that imported surfaces may
be backed by other SVGA3D formats than the default. Therefore some fixes were
needed to avoid using the copy_region_vgpu10() functionality for incompatible
SVGA3D formats where the pipe formats were OK. This situation happens when
using dri3.

Also in some situations, for example where a R8G8_UNORM surface is backed by
an SVGA3D_NV12 format, we can't use the copy_region functionality at all and
thus need to fall back to the quad blitter also for the resource_copy_region
function. This situation doesn't happen currently, but will if we start using
video textures.

The patch makes the blit- and copy_region paths similar and the decision whether
to use a certain gpu command should now be easy to locate. Probably the
resource_copy_region path will suffer from a minor additional cpu overhead,
but on the other hand there are more cases now that we accelerate, since
we try harder before falling back to cpu copies / blits.

v2: Addressed review comments and fixed up piglit failures by sometimes
preferring cpu_copy_region() over blit().
v3: Removed a stray test statement. Updated commit message.

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Brian Paul <brianp@vmware.com>
Reviewed-by: Charmaine Lee <charmainel@vmware.com>
src/gallium/drivers/svga/svga_pipe_blit.c

index 23f5946b14e742fba763dafe2be5e58c69bc4138..677d78ca71c61ef49abbdf0f897db47254961d18 100644 (file)
@@ -1,5 +1,5 @@
 /**********************************************************
- * Copyright 2008-2009 VMware, Inc.  All rights reserved.
+ * Copyright 2008-2017 VMware, Inc.  All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person
  * obtaining a copy of this software and associated documentation
 #define FILE_DEBUG_FLAG DEBUG_BLIT
 
 
+/**
+ * Build a struct pipe_blit_info object from the arguments used by the
+ * pipe::resource_copy_region() function.
+ */
+static void
+build_blit_info(struct pipe_resource *dst_tex,
+                unsigned dst_level,
+                unsigned dst_x,
+                unsigned dst_y,
+                unsigned dst_z,
+                struct pipe_resource *src_tex,
+                unsigned src_level,
+                const struct pipe_box *src_box,
+                struct pipe_blit_info *blit)
+{
+   memset(blit, 0, sizeof(*blit));
+
+   blit->src.format = src_tex->format;
+   blit->dst.format = dst_tex->format;
+
+   blit->mask = util_format_get_mask(blit->dst.format);
+   blit->filter = PIPE_TEX_FILTER_NEAREST;
+   blit->src.resource = src_tex;
+   blit->src.level = src_level;
+   blit->dst.resource = dst_tex;
+   blit->dst.level = dst_level;
+   blit->src.box = *src_box;
+   u_box_3d(dst_x, dst_y, dst_z, src_box->width, src_box->height,
+            src_box->depth, &blit->dst.box);
+}
+
+
 /**
  * Copy an image between textures with the vgpu10 CopyRegion command.
  */
@@ -58,6 +90,8 @@ copy_region_vgpu10(struct svga_context *svga, struct pipe_resource *src_tex,
    stex = svga_texture(src_tex);
    dtex = svga_texture(dst_tex);
 
+   svga_surfaces_flush(svga);
+
    box.x = dst_x;
    box.y = dst_y;
    box.z = dst_z;
@@ -90,6 +124,26 @@ copy_region_vgpu10(struct svga_context *svga, struct pipe_resource *src_tex,
 }
 
 
+/**
+ * Fallback to the copy region utility which uses map/memcpy for the copy
+ */
+static void
+copy_region_fallback(struct svga_context *svga, 
+                     struct pipe_resource *dst_tex, unsigned dst_level,
+                     unsigned dstx, unsigned dsty, unsigned dstz,
+                     struct pipe_resource *src_tex, unsigned src_level,
+                     const struct pipe_box *src_box)
+{
+   struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws;
+
+   SVGA_STATS_TIME_PUSH(sws, SVGA_STATS_TIME_COPYREGIONFALLBACK);
+   util_resource_copy_region(&svga->pipe, dst_tex, dst_level, dstx,
+                             dsty, dstz, src_tex, src_level, src_box);
+   SVGA_STATS_TIME_POP(sws);
+   (void) sws;
+}
+
+
 /**
  * For some texture types, we need to move the z (slice) coordinate
  * to the layer value.  For example, to select the z=3 slice of a 2D ARRAY
@@ -112,123 +166,133 @@ adjust_z_layer(enum pipe_texture_target target,
 }
 
 
-static void
-svga_resource_copy_region(struct pipe_context *pipe,
-                          struct pipe_resource *dst_tex,
-                          unsigned dst_level,
-                          unsigned dstx, unsigned dsty, unsigned dstz,
-                          struct pipe_resource *src_tex,
-                          unsigned src_level,
-                          const struct pipe_box *src_box)
+/**
+ * Are the given SVGA3D formats compatible, in terms of vgpu10's
+ * PredCopyRegion() command?
+ */
+static bool
+formats_compatible(const struct svga_screen *ss,
+                   SVGA3dSurfaceFormat src_svga_fmt,
+                   SVGA3dSurfaceFormat dst_svga_fmt)
 {
-   struct svga_context *svga = svga_context(pipe);
-   struct svga_texture *stex, *dtex;
-   unsigned dst_face_layer, dst_z, src_face_layer, src_z;
-
-   /* Emit buffered drawing commands, and any back copies.
-    */
-   svga_surfaces_flush( svga );
+   src_svga_fmt = svga_typeless_format(src_svga_fmt);
+   dst_svga_fmt = svga_typeless_format(dst_svga_fmt);
 
-   if (dst_tex->target == PIPE_BUFFER && src_tex->target == PIPE_BUFFER) {
-      /* can't copy within the same buffer, unfortunately */
-      if (svga_have_vgpu10(svga) && src_tex != dst_tex) {
-         enum pipe_error ret;
-         struct svga_winsys_surface *src_surf;
-         struct svga_winsys_surface *dst_surf;
-         struct svga_buffer *dbuffer = svga_buffer(dst_tex);
+   return src_svga_fmt == dst_svga_fmt;
+}
 
-         src_surf = svga_buffer_handle(svga, src_tex);
-         dst_surf = svga_buffer_handle(svga, dst_tex);
 
-         ret = SVGA3D_vgpu10_BufferCopy(svga->swc, src_surf, dst_surf,
-                                        src_box->x, dstx, src_box->width);
-         if (ret != PIPE_OK) {
-            svga_context_flush(svga, NULL);
-            ret = SVGA3D_vgpu10_BufferCopy(svga->swc, src_surf, dst_surf,
-                                           src_box->x, dstx, src_box->width);
-            assert(ret == PIPE_OK);
+/**
+ * Check whether the blending is enabled or not
+ */
+static bool
+is_blending_enabled(struct svga_context *svga,
+                    const struct pipe_blit_info *blit)
+{
+   bool blend_enable = false;
+   int i;
+   if (svga->curr.blend) {
+      if (svga->curr.blend->independent_blend_enable) {
+         for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
+            if (svga->curr.framebuffer.cbufs[i]->texture == blit->dst.resource) {
+               if (svga->curr.blend->rt[i].blend_enable) {
+                  blend_enable = true;
+               }
+               break;
+            }
          }
-
-         dbuffer->dirty = TRUE;
       }
       else {
-         /* use map/memcpy fallback */
-         util_resource_copy_region(pipe, dst_tex, dst_level, dstx,
-                                   dsty, dstz, src_tex, src_level, src_box);
+         if (svga->curr.blend->rt[0].blend_enable)
+            blend_enable = true;
       }
-      return;
    }
+   return blend_enable;
+}
 
-   stex = svga_texture(src_tex);
-   dtex = svga_texture(dst_tex);
 
-   adjust_z_layer(src_tex->target, src_box->z, &src_face_layer, &src_z);
-   adjust_z_layer(dst_tex->target, dstz, &dst_face_layer, &dst_z);
-
-   if (svga_have_vgpu10(svga)) {
-      /* vgpu10 */
-      if (util_format_is_compressed(src_tex->format) ==
-          util_format_is_compressed(dst_tex->format) &&
-          stex->handle != dtex->handle &&
-          svga_resource_type(src_tex->target) ==
-          svga_resource_type(dst_tex->target) &&
-          stex->b.b.nr_samples == dtex->b.b.nr_samples) {
-         copy_region_vgpu10(svga,
-                            src_tex,
-                            src_box->x, src_box->y, src_z,
-                            src_level, src_face_layer,
-                            dst_tex,
-                            dstx, dsty, dst_z,
-                            dst_level, dst_face_layer,
-                            src_box->width, src_box->height, src_box->depth);
-      }
-      else {
-         util_resource_copy_region(pipe, dst_tex, dst_level, dstx, dsty, dstz,
-                                   src_tex, src_level, src_box);
-      }
+/**
+ * If GL_FRAMEBUFFER_SRGB is enabled, then output colorspace is
+ * expected to be sRGB if blending is not enabled.
+ * If GL_FRAMEBUFFER_SRGB is disabled, then we can use
+ * copy_region_vgpu10()
+ * Following table basically tells when copy_region_vgpu10 can be
+ * used if GL_FRAMEBUFFER_SRGB is enabled.
+ * ______________________________________________________________
+ *  | src fmt     | dst_fmt   | blending  |Can use       |
+ *  |             |           |           |copy_region   |
+ * ______________________________________________________________
+ *  | linear      | linear    |   N       |     Y        |
+ *  | linear      | linear    |   Y       |     Y        |
+ *  | linear      | sRGB      |   N       |     N        |
+ *  | linear      | sRGB      |   Y       |     Y        |
+ *  | sRGB        | linear    |   N       |     N        |
+ *  | sRGB        | linear    |   Y       |     N        |
+ *  | sRGB        | sRGB      |   N       |     Y        |
+ *  | sRGB        | sRGB      |   Y       |     N        |
+ * ______________________________________________________________
+ *
+ */
+static bool
+check_blending_and_srgb_cond(struct svga_context *svga,
+                             const struct pipe_blit_info *blit)
+{
+   enum pipe_format sFmt = blit->src.format;
+   enum pipe_format dFmt = blit->dst.format;
+
+   if (is_blending_enabled(svga, blit)) {
+      if (!util_format_is_srgb(blit->src.format))
+         return true;
    }
    else {
-      /* vgpu9 */
-      if (src_tex->format == dst_tex->format) {
-         svga_texture_copy_handle(svga,
-                                  stex->handle,
-                                  src_box->x, src_box->y, src_z,
-                                  src_level, src_face_layer,
-                                  dtex->handle,
-                                  dstx, dsty, dst_z,
-                                   dst_level, dst_face_layer,
-                                  src_box->width, src_box->height,
-                                  src_box->depth);
-      }
-      else {
-         util_resource_copy_region(pipe, dst_tex, dst_level, dstx, dsty, dstz,
-                                   src_tex, src_level, src_box);
+      if (util_format_is_srgb(sFmt) && util_format_is_srgb(dFmt))
+         return true;
+      else if (!util_format_is_srgb(sFmt)){
+         if (!util_format_is_srgb(dFmt))
+            return true;
+         else {
+           /**
+            * State tracker converts all sRGB src blit format
+            * to linear if GL_FRAMEBUFFER_SRGB is disabled.
+            * So if src resource format is sRGB and
+            * blit format is linear then it means,
+            * GL_FRAMEBUFFER_SRGB is disabled. In this case also
+            * we can use copy_region_vgpu10().
+            */
+
+            if (util_format_is_srgb(blit->src.resource->format))
+               return true;
+         }
       }
    }
-
-   /* Mark the destination image as being defined */
-   svga_define_texture_level(dtex, dst_face_layer, dst_level);
+   return false;
 }
 
-
 /**
- * Are the given pipe formats compatible, in terms of vgpu10's
- * PredCopyRegion() command?
+ * Do common checks for svga surface copy.
  */
 static bool
-formats_compatible(const struct svga_screen *ss,
-                   enum pipe_format src_fmt,
-                   enum pipe_format dst_fmt)
+can_blit_via_svga_copy_region(struct svga_context *svga,
+                              const struct pipe_blit_info *blit_info)
 {
-   SVGA3dSurfaceFormat src_svga_fmt, dst_svga_fmt;
+   /* check that the blit src/dst regions are same size, no flipping, etc. */
+   if (blit_info->src.box.width != blit_info->dst.box.width ||
+       blit_info->src.box.height != blit_info->dst.box.height)
+      return false;
 
-   src_svga_fmt = svga_translate_format(ss, src_fmt, PIPE_BIND_SAMPLER_VIEW);
-   dst_svga_fmt = svga_translate_format(ss, dst_fmt, PIPE_BIND_SAMPLER_VIEW);
+   /* For depth+stencil formats, copy with mask != PIPE_MASK_ZS is not
+    * supported
+    */
+   if (util_format_is_depth_and_stencil(blit_info->src.format) &&
+      blit_info->mask != (PIPE_MASK_ZS))
+     return false;
 
-   src_svga_fmt = svga_typeless_format(src_svga_fmt);
-   dst_svga_fmt = svga_typeless_format(dst_svga_fmt);
+   if (blit_info->alpha_blend ||
+       (svga->render_condition && blit_info->render_condition_enable) ||
+       blit_info->scissor_enable)
+      return false;
 
-   return src_svga_fmt == dst_svga_fmt;
+   return check_blending_and_srgb_cond(svga, blit_info);
 }
 
 
@@ -244,45 +308,107 @@ can_blit_via_copy_region_vgpu10(struct svga_context *svga,
 {
    struct svga_texture *dtex, *stex;
 
-   if (!svga_have_vgpu10(svga))
+   /* can't copy between different resource types */
+   if (svga_resource_type(blit_info->src.resource->target) !=
+       svga_resource_type(blit_info->dst.resource->target))
       return false;
 
    stex = svga_texture(blit_info->src.resource);
    dtex = svga_texture(blit_info->dst.resource);
 
-   /* can't copy within one resource */
+   if (!svga_have_vgpu10(svga))
+      return false;
+
    if (stex->handle == dtex->handle)
       return false;
 
+   return formats_compatible(svga_screen(svga->pipe.screen),
+                             stex->key.format,
+                             dtex->key.format);
+}
+
+
+/**
+ * Check whether we can blit using the surface_copy command.
+ */
+static bool
+can_blit_via_surface_copy(struct svga_context *svga,
+                          const struct pipe_blit_info *blit_info)
+{
+   struct svga_texture *dtex, *stex;
+
    /* can't copy between different resource types */
    if (svga_resource_type(blit_info->src.resource->target) !=
        svga_resource_type(blit_info->dst.resource->target))
       return false;
 
-   /* check that the blit src/dst regions are same size, no flipping, etc. */
-   if (blit_info->src.box.width != blit_info->dst.box.width ||
-       blit_info->src.box.height != blit_info->dst.box.height)
-      return false;
+   stex = svga_texture(blit_info->src.resource);
+   dtex = svga_texture(blit_info->dst.resource);
 
-   /* check that sample counts are the same */
-   if (stex->b.b.nr_samples != dtex->b.b.nr_samples)
+   if (stex->handle == dtex->handle)
       return false;
 
-   /* For depth+stencil formats, copy with mask != PIPE_MASK_ZS is not
-    * supported
+   /*
+    * This is what we've been using before, but it can probably be
+    * relaxed. The device checks are less stringent.
     */
-   if (util_format_is_depth_and_stencil(blit_info->src.format) &&
-      blit_info->mask != (PIPE_MASK_ZS))
-     return false;
+   return (stex->b.b.format == dtex->b.b.format);
+}
 
-   if (blit_info->alpha_blend ||
-       (svga->render_condition && blit_info->render_condition_enable) ||
-       blit_info->scissor_enable)
+
+/**
+ * Try region copy using one of the region copy commands
+ */
+static bool
+try_copy_region(struct svga_context *svga,
+                const struct pipe_blit_info *blit)
+{
+   unsigned src_face, src_z, dst_face, dst_z;
+
+   if (!can_blit_via_svga_copy_region(svga, blit))
       return false;
 
-   return formats_compatible(svga_screen(svga->pipe.screen),
-                             blit_info->src.resource->format,
-                             blit_info->dst.resource->format);
+   adjust_z_layer(blit->src.resource->target, blit->src.box.z,
+                  &src_face, &src_z);
+
+   adjust_z_layer(blit->dst.resource->target, blit->dst.box.z,
+                  &dst_face, &dst_z);
+
+   if (can_blit_via_copy_region_vgpu10(svga, blit)) {
+      copy_region_vgpu10(svga,
+                         blit->src.resource,
+                         blit->src.box.x, blit->src.box.y, src_z,
+                         blit->src.level, src_face,
+                         blit->dst.resource,
+                         blit->dst.box.x, blit->dst.box.y, dst_z,
+                         blit->dst.level, dst_face,
+                         blit->src.box.width, blit->src.box.height,
+                         blit->src.box.depth);
+      return true;
+   }
+
+   if (can_blit_via_surface_copy(svga, blit)) {
+      struct svga_texture *stex = svga_texture(blit->src.resource);
+      struct svga_texture *dtex = svga_texture(blit->dst.resource);
+
+      svga_surfaces_flush(svga);
+
+      svga_texture_copy_handle(svga,
+                               stex->handle,
+                               blit->src.box.x, blit->src.box.y, src_z,
+                               blit->src.level, src_face,
+                               dtex->handle,
+                               blit->dst.box.x, blit->dst.box.y, dst_z,
+                               blit->dst.level, dst_face,
+                               blit->src.box.width, blit->src.box.height,
+                               blit->src.box.depth);
+
+      svga_define_texture_level(dtex, dst_face, blit->dst.level);
+      svga_set_texture_rendered_to(dtex, dst_face, blit->dst.level);
+      return true;
+   }
+
+   return false;
 }
 
 
@@ -311,58 +437,30 @@ is_view_format_compatible(enum pipe_format surf_fmt,
 }
 
 
-static void
-svga_blit(struct pipe_context *pipe,
-          const struct pipe_blit_info *blit_info)
+/**
+ * Try issuing a quad blit.
+ */
+static bool
+try_blit(struct svga_context *svga, const struct pipe_blit_info *blit_info)
 {
-   struct svga_context *svga = svga_context(pipe);
-   struct pipe_blit_info blit = *blit_info;
-   struct pipe_resource *src = blit.src.resource;
-   struct pipe_resource *dst = blit.dst.resource;
+   struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws;
+   struct pipe_resource *src = blit_info->src.resource;
+   struct pipe_resource *dst = blit_info->dst.resource;
    struct pipe_resource *newSrc = NULL;
    struct pipe_resource *newDst = NULL;
    bool can_create_src_view;
    bool can_create_dst_view;
+   bool ret = true;
+   struct pipe_blit_info blit = *blit_info;
 
-   if (!svga_have_vgpu10(svga) &&
-       blit.src.resource->nr_samples > 1 &&
-       blit.dst.resource->nr_samples <= 1 &&
-       !util_format_is_depth_or_stencil(blit.src.resource->format) &&
-       !util_format_is_pure_integer(blit.src.resource->format)) {
-      debug_printf("svga: color resolve unimplemented\n");
-      return;
-   }
-
-   if (can_blit_via_copy_region_vgpu10(svga, blit_info)) {
-      unsigned src_face, src_z, dst_face, dst_z;
-
-      adjust_z_layer(blit.src.resource->target, blit.src.box.z,
-                     &src_face, &src_z);
-
-      adjust_z_layer(blit.dst.resource->target, blit.dst.box.z,
-                     &dst_face, &dst_z);
-
-      copy_region_vgpu10(svga,
-                         blit.src.resource,
-                         blit.src.box.x, blit.src.box.y, src_z,
-                         blit.src.level, src_face,
-                         blit.dst.resource,
-                         blit.dst.box.x, blit.dst.box.y, dst_z,
-                         blit.dst.level, dst_face,
-                         blit.src.box.width, blit.src.box.height,
-                         blit.src.box.depth);
-      return;
-   }
-
-   if (util_can_blit_via_copy_region(blit_info, TRUE) ||
-       util_can_blit_via_copy_region(blit_info, FALSE)) {
-      util_resource_copy_region(pipe, 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; /* done */
-   }
+   SVGA_STATS_TIME_PUSH(sws, SVGA_STATS_TIME_BLITBLITTER);
+   
+   /**
+    * If format is srgb and blend is enabled then color values need
+    * to be converted into linear format.
+    */
+   if (is_blending_enabled(svga, &blit))
+      blit.src.format = util_format_linear(blit.src.format);
 
    /* Check if we can create shader resource view and
     * render target view for the quad blitter to work
@@ -377,12 +475,19 @@ svga_blit(struct pipe_context *pipe,
 
    if ((blit.mask & PIPE_MASK_S) ||
        ((!can_create_dst_view || !can_create_src_view)
-        && !svga_have_vgpu10(svga)) ||
-       !util_blitter_is_blit_supported(svga->blitter, &blit)) {
+        && !svga_have_vgpu10(svga))) {
+      /* Can't do stencil blits with textured quad blitter */
+      debug_warn_once("using software stencil blit");
+      ret = false;
+      goto done;
+   }
+
+   if (!util_blitter_is_blit_supported(svga->blitter, &blit)) {
       debug_printf("svga: blit unsupported %s -> %s\n",
                    util_format_short_name(blit.src.resource->format),
                    util_format_short_name(blit.dst.resource->format));
-      return;
+      ret = false;
+      goto done;
    }
 
    /* XXX turn off occlusion and streamout queries */
@@ -414,7 +519,7 @@ svga_blit(struct pipe_context *pipe,
 
    if (!can_create_src_view) {
       struct pipe_resource template;
-      unsigned src_face, src_z;
+      struct pipe_blit_info copy_region_blit;
 
       /**
        * If the source blit format is not compatible with the source resource
@@ -429,30 +534,30 @@ svga_blit(struct pipe_context *pipe,
       newSrc = svga_texture_create(svga->pipe.screen, &template);
       if (newSrc == NULL) {
          debug_printf("svga_blit: fails to create temporary src\n");
-         return;
+         ret = false;
+         goto done;
       }
 
-      /* Copy from original resource to the temporary resource */
-      adjust_z_layer(blit.src.resource->target, blit.src.box.z,
-                     &src_face, &src_z);
-
-      copy_region_vgpu10(svga,
-                         blit.src.resource,
-                         blit.src.box.x, blit.src.box.y, src_z,
-                         blit.src.level, src_face,
-                         newSrc,
-                         blit.src.box.x, blit.src.box.y, src_z,
-                         blit.src.level, src_face,
-                         blit.src.box.width, blit.src.box.height,
-                         blit.src.box.depth);
+      /* increment the mksStats for blitter with extra copy */
+      SVGA_STATS_COUNT_INC(sws, SVGA_STATS_COUNT_BLITBLITTERCOPY);
+      build_blit_info(newSrc,
+                      blit.src.level, blit.src.box.x,
+                      blit.src.box.y, blit.src.box.z,
+                      blit.src.resource,
+                      blit.src.level, &blit.src.box,
+                      &copy_region_blit);
+      if (!try_copy_region(svga, &copy_region_blit)) {
+         ret = false;
+         goto done;
+      }
 
       blit.src.resource = newSrc;
    }
-   
+
    if (!can_create_dst_view) {
       struct pipe_resource template;
 
-      /**
+      /*
        * If the destination blit format is not compatible with the destination
        * resource format, we will not be able to create a render target view.
        * In order to avoid falling back to software blit, we'll create
@@ -465,7 +570,8 @@ svga_blit(struct pipe_context *pipe,
       newDst = svga_texture_create(svga->pipe.screen, &template);
       if (newDst == NULL) {
          debug_printf("svga_blit: fails to create temporary dst\n");
-         return;
+         ret = false;
+         goto done;
       }
 
       blit.dst.resource = newDst;
@@ -474,38 +580,173 @@ svga_blit(struct pipe_context *pipe,
    util_blitter_blit(svga->blitter, &blit);
 
    if (blit.dst.resource != dst) {
-      unsigned dst_face, dst_z;
+      struct pipe_blit_info copy_region_blit;
 
-      adjust_z_layer(blit.dst.resource->target, blit.dst.box.z,
-                     &dst_face, &dst_z);
+      /* increment the mksStats for blitter with extra copy */
+      SVGA_STATS_COUNT_INC(sws, SVGA_STATS_COUNT_BLITBLITTERCOPY);
 
-      /**
+      /*
        * A temporary resource was created for the blit, we need to
        * copy from the temporary resource back to the original destination.
        */
-      copy_region_vgpu10(svga,
-                         blit.dst.resource,
-                         blit.dst.box.x, blit.dst.box.y, dst_z,
-                         blit.dst.level, dst_face,
-                         dst,
-                         blit.dst.box.x, blit.dst.box.y, dst_z,
-                         blit.dst.level, dst_face,
-                         blit.dst.box.width, blit.dst.box.height,
-                         blit.dst.box.depth);
-
-      /* unreference the temporary resource */
-      pipe_resource_reference(&newDst, NULL);
-      blit.dst.resource = dst;
+      build_blit_info(blit.dst.resource,
+                      blit.dst.level, blit.dst.box.x,
+                      blit.dst.box.y, blit.dst.box.z,
+                      newDst,
+                      blit.dst.level, &blit.dst.box,
+                      &copy_region_blit);
+      if (!try_copy_region(svga, &copy_region_blit)) {
+         ret = false;
+         goto done;
+      }
+   }
+
+done:
+   /* unreference the temporary resources if needed */
+   pipe_resource_reference(&newDst, NULL);
+   pipe_resource_reference(&newSrc, NULL);
+
+   SVGA_STATS_TIME_POP(sws);  /* SVGA_STATS_TIME_BLITBLITTER */
+   (void) sws;
+
+   return ret;
+}
+
+
+/**
+ * Try a cpu copy_region fallback.
+ */
+static bool
+try_cpu_copy_region(struct svga_context *svga,
+                    const struct pipe_blit_info *blit)
+{
+   if (util_can_blit_via_copy_region(blit, TRUE) ||
+       util_can_blit_via_copy_region(blit, FALSE)) {
+      copy_region_fallback(svga, 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;
+   }
+
+   return false;
+}
+
+
+/**
+ * The pipe::blit member.
+ */
+static void
+svga_blit(struct pipe_context *pipe,
+          const struct pipe_blit_info *blit)
+{
+   struct svga_context *svga = svga_context(pipe);
+   struct svga_winsys_screen *sws = svga_screen(pipe->screen)->sws;
+
+   if (!svga_have_vgpu10(svga) &&
+       blit->src.resource->nr_samples > 1 &&
+       blit->dst.resource->nr_samples <= 1 &&
+       !util_format_is_depth_or_stencil(blit->src.resource->format) &&
+       !util_format_is_pure_integer(blit->src.resource->format)) {
+      debug_printf("svga: color resolve unimplemented\n");
+      return;
    }
 
-   if (blit.src.resource != src) {
-      /* unreference the temporary resource */
-      pipe_resource_reference(&newSrc, NULL);
-      blit.src.resource = src;
+   SVGA_STATS_TIME_PUSH(sws, SVGA_STATS_TIME_BLIT);
+
+   if (try_copy_region(svga, blit))
+      goto done;
+
+   /* FIXME: Ideally, we should call try_blit() before try_cpu_copy_region(),
+    * however that breaks piglit test gl-1.0-scissor-copypixels.
+    */
+   if (try_cpu_copy_region(svga, blit))
+      goto done;
+
+   if (try_blit(svga, blit))
+      debug_printf("svga: Blit failed.\n");
+done:
+   SVGA_STATS_TIME_POP(sws);  /* SVGA_STATS_TIME_BLIT */
+   (void) sws;
+}
+
+
+/**
+ * The pipe::resource_copy_region member.
+ */
+static void
+svga_resource_copy_region(struct pipe_context *pipe,
+                          struct pipe_resource *dst_tex,
+                          unsigned dst_level,
+                          unsigned dstx, unsigned dsty, unsigned dstz,
+                          struct pipe_resource *src_tex,
+                          unsigned src_level,
+                          const struct pipe_box *src_box)
+{
+   struct svga_context *svga = svga_context(pipe);
+   struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws;
+
+   SVGA_STATS_TIME_PUSH(sws, SVGA_STATS_TIME_COPYREGION);
+
+   if (dst_tex->target == PIPE_BUFFER && src_tex->target == PIPE_BUFFER) {
+      /* can't copy within the same buffer, unfortunately */
+      if (svga_have_vgpu10(svga) && src_tex != dst_tex) {
+         enum pipe_error ret;
+         struct svga_winsys_surface *src_surf;
+         struct svga_winsys_surface *dst_surf;
+         struct svga_buffer *dbuffer = svga_buffer(dst_tex);
+
+         src_surf = svga_buffer_handle(svga, src_tex);
+         dst_surf = svga_buffer_handle(svga, dst_tex);
+
+         ret = SVGA3D_vgpu10_BufferCopy(svga->swc, src_surf, dst_surf,
+                                        src_box->x, dstx, src_box->width);
+         if (ret != PIPE_OK) {
+            svga_context_flush(svga, NULL);
+            ret = SVGA3D_vgpu10_BufferCopy(svga->swc, src_surf, dst_surf,
+                                           src_box->x, dstx, src_box->width);
+            assert(ret == PIPE_OK);
+         }
+
+         dbuffer->dirty = TRUE;
+      }
+      else {
+         /* use map/memcpy fallback */
+         copy_region_fallback(svga, dst_tex, dst_level, dstx,
+                              dsty, dstz, src_tex, src_level, src_box);
+      }
+   } else {
+      struct pipe_blit_info blit;
+
+      build_blit_info(dst_tex, dst_level, dstx, dsty, dstz,
+                      src_tex, src_level, src_box, &blit);
+
+      if (try_copy_region(svga, &blit))
+         goto done;
+
+      /* Blits are format-converting which is not what we want, so perform a
+       * strict format-check.
+       * FIXME: Also blits appear broken with 3D source textures.
+       */
+      if (src_tex->format == dst_tex->format &&
+          svga_resource_type(src_tex->target) != SVGA3D_RESOURCE_TEXTURE3D &&
+          try_blit(svga, &blit))
+         goto done;
+
+      copy_region_fallback(svga, dst_tex, dst_level, dstx, dsty, dstz,
+                           src_tex, src_level, src_box);
    }
+
+done:
+   SVGA_STATS_TIME_POP(sws);
+   (void) sws;
 }
 
 
+/**
+ * The pipe::flush_resource member.
+ */
 static void
 svga_flush_resource(struct pipe_context *pipe,
                     struct pipe_resource *resource)
@@ -513,6 +754,9 @@ svga_flush_resource(struct pipe_context *pipe,
 }
 
 
+/**
+ * Setup the pipe blit, resource_copy_region and flush_resource members.
+ */
 void
 svga_init_blit_functions(struct svga_context *svga)
 {