svga: Proper redefine_user_buffer implementation.
[mesa.git] / src / gallium / drivers / svga / svga_resource_buffer_upload.c
index acef60f46472d12197955f2848e9c439f728e371..76a3803224a268ea38ce554c6cab3d95dae832d5 100644 (file)
 #include "svga_debug.h"
 
 
-/* Allocate a winsys_buffer (ie. DMA, aka GMR memory).
+#define MAX_DMA_SIZE (8 * 1024 * 1024)
+
+
+/**
+ * Allocate a winsys_buffer (ie. DMA, aka GMR memory).
+ *
+ * It will flush and retry in case the first attempt to create a DMA buffer
+ * fails, so it should not be called from any function involved in flushing
+ * to avoid recursion.
  */
 struct svga_winsys_buffer *
-svga_winsys_buffer_create( struct svga_screen *ss,
+svga_winsys_buffer_create( struct svga_context *svga,
                            unsigned alignment, 
                            unsigned usage,
                            unsigned size )
 {
-   struct svga_winsys_screen *sws = ss->sws;
+   struct svga_screen *svgascreen = svga_screen(svga->pipe.screen);
+   struct svga_winsys_screen *sws = svgascreen->sws;
    struct svga_winsys_buffer *buf;
    
+   /* XXX this shouldn't be a hard-coded number; it should be queried
+    * somehow.
+    */
+   if (size > MAX_DMA_SIZE) {
+      return NULL;
+   }
+
    /* Just try */
    buf = sws->buffer_create(sws, alignment, usage, size);
    if(!buf) {
@@ -59,9 +75,8 @@ svga_winsys_buffer_create( struct svga_screen *ss,
                size); 
       
       /* Try flushing all pending DMAs */
-      svga_screen_flush(ss, NULL);
+      svga_context_flush(svga, NULL);
       buf = sws->buffer_create(sws, alignment, usage, size);
-
    }
    
    return buf;
@@ -95,11 +110,12 @@ svga_buffer_create_hw_storage(struct svga_screen *ss,
    assert(!sbuf->user);
 
    if(!sbuf->hwbuf) {
+      struct svga_winsys_screen *sws = ss->sws;
       unsigned alignment = 16;
       unsigned usage = 0;
       unsigned size = sbuf->b.b.width0;
       
-      sbuf->hwbuf = svga_winsys_buffer_create(ss, alignment, usage, size);
+      sbuf->hwbuf = sws->buffer_create(sws, alignment, usage, size);
       if(!sbuf->hwbuf)
          return PIPE_ERROR_OUT_OF_MEMORY;
       
@@ -242,6 +258,7 @@ svga_buffer_upload_flush(struct svga_context *svga,
 {
    SVGA3dCopyBox *boxes;
    unsigned i;
+   struct pipe_resource *dummy;
 
    assert(sbuf->handle); 
    assert(sbuf->hwbuf);
@@ -283,9 +300,9 @@ svga_buffer_upload_flush(struct svga_context *svga,
    sbuf->dma.svga = NULL;
    sbuf->dma.boxes = NULL;
 
-   /* Decrement reference count */
-   pipe_reference(&(sbuf->b.b.reference), NULL);
-   sbuf = NULL;
+   /* Decrement reference count (and potentially destroy) */
+   dummy = &sbuf->b.b;
+   pipe_resource_reference(&dummy, NULL);
 }
 
 
@@ -476,12 +493,12 @@ svga_buffer_upload_piecewise(struct svga_screen *ss,
          if (offset + size > range->end)
             size = range->end - offset;
 
-         hwbuf = svga_winsys_buffer_create(ss, alignment, usage, size);
+         hwbuf = sws->buffer_create(sws, alignment, usage, size);
          while (!hwbuf) {
             size /= 2;
             if (!size)
                return PIPE_ERROR_OUT_OF_MEMORY;
-            hwbuf = svga_winsys_buffer_create(ss, alignment, usage, size);
+            hwbuf = sws->buffer_create(sws, alignment, usage, size);
          }
 
          SVGA_DBG(DEBUG_DMA, "  bytes %u - %u\n",
@@ -632,3 +649,54 @@ svga_context_flush_buffers(struct svga_context *svga)
       next = curr->next;
    }
 }
+
+
+void
+svga_redefine_user_buffer(struct pipe_context *pipe,
+                          struct pipe_resource *resource,
+                          unsigned offset,
+                          unsigned size)
+{
+   struct svga_screen *ss = svga_screen(pipe->screen);
+   struct svga_context *svga = svga_context(pipe);
+   struct svga_buffer *sbuf = svga_buffer(resource);
+
+   assert(sbuf->user);
+
+   /*
+    * Release any uploaded user buffer.
+    *
+    * TODO: As an optimization, we could try to update the uploaded buffer
+    * instead.
+    */
+
+   pipe_resource_reference(&sbuf->uploaded.buffer, NULL);
+
+   pipe_mutex_lock(ss->swc_mutex);
+
+   if (offset + size > resource->width0) {
+      /*
+       * User buffers shouldn't have DMA directly, unless
+       * SVGA_COMBINE_USERBUFFERS is not set.
+       */
+
+      if (sbuf->dma.pending) {
+         svga_buffer_upload_flush(svga, sbuf);
+      }
+
+      if (sbuf->handle) {
+         svga_buffer_destroy_host_surface(ss, sbuf);
+      }
+
+      if (sbuf->hwbuf) {
+         svga_buffer_destroy_hw_storage(ss, sbuf);
+      }
+
+      sbuf->key.size.width = sbuf->b.b.width0 = offset + size;
+   }
+
+   pipe_mutex_unlock(ss->swc_mutex);
+
+   svga->curr.any_user_vertex_buffers = TRUE;
+   svga->dirty |= SVGA_NEW_VBUFFER | SVGA_NEW_VELEMENT;
+}