svga: Avoid synchronizing when doing piecewise upload of textures.
[mesa.git] / src / gallium / drivers / svga / svga_resource_texture.c
index f06b0323d8c39269a1b34f8dfaec9eb0ce3e0302..f9eb4949b2c1459ecb1a71be58c4baf093726d80 100644 (file)
 #define SVGA3D_SURFACE_HINT_SCANOUT (1 << 9)
 
 
-static unsigned int
-svga_texture_is_referenced( struct pipe_context *pipe,
-                           struct pipe_resource *texture,
-                           unsigned face, unsigned level)
-{
-   struct svga_texture *tex = svga_texture(texture);
-   struct svga_screen *ss = svga_screen(pipe->screen);
-
-   /**
-    * The screen does not cache texture writes.
-    */
-
-   if (!tex->handle || ss->sws->surface_is_flushed(ss->sws, tex->handle))
-      return PIPE_UNREFERENCED;
-
-   /**
-    * sws->surface_is_flushed() does not distinguish between read references
-    * and write references. So assume a reference is both.
-    */
-
-   return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
-}
-
-
-
 /*
  * Helper function and arrays
  */
@@ -146,16 +121,6 @@ svga_translate_format_render(enum pipe_format format)
    case PIPE_FORMAT_L8_UNORM:
       return svga_translate_format(format);
 
-#if 1
-   /* For on host conversion */
-   case PIPE_FORMAT_DXT1_RGB:
-      return SVGA3D_X8R8G8B8;
-   case PIPE_FORMAT_DXT1_RGBA:
-   case PIPE_FORMAT_DXT3_RGBA:
-   case PIPE_FORMAT_DXT5_RGBA:
-      return SVGA3D_A8R8G8B8;
-#endif
-
    default:
       return SVGA3D_FORMAT_INVALID;
    }
@@ -163,28 +128,16 @@ svga_translate_format_render(enum pipe_format format)
 
 
 static INLINE void
