u_vbuf_mgr: fix max_index computation once again
authorMarek Olšák <maraeo@gmail.com>
Sat, 14 May 2011 17:25:55 +0000 (19:25 +0200)
committerMarek Olšák <maraeo@gmail.com>
Sat, 14 May 2011 18:03:03 +0000 (20:03 +0200)
See how I compute and use the 'unused' variable in the code.
It's crucial for getting max_index right.

Fixed with the help of apitrace.
(bisecting the problematic draw call manually was not fun though)

This should fix:
https://bugs.freedesktop.org/show_bug.cgi?id=36268
https://bugs.freedesktop.org/show_bug.cgi?id=36609

src/gallium/auxiliary/util/u_vbuf_mgr.c

index dea2928f9501f7bc55492ee6c02bc0f567b1e407..a034483ee5c4272bf1e8987fab1029c9d29504b7 100644 (file)
@@ -53,9 +53,11 @@ struct u_vbuf_mgr_elements {
    unsigned count;
    struct pipe_vertex_element ve[PIPE_MAX_ATTRIBS];
 
-   /* If (velem[i].src_format != real_format[i]), the vertex buffer
+   unsigned src_format_size[PIPE_MAX_ATTRIBS];
+
+   /* If (velem[i].src_format != native_format[i]), the vertex buffer
     * referenced by the vertex element cannot be used for rendering and
-    * its vertex data must be translated to real_format[i]. */
+    * its vertex data must be translated to native_format[i]. */
    enum pipe_format native_format[PIPE_MAX_ATTRIBS];
    unsigned native_format_size[PIPE_MAX_ATTRIBS];
 
@@ -353,6 +355,8 @@ u_vbuf_mgr_create_vertex_elements(struct u_vbuf_mgr *mgrb,
    for (i = 0; i < count; i++) {
       enum pipe_format format = ve->ve[i].src_format;
 
+      ve->src_format_size[i] = util_format_get_blocksize(format);
+
       /* Choose a native format.
        * For now we don't care about the alignment, that's going to
        * be sorted out later. */
@@ -460,7 +464,6 @@ void u_vbuf_mgr_set_vertex_buffers(struct u_vbuf_mgr *mgrb,
    struct u_vbuf_mgr_priv *mgr = (struct u_vbuf_mgr_priv*)mgrb;
    unsigned i;
 
-   mgr->b.max_index = ~0;
    mgr->any_user_vbs = FALSE;
    mgr->incompatible_vb_layout = FALSE;
 
@@ -483,23 +486,16 @@ void u_vbuf_mgr_set_vertex_buffers(struct u_vbuf_mgr *mgrb,
       pipe_resource_reference(&mgr->b.vertex_buffer[i].buffer, vb->buffer);
       pipe_resource_reference(&mgr->b.real_vertex_buffer[i], NULL);
 
-      if (u_vbuf_resource(vb->buffer)->user_ptr) {
-         mgr->any_user_vbs = TRUE;
+      if (!vb->buffer) {
          continue;
       }
 
-      pipe_resource_reference(&mgr->b.real_vertex_buffer[i], vb->buffer);
-
-      /* The stride of zero means we will be fetching only the first
-       * vertex, so don't care about max_index. */
-      if (!vb->stride) {
+      if (u_vbuf_resource(vb->buffer)->user_ptr) {
+         mgr->any_user_vbs = TRUE;
          continue;
       }
 
-      /* Update the maximum index. */
-      mgr->b.max_index =
-            MIN2(mgr->b.max_index,
-                 (vb->buffer->width0 - vb->buffer_offset) / vb->stride - 1);
+      pipe_resource_reference(&mgr->b.real_vertex_buffer[i], vb->buffer);
    }
 
    for (; i < mgr->b.nr_real_vertex_buffers; i++) {
@@ -519,7 +515,7 @@ static void u_vbuf_upload_buffers(struct u_vbuf_mgr_priv *mgr,
                                   unsigned instance_count,
                                   boolean *upload_flushed)
 {
-   int i, nr = mgr->ve->count;
+   unsigned i, nr = mgr->ve->count;
    unsigned count = max_index + 1 - min_index;
    boolean uploaded[PIPE_MAX_ATTRIBS] = {0};
 
@@ -562,6 +558,40 @@ static void u_vbuf_upload_buffers(struct u_vbuf_mgr_priv *mgr,
    }
 }
 
+static void u_vbuf_mgr_compute_max_index(struct u_vbuf_mgr_priv *mgr)
+{
+   unsigned i, nr = mgr->ve->count;
+
+   mgr->b.max_index = ~0;
+
+   for (i = 0; i < nr; i++) {
+      struct pipe_vertex_buffer *vb =
+            &mgr->b.vertex_buffer[mgr->ve->ve[i].vertex_buffer_index];
+      int unused;
+      unsigned max_index;
+
+      if (!vb->buffer ||
+          !vb->stride ||
+          u_vbuf_resource(vb->buffer)->user_ptr) {
+         continue;
+      }
+
+      /* How many bytes is unused after the last vertex.
+       * width0 may be "count*stride - unused" and we have to compensate
+       * for that when dividing by stride. */
+      unused = vb->stride -
+               (mgr->ve->ve[i].src_offset + mgr->ve->src_format_size[i]);
+      assert(unused >= 0);
+
+      /* Compute the maximum index for this vertex element. */
+      max_index =
+         (vb->buffer->width0 - vb->buffer_offset + (unsigned)unused) /
+         vb->stride - 1;
+
+      mgr->b.max_index = MIN2(mgr->b.max_index, max_index);
+   }
+}
+
 void u_vbuf_mgr_draw_begin(struct u_vbuf_mgr *mgrb,
                            const struct pipe_draw_info *info,
                            boolean *buffers_updated,
@@ -571,6 +601,8 @@ void u_vbuf_mgr_draw_begin(struct u_vbuf_mgr *mgrb,
    boolean bufs_updated = FALSE, upload_flushed = FALSE;
    int min_index, max_index;
 
+   u_vbuf_mgr_compute_max_index(mgr);
+
    min_index = info->min_index - info->index_bias;
    if (info->max_index == ~0) {
       max_index = mgr->b.max_index;