Split too-large draw commands.
authorKeith Whitwell <keith@tungstengraphics.com>
Mon, 15 Jan 2007 13:54:08 +0000 (13:54 +0000)
committerKeith Whitwell <keith@tungstengraphics.com>
Mon, 15 Jan 2007 13:54:08 +0000 (13:54 +0000)
Use the vbo_split_ functionality to split incoming drawing command
to fit within the fixed-size buffers used by software t&l module.

src/mesa/tnl/t_draw.c

index 0f9615e7cc49223dce3c9c72b50a9e80dd3793d8..25b8708948e7e51725e1af23c782df6364842171 100644 (file)
@@ -32,6 +32,7 @@
 #include "state.h"
 #include "mtypes.h"
 #include "macros.h"
+#include "enums.h"
 
 #include "t_context.h"
 #include "t_pipeline.h"
@@ -182,7 +183,7 @@ static GLboolean *_tnl_import_edgeflag( GLcontext *ctx,
 
 static void bind_inputs( GLcontext *ctx, 
                         const struct gl_client_array *inputs[],
-                        GLint start, GLint end,
+                        GLint min_index, GLint max_index,
                         struct gl_buffer_object **bo,
                         GLuint *nr_bo )
 {
@@ -214,15 +215,20 @@ static void bind_inputs( GLcontext *ctx,
         ptr = inputs[i]->Ptr;
 
       /* Just make sure the array is floating point, otherwise convert to
-       * temporary storage.  Rebase arrays so that 'start' becomes
+       * temporary storage.  Rebase arrays so that 'min_index' becomes
        * element zero.
        *
        * XXX: remove the GLvector4f type at some stage and just use
        * client arrays.
        */
-      _tnl_import_array(ctx, i, start, end, inputs[i], ptr);
+      _tnl_import_array(ctx, i, min_index, max_index, inputs[i], ptr);
    }
 
+   /* We process only the vertices between min & max index:
+    */
+   VB->Count = max_index - min_index;
+
+
    /* Legacy pointers -- remove one day.
     */
    VB->ObjPtr = VB->AttribPtr[_TNL_ATTRIB_POS];
@@ -256,10 +262,11 @@ static void bind_inputs( GLcontext *ctx,
 
 /* Translate indices to GLuints and store in VB->Elts.
  */
-static void bind_indicies( GLcontext *ctx,
-                          const struct _mesa_index_buffer *ib,
-                          struct gl_buffer_object **bo,
-                          GLuint *nr_bo)
+static void bind_indices( GLcontext *ctx,
+                         const struct _mesa_index_buffer *ib,
+                         GLuint min_index,
+                         struct gl_buffer_object **bo,
+                         GLuint *nr_bo)
 {
    TNLcontext *tnl = TNL_CONTEXT(ctx);
    struct vertex_buffer *VB = &tnl->vb;
@@ -282,7 +289,7 @@ static void bind_indicies( GLcontext *ctx,
 
    ptr = ADD_POINTERS(ib->obj->Pointer, ib->ptr);
 
-   if (ib->type == GL_UNSIGNED_INT) {
+   if (ib->type == GL_UNSIGNED_INT && min_index == 0) {
       VB->Elts = (GLuint *) ptr;
       VB->Elts += ib->rebase;
    }
@@ -291,22 +298,54 @@ static void bind_indicies( GLcontext *ctx,
       VB->Elts = elts;
 
       switch (ib->type) {
+      case GL_UNSIGNED_INT: {
+        const GLuint *in = ((GLuint *)ptr) + ib->rebase;
+        for (i = 0; i < ib->count; i++) 
+           *elts++ = *in++ - min_index;
+        break;
+      }
       case GL_UNSIGNED_SHORT: {
         const GLushort *in = ((GLushort *)ptr) + ib->rebase;
         for (i = 0; i < ib->count; i++) 
-           *elts++ = *in++;
+           *elts++ = (GLuint)(*in++) - min_index;
         break;
       }
       case GL_UNSIGNED_BYTE: {
         const GLubyte *in = ((GLubyte *)ptr) + ib->rebase;
         for (i = 0; i < ib->count; i++) 
-           *elts++ = *in++;
+           *elts++ = (GLuint)(*in++) - min_index;
         break;
       }
       }      
    }
 }
 
+static void bind_prims( GLcontext *ctx,
+                       const struct _mesa_prim *prim,
+                       GLuint nr_prims,
+                       GLuint min_index )
+{
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+   struct vertex_buffer *VB = &tnl->vb;
+   GLuint i;
+
+   if (min_index != 0) {
+      struct _mesa_prim *tmp = (struct _mesa_prim *)get_space(ctx, nr_prims * sizeof(*prim));
+
+      for (i = 0; i < nr_prims; i++) {
+        tmp[i] = prim[i];
+        tmp[i].start -= min_index;
+      }
+
+      VB->Primitive = tmp;
+   }
+   else {
+      VB->Primitive = prim;
+   }
+
+   VB->PrimitiveCount = nr_prims;
+}
+
 static void unmap_vbos( GLcontext *ctx,
                        struct gl_buffer_object **bo,
                        GLuint nr_bo )
@@ -335,26 +374,63 @@ void _tnl_draw_prims( GLcontext *ctx,
 {
    TNLcontext *tnl = TNL_CONTEXT(ctx);
    struct vertex_buffer *VB = &tnl->vb;
+   GLint max = VB->Size;
+   GLuint i;
 
-   /* May need to map a vertex buffer object for every attribute plus
-    * one for the index buffer.
-    */
-   struct gl_buffer_object *bo[VERT_ATTRIB_MAX + 1];
-   GLuint nr_bo = 0;
-
-   /* Binding inputs may imply mapping some vertex buffer objects.
-    * They will need to be unmapped below.
+#ifdef TEST_SPLIT
+   max = 8 + MAX_CLIPPED_VERTICES;
+#endif
+   
+   assert(max_index > min_index);
+   assert(!(max_index & 0x80000000));
+
+   VB->Elts = NULL;
+
+#if 0
+   _mesa_printf("%s %d..%d\n", __FUNCTION__, min_index, max_index);
+   for (i = 0; i < nr_prims; i++)
+      _mesa_printf("prim %d: %s start %d count %d\n", i, 
+                  _mesa_lookup_enum_by_nr(prim[i].mode),
+                  prim[i].start,
+                  prim[i].count);
+#endif
+
+   /* The software TNL pipeline has a fixed amount of storage for
+    * vertices and it is necessary to split incoming drawing commands
+    * if they exceed that limit.
     */
-   bind_inputs(ctx, arrays, min_index, max_index, bo, &nr_bo);
-   bind_indicies(ctx, ib, bo, &nr_bo);
+   if (max_index - min_index >= max - MAX_CLIPPED_VERTICES) {
+      struct split_limits limits;
+      limits.max_verts = max - MAX_CLIPPED_VERTICES;
+      limits.max_vb_size = ~0;
+      limits.max_indices = ~0;
+
+      /* This will split the buffers one way or another and
+       * recursively call back into this function.
+       */
+      vbo_split_prims( ctx, arrays, prim, nr_prims, ib, 
+                      min_index, max_index,
+                      _tnl_draw_prims,
+                      &limits );
+   }
+   else {
+      /* May need to map a vertex buffer object for every attribute plus
+       * one for the index buffer.
+       */
+      struct gl_buffer_object *bo[VERT_ATTRIB_MAX + 1];
+      GLuint nr_bo = 0;
 
-   VB->Primitive = prim;
-   VB->PrimitiveCount = nr_prims;
-   VB->Count = max_index - min_index;
+      /* Binding inputs may imply mapping some vertex buffer objects.
+       * They will need to be unmapped below.
+       */
+      bind_inputs(ctx, arrays, min_index, max_index+1, bo, &nr_bo);
+      bind_indices(ctx, ib, min_index, bo, &nr_bo);
+      bind_prims(ctx, prim, nr_prims, VB->Elts ? 0 : min_index );
 
-   TNL_CONTEXT(ctx)->Driver.RunPipeline(ctx);
+      TNL_CONTEXT(ctx)->Driver.RunPipeline(ctx);
 
-   unmap_vbos(ctx, bo, nr_bo);
-   free_space(ctx);
+      unmap_vbos(ctx, bo, nr_bo);
+      free_space(ctx);
+   }
 }