svga: fix texture upload path condition
authorCharmaine Lee <charmainel@vmware.com>
Fri, 30 Sep 2016 22:52:14 +0000 (15:52 -0700)
committerBrian Paul <brianp@vmware.com>
Thu, 3 Nov 2016 20:29:22 +0000 (14:29 -0600)
As Thomas suggested, we'll first try to map directly to a GB surface.
If it is blocked, then we'll use texture upload buffer.
Also if a texture is already "rendered to", that is, the GB surface
is already out of sync, then we'll use the texture upload buffer
to avoid syncing the GB surface.

Tested with Lightsmark2008, Tropics, MTT piglit, glretrace.

Reviewed-by: Brian Paul <brianp@vmware.com>
src/gallium/drivers/svga/svga_resource_texture.c

index 5792961ae282c625875a622150962784580b8ca3..28497e45de12e783d39096fc43c8c2b31ad0baa2 100644 (file)
@@ -251,10 +251,32 @@ svga_texture_destroy(struct pipe_screen *screen,
 }
 
 
+/**
+ * Determine if the resource was rendered to
+ */
+static inline boolean
+was_tex_rendered_to(struct pipe_resource *resource,
+                    const struct pipe_transfer *transfer)
+{
+   unsigned face;
+
+   if (resource->target == PIPE_TEXTURE_CUBE) {
+      assert(transfer->box.depth == 1);
+      face = transfer->box.z;
+   }
+   else {
+      face = 0;
+   }
+
+   return svga_was_texture_rendered_to(svga_texture(resource),
+                                       face, transfer->level);
+}
+
+
 /**
  * Determine if we need to read back a texture image before mapping it.
  */
-static boolean
+static inline boolean
 need_tex_readback(struct pipe_transfer *transfer)
 {
    struct svga_texture *t = svga_texture(transfer->resource);
@@ -264,18 +286,7 @@ need_tex_readback(struct pipe_transfer *transfer)
 
    if ((transfer->usage & PIPE_TRANSFER_WRITE) &&
        ((transfer->usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) == 0)) {
-      unsigned face;
-
-      if (transfer->resource->target == PIPE_TEXTURE_CUBE) {
-         assert(transfer->box.depth == 1);
-         face = transfer->box.z;
-      }
-      else {
-         face = 0;
-      }
-      if (svga_was_texture_rendered_to(t, face, transfer->level)) {
-         return TRUE;
-      }
+      return was_tex_rendered_to(transfer->resource, transfer);
    }
 
    return FALSE;
@@ -404,15 +415,6 @@ svga_texture_transfer_map_direct(struct svga_context *svga,
    unsigned w, h, nblocksx, nblocksy;
    unsigned usage = st->base.usage;
 
-   /* we'll directly access the guest-backed surface */
-   w = u_minify(texture->width0, level);
-   h = u_minify(texture->height0, level);
-   nblocksx = util_format_get_nblocksx(texture->format, w);
-   nblocksy = util_format_get_nblocksy(texture->format, h);
-   st->hw_nblocksy = nblocksy;
-   st->base.stride = nblocksx*util_format_get_blocksize(texture->format);
-   st->base.layer_stride = st->base.stride * nblocksy;
-
    if (need_tex_readback(transfer)) {
       enum pipe_error ret;
 
@@ -432,7 +434,6 @@ svga_texture_transfer_map_direct(struct svga_context *svga,
       (void) ret;
 
       svga_context_flush(svga, NULL);
-
       /*
        * Note: if PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE were specified
        * we could potentially clear the flag for all faces/layers/mips.
@@ -457,6 +458,15 @@ svga_texture_transfer_map_direct(struct svga_context *svga,
       }
    }
 
+   /* we'll directly access the guest-backed surface */
+   w = u_minify(texture->width0, level);
+   h = u_minify(texture->height0, level);
+   nblocksx = util_format_get_nblocksx(texture->format, w);
+   nblocksy = util_format_get_nblocksy(texture->format, h);
+   st->hw_nblocksy = nblocksy;
+   st->base.stride = nblocksx*util_format_get_blocksize(texture->format);
+   st->base.layer_stride = st->base.stride * nblocksy;
+
    /*
     * Begin mapping code
     */
@@ -513,7 +523,6 @@ svga_texture_transfer_map_direct(struct svga_context *svga,
                                                st->base.box.x,
                                                st->base.box.y,
                                                st->base.box.z);
-
       return (void *) (map + offset);
    }
 }
@@ -596,13 +605,37 @@ svga_texture_transfer_map(struct pipe_context *pipe,
       map = svga_texture_transfer_map_dma(svga, st);
    }
    else {
-      if (svga_texture_transfer_map_can_upload(svga, st)) {
-         /* upload to the texture upload buffer */
+      boolean can_upload = svga_texture_transfer_map_can_upload(svga, st);
+      boolean was_rendered_to = was_tex_rendered_to(texture, &st->base);
+
+      /* If the texture was already rendered to and upload buffer
+       * is supported, then we will use upload buffer to
+       * avoid the need to read back the texture content; otherwise,
+       * we'll first try to map directly to the GB surface, if it is blocked,
+       * then we'll try the upload buffer.
+       */
+      if (was_rendered_to && can_upload) {
          map = svga_texture_transfer_map_upload(svga, st);
       }
+      else {
+         unsigned orig_usage = st->base.usage;
+
+         /* try direct map to the GB surface */
+         if (can_upload)
+            st->base.usage |= PIPE_TRANSFER_DONTBLOCK;
+         map = svga_texture_transfer_map_direct(svga, st);
+         st->base.usage = orig_usage;
+
+         if (!map && can_upload) {
+            /* if direct map with DONTBLOCK fails, then try upload to the
+             * texture upload buffer.
+             */
+            map = svga_texture_transfer_map_upload(svga, st);
+         }
+      }
 
+      /* if upload fails, then try direct map again without DONTBLOCK */
       if (!map) {
-         /* map directly to the GBS surface */
          map = svga_texture_transfer_map_direct(svga, st);
       }
    }
@@ -1299,9 +1332,6 @@ svga_texture_transfer_map_can_upload(struct svga_context *svga,
 {
    struct pipe_resource *texture = st->base.resource;
 
-   if (!svga_have_vgpu10(svga))
-      return FALSE;
-
    if (svga_sws(svga)->have_transfer_from_buffer_cmd == FALSE)
       return FALSE;