svga: refactor svga_texture_transfer_map/unmap functions
authorCharmaine Lee <charmainel@vmware.com>
Fri, 2 Sep 2016 00:45:28 +0000 (17:45 -0700)
committerBrian Paul <brianp@vmware.com>
Sat, 17 Sep 2016 16:24:12 +0000 (10:24 -0600)
Split the functions into separate functions for dma and direct map to make
the code more readable.

Tested with MTT piglit, glretrace, viewperf, conform, various OpenGL apps

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

index 484a24049d9d2702b82bf350742e5605ffab1532..85e1805c546ffb0d9027fb8cbc9a93836200c811 100644 (file)
@@ -200,6 +200,7 @@ svga_transfer_dma(struct svga_context *svga,
 }
 
 
+
 static boolean
 svga_texture_get_handle(struct pipe_screen *screen,
                         struct pipe_resource *texture,
@@ -317,221 +318,164 @@ readback_image_vgpu10(struct svga_context *svga,
 }
 
 
+/**
+ * Use DMA for the transfer request
+ */
 static void *
-svga_texture_transfer_map(struct pipe_context *pipe,
-                          struct pipe_resource *texture,
-                          unsigned level,
-                          unsigned usage,
-                          const struct pipe_box *box,
-                          struct pipe_transfer **ptransfer)
+svga_texture_transfer_map_dma(struct svga_context *svga,
+                              struct svga_transfer *st)
 {
-   struct svga_context *svga = svga_context(pipe);
-   struct svga_screen *ss = svga_screen(pipe->screen);
-   struct svga_winsys_screen *sws = ss->sws;
-   struct svga_texture *tex = svga_texture(texture);
-   struct svga_transfer *st;
+   struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws;
+   struct pipe_resource *texture = st->base.resource;
    unsigned nblocksx, nblocksy;
-   boolean use_direct_map = svga_have_gb_objects(svga) &&
-      !svga_have_gb_dma(svga);
    unsigned d;
-   void *returnVal = NULL;
-   int64_t begin = svga_get_time(svga);
+   unsigned usage = st->base.usage;
 
-   SVGA_STATS_TIME_PUSH(sws, SVGA_STATS_TIME_TEXTRANSFERMAP);
-
-   /* We can't map texture storage directly unless we have GB objects */
-   if (usage & PIPE_TRANSFER_MAP_DIRECTLY) {
-      if (svga_have_gb_objects(svga))
-         use_direct_map = TRUE;
-      else
-         goto done;
-   }
-
-   st = CALLOC_STRUCT(svga_transfer);
-   if (!st)
-      goto done;
-
-   st->base.level = level;
-   st->base.usage = usage;
-   st->base.box = *box;
+   /* we'll put the data into a tightly packed buffer */
+   nblocksx = util_format_get_nblocksx(texture->format, st->base.box.width);
+   nblocksy = util_format_get_nblocksy(texture->format, st->base.box.height);
+   d = st->base.box.depth;
 
-   switch (tex->b.b.target) {
-   case PIPE_TEXTURE_CUBE:
-      st->slice = st->base.box.z;
-      st->base.box.z = 0;   /* so we don't apply double offsets below */
-      break;
-   case PIPE_TEXTURE_2D_ARRAY:
-   case PIPE_TEXTURE_1D_ARRAY:
-      st->slice = st->base.box.z;
-      st->base.box.z = 0;   /* so we don't apply double offsets below */
+   st->base.stride = nblocksx*util_format_get_blocksize(texture->format);
+   st->base.layer_stride = st->base.stride * nblocksy;
+   st->hw_nblocksy = nblocksy;
 
-      /* Force direct map for transfering multiple slices */
-      if (st->base.box.depth > 1)
-         use_direct_map = svga_have_gb_objects(svga);
+   st->hwbuf = svga_winsys_buffer_create(svga, 1, 0,
+                                         st->hw_nblocksy * st->base.stride * d);
 
-      break;
-   default:
-      st->slice = 0;
-      break;
+   while (!st->hwbuf && (st->hw_nblocksy /= 2)) {
+      st->hwbuf =
+         svga_winsys_buffer_create(svga, 1, 0,
+                                   st->hw_nblocksy * st->base.stride * d);
    }
 
-   {
-      unsigned w, h;
-      if (use_direct_map) {
-         /* we'll directly access the guest-backed surface */
-         w = u_minify(texture->width0, level);
-         h = u_minify(texture->height0, level);
-         d = u_minify(texture->depth0, level);
+   if (!st->hwbuf)
+      return NULL;
+
+   if (st->hw_nblocksy < nblocksy) {
+      /* We couldn't allocate a hardware buffer big enough for the transfer,
+       * so allocate regular malloc memory instead
+       */
+      if (0) {
+         debug_printf("%s: failed to allocate %u KB of DMA, "
+                      "splitting into %u x %u KB DMA transfers\n",
+                      __FUNCTION__,
+                      (nblocksy * st->base.stride + 1023) / 1024,
+                      (nblocksy + st->hw_nblocksy - 1) / st->hw_nblocksy,
+                      (st->hw_nblocksy * st->base.stride + 1023) / 1024);
       }
-      else {
-         /* we'll put the data into a tightly packed buffer */
-         w = box->width;
-         h = box->height;
-         d = box->depth;
+
+      st->swbuf = MALLOC(nblocksy * st->base.stride * d);
+      if (!st->swbuf) {
+         sws->buffer_destroy(sws, st->hwbuf);
+         return NULL;
       }
-      nblocksx = util_format_get_nblocksx(texture->format, w);
-      nblocksy = util_format_get_nblocksy(texture->format, h);
    }
 
-   pipe_resource_reference(&st->base.resource, texture);
-
-   st->base.stride = nblocksx*util_format_get_blocksize(texture->format);
-   st->base.layer_stride = st->base.stride * nblocksy;
-   st->use_direct_map = use_direct_map;
-
-   *ptransfer = &st->base;
-
+   if (usage & PIPE_TRANSFER_READ) {
+      SVGA3dSurfaceDMAFlags flags;
+      memset(&flags, 0, sizeof flags);
+      svga_transfer_dma(svga, st, SVGA3D_READ_HOST_VRAM, flags);
+   }
 
-   if (usage & PIPE_TRANSFER_WRITE) {
-      /* record texture upload for HUD */
-      svga->hud.num_bytes_uploaded +=
-         nblocksx * nblocksy * d * util_format_get_blocksize(texture->format);
+   if (st->swbuf) {
+      return st->swbuf;
+   }
+   else {
+      return sws->buffer_map(sws, st->hwbuf, usage);
    }
+}
 
-   if (!use_direct_map) {
-      /* Use a DMA buffer */
-      st->hw_nblocksy = nblocksy;
 
-      st->hwbuf = svga_winsys_buffer_create(svga, 1, 0,
-                                   st->hw_nblocksy * st->base.stride * d);
-      while(!st->hwbuf && (st->hw_nblocksy /= 2)) {
-         st->hwbuf = svga_winsys_buffer_create(svga, 1, 0,
-                                   st->hw_nblocksy * st->base.stride * d);
-      }
+/**
+ * Use direct map for the transfer request
+ */
+static void *
+svga_texture_transfer_map_direct(struct svga_context *svga,
+                                 struct svga_transfer *st)
+{
+   struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws;
+   struct pipe_transfer *transfer = &st->base;
+   struct pipe_resource *texture = transfer->resource;
+   struct svga_texture *tex = svga_texture(texture);
+   struct svga_winsys_surface *surf = tex->handle;
+   unsigned level = st->base.level;
+   unsigned w, h, nblocksx, nblocksy;
+   unsigned usage = st->base.usage;
 
-      if (!st->hwbuf) {
-         FREE(st);
-         goto done;
-      }
+   if (!surf) {
+      FREE(st);
+      return NULL;
+   }
 
-      if (st->hw_nblocksy < nblocksy) {
-         /* We couldn't allocate a hardware buffer big enough for the transfer,
-          * so allocate regular malloc memory instead */
-         if (0) {
-            debug_printf("%s: failed to allocate %u KB of DMA, "
-                         "splitting into %u x %u KB DMA transfers\n",
-                         __FUNCTION__,
-                         (nblocksy * st->base.stride + 1023) / 1024,
-                         (nblocksy + st->hw_nblocksy - 1) / st->hw_nblocksy,
-                         (st->hw_nblocksy * st->base.stride + 1023) / 1024);
-         }
+   /* 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;
 
-         st->swbuf = MALLOC(nblocksy * st->base.stride * d);
-         if (!st->swbuf) {
-            sws->buffer_destroy(sws, st->hwbuf);
-            FREE(st);
-            goto done;
-         }
-      }
+   /* If this is the first time mapping to the surface in this
+    * command buffer, clear the dirty masks of this surface.
+    */
+   if (sws->surface_is_flushed(sws, surf)) {
+      svga_clear_texture_dirty(tex);
+   }
 
-      if (usage & PIPE_TRANSFER_READ) {
-         SVGA3dSurfaceDMAFlags flags;
-         memset(&flags, 0, sizeof flags);
-         svga_transfer_dma(svga, st, SVGA3D_READ_HOST_VRAM, flags);
-      }
-   } else {
-      struct pipe_transfer *transfer = &st->base;
-      struct svga_winsys_surface *surf = tex->handle;
+   if (need_tex_readback(transfer)) {
+      enum pipe_error ret;
 
-      if (!surf) {
-         FREE(st);
-         goto done;
-      }
+      svga_surfaces_flush(svga);
 
-      /* If this is the first time mapping to the surface in this
-       * command buffer, clear the dirty masks of this surface.
-       */
-      if (sws->surface_is_flushed(sws, surf)) {
-         svga_clear_texture_dirty(tex);
+      if (svga_have_vgpu10(svga)) {
+         ret = readback_image_vgpu10(svga, surf, st->slice, level,
+                                     tex->b.b.last_level + 1);
+      } else {
+         ret = readback_image_vgpu9(svga, surf, st->slice, level);
       }
 
-      if (need_tex_readback(transfer)) {
-        enum pipe_error ret;
+      svga->hud.num_readbacks++;
+      SVGA_STATS_COUNT_INC(sws, SVGA_STATS_COUNT_TEXREADBACK);
 
-         svga_surfaces_flush(svga);
-
-         if (svga_have_vgpu10(svga)) {
-            ret = readback_image_vgpu10(svga, surf, st->slice, level,
-                                        tex->b.b.last_level + 1);
-         } else {
-            ret = readback_image_vgpu9(svga, surf, st->slice, level);
-         }
-
-         svga->hud.num_readbacks++;
-         SVGA_STATS_COUNT_INC(sws, SVGA_STATS_COUNT_TEXREADBACK);
-
-         assert(ret == PIPE_OK);
-         (void) ret;
+      assert(ret == PIPE_OK);
+      (void) ret;
 
-        svga_context_flush(svga, NULL);
+      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.
-          */
-         svga_clear_texture_rendered_to(tex, st->slice, level);
-      }
-      else {
-        assert(usage & PIPE_TRANSFER_WRITE);
-        if ((usage & PIPE_TRANSFER_UNSYNCHRONIZED) == 0) {
-            if (svga_is_texture_dirty(tex, st->slice, level)) {
-               /*
-                * do a surface flush if the subresource has been modified
-                * in this command buffer.
-                */
-               svga_surfaces_flush(svga);
-               if (!sws->surface_is_flushed(sws, surf)) {
-                  svga->hud.surface_write_flushes++;
-                  SVGA_STATS_COUNT_INC(sws, SVGA_STATS_COUNT_SURFACEWRITEFLUSH);
-                  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.
+       */
+      svga_clear_texture_rendered_to(tex, st->slice, level);
+   }
+   else {
+      assert(usage & PIPE_TRANSFER_WRITE);
+      if ((usage & PIPE_TRANSFER_UNSYNCHRONIZED) == 0) {
+         if (svga_is_texture_dirty(tex, st->slice, level)) {
+            /*
+             * do a surface flush if the subresource has been modified
+             * in this command buffer.
+             */
+            svga_surfaces_flush(svga);
+            if (!sws->surface_is_flushed(sws, surf)) {
+               svga->hud.surface_write_flushes++;
+               SVGA_STATS_COUNT_INC(sws, SVGA_STATS_COUNT_SURFACEWRITEFLUSH);
+               svga_context_flush(svga, NULL);
             }
-        }
-      }
-      if (usage & PIPE_TRANSFER_WRITE) {
-         /* mark this texture level as dirty */
-         svga_set_texture_dirty(tex, st->slice, level);
+         }
       }
    }
 
    /*
     * Begin mapping code
     */
-   if (st->swbuf) {
-      returnVal = st->swbuf;
-   }
-   else if (!use_direct_map) {
-      returnVal = sws->buffer_map(sws, st->hwbuf, usage);
-   }
-   else {
+   {
       SVGA3dSize baseLevelSize;
-      struct svga_winsys_surface *surf = tex->handle;
       uint8_t *map;
       boolean retry;
       unsigned offset, mip_width, mip_height;
-      unsigned xoffset = st->base.box.x;
-      unsigned yoffset = st->base.box.y;
-      unsigned zoffset = st->base.box.z;
 
       map = svga->swc->surface_map(svga->swc, surf, usage, &retry);
       if (map == NULL && retry) {
@@ -548,9 +492,7 @@ svga_texture_transfer_map(struct pipe_context *pipe,
        * Make sure we return NULL if the map fails
        */
       if (!map) {
-         FREE(st);
-         returnVal = map;
-         goto done;
+         return NULL;
       }
 
       /**
@@ -579,19 +521,107 @@ svga_texture_transfer_map(struct pipe_context *pipe,
 
       offset += svga3dsurface_get_pixel_offset(tex->key.format,
                                                mip_width, mip_height,
-                                               xoffset, yoffset, zoffset);
-      returnVal = (void *) (map + offset);
+                                               st->base.box.x,
+                                               st->base.box.y,
+                                               st->base.box.z);
+
+      if (usage & PIPE_TRANSFER_WRITE) {
+         /* mark this texture level as dirty */
+         svga_set_texture_dirty(tex, st->slice, level);
+      }
+
+      return (void *) (map + offset);
    }
+}
 
-   svga->hud.map_buffer_time += (svga_get_time(svga) - begin);
-   svga->hud.num_textures_mapped++;
+
+/**
+ * Request a transfer map to the texture resource
+ */
+static void *
+svga_texture_transfer_map(struct pipe_context *pipe,
+                          struct pipe_resource *texture,
+                          unsigned level,
+                          unsigned usage,
+                          const struct pipe_box *box,
+                          struct pipe_transfer **ptransfer)
+{
+   struct svga_context *svga = svga_context(pipe);
+   struct svga_winsys_screen *sws = svga_screen(pipe->screen)->sws;
+   struct svga_texture *tex = svga_texture(texture);
+   struct svga_transfer *st;
+   boolean use_direct_map = svga_have_gb_objects(svga) &&
+                            !svga_have_gb_dma(svga);
+   void *returnVal = NULL;
+   int64_t begin = svga_get_time(svga);
+
+   SVGA_STATS_TIME_PUSH(sws, SVGA_STATS_TIME_TEXTRANSFERMAP);
+
+   /* We can't map texture storage directly unless we have GB objects */
+   if (usage & PIPE_TRANSFER_MAP_DIRECTLY) {
+      if (svga_have_gb_objects(svga))
+         use_direct_map = TRUE;
+      else
+         goto done;
+   }
+
+   st = CALLOC_STRUCT(svga_transfer);
+   if (!st)
+      goto done;
+
+   st->base.level = level;
+   st->base.usage = usage;
+   st->base.box = *box;
+
+   switch (tex->b.b.target) {
+   case PIPE_TEXTURE_CUBE:
+      st->slice = st->base.box.z;
+      st->base.box.z = 0;   /* so we don't apply double offsets below */
+      break;
+   case PIPE_TEXTURE_2D_ARRAY:
+   case PIPE_TEXTURE_1D_ARRAY:
+      st->slice = st->base.box.z;
+      st->base.box.z = 0;   /* so we don't apply double offsets below */
+
+      /* Force direct map for transfering multiple slices */
+      if (st->base.box.depth > 1)
+         use_direct_map = svga_have_gb_objects(svga);
+
+      break;
+   default:
+      st->slice = 0;
+      break;
+   }
+
+   st->use_direct_map = use_direct_map;
+   pipe_resource_reference(&st->base.resource, texture);
+
+   if (use_direct_map) {
+      returnVal = svga_texture_transfer_map_direct(svga, st);
+   }
+   else {
+      returnVal = svga_texture_transfer_map_dma(svga, st);
+   }
+
+   if (!returnVal) {
+      FREE(st);
+   }
+   else {
+      *ptransfer = &st->base;
+      svga->hud.num_textures_mapped++;
+      if (usage & PIPE_TRANSFER_WRITE) {
+         /* record texture upload for HUD */
+         svga->hud.num_bytes_uploaded +=
+            st->base.layer_stride * st->base.box.depth;
+      }
+   }
 
 done:
+   svga->hud.map_buffer_time += (svga_get_time(svga) - begin);
    SVGA_STATS_TIME_POP(sws);
    return returnVal;
 }
 
-
 /**
  * Unmap a GB texture surface.
  */
@@ -658,41 +688,51 @@ update_image_vgpu10(struct svga_context *svga,
 }
 
 
+/**
+ * unmap DMA transfer request
+ */
 static void
-svga_texture_transfer_unmap(struct pipe_context *pipe,
-                           struct pipe_transfer *transfer)
+svga_texture_transfer_unmap_dma(struct svga_context *svga,
+                               struct svga_transfer *st)
 {
-   struct svga_context *svga = svga_context(pipe);
-   struct svga_screen *ss = svga_screen(pipe->screen);
-   struct svga_winsys_screen *sws = ss->sws;
-   struct svga_transfer *st = svga_transfer(transfer);
-   struct svga_texture *tex = svga_texture(transfer->resource);
+   struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws;
 
-   SVGA_STATS_TIME_PUSH(sws, SVGA_STATS_TIME_TEXTRANSFERUNMAP);
-
-   if (!st->swbuf) {
-      if (st->use_direct_map) {
-         svga_texture_surface_unmap(svga, transfer);
-      }
-      else {
-         sws->buffer_unmap(sws, st->hwbuf);
-      }
-   }
+   if (st->hwbuf) 
+      sws->buffer_unmap(sws, st->hwbuf);
 
-   if (!st->use_direct_map && (st->base.usage & PIPE_TRANSFER_WRITE)) {
+   if (st->base.usage & PIPE_TRANSFER_WRITE) {
       /* Use DMA to transfer texture data */
       SVGA3dSurfaceDMAFlags flags;
 
       memset(&flags, 0, sizeof flags);
-      if (transfer->usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
+      if (st->base.usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
          flags.discard = TRUE;
       }
-      if (transfer->usage & PIPE_TRANSFER_UNSYNCHRONIZED) {
+      if (st->base.usage & PIPE_TRANSFER_UNSYNCHRONIZED) {
          flags.unsynchronized = TRUE;
       }
 
       svga_transfer_dma(svga, st, SVGA3D_WRITE_HOST_VRAM, flags);
-   } else if (transfer->usage & PIPE_TRANSFER_WRITE) {
+   }
+
+   FREE(st->swbuf);
+   sws->buffer_destroy(sws, st->hwbuf);
+}
+
+
+/**
+ * unmap direct map transfer request
+ */
+static void
+svga_texture_transfer_unmap_direct(struct svga_context *svga,
+                                  struct svga_transfer *st)
+{
+   struct pipe_transfer *transfer = &st->base;
+   struct svga_texture *tex = svga_texture(transfer->resource);
+
+   svga_texture_surface_unmap(svga, transfer);
+
+   if (st->base.usage & PIPE_TRANSFER_WRITE) {
       struct svga_winsys_surface *surf = tex->handle;
       SVGA3dBox box;
       enum pipe_error ret;
@@ -745,25 +785,40 @@ svga_texture_transfer_unmap(struct pipe_context *pipe,
          ret = update_image_vgpu9(svga, surf, &box, st->slice, transfer->level);
          assert(ret == PIPE_OK);
       }
+   }
+}
 
-      svga->hud.num_resource_updates++;
+static void
+svga_texture_transfer_unmap(struct pipe_context *pipe,
+                           struct pipe_transfer *transfer)
+{
+   struct svga_context *svga = svga_context(pipe);
+   struct svga_screen *ss = svga_screen(pipe->screen);
+   struct svga_winsys_screen *sws = ss->sws;
+   struct svga_transfer *st = svga_transfer(transfer);
+   struct svga_texture *tex = svga_texture(transfer->resource);
 
-      (void) ret;
-   }
+   SVGA_STATS_TIME_PUSH(sws, SVGA_STATS_TIME_TEXTRANSFERUNMAP);
 
-   ss->texture_timestamp++;
-   svga_age_texture_view(tex, transfer->level);
-   if (transfer->resource->target == PIPE_TEXTURE_CUBE)
-      svga_define_texture_level(tex, st->slice, transfer->level);
-   else
-      svga_define_texture_level(tex, 0, transfer->level);
+   if (st->use_direct_map) {
+      svga_texture_transfer_unmap_direct(svga, st);
+   }
+   else {
+      svga_texture_transfer_unmap_dma(svga, st);
+   }
 
-   pipe_resource_reference(&st->base.resource, NULL);
+   if (st->base.usage & PIPE_TRANSFER_WRITE) {
+      svga->hud.num_resource_updates++;
 
-   FREE(st->swbuf);
-   if (!st->use_direct_map) {
-      sws->buffer_destroy(sws, st->hwbuf);
+      ss->texture_timestamp++;
+      svga_age_texture_view(tex, transfer->level);
+      if (transfer->resource->target == PIPE_TEXTURE_CUBE)
+         svga_define_texture_level(tex, st->slice, transfer->level);
+      else
+         svga_define_texture_level(tex, 0, transfer->level);
    }
+
+   pipe_resource_reference(&st->base.resource, NULL);
    FREE(st);
    SVGA_STATS_TIME_POP(sws);
 }