mesa: add const qualifier to _mesa_is_legal_format_and_type()
[mesa.git] / src / mesa / vbo / vbo_split_inplace.c
index 958afccd0c0a278e2c30a5288a6cc2a5f64e89a0..789cf31364be92ca579a8ac9daf0a5bc9c21c85d 100644 (file)
 #include "main/mtypes.h"
 #include "main/macros.h"
 #include "main/enums.h"
+#include "main/image.h"
 #include "vbo_split.h"
 
 
 #define MAX_PRIM 32
 
-/* Used for splitting without copying.
+/* Used for splitting without copying. No attempt is made to handle
+ * too large indexed vertex buffers: In general you need to copy to do
+ * that.
  */
 struct split_context {
-   GLcontext *ctx;
+   struct gl_context *ctx;
    const struct gl_client_array **array;
    const struct _mesa_prim *prim;
    GLuint nr_prims;
@@ -48,6 +51,7 @@ struct split_context {
    vbo_draw_func draw;
 
    const struct split_limits *limits;
+   GLuint limit;
 
    struct _mesa_prim dstprim[MAX_PRIM];
    GLuint dstprim_nr;
@@ -58,53 +62,38 @@ struct split_context {
 
 static void flush_vertex( struct split_context *split )
 {
-   GLint min_index, max_index;
+   struct _mesa_index_buffer ib;
+   GLuint i;
 
    if (!split->dstprim_nr) 
       return;
 
    if (split->ib) {
-      /* This should basically be multipass rendering over the same
-       * unchanging set of VBO's.  Would like the driver not to
-       * re-upload the data, or swtnl not to re-transform the
-       * vertices.
-       */
-      assert(split->max_index - split->min_index < split->limits->max_verts);
-      min_index = split->min_index;
-      max_index = split->max_index;
-   }
-   else {
-      /* Non-indexed rendering.  Cannot assume that the primitives are
-       * ordered by increasing vertex, because of entrypoints like
-       * MultiDrawArrays.
-       */
-      GLuint i;
-      min_index = split->dstprim[0].start;
-      max_index = min_index + split->dstprim[0].count - 1;
-
-      for (i = 1; i < split->dstprim_nr; i++) {
-        GLuint tmp_min = split->dstprim[i].start;
-        GLuint tmp_max = tmp_min + split->dstprim[i].count - 1;
-
-        if (tmp_min < min_index) 
-           min_index = tmp_min;
-
-        if (tmp_max > max_index) 
-           max_index = tmp_max;
-      }
+      ib = *split->ib;
+
+      ib.count = split->max_index - split->min_index + 1;
+      ib.ptr = (const void *)((const char *)ib.ptr + 
+                              split->min_index * _mesa_sizeof_type(ib.type));
+
+      /* Rebase the primitives to save index buffer entries. */
+      for (i = 0; i < split->dstprim_nr; i++)
+        split->dstprim[i].start -= split->min_index;
    }
 
-   assert(max_index >= min_index);
+   assert(split->max_index >= split->min_index);
 
-   split->draw( split->ctx, 
-               split->array, 
-               split->dstprim,
-               split->dstprim_nr,
-               NULL,
-               min_index,
-               max_index);
+   split->draw(split->ctx,
+              split->array,
+              split->dstprim,
+              split->dstprim_nr,
+              split->ib ? &ib : NULL,
+              !split->ib,
+              split->min_index,
+              split->max_index);
 
    split->dstprim_nr = 0;
+   split->min_index = ~0;
+   split->max_index = 0;
 }
 
 
@@ -121,62 +110,67 @@ static struct _mesa_prim *next_outprim( struct split_context *split )
    }
 }
 
-static int align(int value, int alignment)
+static void update_index_bounds(struct split_context *split,
+                               const struct _mesa_prim *prim)
 {
-   return (value + alignment - 1) & ~(alignment - 1);
+   split->min_index = MIN2(split->min_index, prim->start);
+   split->max_index = MAX2(split->max_index, prim->start + prim->count - 1);
 }
 
-
+/* Return the maximum amount of vertices that can be emitted for a
+ * primitive starting at 'prim->start', depending on the previous
+ * index bounds.
+ */
+static GLuint get_max_vertices(struct split_context *split,
+                              const struct _mesa_prim *prim)
+{
+   if ((prim->start > split->min_index &&
+       prim->start - split->min_index >= split->limit) ||
+       (prim->start < split->max_index &&
+        split->max_index - prim->start >= split->limit))
+      /* "prim" starts too far away from the old range. */
+      return 0;
+
+   return MIN2(split->min_index, prim->start) + split->limit - prim->start;
+}
 
 /* Break large primitives into smaller ones.  If not possible, convert
  * the primitive to indexed and pass to split_elts().
  */
 static void split_prims( struct split_context *split) 
 {
-   GLuint csr = 0;
    GLuint i;
 
    for (i = 0; i < split->nr_prims; i++) {
       const struct _mesa_prim *prim = &split->prim[i];
       GLuint first, incr;
       GLboolean split_inplace = split_prim_inplace(prim->mode, &first, &incr);
-      GLuint count;
-
-      /* Always wrap on an even numbered vertex to avoid problems with
-       * triangle strips.  
-       */
-      GLuint available = align(split->limits->max_verts - csr - 1, 2); 
-      assert(split->limits->max_verts >= csr);
+      GLuint available = get_max_vertices(split, prim);
+      GLuint count = prim->count - (prim->count - first) % incr;
 
       if (prim->count < first)
         continue;
-      
-      count = prim->count - (prim->count - first) % incr; 
 
-
-      if ((available < count && !split_inplace) || 
+      if ((available < count && !split_inplace) ||
          (available < first && split_inplace)) {
         flush_vertex(split);
-        csr = 0;
-        available = align(split->limits->max_verts - csr - 1, 2);
+        available = get_max_vertices(split, prim);
       }
       
       if (available >= count) {
         struct _mesa_prim *outprim = next_outprim(split);
+
         *outprim = *prim;
-        csr += prim->count;
-        available = align(split->limits->max_verts - csr - 1, 2); 
-      } 
+        update_index_bounds(split, outprim);
+      }
       else if (split_inplace) {
         GLuint j, nr;
 
-
         for (j = 0 ; j < count ; ) {
            GLuint remaining = count - j;
            struct _mesa_prim *outprim = next_outprim(split);
 
            nr = MIN2( available, remaining );
-           
            nr -= (nr - first) % incr;
            
            outprim->mode = prim->mode;
@@ -184,21 +178,20 @@ static void split_prims( struct split_context *split)
            outprim->end = (nr == remaining && prim->end);
            outprim->start = prim->start + j;
            outprim->count = nr;
-           
+
+           update_index_bounds(split, outprim);
+
            if (nr == remaining) {
               /* Finished. 
                */
-              j += nr;         
-              csr += nr;
-              available = align(split->limits->max_verts - csr - 1, 2); 
+              j += nr;
            }
            else {
               /* Wrapped the primitive: 
                */
               j += nr - (first - incr);
               flush_vertex(split);
-              csr = 0;
-              available = align(split->limits->max_verts - csr - 1, 2); 
+              available = get_max_vertices(split, prim);
            }
         }
       }
@@ -221,7 +214,7 @@ static void split_prims( struct split_context *split)
 
         ib.count = count;
         ib.type = GL_UNSIGNED_INT;
-        ib.obj = split->ctx->Array.NullBufferObj;
+        ib.obj = split->ctx->Shared->NullBufferObj;
         ib.ptr = elts;
            
         tmpprim = *prim;
@@ -256,7 +249,7 @@ static void split_prims( struct split_context *split)
 }
 
 
-void vbo_split_inplace( GLcontext *ctx,
+void vbo_split_inplace( struct gl_context *ctx,
                        const struct gl_client_array *arrays[],
                        const struct _mesa_prim *prim,
                        GLuint nr_prims,
@@ -275,10 +268,14 @@ void vbo_split_inplace( GLcontext *ctx,
    split.prim = prim;
    split.nr_prims = nr_prims;
    split.ib = ib;
-   split.min_index = min_index;
-   split.max_index = max_index;
+
+   /* Empty interval, makes calculations simpler. */
+   split.min_index = ~0;
+   split.max_index = 0;
+
    split.draw = draw;
    split.limits = limits;
+   split.limit = ib ? limits->max_indices : limits->max_verts;
 
    split_prims( &split );
 }