-svga_transfer_dma_band(struct svga_transfer *st,
+svga_transfer_dma_band(struct svga_context *svga,
+                       struct svga_transfer *st,
                        SVGA3dTransferType transfer,
-                       unsigned y, unsigned h, unsigned srcy)
+                       unsigned y, unsigned h, unsigned srcy,
+                       SVGA3dSurfaceDMAFlags flags)
 {
    struct svga_texture *texture = svga_texture(st->base.resource); 
-   struct svga_screen *screen = svga_screen(texture->b.b.screen);
    SVGA3dCopyBox box;
    enum pipe_error ret;
-   
-   SVGA_DBG(DEBUG_DMA, "dma %s sid %p, face %u, (%u, %u, %u) - (%u, %u, %u), %ubpp\n",
-                transfer == SVGA3D_WRITE_HOST_VRAM ? "to" : "from", 
-                texture->handle,
-                st->base.sr.face,
-                st->base.box.x,
-                y,
-                st->base.box.z,
-                st->base.box.x + st->base.box.width,
-                y + h,
-                st->base.box.z + 1,
-                util_format_get_blocksize(texture->b.b.format) * 8 /
-                (util_format_get_blockwidth(texture->b.b.format)*util_format_get_blockheight(texture->b.b.format)));
-   
    box.x = st->base.box.x;
    box.y = y;
    box.z = st->base.box.z;
@@ -195,38 +148,64 @@ svga_transfer_dma_band(struct svga_transfer *st,
    box.srcy = srcy;
    box.srcz = 0;
 
-   pipe_mutex_lock(screen->swc_mutex);
-   ret = SVGA3D_SurfaceDMA(screen->swc, st, transfer, &box, 1);
+   if (st->base.resource->target == PIPE_TEXTURE_CUBE) {
+      st->face = st->base.box.z;
+      box.z = 0;
+   }
+   else
+      st->face = 0;
+
+   SVGA_DBG(DEBUG_DMA, "dma %s sid %p, face %u, (%u, %u, %u) - (%u, %u, %u), %ubpp\n",
+                transfer == SVGA3D_WRITE_HOST_VRAM ? "to" : "from", 
+                texture->handle,
+                st->face,
+                st->base.box.x,
+                y,
+                box.z,
+                st->base.box.x + st->base.box.width,
+                y + h,
+                box.z + 1,
+                util_format_get_blocksize(texture->b.b.format) * 8 /
+                (util_format_get_blockwidth(texture->b.b.format)*util_format_get_blockheight(texture->b.b.format)));
+
+   ret = SVGA3D_SurfaceDMA(svga->swc, st, transfer, &box, 1, flags);
    if(ret != PIPE_OK) {
-      screen->swc->flush(screen->swc, NULL);
-      ret = SVGA3D_SurfaceDMA(screen->swc, st, transfer, &box, 1);
+      svga_context_flush(svga, NULL);
+      ret = SVGA3D_SurfaceDMA(svga->swc, st, transfer, &box, 1, flags);
       assert(ret == PIPE_OK);
    }
-   pipe_mutex_unlock(screen->swc_mutex);
 }
 
 
 static INLINE void
-svga_transfer_dma(struct svga_transfer *st,
-                 SVGA3dTransferType transfer)
+svga_transfer_dma(struct svga_context *svga,
+                  struct svga_transfer *st,
+                  SVGA3dTransferType transfer,
+                  SVGA3dSurfaceDMAFlags flags)
 {
    struct svga_texture *texture = svga_texture(st->base.resource); 
    struct svga_screen *screen = svga_screen(texture->b.b.screen);
    struct svga_winsys_screen *sws = screen->sws;
    struct pipe_fence_handle *fence = NULL;
-   
+
    if (transfer == SVGA3D_READ_HOST_VRAM) {
       SVGA_DBG(DEBUG_PERF, "%s: readback transfer\n", __FUNCTION__);
    }
 
+   /* Ensure any pending operations on host surfaces are queued on the command
+    * buffer first.
+    */
+   svga_surfaces_flush( svga );
 
    if(!st->swbuf) {
       /* Do the DMA transfer in a single go */
-      
-      svga_transfer_dma_band(st, transfer, st->base.box.y, st->base.box.height, 0);
+
+      svga_transfer_dma_band(svga, st, transfer,
+                             st->base.box.y, st->base.box.height, 0,
+                             flags);
 
       if(transfer == SVGA3D_READ_HOST_VRAM) {
-         svga_screen_flush(screen, &fence);
+         svga_context_flush(svga, &fence);
          sws->fence_finish(sws, fence, 0);
          sws->fence_reference(sws, &fence, NULL);
       }
@@ -246,33 +225,41 @@ svga_transfer_dma(struct svga_transfer *st,
          /* Transfer band must be aligned to pixel block boundaries */
          assert(y % blockheight == 0);
          assert(h % blockheight == 0);
-         
+
          offset = y * st->base.stride / blockheight;
          length = h * st->base.stride / blockheight;
 
          sw = (uint8_t *)st->swbuf + offset;
-         
-         if(transfer == SVGA3D_WRITE_HOST_VRAM) {
+
+         if (transfer == SVGA3D_WRITE_HOST_VRAM) {
+            unsigned usage = PIPE_TRANSFER_WRITE;
+
             /* Wait for the previous DMAs to complete */
             /* TODO: keep one DMA (at half the size) in the background */
-            if(y) {
-               svga_screen_flush(screen, &fence);
-               sws->fence_finish(sws, fence, 0);
-               sws->fence_reference(sws, &fence, NULL);
+            if (y) {
+               svga_context_flush(svga, NULL);
+               usage |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
             }
 
-            hw = sws->buffer_map(sws, st->hwbuf, PIPE_TRANSFER_WRITE);
+            hw = sws->buffer_map(sws, st->hwbuf, usage);
             assert(hw);
-            if(hw) {
+            if (hw) {
                memcpy(hw, sw, length);
                sws->buffer_unmap(sws, st->hwbuf);
             }
          }
-         
-         svga_transfer_dma_band(st, transfer, y, h, srcy);
-         
+
+         svga_transfer_dma_band(svga, st, transfer, y, h, srcy, flags);
+
+         /*
+          * Prevent the texture contents to be discarded on the next band
+          * upload.
+          */
+
+         flags.discard = FALSE;
+
          if(transfer == SVGA3D_READ_HOST_VRAM) {
-            svga_screen_flush(screen, &fence);
+            svga_context_flush(svga, &fence);
             sws->fence_finish(sws, fence, 0);
 
             hw = sws->buffer_map(sws, st->hwbuf, PIPE_TRANSFER_READ);
@@ -337,11 +324,12 @@ svga_texture_destroy(struct pipe_screen *screen,
  */
 static struct pipe_transfer *
 svga_texture_get_transfer(struct pipe_context *pipe,
-                         struct pipe_resource *texture,
-                         struct pipe_subresource sr,
-                         unsigned usage,
-                         const struct pipe_box *box)
+                          struct pipe_resource *texture,
+                          unsigned level,
+                          unsigned usage,
+                          const struct pipe_box *box)
 {
+   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;
@@ -352,25 +340,26 @@ svga_texture_get_transfer(struct pipe_context *pipe,
    if (usage & PIPE_TRANSFER_MAP_DIRECTLY)
       return NULL;
 
+   assert(box->depth == 1);
    st = CALLOC_STRUCT(svga_transfer);
    if (!st)
       return NULL;
-   
+
    pipe_resource_reference(&st->base.resource, texture);
-   st->base.sr = sr;
+   st->base.level = level;
    st->base.usage = usage;
    st->base.box = *box;
    st->base.stride = nblocksx*util_format_get_blocksize(texture->format);
-   st->base.slice_stride = 0;
+   st->base.layer_stride = 0;
 
    st->hw_nblocksy = nblocksy;
-   
-   st->hwbuf = svga_winsys_buffer_create(ss, 
+
+   st->hwbuf = svga_winsys_buffer_create(svga,
                                          1, 
                                          0,
                                          st->hw_nblocksy*st->base.stride);
    while(!st->hwbuf && (st->hw_nblocksy /= 2)) {
-      st->hwbuf = svga_winsys_buffer_create(ss, 
+      st->hwbuf = svga_winsys_buffer_create(svga,
                                             1, 
                                             0,
                                             st->hw_nblocksy*st->base.stride);
@@ -382,18 +371,25 @@ svga_texture_get_transfer(struct pipe_context *pipe,
    if(st->hw_nblocksy < nblocksy) {
       /* We couldn't allocate a hardware buffer big enough for the transfer, 
        * so allocate regular malloc memory instead */
-      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);
+      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);
+      }
+
       st->swbuf = MALLOC(nblocksy*st->base.stride);
       if(!st->swbuf)
          goto no_swbuf;
    }
-   
-   if (usage & PIPE_TRANSFER_READ)
-      svga_transfer_dma(st, SVGA3D_READ_HOST_VRAM);
+
+   if (usage & PIPE_TRANSFER_READ) {
+      SVGA3dSurfaceDMAFlags flags;
+      memset(&flags, 0, sizeof flags);
+      svga_transfer_dma(svga, st, SVGA3D_READ_HOST_VRAM, flags);
+   }
 
    return &st->base;
 
@@ -445,16 +441,30 @@ static void
 svga_texture_transfer_destroy(struct pipe_context *pipe,
                              struct pipe_transfer *transfer)
 {
+   struct svga_context *svga = svga_context(pipe);
    struct svga_texture *tex = svga_texture(transfer->resource);
    struct svga_screen *ss = svga_screen(pipe->screen);
    struct svga_winsys_screen *sws = ss->sws;
    struct svga_transfer *st = svga_transfer(transfer);
 
    if (st->base.usage & PIPE_TRANSFER_WRITE) {
-      svga_transfer_dma(st, SVGA3D_WRITE_HOST_VRAM);
+      SVGA3dSurfaceDMAFlags flags;
+
+      memset(&flags, 0, sizeof flags);
+      if (transfer->usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
+         flags.discard = TRUE;
+      }
+      if (transfer->usage & PIPE_TRANSFER_UNSYNCHRONIZED) {
+         flags.unsynchronized = TRUE;
+      }
+
+      svga_transfer_dma(svga, st, SVGA3D_WRITE_HOST_VRAM, flags);
       ss->texture_timestamp++;
-      tex->view_age[transfer->sr.level] = ++(tex->age);
-      tex->defined[transfer->sr.face][transfer->sr.level] = TRUE;
+      tex->view_age[transfer->level] = ++(tex->age);
+      if (transfer->resource->target == PIPE_TEXTURE_CUBE)
+         tex->defined[transfer->box.z][transfer->level] = TRUE;
+      else
+         tex->defined[0][transfer->level] = TRUE;
    }
 
    pipe_resource_reference(&st->base.resource, NULL);
@@ -471,7 +481,6 @@ struct u_resource_vtbl svga_texture_vtbl =
 {
    svga_texture_get_handle,          /* get_handle */
    svga_texture_destroy,             /* resource_destroy */
-   svga_texture_is_referenced,       /* is_resource_referenced */
    svga_texture_get_transfer,        /* get_transfer */
    svga_texture_transfer_destroy,     /* transfer_destroy */
    svga_texture_transfer_map,        /* transfer_map */
@@ -489,7 +498,7 @@ svga_texture_create(struct pipe_screen *screen,
 {
    struct svga_screen *svgascreen = svga_screen(screen);
    struct svga_texture *tex = CALLOC_STRUCT(svga_texture);
-   
+
    if (!tex)
       goto error1;
 
@@ -506,7 +515,7 @@ svga_texture_create(struct pipe_screen *screen,
    tex->key.size.width = template->width0;
    tex->key.size.height = template->height0;
    tex->key.size.depth = template->depth0;
-   
+
    if(template->target == PIPE_TEXTURE_CUBE) {
       tex->key.flags |= SVGA3D_SURFACE_CUBEMAP;
       tex->key.numFaces = 6;
@@ -515,7 +524,8 @@ svga_texture_create(struct pipe_screen *screen,
       tex->key.numFaces = 1;
    }
 
-   tex->key.cachable = 1;
+   /* XXX: Disabled for now */
+   tex->key.cachable = 0;
 
    if (template->bind & PIPE_BIND_SAMPLER_VIEW)
       tex->key.flags |= SVGA3D_SURFACE_HINT_TEXTURE;
@@ -559,6 +569,9 @@ svga_texture_create(struct pipe_screen *screen,
    if (tex->handle)
       SVGA_DBG(DEBUG_DMA, "  --> got sid %p (texture)\n", tex->handle);
 
+   debug_reference(&tex->b.b.reference,
+                   (debug_reference_descriptor)debug_describe_resource, 0);
+
    return &tex->b.b;
 
 error2:
@@ -582,7 +595,8 @@ svga_texture_from_handle(struct pipe_screen *screen,
    assert(screen);
 
    /* Only supports one type */
-   if (template->target != PIPE_TEXTURE_2D ||
+   if ((template->target != PIPE_TEXTURE_2D &&
+       template->target != PIPE_TEXTURE_RECT) ||
        template->last_level != 0 ||
        template->depth0 != 1) {
       return NULL;