u_vbuf_mgr: rework user buffer uploads
authorMarek Olšák <maraeo@gmail.com>
Sun, 25 Sep 2011 17:57:35 +0000 (19:57 +0200)
committerMarek Olšák <maraeo@gmail.com>
Mon, 26 Sep 2011 13:25:05 +0000 (15:25 +0200)
- first determine the buffer range to upload for each buffer by walking over
  vertex elements
- take buffer_offset into account
- take src_offset into account
- take src_format into account in more places
- don't just blindly upload (stride*count) bytes

NOTE: This is a candidate for the 7.11 branch.

src/gallium/auxiliary/util/u_vbuf_mgr.c

index 6ed1d0b2b7e4923ed82fc17dc2e3f17a8a049c4f..46b37aa74841347026b447c46ef17b2aec1328d4 100644 (file)
@@ -507,51 +507,73 @@ u_vbuf_upload_buffers(struct u_vbuf_priv *mgr,
                       int min_index, int max_index,
                       unsigned instance_count)
 {
-   unsigned i, nr = mgr->ve->count;
+   unsigned i;
    unsigned count = max_index + 1 - min_index;
-   boolean uploaded[PIPE_MAX_ATTRIBS] = {0};
-
-   for (i = 0; i < nr; i++) {
-      unsigned index = mgr->ve->ve[i].vertex_buffer_index;
+   unsigned nr_velems = mgr->ve->count;
+   unsigned nr_vbufs = mgr->b.nr_vertex_buffers;
+   unsigned start_offset[PIPE_MAX_ATTRIBS];
+   unsigned end_offset[PIPE_MAX_ATTRIBS] = {0};
+
+   /* Determine how much data needs to be uploaded. */
+   for (i = 0; i < nr_velems; i++) {
+      struct pipe_vertex_element *velem = &mgr->ve->ve[i];
+      unsigned index = velem->vertex_buffer_index;
+      unsigned instance_div = velem->instance_divisor;
       struct pipe_vertex_buffer *vb = &mgr->b.vertex_buffer[index];
+      unsigned first, size;
 
-      if (vb->buffer &&
-          u_vbuf_resource(vb->buffer)->user_ptr &&
-          !uploaded[index]) {
-         unsigned first, size;
-         boolean flushed;
-         unsigned instance_div = mgr->ve->ve[i].instance_divisor;
-
-         if (instance_div) {
-            first = 0;
-            size = vb->stride *
-                   ((instance_count + instance_div - 1) / instance_div);
-         } else if (vb->stride) {
-            first = vb->stride * min_index;
-            size = vb->stride * count;
-
-            /* Unusual case when stride is smaller than the format size.
-             * XXX This won't work with interleaved arrays. */
-            if (mgr->ve->native_format_size[i] > vb->stride)
-               size += mgr->ve->native_format_size[i] - vb->stride;
-         } else {
-            first = 0;
-            size = mgr->ve->native_format_size[i];
-         }
+      assert(vb->buffer);
+
+      if (!u_vbuf_resource(vb->buffer)->user_ptr) {
+         continue;
+      }
 
-         u_upload_data(mgr->b.uploader, first, size,
-                       u_vbuf_resource(vb->buffer)->user_ptr + first,
-                       &mgr->b.real_vertex_buffer[index].buffer_offset,
-                       &mgr->b.real_vertex_buffer[index].buffer,
-                       &flushed);
+      first = vb->buffer_offset + velem->src_offset;
 
-         mgr->b.real_vertex_buffer[index].buffer_offset -= first;
+      if (!vb->stride) {
+         /* Constant attrib. */
+         size = mgr->ve->src_format_size[i];
+      } else if (instance_div) {
+         /* Per-instance attrib. */
+         unsigned count = (instance_count + instance_div - 1) / instance_div;
+         size = vb->stride * (count - 1) + mgr->ve->src_format_size[i];
+      } else {
+         /* Per-vertex attrib. */
+         first += vb->stride * min_index;
+         size = vb->stride * (count - 1) + mgr->ve->src_format_size[i];
+      }
 
-         uploaded[index] = TRUE;
+      /* Update offsets. */
+      if (!end_offset[index]) {
+         start_offset[index] = first;
+         end_offset[index] = first + size;
       } else {
-         assert(mgr->b.real_vertex_buffer[index].buffer);
+         if (first < start_offset[index])
+            start_offset[index] = first;
+         if (first + size > end_offset[index])
+            end_offset[index] = first + size;
       }
    }
+
+   /* Upload buffers. */
+   for (i = 0; i < nr_vbufs; i++) {
+      unsigned start = start_offset[i];
+      unsigned end = end_offset[i];
+      boolean flushed;
+
+      if (!end) {
+         continue;
+      }
+      assert(start < end);
+
+      u_upload_data(mgr->b.uploader, start, end - start,
+                    u_vbuf_resource(mgr->b.vertex_buffer[i].buffer)->user_ptr + start,
+                    &mgr->b.real_vertex_buffer[i].buffer_offset,
+                    &mgr->b.real_vertex_buffer[i].buffer,
+                    &flushed);
+
+      mgr->b.real_vertex_buffer[i].buffer_offset -= start;
+   }
 }
 
 static void u_vbuf_compute_max_index(struct u_vbuf_priv *mgr)