svga: Fix multiple uploads of the same user-buffer.
[mesa.git] / src / gallium / drivers / svga / svga_pipe_draw.c
index 358ef82db311d3c2cfad2a4300f0eea664ad8a82..0b4d41bb807e833855a06205867e2a190595bbc6 100644 (file)
 #include "util/u_upload_mgr.h"
 
 /**
- * svga_upload_user_buffers - upload parts of user buffers
+ * Determine the ranges to upload for the user-buffers referenced
+ * by the next draw command.
  *
- * This function streams a part of a user buffer to hw and sets
- * svga_buffer::source_offset to the first byte uploaded. After upload
- * also svga_buffer::uploaded::buffer is set to !NULL
+ * TODO: It might be beneficial to support multiple ranges. In that case,
+ * the struct svga_buffer::uploaded member should be made an array or a
+ * list, since we need to account for the possibility that different ranges
+ * may be uploaded to different hardware buffers chosen by the utility
+ * upload manager.
  */
 
-static int
-svga_upload_user_buffers(struct svga_context *svga,
-                         unsigned start,
-                         unsigned count,
-                         unsigned instance_count)
+static void
+svga_user_buffer_range(struct svga_context *svga,
+                       unsigned start,
+                       unsigned count,
+                       unsigned instance_count)
 {
    const struct pipe_vertex_element *ve = svga->curr.velems->velem;
-   unsigned i;
-   int ret;
+   int i;
+
+   /*
+    * Release old uploaded range (if not done already) and
+    * initialize new ranges.
+    */
+
+   for (i=0; i < svga->curr.velems->count; i++) {
+      struct pipe_vertex_buffer *vb =
+         &svga->curr.vb[ve[i].vertex_buffer_index];
+
+      if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) {
+         struct svga_buffer *buffer = svga_buffer(vb->buffer);
+
+         pipe_resource_reference(&buffer->uploaded.buffer, NULL);
+         buffer->uploaded.start = ~0;
+         buffer->uploaded.end = 0;
+      }
+   }
 
    for (i=0; i < svga->curr.velems->count; i++) {
       struct pipe_vertex_buffer *vb =
@@ -66,30 +86,71 @@ svga_upload_user_buffers(struct svga_context *svga,
       if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) {
          struct svga_buffer *buffer = svga_buffer(vb->buffer);
          unsigned first, size;
-         boolean flushed;
          unsigned instance_div = ve[i].instance_divisor;
          unsigned elemSize = util_format_get_blocksize(ve->src_format);
 
          svga->dirty |= SVGA_NEW_VBUFFER;
 
          if (instance_div) {
-            first = 0;
+            first = ve[i].src_offset;
             count = (instance_count + instance_div - 1) / instance_div;
             size = vb->stride * (count - 1) + elemSize;
          } else if (vb->stride) {
-            first = vb->stride * start;
+            first = vb->stride * start + ve[i].src_offset;
             size = vb->stride * (count - 1) + elemSize;
          } else {
             /* Only a single vertex!
              * Upload with the largest vertex size the hw supports,
              * if possible.
              */
-            first = 0;
+            first = ve[i].src_offset;
             size = MIN2(16, vb->buffer->width0);
          }
 
+         buffer->uploaded.start = MIN2(buffer->uploaded.start, first);
+         buffer->uploaded.end = MAX2(buffer->uploaded.end, first + size);
+      }
+   }
+}
+
+/**
+ * svga_upload_user_buffers - upload parts of user buffers
+ *
+ * This function streams a part of a user buffer to hw and fills
+ * svga_buffer::uploaded with information on the upload.
+ */
+
+static int
+svga_upload_user_buffers(struct svga_context *svga,
+                         unsigned start,
+                         unsigned count,
+                         unsigned instance_count)
+{
+   const struct pipe_vertex_element *ve = svga->curr.velems->velem;
+   unsigned i;
+   int ret;
+
+   svga_user_buffer_range(svga, start, count, instance_count);
+
+   for (i=0; i < svga->curr.velems->count; i++) {
+      struct pipe_vertex_buffer *vb =
+         &svga->curr.vb[ve[i].vertex_buffer_index];
+
+      if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) {
+         struct svga_buffer *buffer = svga_buffer(vb->buffer);
+         boolean flushed;
+
+         /*
+          * Check if already uploaded. Otherwise go ahead and upload.
+          */
+
+         if (buffer->uploaded.buffer)
+            continue;
+
          ret = u_upload_buffer( svga->upload_vb,
-                                0, first, size,
+                                0,
+                                buffer->uploaded.start,
+                                buffer->uploaded.end - buffer->uploaded.start,
                                 &buffer->b.b,
                                 &buffer->uploaded.offset,
                                 &buffer->uploaded.buffer,
@@ -106,11 +167,10 @@ svga_upload_user_buffers(struct svga_context *svga,
                          buffer,
                          buffer->uploaded.buffer,
                          buffer->uploaded.offset,
-                         first,
-                         size);
+                         buffer->uploaded.start,
+                         buffer->uploaded.end - buffer->uploaded.start);
 
          vb->buffer_offset = buffer->uploaded.offset;
-         buffer->source_offset = first;
       }
    }
 
@@ -143,7 +203,8 @@ svga_release_user_upl_buffers(struct svga_context *svga)
       if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) {
          struct svga_buffer *buffer = svga_buffer(vb->buffer);
 
-         buffer->source_offset = 0;
+         buffer->uploaded.start = ~0;
+         buffer->uploaded.end = 0;
          if (buffer->uploaded.buffer)
             pipe_resource_reference(&buffer->uploaded.buffer, NULL);
       }