svga: Fix multiple uploads of the same user-buffer.
authorThomas Hellstrom <thellstrom@vmware.com>
Thu, 30 Jun 2011 06:52:19 +0000 (08:52 +0200)
committerThomas Hellstrom <thellstrom@vmware.com>
Fri, 1 Jul 2011 11:30:41 +0000 (13:30 +0200)
If a user-buffer was referenced twice by a draw command, the affected ranges
were uploaded separately, with only the last one being referenced by the
hardware. Make sure we upload only a single range.

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
src/gallium/drivers/svga/svga_pipe_draw.c
src/gallium/drivers/svga/svga_resource_buffer.h
src/gallium/drivers/svga/svga_state_vdecl.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);
       }
index 69d6f72a11c0ae6e9f2106e0b83c8cf22104fa2a..ca8c8d1f5ea3a37d5d47fe939aa17922667d85df 100644 (file)
@@ -129,14 +129,13 @@ struct svga_buffer
        * is the relative offset within that buffer.
        */
       unsigned offset;
-   } uploaded;
 
-   /**
-    * For user buffers, this is the offset to the data about to be
-    * referenced by the next draw command, and hence the data that needs
-    * to be uploaded.
-    */
-   unsigned source_offset;
+      /**
+       * Range of user buffer that is uploaded in @buffer at @offset.
+       */
+      unsigned start;
+      unsigned end;
+   } uploaded;
 
    /**
     * DMA'ble memory.
index 2375a022f97a7195d95df036a3dbf44f9350c810..47eab1a9739eadcbf171c7bc71978c1ba57cee8b 100644 (file)
@@ -82,8 +82,8 @@ static int emit_hw_vs_vdecl( struct svga_context *svga,
          continue;
 
       buffer = svga_buffer(vb->buffer);
-      if (buffer->source_offset > offset) {
-         tmp_neg_bias = buffer->source_offset - offset;
+      if (buffer->uploaded.start > offset) {
+         tmp_neg_bias = buffer->uploaded.start - offset;
          if (vb->stride)
             tmp_neg_bias = (tmp_neg_bias + vb->stride - 1) / vb->stride;
          neg_bias = MAX2(neg_bias, tmp_neg_bias);
@@ -116,7 +116,7 @@ static int emit_hw_vs_vdecl( struct svga_context *svga,
       decl.array.offset = (vb->buffer_offset
                            + ve[i].src_offset
                           + neg_bias * vb->stride
-                          - buffer->source_offset);
+                          - buffer->uploaded.start);
 
       assert(decl.array.offset >= 0);