mesa: Branch 'vbo-0.2' - 2 commits

Keith Whitwell keithw at kemper.freedesktop.org
Wed Jan 31 14:03:23 UTC 2007


 src/mesa/drivers/dri/i965/brw_draw.c        |   53 ++++++
 src/mesa/drivers/dri/i965/brw_draw_upload.c |  105 ++-----------
 src/mesa/sources                            |    1 
 src/mesa/tnl/t_draw.c                       |  108 ++++---------
 src/mesa/vbo/vbo.h                          |   15 +
 src/mesa/vbo/vbo_exec_array.c               |  146 +++++++++---------
 src/mesa/vbo/vbo_rebase.c                   |  222 ++++++++++++++++++++++++++++
 src/mesa/vbo/vbo_split_copy.c               |    1 
 src/mesa/vbo/vbo_split_inplace.c            |    1 
 9 files changed, 420 insertions(+), 232 deletions(-)

New commits:
diff-tree 893526b8a823fe1b88f2b46376155afb91c84016 (from 240641de0c8532009fd21be7d4b0b84e471e91e8)
Author: Keith Whitwell <keith at tungstengraphics.com>
Date:   Tue Jan 30 20:22:55 2007 +0000

    Use new rebase helper.  Remove other rebase code.

diff --git a/src/mesa/drivers/dri/i965/brw_draw.c b/src/mesa/drivers/dri/i965/brw_draw.c
index 63cb079..7d8f837 100644
--- a/src/mesa/drivers/dri/i965/brw_draw.c
+++ b/src/mesa/drivers/dri/i965/brw_draw.c
@@ -198,7 +198,9 @@ static void brw_merge_inputs( struct brw
       brw->state.dirty.brw |= BRW_NEW_INPUT_VARYING;
 }
 
-
+/* XXX: could split the primitive list to fallback only on the
+ * non-conformant primitives.
+ */
 static GLboolean check_fallbacks( struct brw_context *brw,
 				  const struct _mesa_prim *prim,
 				  GLuint nr_prims )
@@ -251,7 +253,9 @@ static GLboolean check_fallbacks( struct
    return GL_FALSE;
 }
 
-
+/* May fail if out of video memory for texture or vbo upload, or on
+ * fallback conditions.
+ */
 static GLboolean brw_try_draw_prims( GLcontext *ctx,
 				     const struct gl_client_array *arrays[],
 				     const struct _mesa_prim *prim,
@@ -376,6 +380,33 @@ static GLboolean brw_try_draw_prims( GLc
    return retval;
 }
 
+static GLboolean brw_need_rebase( GLcontext *ctx,
+				  const struct gl_client_array *arrays[],
+				  const struct _mesa_index_buffer *ib,
+				  GLuint min_index )
+{
+   if (min_index == 0) 
+      return GL_FALSE;
+
+   if (ib) {
+      if (!vbo_all_varyings_in_vbos(arrays))
+	 return GL_TRUE;
+      else
+	 return GL_FALSE;
+   }
+   else {
+      /* Hmm.  This isn't quite what I wanted.  BRW can actually
+       * handle the mixed case well enough that we shouldn't need to
+       * rebase.  However, it's probably not very common, nor hugely
+       * expensive to do it this way:
+       */
+      if (!vbo_all_varyings_in_vbos(arrays))
+	 return GL_TRUE;
+      else
+	 return GL_FALSE;
+   }
+}
+				  
 
 void brw_draw_prims( GLcontext *ctx,
 		     const struct gl_client_array *arrays[],
@@ -388,6 +419,21 @@ void brw_draw_prims( GLcontext *ctx,
    struct intel_context *intel = intel_context(ctx);
    GLboolean retval;
 
+   /* Decide if we want to rebase.  If so we end up recursing once
+    * only into this function.
+    */
+   if (brw_need_rebase( ctx, arrays, ib, min_index )) {
+      vbo_rebase_prims( ctx, arrays, 
+			prim, nr_prims, 
+			ib, min_index, max_index, 
+			brw_draw_prims );
+      
+      return;
+   }
+
+
+   /* Make a first attempt at drawing:
+    */
    retval = brw_try_draw_prims(ctx, arrays, prim, nr_prims, ib, min_index, max_index);
 
    
@@ -440,14 +486,13 @@ void brw_draw_init( struct brw_context *
    for (i = 0; i < BRW_NR_UPLOAD_BUFS; i++) {
       brw->vb.upload.vbo[i] = ctx->Driver.NewBufferObject(ctx, 1, GL_ARRAY_BUFFER_ARB);
       
-      /* XXX: Set these to no-backing-store
+      /* NOTE:  These are set to no-backing-store.
        */
       bmBufferSetInvalidateCB(&brw->intel,
 			      intel_bufferobj_buffer(intel_buffer_object(brw->vb.upload.vbo[i])),
 			      brw_invalidate_vbo_cb,
 			      &brw->intel,
 			      GL_TRUE);
-
    }
 
    ctx->Driver.BufferData( ctx, 
diff --git a/src/mesa/drivers/dri/i965/brw_draw_upload.c b/src/mesa/drivers/dri/i965/brw_draw_upload.c
index 90637d1..6968d74 100644
--- a/src/mesa/drivers/dri/i965/brw_draw_upload.c
+++ b/src/mesa/drivers/dri/i965/brw_draw_upload.c
@@ -309,7 +309,6 @@ copy_array_to_vbo_array( struct brw_cont
 			 GLuint i,
 			 const struct gl_client_array *array,
 			 GLuint element_size,
-			 GLuint min_index,
 			 GLuint count)
 {
    GLcontext *ctx = &brw->intel.ctx;
@@ -347,7 +346,7 @@ copy_array_to_vbo_array( struct brw_cont
       map += offset;
 
       copy_strided_array( map, 
-			  array->Ptr + min_index * array->StrideB,
+			  array->Ptr,
 			  element_size,
 			  array->StrideB,
 			  count);
@@ -438,10 +437,8 @@ GLboolean brw_upload_vertices( struct br
 	 }
 
 	 upload[nr_uploads++] = input;
-	 input->vbo_rebase_offset = 0;
+	 assert(min_index == 0);
       }
-      else 
-	 input->vbo_rebase_offset = min_index * input->glarray->StrideB;
    }
 
    /* Upload interleaved arrays if all uploads are interleaved
@@ -454,7 +451,6 @@ GLboolean brw_upload_vertices( struct br
       input0->glarray = copy_array_to_vbo_array(brw, 0,
 						input0->glarray, 
 						interleave,
-						min_index,
 						input0->count);
 
       for (i = 1; i < nr_uploads; i++) {
@@ -472,7 +468,6 @@ GLboolean brw_upload_vertices( struct br
 	 input->glarray = copy_array_to_vbo_array(brw, i, 
 						  input->glarray,
 						  input->element_size,
-						  min_index,
 						  input->count);
 
       }
@@ -520,9 +515,9 @@ GLboolean brw_upload_vertices( struct br
       vbp.vb[i].vb0.bits.pad = 0;
       vbp.vb[i].vb0.bits.access_type = BRW_VERTEXBUFFER_ACCESS_VERTEXDATA;
       vbp.vb[i].vb0.bits.vb_index = i;
-      vbp.vb[i].offset = (GLuint)input->glarray->Ptr + input->vbo_rebase_offset;
+      vbp.vb[i].offset = (GLuint)input->glarray->Ptr;
       vbp.vb[i].buffer = array_buffer(input->glarray);
-      vbp.vb[i].max_index = max_index - min_index;
+      vbp.vb[i].max_index = max_index;
    }
 
 
@@ -563,94 +558,32 @@ static GLuint element_size( GLenum type 
 
 
 
-
-static void rebase_indices_to_vbo_indices( struct brw_context *brw, 
-					   const struct _mesa_index_buffer *index_buffer,
-					   struct gl_buffer_object **vbo_return,
-					   GLuint *offset_return )
+void brw_upload_indices( struct brw_context *brw,
+			 const struct _mesa_index_buffer *index_buffer )
 {
    GLcontext *ctx = &brw->intel.ctx;
-   GLuint min_index = index_buffer->rebase;
-   const void *indices = index_buffer->ptr;
-   GLsizei count = index_buffer->count;
-   GLenum type = index_buffer->type;
-   GLuint size = element_size(type) * count;
-   struct gl_buffer_object *bufferobj;
-   GLuint offset;
-   GLuint i;
-
-   get_space(brw, size, &bufferobj, &offset);
+   struct intel_context *intel = &brw->intel;
+   GLuint ib_size = get_size(index_buffer->type) * index_buffer->count;
+   struct gl_buffer_object *bufferobj = index_buffer->obj;
+   GLuint offset = (GLuint)index_buffer->ptr;
 
-   *vbo_return = bufferobj;
-   *offset_return = offset;
+   /* Turn into a proper VBO:
+    */
+   if (!bufferobj->Name) {
+     
+      /* Get new bufferobj, offset:
+       */
+      get_space(brw, ib_size, &bufferobj, &offset);
 
-   if (min_index == 0) {
       /* Straight upload
        */
       ctx->Driver.BufferSubData( ctx,
 				 GL_ELEMENT_ARRAY_BUFFER_ARB,
 				 offset, 
-				 size,
-				 indices,
+				 ib_size,
+				 index_buffer->ptr,
 				 bufferobj);
    }
-   else {
-      void *map = ctx->Driver.MapBuffer(ctx,
-					GL_ELEMENT_ARRAY_BUFFER_ARB,
-					GL_DYNAMIC_DRAW_ARB,
-					bufferobj);
-
-      map += offset;
-
-      switch (type) {
-      case GL_UNSIGNED_INT: {
-	 GLuint *ui_map = (GLuint *)map;
-	 const GLuint *ui_indices = (const GLuint *)indices;
-
-	 for (i = 0; i < count; i++)
-	    ui_map[i] = ui_indices[i] - min_index;
-	 break;
-      }
-      case GL_UNSIGNED_SHORT:  {
-	 GLushort *us_map = (GLushort *)map;
-	 const GLushort *us_indices = (const GLushort *)indices;
-
-	 for (i = 0; i < count; i++)
-	    us_map[i] = us_indices[i] - min_index;
-	 break;
-      }
-      case GL_UNSIGNED_BYTE:  {
-	 GLubyte *ub_map = (GLubyte *)map;
-	 const GLubyte *ub_indices = (const GLubyte *)indices;
-
-	 for (i = 0; i < count; i++)
-	    ub_map[i] = ub_indices[i] - min_index;
-	 break;
-      }
-      }
-
-      ctx->Driver.UnmapBuffer(ctx, 
-			      GL_ELEMENT_ARRAY_BUFFER_ARB, 
-			      bufferobj);
-
-   }
-}
-
-
-
-void brw_upload_indices( struct brw_context *brw,
-			 const struct _mesa_index_buffer *index_buffer)
-{
-   struct intel_context *intel = &brw->intel;
-   GLuint ib_size = get_size(index_buffer->type) * index_buffer->count;
-   struct gl_buffer_object *bufferobj = index_buffer->obj;
-   GLuint offset = (GLuint)index_buffer->ptr;
-
-   /* Already turned into a proper VBO:
-    */
-   if (!index_buffer->obj->Name) {
-      rebase_indices_to_vbo_indices(brw, index_buffer, &bufferobj, &offset );
-   }
 
    /* Emit the indexbuffer packet:
     */
diff --git a/src/mesa/tnl/t_draw.c b/src/mesa/tnl/t_draw.c
index 0e7c2b6..c97cf5f 100644
--- a/src/mesa/tnl/t_draw.c
+++ b/src/mesa/tnl/t_draw.c
@@ -95,18 +95,14 @@ static void free_space(GLcontext *ctx)
  */
 static void _tnl_import_array( GLcontext *ctx,
 			       GLuint attrib,
-			       GLuint start,
-			       GLuint end,
+			       GLuint count,
 			       const struct gl_client_array *input,
 			       const GLubyte *ptr )
 {
    TNLcontext *tnl = TNL_CONTEXT(ctx);
    struct vertex_buffer *VB = &tnl->vb;
-   const GLuint count = end - start;
    GLuint stride = input->StrideB;
 
-   ptr += start * stride;
-
    if (input->Type != GL_FLOAT) {
       const GLuint sz = input->Size;
       GLubyte *buf = get_space(ctx, count * sz * sizeof(GLfloat));
@@ -183,7 +179,7 @@ static GLboolean *_tnl_import_edgeflag( 
 
 static void bind_inputs( GLcontext *ctx, 
 			 const struct gl_client_array *inputs[],
-			 GLint min_index, GLint max_index,
+			 GLint count,
 			 struct gl_buffer_object **bo,
 			 GLuint *nr_bo )
 {
@@ -215,18 +211,17 @@ 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 'min_index' becomes
-       * element zero.
+       * temporary storage.  
        *
        * XXX: remove the GLvector4f type at some stage and just use
        * client arrays.
        */
-      _tnl_import_array(ctx, i, min_index, max_index, inputs[i], ptr);
+      _tnl_import_array(ctx, i, count, inputs[i], ptr);
    }
 
    /* We process only the vertices between min & max index:
     */
-   VB->Count = max_index - min_index;
+   VB->Count = count;
 
 
    /* Legacy pointers -- remove one day.
@@ -264,7 +259,6 @@ static void bind_inputs( GLcontext *ctx,
  */
 static void bind_indices( GLcontext *ctx,
 			  const struct _mesa_index_buffer *ib,
-			  GLuint min_index,
 			  struct gl_buffer_object **bo,
 			  GLuint *nr_bo)
 {
@@ -273,8 +267,10 @@ static void bind_indices( GLcontext *ctx
    GLuint i;
    void *ptr;
 
-   if (!ib)
+   if (!ib) {
+      VB->Elts = NULL;
       return;
+   }
 
    if (ib->obj->Name && !ib->obj->Pointer) {
       bo[*nr_bo] = ib->obj;
@@ -289,60 +285,34 @@ static void bind_indices( GLcontext *ctx
 
    ptr = ADD_POINTERS(ib->obj->Pointer, ib->ptr);
 
-   if (ib->type == GL_UNSIGNED_INT && min_index == 0) {
+   if (ib->type == GL_UNSIGNED_INT) {
       VB->Elts = (GLuint *) ptr;
-      VB->Elts += ib->rebase;
    }
    else {
       GLuint *elts = (GLuint *)get_space(ctx, ib->count * sizeof(GLuint));
       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;
+      if (ib->type == GL_UNSIGNED_SHORT) {
+	 const GLushort *in = (GLushort *)ptr;
 	 for (i = 0; i < ib->count; i++) 
-	    *elts++ = (GLuint)(*in++) - min_index;
-	 break;
+	    *elts++ = (GLuint)(*in++);
       }
-      case GL_UNSIGNED_BYTE: {
-	 const GLubyte *in = ((GLubyte *)ptr) + ib->rebase;
+      else {
+	 const GLubyte *in = (GLubyte *)ptr;
 	 for (i = 0; i < ib->count; i++) 
-	    *elts++ = (GLuint)(*in++) - min_index;
-	 break;
+	    *elts++ = (GLuint)(*in++);
       }
-      }      
    }
 }
 
 static void bind_prims( GLcontext *ctx,
 			const struct _mesa_prim *prim,
-			GLuint nr_prims,
-			GLuint min_index )
+			GLuint nr_prims )
 {
    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->Primitive = prim;
    VB->PrimitiveCount = nr_prims;
 }
 
@@ -373,19 +343,10 @@ void _tnl_draw_prims( GLcontext *ctx,
 		      GLuint max_index)
 {
    TNLcontext *tnl = TNL_CONTEXT(ctx);
-   struct vertex_buffer *VB = &tnl->vb;
-   GLint max = VB->Size;
-
-#ifdef TEST_SPLIT
-   max = 8 + MAX_CLIPPED_VERTICES;
-#endif
-   
-   assert(max_index > min_index);
-   assert(!(max_index & 0x80000000));
+   const GLuint TEST_SPLIT = 0;
+   const GLint max = TEST_SPLIT ? 8 : tnl->vb.Size - MAX_CLIPPED_VERTICES;
 
-   VB->Elts = NULL;
-
-#if 0
+   if (0)
    {
       GLuint i;
       _mesa_printf("%s %d..%d\n", __FUNCTION__, min_index, max_index);
@@ -395,15 +356,22 @@ void _tnl_draw_prims( GLcontext *ctx,
 		      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.
-    */
-   if (max_index - min_index >= max - MAX_CLIPPED_VERTICES) {
+   if (min_index) {
+      /* We always translate away calls with min_index != 0. 
+       */
+      vbo_rebase_prims( ctx, arrays, prim, nr_prims, ib, 
+			min_index, max_index,
+			_tnl_draw_prims );
+      return;
+   }
+   else if (max_index >= max) {
+      /* 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.
+       */
       struct split_limits limits;
-      limits.max_verts = max - MAX_CLIPPED_VERTICES;
+      limits.max_verts = max;
       limits.max_vb_size = ~0;
       limits.max_indices = ~0;
 
@@ -411,7 +379,7 @@ void _tnl_draw_prims( GLcontext *ctx,
        * recursively call back into this function.
        */
       vbo_split_prims( ctx, arrays, prim, nr_prims, ib, 
-		       min_index, max_index,
+		       0, max_index,
 		       _tnl_draw_prims,
 		       &limits );
    }
@@ -425,9 +393,9 @@ void _tnl_draw_prims( GLcontext *ctx,
       /* 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 );
+      bind_inputs(ctx, arrays, max_index+1, bo, &nr_bo);
+      bind_indices(ctx, ib, bo, &nr_bo);
+      bind_prims(ctx, prim, nr_prims );
 
       TNL_CONTEXT(ctx)->Driver.RunPipeline(ctx);
 
diff --git a/src/mesa/vbo/vbo.h b/src/mesa/vbo/vbo.h
index 6a6fb28..874a5f9 100644
--- a/src/mesa/vbo/vbo.h
+++ b/src/mesa/vbo/vbo.h
@@ -55,7 +55,6 @@ struct _mesa_index_buffer {
    GLenum type;
    struct gl_buffer_object *obj;
    const void *ptr;
-   GLuint rebase;
 };
 
 
diff --git a/src/mesa/vbo/vbo_exec_array.c b/src/mesa/vbo/vbo_exec_array.c
index 5a3a748..f96df5f 100644
--- a/src/mesa/vbo/vbo_exec_array.c
+++ b/src/mesa/vbo/vbo_exec_array.c
@@ -34,45 +34,55 @@
 
 #include "vbo_context.h"
 
-static GLuint get_max_index( GLuint count, GLuint type, 
-			     const GLvoid *indices )
+/* Compute min and max elements for drawelements calls.
+ */
+static void get_minmax_index( GLuint count, GLuint type, 
+			      const GLvoid *indices,
+			      GLuint *min_index,
+			      GLuint *max_index)
 {
    GLint i;
 
-   /* Compute max element.  This is only needed for upload of non-VBO,
-    * non-constant data elements.
-    *
-    * XXX: Postpone this calculation until it is known that it is
-    * needed.  Otherwise could scan this pointlessly in the all-vbo
-    * case.
-    */
    switch(type) {
    case GL_UNSIGNED_INT: {
       const GLuint *ui_indices = (const GLuint *)indices;
-      GLuint max_ui = 0;
-      for (i = 0; i < count; i++)
-	 if (ui_indices[i] > max_ui)
-	    max_ui = ui_indices[i];
-      return max_ui;
+      GLuint max_ui = ui_indices[0];
+      GLuint min_ui = ui_indices[0];
+      for (i = 1; i < count; i++) {
+	 if (ui_indices[i] > max_ui) max_ui = ui_indices[i];
+	 if (ui_indices[i] < min_ui) min_ui = ui_indices[i];
+      }
+      *min_index = min_ui;
+      *max_index = max_ui;
+      break;
    }
    case GL_UNSIGNED_SHORT: {
       const GLushort *us_indices = (const GLushort *)indices;
-      GLuint max_us = 0;
-      for (i = 0; i < count; i++)
-	 if (us_indices[i] > max_us)
-	    max_us = us_indices[i];
-      return max_us;
+      GLuint max_us = us_indices[0];
+      GLuint min_us = us_indices[0];
+      for (i = 1; i < count; i++) {
+	 if (us_indices[i] > max_us) max_us = us_indices[i];
+	 if (us_indices[i] < min_us) min_us = us_indices[i];
+      }
+      *min_index = min_us;
+      *max_index = max_us;
+      break;
    }
    case GL_UNSIGNED_BYTE: {
       const GLubyte *ub_indices = (const GLubyte *)indices;
-      GLuint max_ub = 0;
-      for (i = 0; i < count; i++)
-	 if (ub_indices[i] > max_ub)
-	    max_ub = ub_indices[i];
-      return max_ub;
+      GLuint max_ub = ub_indices[0];
+      GLuint min_ub = ub_indices[0];
+      for (i = 1; i < count; i++) {
+	 if (ub_indices[i] > max_ub) max_ub = ub_indices[i];
+	 if (ub_indices[i] < min_ub) min_ub = ub_indices[i];
+      }
+      *min_index = min_ub;
+      *max_index = max_ub;
+      break;
    }
    default:
-      return 0;
+      assert(0);
+      break;
    }
 }
 
@@ -241,31 +251,12 @@ vbo_exec_DrawArrays(GLenum mode, GLint s
    prim[0].end = 1;
    prim[0].weak = 0;
    prim[0].pad = 0;
+   prim[0].mode = mode;
+   prim[0].start = start;
+   prim[0].count = count;
+   prim[0].indexed = 0;
 
-   if (exec->array.inputs[0]->BufferObj->Name) {
-      /* Use vertex attribute as a hint to tell us if we expect all
-       * arrays to be in VBO's and if so, don't worry about avoiding
-       * the upload of elements < start.
-       */
-      prim[0].mode = mode;
-      prim[0].start = start;
-      prim[0].count = count;
-      prim[0].indexed = 0;
-
-      vbo->draw_prims( ctx, exec->array.inputs, prim, 1, NULL, 0, start + count );
-   }
-   else {
-      /* If not using VBO's, we don't want to upload any more elements
-       * than necessary from the arrays as they will not be valid next
-       * time the application tries to draw with them.
-       */
-      prim[0].mode = mode;
-      prim[0].start = 0;
-      prim[0].count = count;
-      prim[0].indexed = 0;
-
-      vbo->draw_prims( ctx, exec->array.inputs, prim, 1, NULL, start, start + count );
-   }
+   vbo->draw_prims( ctx, exec->array.inputs, prim, 1, NULL, start, start + count - 1 );
 }
 
 
@@ -296,20 +287,6 @@ vbo_exec_DrawRangeElements(GLenum mode,
    ib.obj = ctx->Array.ElementArrayBufferObj;
    ib.ptr = indices;
 
-   if (ctx->Array.ElementArrayBufferObj->Name) {
-      /* Use the fact that indices are in a VBO as a hint that the
-       * program has put all the arrays in VBO's and we don't have to
-       * worry about performance implications of start > 0.
-       *
-       * XXX: consider passing start as min_index to draw_prims instead.
-       * XXX: don't rebase because it didn't work.
-       */
-      ib.rebase = 0;
-   }
-   else {
-      ib.rebase = /*start*/ 0;
-   }
-
    prim[0].begin = 1;
    prim[0].end = 1;
    prim[0].weak = 0;
@@ -319,15 +296,46 @@ vbo_exec_DrawRangeElements(GLenum mode,
    prim[0].count = count;
    prim[0].indexed = 1;
 
-   vbo->draw_prims( ctx, exec->array.inputs, prim, 1, &ib, /*ib.rebase*/ start, end+1 );
-}
+   /* Need to give special consideration to rendering a range of
+    * indices starting somewhere above zero.  Typically the
+    * application is issuing multiple DrawRangeElements() to draw
+    * successive primitives layed out linearly in the vertex arrays.
+    * Unless the vertex arrays are all in a VBO (or locked as with
+    * CVA), the OpenGL semantics imply that we need to re-read or
+    * re-upload the vertex data on each draw call.  
+    *
+    * In the case of hardware tnl, we want to avoid starting the
+    * upload at zero, as it will mean every draw call uploads an
+    * increasing amount of not-used vertex data.  Worse - in the
+    * software tnl module, all those vertices might be transformed and
+    * lit but never rendered.
+    *
+    * If we just upload or transform the vertices in start..end,
+    * however, the indices will be incorrect.
+    *
+    * At this level, we don't know exactly what the requirements of
+    * the backend are going to be, though it will likely boil down to
+    * either:
+    *
+    * 1) Do nothing, everything is in a VBO and is processed once
+    *       only.
+    *
+    * 2) Adjust the indices and vertex arrays so that start becomes
+    *    zero.
+    *
+    * Rather than doing anything here, I'll provide a helper function
+    * for the latter case elsewhere.
+    */
 
+   vbo->draw_prims( ctx, exec->array.inputs, prim, 1, &ib, start, end );
+}
 
 static void GLAPIENTRY
 vbo_exec_DrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
 {
    GET_CURRENT_CONTEXT(ctx);
-   GLuint max_index;
+   GLuint min_index = 0;
+   GLuint max_index = 0;
 
    if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices ))
       return;
@@ -338,17 +346,17 @@ vbo_exec_DrawElements(GLenum mode, GLsiz
 						 GL_READ_ONLY,
 						 ctx->Array.ElementArrayBufferObj);
 
-      max_index = get_max_index(count, type, ADD_POINTERS(map, indices));
+      get_minmax_index(count, type, ADD_POINTERS(map, indices), &min_index, &max_index);
 
       ctx->Driver.UnmapBuffer(ctx,
 			      GL_ELEMENT_ARRAY_BUFFER_ARB,
 			      ctx->Array.ElementArrayBufferObj);
    }
    else {
-      max_index = get_max_index(count, type, indices);
+      get_minmax_index(count, type, indices, &min_index, &max_index);
    }
 
-   vbo_exec_DrawRangeElements(mode, 0, max_index, count, type, indices);
+   vbo_exec_DrawRangeElements(mode, min_index, max_index, count, type, indices);
 }
 
 
diff --git a/src/mesa/vbo/vbo_rebase.c b/src/mesa/vbo/vbo_rebase.c
index 2a6f037..bc4211d 100644
--- a/src/mesa/vbo/vbo_rebase.c
+++ b/src/mesa/vbo/vbo_rebase.c
@@ -123,7 +123,8 @@ void vbo_rebase_prims( GLcontext *ctx,
 
    assert(min_index != 0);
 
-   _mesa_printf("%s %d..%d\n", __FUNCTION__, min_index, max_index);
+   if (0)
+      _mesa_printf("%s %d..%d\n", __FUNCTION__, min_index, max_index);
 
    if (ib) {
       /* Unfortunately need to adjust each index individually.
diff --git a/src/mesa/vbo/vbo_split_copy.c b/src/mesa/vbo/vbo_split_copy.c
index d9c5853..ef97acb 100644
--- a/src/mesa/vbo/vbo_split_copy.c
+++ b/src/mesa/vbo/vbo_split_copy.c
@@ -479,7 +479,6 @@ static void replay_init( struct copy_con
    copy->dstib.type = GL_UNSIGNED_INT;
    copy->dstib.obj = ctx->Array.NullBufferObj;
    copy->dstib.ptr = copy->dstelt;
-   copy->dstib.rebase = 0;	
 }
 
 
diff --git a/src/mesa/vbo/vbo_split_inplace.c b/src/mesa/vbo/vbo_split_inplace.c
index d3649c5..ea62866 100644
--- a/src/mesa/vbo/vbo_split_inplace.c
+++ b/src/mesa/vbo/vbo_split_inplace.c
@@ -223,7 +223,6 @@ static void split_prims( struct split_co
 	 ib.type = GL_UNSIGNED_INT;
 	 ib.obj = split->ctx->Array.NullBufferObj;
 	 ib.ptr = elts;
-	 ib.rebase = 0;		/* ? */
 	    
 	 tmpprim = *prim;
 	 tmpprim.indexed = 1;
diff-tree 240641de0c8532009fd21be7d4b0b84e471e91e8 (from 48c638b6712734a09b6d8632045b0e905195e345)
Author: Keith Whitwell <keith at tungstengraphics.com>
Date:   Tue Jan 30 19:27:53 2007 +0000

    Helper for rebasing draw requests where min_index != 0.

diff --git a/src/mesa/sources b/src/mesa/sources
index fd6e8b4..6d6d228 100644
--- a/src/mesa/sources
+++ b/src/mesa/sources
@@ -143,6 +143,7 @@ VBO_SOURCES = \
 	vbo/vbo_exec_array.c \
 	vbo/vbo_exec_draw.c \
 	vbo/vbo_exec_eval.c \
+	vbo/vbo_rebase.c \
 	vbo/vbo_split.c \
 	vbo/vbo_split_copy.c \
 	vbo/vbo_split_inplace.c \
diff --git a/src/mesa/vbo/vbo.h b/src/mesa/vbo/vbo.h
index c81d83f..6a6fb28 100644
--- a/src/mesa/vbo/vbo.h
+++ b/src/mesa/vbo/vbo.h
@@ -101,4 +101,18 @@ void vbo_split_prims( GLcontext *ctx,
 		      const struct split_limits *limits );
 
 
+/* Helpers for dealing translating away non-zero min_index.
+ */
+GLboolean vbo_all_varyings_in_vbos( const struct gl_client_array *arrays[] );
+
+void vbo_rebase_prims( GLcontext *ctx,
+		       const struct gl_client_array *arrays[],
+		       const struct _mesa_prim *prim,
+		       GLuint nr_prims,
+		       const struct _mesa_index_buffer *ib,
+		       GLuint min_index,
+		       GLuint max_index,
+		       vbo_draw_func draw );
+
+
 #endif
diff --git a/src/mesa/vbo/vbo_rebase.c b/src/mesa/vbo/vbo_rebase.c
new file mode 100644
index 0000000..2a6f037
--- /dev/null
+++ b/src/mesa/vbo/vbo_rebase.c
@@ -0,0 +1,221 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  6.5
+ *
+ * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Keith Whitwell <keith at tungstengraphics.com>
+ */
+
+/* Helper for drivers which find themselves rendering a range of
+ * indices starting somewhere above zero.  Typically the application
+ * is issuing multiple DrawArrays() or DrawElements() to draw
+ * successive primitives layed out linearly in the vertex arrays.
+ * Unless the vertex arrays are all in a VBO, the OpenGL semantics
+ * imply that we need to re-upload the vertex data on each draw call.
+ * In that case, we want to avoid starting the upload at zero, as it
+ * will mean every draw call uploads an increasing amount of not-used
+ * vertex data.  Worse - in the software tnl module, all those
+ * vertices will be transformed and lit.
+ *
+ * If we just upload the new data, however, the indices will be
+ * incorrect as we tend to upload each set of vertex data to a new
+ * region.  
+ *
+ * This file provides a helper to adjust the arrays, primitives and
+ * indices of a draw call so that it can be re-issued with a min_index
+ * of zero.
+ */
+
+#include "glheader.h"
+#include "imports.h"
+#include "mtypes.h"
+
+#include "vbo.h"
+
+
+#define REBASE(TYPE) 						\
+static void *rebase_##TYPE( const void *ptr,			\
+			  GLuint count, 			\
+			  TYPE min_index )			\
+{								\
+   const TYPE *in = (TYPE *)ptr;				\
+   TYPE *tmp_indices = malloc(count * sizeof(TYPE));	\
+   GLuint i;							\
+								\
+   for (i = 0; i < count; i++)  				\
+      tmp_indices[i] = in[i] - min_index;			\
+								\
+   return (void *)tmp_indices;					\
+}
+
+
+REBASE(GLuint)
+REBASE(GLushort)
+REBASE(GLubyte)
+
+GLboolean vbo_all_varyings_in_vbos( const struct gl_client_array *arrays[] )
+{
+   GLuint i;
+   
+   for (i = 0; i < VERT_ATTRIB_MAX; i++)
+      if (arrays[i]->StrideB &&
+	  arrays[i]->BufferObj->Name == 0)
+	 return GL_FALSE;
+
+   return GL_TRUE;
+}
+
+/* Adjust primitives, indices and vertex definitions so that min_index
+ * becomes zero. There are lots of reasons for wanting to do this, eg:
+ *
+ * Software tnl:
+ *    - any time min_index != 0, otherwise unused vertices lower than
+ *      min_index will be transformed.
+ *
+ * Hardware tnl:
+ *    - if ib != NULL and min_index != 0, otherwise vertices lower than 
+ *      min_index will be uploaded.  Requires adjusting index values.
+ *
+ *    - if ib == NULL and min_index != 0, just for convenience so this doesn't
+ *      have to be handled within the driver.
+ *
+ * Hardware tnl with VBO support:
+ *    - as above, but only when vertices are not (all?) in VBO's.
+ *    - can't save time by trying to upload half a vbo - typically it is
+ *      all or nothing.
+ */
+void vbo_rebase_prims( GLcontext *ctx,
+		       const struct gl_client_array *arrays[],
+		       const struct _mesa_prim *prim,
+		       GLuint nr_prims,
+		       const struct _mesa_index_buffer *ib,
+		       GLuint min_index,
+		       GLuint max_index,
+		       vbo_draw_func draw )
+{
+   struct gl_client_array tmp_arrays[VERT_ATTRIB_MAX];
+   const struct gl_client_array *tmp_array_pointers[VERT_ATTRIB_MAX];
+
+   struct _mesa_index_buffer tmp_ib;
+   struct _mesa_prim *tmp_prims = NULL;
+   void *tmp_indices = NULL;
+   GLuint i;
+
+   assert(min_index != 0);
+
+   _mesa_printf("%s %d..%d\n", __FUNCTION__, min_index, max_index);
+
+   if (ib) {
+      /* Unfortunately need to adjust each index individually.
+       */
+      GLboolean map_ib = ib->obj->Name && !ib->obj->Pointer;
+      void *ptr;
+
+      if (map_ib) 
+	 ctx->Driver.MapBuffer(ctx, 
+			       GL_ELEMENT_ARRAY_BUFFER,
+			       GL_READ_ONLY_ARB,
+			       ib->obj);
+
+
+      ptr = ADD_POINTERS(ib->obj->Pointer, ib->ptr);
+
+      /* Some users might prefer it if we translated elements to
+       * GLuints here.  Others wouldn't...
+       */
+      switch (ib->type) {
+      case GL_UNSIGNED_INT: 
+	 tmp_indices = rebase_GLuint( ptr, ib->count, min_index );
+	 break;
+      case GL_UNSIGNED_SHORT: 
+	 tmp_indices = rebase_GLushort( ptr, ib->count, min_index );
+	 break;
+      case GL_UNSIGNED_BYTE: 
+	 tmp_indices = rebase_GLubyte( ptr, ib->count, min_index );
+	 break;
+      }      
+
+      if (map_ib) 
+	 ctx->Driver.UnmapBuffer(ctx, 
+				 GL_ELEMENT_ARRAY_BUFFER,
+				 ib->obj);
+
+      tmp_ib.obj = ctx->Array.NullBufferObj;
+      tmp_ib.ptr = tmp_indices;
+      tmp_ib.count = ib->count;
+      tmp_ib.type = ib->type;
+
+      ib = &tmp_ib;
+   }
+   else {
+      /* Otherwise the primitives need adjustment.
+       */
+      tmp_prims = (struct _mesa_prim *)_mesa_malloc(sizeof(*prim) * nr_prims);
+
+      for (i = 0; i < nr_prims; i++) {
+	 /* If this fails, it could indicate an application error:
+	  */
+	 assert(prim[i].start >= min_index);
+
+	 tmp_prims[i] = prim[i];
+	 tmp_prims[i].start -= min_index;
+      }
+
+      prim = tmp_prims;
+   }
+
+   /* Just need to adjust the pointer values on each incoming array.
+    * This works for VBO and non-vbo rendering and shouldn't pesimize
+    * VBO-based upload schemes.  However this may still not be a fast
+    * path for hardware tnl for VBO based rendering as most machines
+    * will be happier if you just specify a starting vertex value in
+    * each primitive.
+    *
+    * For drivers with hardware tnl, you only want to do this if you
+    * are forced to, eg non-VBO indexed rendering with start != 0.
+    */
+   for (i = 0; i < VERT_ATTRIB_MAX; i++) {
+      tmp_arrays[i] = *arrays[i];
+      tmp_arrays[i].Ptr += min_index * tmp_arrays[i].StrideB;
+      tmp_array_pointers[i] = &tmp_arrays[i];
+   }
+   
+   /* Re-issue the draw call.
+    */
+   draw( ctx, 
+	 tmp_array_pointers, 
+	 prim, 
+	 nr_prims, 
+	 ib, 
+	 0, 
+	 max_index - min_index );
+   
+   if (tmp_indices)
+      _mesa_free(tmp_indices);
+   
+   if (tmp_prims)
+      _mesa_free(tmp_prims);
+}
+
+
+



More information about the mesa-commit mailing list