mesa: Add support for ARB_draw_elements_base_vertex.
authorEric Anholt <eric@anholt.net>
Thu, 27 Aug 2009 17:09:24 +0000 (10:09 -0700)
committerEric Anholt <eric@anholt.net>
Tue, 8 Sep 2009 22:12:20 +0000 (15:12 -0700)
20 files changed:
src/mesa/drivers/dri/swrast/swrast.c
src/mesa/drivers/x11/xm_api.c
src/mesa/main/api_noop.c
src/mesa/main/api_noop.h
src/mesa/main/api_validate.c
src/mesa/main/api_validate.h
src/mesa/main/dd.h
src/mesa/main/dlist.c
src/mesa/main/extensions.c
src/mesa/main/mtypes.h
src/mesa/main/varray.h
src/mesa/main/vtxfmt.c
src/mesa/main/vtxfmt_tmp.h
src/mesa/tnl/t_draw.c
src/mesa/vbo/vbo.h
src/mesa/vbo/vbo_exec_array.c
src/mesa/vbo/vbo_rebase.c
src/mesa/vbo/vbo_save_api.c
src/mesa/vbo/vbo_split.c
src/mesa/vbo/vbo_split_copy.c

index 2d2aa5e..3016987 100644 (file)
@@ -62,6 +62,7 @@
 #define need_GL_SGI_color_table
 
 /* sw extensions not associated with some GL version */
+#define need_GL_ARB_draw_elements_base_vertex
 #define need_GL_ARB_shader_objects
 #define need_GL_ARB_vertex_array_object
 #define need_GL_ARB_vertex_program
@@ -96,6 +97,7 @@ const struct dri_extension card_extensions[] =
     { "GL_SGI_color_table",            GL_SGI_color_table_functions },
 
     { "GL_ARB_depth_clamp",            NULL },
+    { "GL_ARB_draw_elements_base_vertex", GL_ARB_draw_elements_base_vertex_functions },
     { "GL_ARB_shader_objects",         GL_ARB_shader_objects_functions },
     { "GL_ARB_vertex_array_object",    GL_ARB_vertex_array_object_functions },
     { "GL_ARB_vertex_program",         GL_ARB_vertex_program_functions },
index 777635b..662c61a 100644 (file)
@@ -1317,6 +1317,7 @@ xmesa_convert_from_x_visual_type( int visualType )
 #define need_GL_SGI_color_table
 
 /* sw extensions not associated with some GL version */
+#define need_GL_ARB_draw_elements_base_vertex
 #define need_GL_ARB_shader_objects
 #define need_GL_ARB_sync
 #define need_GL_ARB_vertex_program
@@ -1348,6 +1349,7 @@ const struct dri_extension card_extensions[] =
    { "GL_SGI_color_table",             GL_SGI_color_table_functions },
 
    { "GL_ARB_depth_clamp",             NULL },
+   { "GL_ARB_draw_elements_base_vertex", GL_ARB_draw_elements_base_vertex_functions },
    { "GL_ARB_shader_objects",          GL_ARB_shader_objects_functions },
    { "GL_ARB_sync",                    GL_ARB_sync_functions },
    { "GL_ARB_vertex_program",          GL_ARB_vertex_program_functions },
index 09ba7e5..0b669e7 100644 (file)
@@ -731,7 +731,7 @@ _mesa_noop_DrawElements(GLenum mode, GLsizei count, GLenum type,
    GET_CURRENT_CONTEXT(ctx);
    GLint i;
 
-   if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices ))
+   if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, 0 ))
       return;
 
    CALL_Begin(GET_DISPATCH(), (mode));
@@ -757,6 +757,43 @@ _mesa_noop_DrawElements(GLenum mode, GLsizei count, GLenum type,
    CALL_End(GET_DISPATCH(), ());
 }
 
+static void GLAPIENTRY
+_mesa_noop_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
+                                 const GLvoid *indices, GLint basevertex)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   GLint i;
+
+   if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices,
+                                    basevertex ))
+      return;
+
+   CALL_Begin(GET_DISPATCH(), (mode));
+
+   switch (type) {
+   case GL_UNSIGNED_BYTE:
+      for (i = 0 ; i < count ; i++)
+         CALL_ArrayElement(GET_DISPATCH(), ( ((GLubyte *)indices)[i] +
+                                             basevertex));
+      break;
+   case GL_UNSIGNED_SHORT:
+      for (i = 0 ; i < count ; i++)
+         CALL_ArrayElement(GET_DISPATCH(), ( ((GLushort *)indices)[i] +
+                                             basevertex ));
+      break;
+   case GL_UNSIGNED_INT:
+      for (i = 0 ; i < count ; i++)
+         CALL_ArrayElement(GET_DISPATCH(), ( ((GLuint *)indices)[i] +
+                                             basevertex ));
+      break;
+   default:
+      _mesa_error( ctx, GL_INVALID_ENUM, "glDrawElementsBaseVertex(type)" );
+      break;
+   }
+
+   CALL_End(GET_DISPATCH(), ());
+}
+
 
 static void GLAPIENTRY
 _mesa_noop_DrawRangeElements(GLenum mode,
@@ -768,7 +805,7 @@ _mesa_noop_DrawRangeElements(GLenum mode,
 
    if (_mesa_validate_DrawRangeElements( ctx, mode,
                                         start, end,
-                                        count, type, indices ))
+                                        count, type, indices, 0 ))
        CALL_DrawElements(GET_DISPATCH(), (mode, count, type, indices));
 }
 
@@ -786,6 +823,40 @@ _mesa_noop_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type,
    }
 }
 
+static void GLAPIENTRY
+_mesa_noop_DrawRangeElementsBaseVertex(GLenum mode,
+                                      GLuint start, GLuint end,
+                                      GLsizei count, GLenum type,
+                                      const GLvoid *indices, GLint basevertex)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (_mesa_validate_DrawRangeElements( ctx, mode,
+                                        start, end,
+                                        count, type, indices, basevertex ))
+      CALL_DrawElementsBaseVertex(GET_DISPATCH(), (mode, count, type, indices,
+                                                  basevertex));
+}
+
+/* GL_EXT_multi_draw_arrays */
+void GLAPIENTRY
+_mesa_noop_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
+                                      GLenum type,
+                                      const GLvoid **indices,
+                                      GLsizei primcount,
+                                      const GLint *basevertex)
+{
+   GLsizei i;
+
+   for (i = 0; i < primcount; i++) {
+      if (count[i] > 0) {
+        CALL_DrawElementsBaseVertex(GET_DISPATCH(), (mode, count[i], type,
+                                                     indices[i],
+                                                     basevertex[i]));
+      }
+   }
+}
+
 /*
  * Eval Mesh
  */
@@ -995,6 +1066,9 @@ _mesa_noop_vtxfmt_init( GLvertexformat *vfmt )
    vfmt->DrawElements = _mesa_noop_DrawElements;
    vfmt->DrawRangeElements = _mesa_noop_DrawRangeElements;
    vfmt->MultiDrawElementsEXT = _mesa_noop_MultiDrawElements;
+   vfmt->DrawElementsBaseVertex = _mesa_noop_DrawElementsBaseVertex;
+   vfmt->DrawRangeElementsBaseVertex = _mesa_noop_DrawRangeElementsBaseVertex;
+   vfmt->MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex;
    vfmt->EvalMesh1 = _mesa_noop_EvalMesh1;
    vfmt->EvalMesh2 = _mesa_noop_EvalMesh2;
 }
index a7956d0..1150984 100644 (file)
@@ -44,6 +44,13 @@ extern void GLAPIENTRY
 _mesa_noop_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type,
                             const GLvoid **indices, GLsizei primcount);
 
+extern void GLAPIENTRY
+_mesa_noop_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
+                                      GLenum type,
+                                      const GLvoid **indices,
+                                      GLsizei primcount,
+                                      const GLint *basevertex);
+
 extern void
 _mesa_noop_vtxfmt_init(GLvertexformat *vfmt);
 
index 2df4f17..4a1448d 100644 (file)
@@ -29,7 +29,7 @@
 #include "imports.h"
 #include "mtypes.h"
 #include "state.h"
-
+#include "vbo/vbo.h"
 
 
 /**
@@ -52,51 +52,6 @@ index_bytes(GLenum type, GLsizei count)
 
 
 /**
- * Find the max index in the given element/index buffer
- */
-static GLuint
-max_buffer_index(GLcontext *ctx, GLuint count, GLenum type,
-                 const void *indices,
-                 struct gl_buffer_object *elementBuf)
-{
-   const GLubyte *map = NULL;
-   GLuint max = 0;
-   GLuint i;
-
-   if (_mesa_is_bufferobj(elementBuf)) {
-      /* elements are in a user-defined buffer object.  need to map it */
-      map = ctx->Driver.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER,
-                                  GL_READ_ONLY, elementBuf);
-      /* Actual address is the sum of pointers */
-      indices = (const GLvoid *) ADD_POINTERS(map, (const GLubyte *) indices);
-   }
-
-   if (type == GL_UNSIGNED_INT) {
-      for (i = 0; i < count; i++)
-         if (((GLuint *) indices)[i] > max)
-            max = ((GLuint *) indices)[i];
-   }
-   else if (type == GL_UNSIGNED_SHORT) {
-      for (i = 0; i < count; i++)
-         if (((GLushort *) indices)[i] > max)
-            max = ((GLushort *) indices)[i];
-   }
-   else {
-      ASSERT(type == GL_UNSIGNED_BYTE);
-      for (i = 0; i < count; i++)
-         if (((GLubyte *) indices)[i] > max)
-            max = ((GLubyte *) indices)[i];
-   }
-
-   if (map) {
-      ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, elementBuf);
-   }
-
-   return max;
-}
-
-
-/**
  * Check if OK to draw arrays/elements.
  */
 static GLboolean
@@ -124,6 +79,40 @@ check_valid_to_render(GLcontext *ctx, const char *function)
    return GL_TRUE;
 }
 
+static GLboolean
+check_index_bounds(GLcontext *ctx, GLsizei count, GLenum type,
+                  const GLvoid *indices, GLint basevertex)
+{
+   struct _mesa_prim prim;
+   struct _mesa_index_buffer ib;
+   GLuint min, max;
+
+   /* Only the X Server needs to do this -- otherwise, accessing outside
+    * array/BO bounds allows application termination.
+    */
+   if (!ctx->Const.CheckArrayBounds)
+      return GL_TRUE;
+
+   memset(&prim, 0, sizeof(prim));
+   prim.count = count;
+
+   memset(&ib, 0, sizeof(ib));
+   ib.type = type;
+   ib.ptr = indices;
+   ib.obj = ctx->Array.ElementArrayBufferObj;
+
+   vbo_get_minmax_index(ctx, &prim, &ib, &min, &max);
+
+   if (min + basevertex < 0 ||
+       max + basevertex > ctx->Array.ArrayObj->_MaxElement) {
+      /* the max element is out of bounds of one or more enabled arrays */
+      _mesa_warning(ctx, "glDrawElements() index=%u is "
+                   "out of bounds (max=%u)", max, ctx->Array.ArrayObj->_MaxElement);
+      return GL_FALSE;
+   }
+
+   return GL_TRUE;
+}
 
 /**
  * Error checking for glDrawElements().  Includes parameter checking
@@ -133,7 +122,7 @@ check_valid_to_render(GLcontext *ctx, const char *function)
 GLboolean
 _mesa_validate_DrawElements(GLcontext *ctx,
                            GLenum mode, GLsizei count, GLenum type,
-                           const GLvoid *indices)
+                           const GLvoid *indices, GLint basevertex)
 {
    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx,  GL_FALSE);
 
@@ -177,17 +166,8 @@ _mesa_validate_DrawElements(GLcontext *ctx,
          return GL_FALSE;
    }
 
-   if (ctx->Const.CheckArrayBounds) {
-      /* find max array index */
-      GLuint max = max_buffer_index(ctx, count, type, indices,
-                                    ctx->Array.ElementArrayBufferObj);
-      if (max >= ctx->Array.ArrayObj->_MaxElement) {
-         /* the max element is out of bounds of one or more enabled arrays */
-         _mesa_warning(ctx, "glDrawElements() index=%u is "
-                       "out of bounds (max=%u)", max, ctx->Array.ArrayObj->_MaxElement);
-         return GL_FALSE;
-      }
-   }
+   if (!check_index_bounds(ctx, count, type, indices, basevertex))
+      return GL_FALSE;
 
    return GL_TRUE;
 }
@@ -202,7 +182,7 @@ GLboolean
 _mesa_validate_DrawRangeElements(GLcontext *ctx, GLenum mode,
                                 GLuint start, GLuint end,
                                 GLsizei count, GLenum type,
-                                const GLvoid *indices)
+                                const GLvoid *indices, GLint basevertex)
 {
    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
 
@@ -250,14 +230,8 @@ _mesa_validate_DrawRangeElements(GLcontext *ctx, GLenum mode,
          return GL_FALSE;
    }
 
-   if (ctx->Const.CheckArrayBounds) {
-      GLuint max = max_buffer_index(ctx, count, type, indices,
-                                    ctx->Array.ElementArrayBufferObj);
-      if (max >= ctx->Array.ArrayObj->_MaxElement) {
-         /* the max element is out of bounds of one or more enabled arrays */
-         return GL_FALSE;
-      }
-   }
+   if (!check_index_bounds(ctx, count, type, indices, basevertex))
+      return GL_FALSE;
 
    return GL_TRUE;
 }
index 10f0c34..1d3ae15 100644 (file)
@@ -37,13 +37,13 @@ _mesa_validate_DrawArrays(GLcontext *ctx,
 extern GLboolean
 _mesa_validate_DrawElements(GLcontext *ctx,
                            GLenum mode, GLsizei count, GLenum type,
-                           const GLvoid *indices);
+                           const GLvoid *indices, GLint basevertex);
 
 extern GLboolean
 _mesa_validate_DrawRangeElements(GLcontext *ctx, GLenum mode,
                                 GLuint start, GLuint end,
                                 GLsizei count, GLenum type,
-                                const GLvoid *indices);
+                                const GLvoid *indices, GLint basevertex);
 
 
 #endif
index 4a700b5..ce5e158 100644 (file)
@@ -1172,7 +1172,22 @@ typedef struct {
                                            GLenum type,
                                            const GLvoid **indices,
                                            GLsizei primcount);
-  /*@}*/
+   void (GLAPIENTRYP DrawElementsBaseVertex)( GLenum mode, GLsizei count,
+                                             GLenum type,
+                                             const GLvoid *indices,
+                                             GLint basevertex );
+   void (GLAPIENTRYP DrawRangeElementsBaseVertex)( GLenum mode, GLuint start,
+                                                  GLuint end, GLsizei count,
+                                                  GLenum type,
+                                                  const GLvoid *indices,
+                                                  GLint basevertex);
+   void (GLAPIENTRYP MultiDrawElementsBaseVertex)( GLenum mode,
+                                                  const GLsizei *count,
+                                                  GLenum type,
+                                                  const GLvoid **indices,
+                                                  GLsizei primcount,
+                                                  const GLint *basevertex);
+   /*@}*/
 
    /**
     * \name Eval
index 8cff9ea..d721f69 100644 (file)
@@ -8711,6 +8711,9 @@ _mesa_save_vtxfmt_init(GLvertexformat * vfmt)
    vfmt->DrawElements = 0;
    vfmt->DrawRangeElements = 0;
    vfmt->MultiDrawElemementsEXT = 0;
+   vfmt->DrawElementsBaseVertex = 0;
+   vfmt->DrawRangeElementsBaseVertex = 0;
+   vfmt->MultiDrawElemementsBaseVertex = 0;
 #endif
 }
 
index d0e77ba..2ad66de 100644 (file)
@@ -49,6 +49,7 @@ static const struct {
    { OFF, "GL_ARB_depth_texture",              F(ARB_depth_texture) },
    { OFF, "GL_ARB_depth_clamp",                F(ARB_depth_clamp) },
    { ON,  "GL_ARB_draw_buffers",               F(ARB_draw_buffers) },
+   { OFF, "GL_ARB_draw_elements_base_vertex",  F(ARB_draw_elements_base_vertex) },
    { OFF, "GL_ARB_fragment_program",           F(ARB_fragment_program) },
    { OFF, "GL_ARB_fragment_program_shadow",    F(ARB_fragment_program_shadow) },
    { OFF, "GL_ARB_fragment_shader",            F(ARB_fragment_shader) },
@@ -197,6 +198,7 @@ _mesa_enable_sw_extensions(GLcontext *ctx)
    ctx->Extensions.ARB_depth_clamp = GL_TRUE;
    ctx->Extensions.ARB_depth_texture = GL_TRUE;
    /*ctx->Extensions.ARB_draw_buffers = GL_TRUE;*/
+   ctx->Extensions.ARB_draw_elements_base_vertex = GL_TRUE;
 #if FEATURE_ARB_fragment_program
    ctx->Extensions.ARB_fragment_program = GL_TRUE;
    ctx->Extensions.ARB_fragment_program_shadow = GL_TRUE;
index 20cd3aa..ae169fb 100644 (file)
@@ -2478,6 +2478,7 @@ struct gl_extensions
    GLboolean ARB_depth_texture;
    GLboolean ARB_depth_clamp;
    GLboolean ARB_draw_buffers;
+   GLboolean ARB_draw_elements_base_vertex;
    GLboolean ARB_fragment_program;
    GLboolean ARB_fragment_program_shadow;
    GLboolean ARB_fragment_shader;
index becc67c..ef790c5 100644 (file)
@@ -129,6 +129,11 @@ extern void GLAPIENTRY
 _mesa_MultiDrawElementsEXT( GLenum mode, const GLsizei *count, GLenum type,
                             const GLvoid **indices, GLsizei primcount );
 
+extern void GLAPIENTRY
+_mesa_MultiDrawElementsBaseVertex( GLenum mode,
+                                  const GLsizei *count, GLenum type,
+                                  const GLvoid **indices, GLsizei primcount,
+                                  const GLint *basevertex);
 
 extern void GLAPIENTRY
 _mesa_MultiModeDrawArraysIBM( const GLenum * mode, const GLint * first,
@@ -159,6 +164,16 @@ extern void GLAPIENTRY
 _mesa_DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count,
                         GLenum type, const GLvoid *indices);
 
+extern void GLAPIENTRY
+_mesa_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
+                            const GLvoid *indices, GLint basevertex);
+
+extern void GLAPIENTRY
+_mesa_DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end,
+                                 GLsizei count, GLenum type,
+                                 const GLvoid *indices,
+                                 GLint basevertex);
+
 
 extern void
 _mesa_copy_client_array(GLcontext *ctx,
index 8d6f560..91412f1 100644 (file)
@@ -134,6 +134,9 @@ install_vtxfmt( struct _glapi_table *tab, const GLvertexformat *vfmt )
    SET_DrawElements(tab, vfmt->DrawElements);
    SET_DrawRangeElements(tab, vfmt->DrawRangeElements);
    SET_MultiDrawElementsEXT(tab, vfmt->MultiDrawElementsEXT);
+   SET_DrawElementsBaseVertex(tab, vfmt->DrawElementsBaseVertex);
+   SET_DrawRangeElementsBaseVertex(tab, vfmt->DrawRangeElementsBaseVertex);
+   SET_MultiDrawElementsBaseVertex(tab, vfmt->MultiDrawElementsBaseVertex);
    SET_EvalMesh1(tab, vfmt->EvalMesh1);
    SET_EvalMesh2(tab, vfmt->EvalMesh2);
    ASSERT(tab->EvalMesh2);
index 1308d0a..d56a2bb 100644 (file)
@@ -354,6 +354,44 @@ static void GLAPIENTRY TAG(DrawRangeElements)( GLenum mode, GLuint start,
    CALL_DrawRangeElements(GET_DISPATCH(), ( mode, start, end, count, type, indices ));
 }
 
+static void GLAPIENTRY TAG(DrawElementsBaseVertex)( GLenum mode,
+                                                   GLsizei count,
+                                                   GLenum type,
+                                                   const GLvoid *indices,
+                                                   GLint basevertex)
+{
+   PRE_LOOPBACK( DrawElementsBaseVertex );
+   CALL_DrawElementsBaseVertex(GET_DISPATCH(), ( mode, count, type,
+                                                indices, basevertex ));
+}
+
+static void GLAPIENTRY TAG(DrawRangeElementsBaseVertex)( GLenum mode,
+                                                        GLuint start,
+                                                        GLuint end,
+                                                        GLsizei count,
+                                                        GLenum type,
+                                                        const GLvoid *indices,
+                                                        GLint basevertex)
+{
+   PRE_LOOPBACK( DrawRangeElementsBaseVertex );
+   CALL_DrawRangeElementsBaseVertex(GET_DISPATCH(), ( mode, start, end,
+                                                     count, type, indices,
+                                                     basevertex ));
+}
+
+static void GLAPIENTRY TAG(MultiDrawElementsBaseVertex)( GLenum mode,
+                                                        const GLsizei *count,
+                                                        GLenum type,
+                                                        const GLvoid **indices,
+                                                        GLsizei primcount,
+                                                        const GLint *basevertex)
+{
+   PRE_LOOPBACK( MultiDrawElementsBaseVertex );
+   CALL_MultiDrawElementsBaseVertex(GET_DISPATCH(), ( mode, count, type,
+                                                     indices,
+                                                     primcount, basevertex ));
+}
+
 static void GLAPIENTRY TAG(EvalMesh1)( GLenum mode, GLint i1, GLint i2 )
 {
    PRE_LOOPBACK( EvalMesh1 );
@@ -534,6 +572,9 @@ static GLvertexformat TAG(vtxfmt) = {
    TAG(DrawElements),
    TAG(DrawRangeElements),
    TAG(MultiDrawElementsEXT),
+   TAG(DrawElementsBaseVertex),
+   TAG(DrawRangeElementsBaseVertex),
+   TAG(MultiDrawElementsBaseVertex),
    TAG(EvalMesh1),
    TAG(EvalMesh2)
 };
index c64c2c2..04fa106 100644 (file)
@@ -316,22 +316,27 @@ static void bind_indices( GLcontext *ctx,
 
    ptr = ADD_POINTERS(ib->obj->Pointer, ib->ptr);
 
-   if (ib->type == GL_UNSIGNED_INT) {
+   if (ib->type == GL_UNSIGNED_INT && VB->Primitive[0].basevertex == 0) {
       VB->Elts = (GLuint *) ptr;
    }
    else {
       GLuint *elts = (GLuint *)get_space(ctx, ib->count * sizeof(GLuint));
       VB->Elts = elts;
 
-      if (ib->type == GL_UNSIGNED_SHORT) {
+      if (ib->type == GL_UNSIGNED_INT) {
+        const GLuint *in = (GLuint *)ptr;
+        for (i = 0; i < ib->count; i++)
+           *elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex;
+      }
+      else if (ib->type == GL_UNSIGNED_SHORT) {
         const GLushort *in = (GLushort *)ptr;
         for (i = 0; i < ib->count; i++) 
-           *elts++ = (GLuint)(*in++);
+           *elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex;
       }
       else {
         const GLubyte *in = (GLubyte *)ptr;
         for (i = 0; i < ib->count; i++) 
-           *elts++ = (GLuint)(*in++);
+           *elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex;
       }
    }
 }
@@ -390,10 +395,14 @@ void _tnl_draw_prims( GLcontext *ctx,
    TNLcontext *tnl = TNL_CONTEXT(ctx);
    const GLuint TEST_SPLIT = 0;
    const GLint max = TEST_SPLIT ? 8 : tnl->vb.Size - MAX_CLIPPED_VERTICES;
+   GLuint max_basevertex = prim->basevertex;
+   GLuint i;
+
+   for (i = 1; i < nr_prims; i++)
+      max_basevertex = MAX2(max_basevertex, prim[i].basevertex);
 
    if (0)
    {
-      GLuint i;
       _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, 
@@ -410,7 +419,7 @@ void _tnl_draw_prims( GLcontext *ctx,
                        _tnl_vbo_draw_prims );
       return;
    }
-   else if (max_index > max) {
+   else if (max_index + max_basevertex > 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.
@@ -424,7 +433,7 @@ void _tnl_draw_prims( GLcontext *ctx,
        * recursively call back into this function.
        */
       vbo_split_prims( ctx, arrays, prim, nr_prims, ib, 
-                      0, max_index,
+                      0, max_index + prim->basevertex,
                       _tnl_vbo_draw_prims,
                       &limits );
    }
@@ -435,17 +444,34 @@ void _tnl_draw_prims( GLcontext *ctx,
       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.
-       */
-      bind_inputs(ctx, arrays, max_index+1, bo, &nr_bo);
-      bind_indices(ctx, ib, bo, &nr_bo);
-      bind_prims(ctx, prim, nr_prims );
+      for (i = 0; i < nr_prims;) {
+        GLuint this_nr_prims;
+
+        /* Our SW TNL pipeline doesn't handle basevertex yet, so bind_indices
+         * will rebase the elements to the basevertex, and we'll only
+         * emit strings of prims with the same basevertex in one draw call.
+         */
+        for (this_nr_prims = 1; i + this_nr_prims < nr_prims;
+             this_nr_prims++) {
+           if (prim[i].basevertex != prim[i + this_nr_prims].basevertex)
+              break;
+        }
+
+        /* Binding inputs may imply mapping some vertex buffer objects.
+         * They will need to be unmapped below.
+         */
+        bind_prims(ctx, &prim[i], this_nr_prims);
+        bind_inputs(ctx, arrays, max_index + prim[i].basevertex + 1,
+                    bo, &nr_bo);
+        bind_indices(ctx, ib, bo, &nr_bo);
 
-      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);
+
+        i += this_nr_prims;
+      }
    }
 }
 
index 5986e93..b24ecfd 100644 (file)
@@ -44,6 +44,7 @@ struct _mesa_prim {
 
    GLuint start;
    GLuint count;
+   GLint basevertex;
 };
 
 /* Would like to call this a "vbo_index_buffer", but this would be
index 12911f5..b9550d6 100644 (file)
@@ -181,7 +181,7 @@ unmap_array_buffer(GLcontext *ctx, struct gl_client_array *array)
  */
 static void
 check_draw_elements_data(GLcontext *ctx, GLsizei count, GLenum elemType,
-                         const void *elements)
+                         const void *elements, GLint basevertex)
 {
    struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
    const void *elemMap;
@@ -518,6 +518,7 @@ vbo_exec_DrawArrays(GLenum mode, GLint start, GLsizei count)
    prim[0].start = start;
    prim[0].count = count;
    prim[0].indexed = 0;
+   prim[0].basevertex = 0;
 
    vbo->draw_prims( ctx, exec->array.inputs, prim, 1, NULL,
                     GL_TRUE, start, start + count - 1 );
@@ -592,7 +593,8 @@ vbo_validated_drawrangeelements(GLcontext *ctx, GLenum mode,
                                GLboolean index_bounds_valid,
                                GLuint start, GLuint end,
                                GLsizei count, GLenum type,
-                               const GLvoid *indices)
+                               const GLvoid *indices,
+                               GLint basevertex)
 {
    struct vbo_context *vbo = vbo_context(ctx);
    struct vbo_exec_context *exec = &vbo->exec;
@@ -626,6 +628,7 @@ vbo_validated_drawrangeelements(GLcontext *ctx, GLenum mode,
    prim[0].start = 0;
    prim[0].count = count;
    prim[0].indexed = 1;
+   prim[0].basevertex = basevertex;
 
    /* Need to give special consideration to rendering a range of
     * indices starting somewhere above zero.  Typically the
@@ -663,23 +666,25 @@ vbo_validated_drawrangeelements(GLcontext *ctx, GLenum mode,
 }
 
 static void GLAPIENTRY
-vbo_exec_DrawRangeElements(GLenum mode,
-                          GLuint start, GLuint end,
-                          GLsizei count, GLenum type, const GLvoid *indices)
+vbo_exec_DrawRangeElementsBaseVertex(GLenum mode,
+                                    GLuint start, GLuint end,
+                                    GLsizei count, GLenum type,
+                                    const GLvoid *indices,
+                                    GLint basevertex)
 {
    GET_CURRENT_CONTEXT(ctx);
 
    if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count,
-                                          type, indices ))
+                                          type, indices, basevertex ))
       return;
 
    if (end >= ctx->Array.ArrayObj->_MaxElement) {
       /* the max element is out of bounds of one or more enabled arrays */
-      _mesa_warning(ctx, "glDraw[Range]Elements(start %u, end %u, count %d, "
-                    "type 0x%x, indices=%p)\n"
+      _mesa_warning(ctx, "glDraw[Range]Elements{,BaseVertex}(start %u, end %u, "
+                   "count %d, type 0x%x, indices=%p, base=%d)\n"
                     "\tindex=%u is out of bounds (max=%u)  "
                     "Element Buffer %u (size %d)",
-                    start, end, count, type, indices, end,
+                    start, end, count, type, indices, end, basevertex,
                     ctx->Array.ArrayObj->_MaxElement - 1,
                     ctx->Array.ElementArrayBufferObj->Name,
                     ctx->Array.ElementArrayBufferObj->Size);
@@ -692,10 +697,12 @@ vbo_exec_DrawRangeElements(GLenum mode,
       return;
    }
    else if (0) {
-      _mesa_printf("glDraw[Range]Elements"
-                   "(start %u, end %u, type 0x%x, count %d) ElemBuf %u\n",
+      _mesa_printf("glDraw[Range]Elements{,BaseVertex}"
+                   "(start %u, end %u, type 0x%x, count %d) ElemBuf %u, "
+                  "base %d\n",
                    start, end, type, count,
-                   ctx->Array.ElementArrayBufferObj->Name);
+                   ctx->Array.ElementArrayBufferObj->Name,
+                  basevertex);
    }
 
 #if 0
@@ -705,7 +712,17 @@ vbo_exec_DrawRangeElements(GLenum mode,
 #endif
 
    vbo_validated_drawrangeelements(ctx, mode, GL_TRUE, start, end,
-                                  count, type, indices);
+                                  count, type, indices, basevertex);
+}
+
+static void GLAPIENTRY
+vbo_exec_DrawRangeElements(GLenum mode,
+                                    GLuint start, GLuint end,
+                                    GLsizei count, GLenum type,
+                                    const GLvoid *indices)
+{
+   vbo_exec_DrawRangeElementsBaseVertex(mode, start, end, count, type,
+                                       indices, 0);
 }
 
 
@@ -715,18 +732,33 @@ vbo_exec_DrawElements(GLenum mode, GLsizei count, GLenum type,
 {
    GET_CURRENT_CONTEXT(ctx);
 
-   if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices ))
+   if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, 0 ))
+      return;
+
+   vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
+                                  count, type, indices, 0);
+}
+
+static void GLAPIENTRY
+vbo_exec_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
+                               const GLvoid *indices, GLint basevertex)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices,
+                                    basevertex ))
       return;
 
    vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
-                                  count, type, indices);
+                                  count, type, indices, basevertex);
 }
 
 /* Inner support for both _mesa_DrawElements and _mesa_DrawRangeElements */
 static void
 vbo_validated_multidrawelements(GLcontext *ctx, GLenum mode,
                                const GLsizei *count, GLenum type,
-                               const GLvoid **indices, GLsizei primcount)
+                               const GLvoid **indices, GLsizei primcount,
+                               const GLint *basevertex)
 {
    struct vbo_context *vbo = vbo_context(ctx);
    struct vbo_exec_context *exec = &vbo->exec;
@@ -820,6 +852,10 @@ vbo_validated_multidrawelements(GLcontext *ctx, GLenum mode,
         prim[i].start = ((uintptr_t)indices[i] - min_index_ptr) / index_type_size;
         prim[i].count = count[i];
         prim[i].indexed = 1;
+        if (basevertex != NULL)
+           prim[i].basevertex = basevertex[i];
+        else
+           prim[i].basevertex = 0;
       }
 
       vbo->draw_prims(ctx, exec->array.inputs, prim, primcount, &ib,
@@ -840,6 +876,10 @@ vbo_validated_multidrawelements(GLcontext *ctx, GLenum mode,
         prim[0].start = 0;
         prim[0].count = count[i];
         prim[0].indexed = 1;
+        if (basevertex != NULL)
+           prim[0].basevertex = basevertex[i];
+        else
+           prim[0].basevertex = 0;
       }
 
       vbo->draw_prims(ctx, exec->array.inputs, prim, 1, &ib,
@@ -860,13 +900,36 @@ vbo_exec_MultiDrawElements(GLenum mode,
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
    for (i = 0; i < primcount; i++) {
-      if (!_mesa_validate_DrawElements( ctx, mode, count[i], type, indices[i] ))
+      if (!_mesa_validate_DrawElements(ctx, mode, count[i], type, indices[i],
+                                      0))
         return;
    }
 
-   vbo_validated_multidrawelements(ctx, mode, count, type, indices, primcount);
+   vbo_validated_multidrawelements(ctx, mode, count, type, indices, primcount,
+                                  NULL);
 }
 
+static void GLAPIENTRY
+vbo_exec_MultiDrawElementsBaseVertex(GLenum mode,
+                                    const GLsizei *count, GLenum type,
+                                    const GLvoid **indices,
+                                    GLsizei primcount,
+                                    const GLsizei *basevertex)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   GLint i;
+
+   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+
+   for (i = 0; i < primcount; i++) {
+      if (!_mesa_validate_DrawElements(ctx, mode, count[i], type, indices[i],
+                                      basevertex[i]))
+        return;
+   }
+
+   vbo_validated_multidrawelements(ctx, mode, count, type, indices, primcount,
+                                  basevertex);
+}
 
 
 /***********************************************************************
@@ -881,11 +944,17 @@ vbo_exec_array_init( struct vbo_exec_context *exec )
    exec->vtxfmt.DrawElements = vbo_exec_DrawElements;
    exec->vtxfmt.DrawRangeElements = vbo_exec_DrawRangeElements;
    exec->vtxfmt.MultiDrawElementsEXT = vbo_exec_MultiDrawElements;
+   exec->vtxfmt.DrawElementsBaseVertex = vbo_exec_DrawElementsBaseVertex;
+   exec->vtxfmt.DrawRangeElementsBaseVertex = vbo_exec_DrawRangeElementsBaseVertex;
+   exec->vtxfmt.MultiDrawElementsBaseVertex = vbo_exec_MultiDrawElementsBaseVertex;
 #else
    exec->vtxfmt.DrawArrays = _mesa_noop_DrawArrays;
    exec->vtxfmt.DrawElements = _mesa_noop_DrawElements;
    exec->vtxfmt.DrawRangeElements = _mesa_noop_DrawRangeElements;
    exec->vtxfmt.MultiDrawElementsEXT = _mesa_noop_MultiDrawElements;
+   exec->vtxfmt.DrawElementsBaseVertex = _mesa_noop_DrawElementsBaseVertex;
+   exec->vtxfmt.DrawRangeElementsBaseVertex = _mesa_noop_DrawRangeElementsBaseVertex;
+   exec->vtxfmt.MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex;
 #endif
 }
 
@@ -913,6 +982,13 @@ _mesa_DrawElements(GLenum mode, GLsizei count, GLenum type,
    vbo_exec_DrawElements(mode, count, type, indices);
 }
 
+void GLAPIENTRY
+_mesa_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
+                            const GLvoid *indices, GLint basevertex)
+{
+   vbo_exec_DrawElementsBaseVertex(mode, count, type, indices, basevertex);
+}
+
 
 /* This API entrypoint is not ordinarily used */
 void GLAPIENTRY
@@ -922,6 +998,15 @@ _mesa_DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count,
    vbo_exec_DrawRangeElements(mode, start, end, count, type, indices);
 }
 
+void GLAPIENTRY
+_mesa_DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end,
+                                 GLsizei count, GLenum type,
+                                 const GLvoid *indices, GLint basevertex)
+{
+   vbo_exec_DrawRangeElementsBaseVertex(mode, start, end, count, type,
+                                       indices, basevertex);
+}
+
 /* GL_EXT_multi_draw_arrays */
 void GLAPIENTRY
 _mesa_MultiDrawElementsEXT(GLenum mode, const GLsizei *count, GLenum type,
@@ -929,3 +1014,13 @@ _mesa_MultiDrawElementsEXT(GLenum mode, const GLsizei *count, GLenum type,
 {
    vbo_exec_MultiDrawElements(mode, count, type, indices, primcount);
 }
+
+void GLAPIENTRY
+_mesa_MultiDrawElementsBaseVertex(GLenum mode,
+                                 const GLsizei *count, GLenum type,
+                                 const GLvoid **indices, GLsizei primcount,
+                                 const GLint *basevertex)
+{
+   vbo_exec_MultiDrawElementsBaseVertex(mode, count, type, indices,
+                                       primcount, basevertex);
+}
index 3bf7ef5..799a25f 100644 (file)
@@ -126,7 +126,20 @@ void vbo_rebase_prims( GLcontext *ctx,
    if (0)
       _mesa_printf("%s %d..%d\n", __FUNCTION__, min_index, max_index);
 
-   if (ib) {
+
+   if (ib && ctx->Extensions.ARB_draw_elements_base_vertex) {
+      /* If we can just tell the hardware or the TNL to interpret our
+       * indices with a different base, do so.
+       */
+      tmp_prims = (struct _mesa_prim *)_mesa_malloc(sizeof(*prim) * nr_prims);
+
+      for (i = 0; i < nr_prims; i++) {
+        tmp_prims[i] = prim[i];
+        tmp_prims[i].basevertex -= min_index;
+      }
+
+      prim = tmp_prims;
+   } else if (ib) {
       /* Unfortunately need to adjust each index individually.
        */
       GLboolean map_ib = ib->obj->Name && !ib->obj->Pointer;
index 1771510..41cd21d 100644 (file)
@@ -826,6 +826,33 @@ static void GLAPIENTRY _save_DrawRangeElements(GLenum mode,
    _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" );
 }
 
+static void GLAPIENTRY _save_DrawElementsBaseVertex(GLenum mode,
+                                                   GLsizei count,
+                                                   GLenum type,
+                                                   const GLvoid *indices,
+                                                   GLint basevertex)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   (void) mode; (void) count; (void) type; (void) indices; (void)basevertex;
+
+   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawElements" );
+}
+
+static void GLAPIENTRY _save_DrawRangeElementsBaseVertex(GLenum mode,
+                                                        GLuint start,
+                                                        GLuint end,
+                                                        GLsizei count,
+                                                        GLenum type,
+                                                        const GLvoid *indices,
+                                                        GLint basevertex)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   (void) mode; (void) start; (void) end; (void) count; (void) type;
+   (void) indices; (void)basevertex;
+
+   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" );
+}
+
 static void GLAPIENTRY _save_DrawArrays(GLenum mode, GLint start, GLsizei count)
 {
    GET_CURRENT_CONTEXT(ctx);
@@ -907,7 +934,7 @@ static void GLAPIENTRY _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum
    GET_CURRENT_CONTEXT(ctx);
    GLint i;
 
-   if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices ))
+   if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, 0 ))
       return;
 
    _ae_map_vbos( ctx );
@@ -948,7 +975,7 @@ static void GLAPIENTRY _save_OBE_DrawRangeElements(GLenum mode,
    GET_CURRENT_CONTEXT(ctx);
    if (_mesa_validate_DrawRangeElements( ctx, mode,
                                         start, end,
-                                        count, type, indices ))
+                                        count, type, indices, 0 ))
       _save_OBE_DrawElements( mode, count, type, indices );
 }
 
@@ -1039,9 +1066,11 @@ static void _save_vtxfmt_init( GLcontext *ctx )
    vfmt->DrawArrays = _save_DrawArrays;
    vfmt->DrawElements = _save_DrawElements;
    vfmt->DrawRangeElements = _save_DrawRangeElements;
+   vfmt->DrawElementsBaseVertex = _save_DrawElementsBaseVertex;
+   vfmt->DrawRangeElementsBaseVertex = _save_DrawRangeElementsBaseVertex;
    /* Loops back into vfmt->DrawElements */
    vfmt->MultiDrawElementsEXT = _mesa_noop_MultiDrawElements;
-
+   vfmt->MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex;
 }
 
 
@@ -1233,6 +1262,7 @@ void vbo_save_api_init( struct vbo_save_context *save )
    ctx->ListState.ListVtxfmt.DrawRangeElements = _save_OBE_DrawRangeElements;
    /* loops back into _save_OBE_DrawElements */
    ctx->ListState.ListVtxfmt.MultiDrawElementsEXT = _mesa_noop_MultiDrawElements;
+   ctx->ListState.ListVtxfmt.MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex;
    _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
 }
 
index 58e8796..c445acc 100644 (file)
@@ -50,6 +50,7 @@
 #include "main/glheader.h"
 #include "main/imports.h"
 #include "main/mtypes.h"
+#include "main/macros.h"
 
 #include "vbo_split.h"
 #include "vbo.h"
@@ -107,7 +108,12 @@ void vbo_split_prims( GLcontext *ctx,
                      vbo_draw_func draw,
                      const struct split_limits *limits )
 {
-  
+   GLuint max_basevertex = prim->basevertex;
+   GLuint i;
+
+   for (i = 1; i < nr_prims; i++)
+      max_basevertex = MAX2(max_basevertex, prim[i].basevertex);
+
    if (ib) {
       if (limits->max_indices == 0) {
         /* Could traverse the indices, re-emitting vertices in turn.
index 8ec180d..c45190b 100644 (file)
@@ -589,28 +589,40 @@ void vbo_split_copy( GLcontext *ctx,
                     const struct split_limits *limits )
 {
    struct copy_context copy;
-   GLuint i;
+   GLuint i, this_nr_prims;
+
+   for (i = 0; i < nr_prims;) {
+      /* Our SW TNL pipeline doesn't handle basevertex yet, so bind_indices
+       * will rebase the elements to the basevertex, and we'll only
+       * emit strings of prims with the same basevertex in one draw call.
+       */
+      for (this_nr_prims = 1; i + this_nr_prims < nr_prims;
+          this_nr_prims++) {
+        if (prim[i].basevertex != prim[i + this_nr_prims].basevertex)
+           break;
+      }
 
-   memset(&copy, 0, sizeof(copy));
+      memset(&copy, 0, sizeof(copy));
 
-   /* Require indexed primitives:
-    */
-   assert(ib);
-   
-   copy.ctx = ctx;
-   copy.array = arrays;
-   copy.prim = prim;
-   copy.nr_prims = nr_prims;
-   copy.ib = ib;
-   copy.draw = draw;
-   copy.limits = limits;
+      /* Require indexed primitives:
+       */
+      assert(ib);
 
-   /* Clear the vertex cache:
-    */
-   for (i = 0; i < ELT_TABLE_SIZE; i++)
-      copy.vert_cache[i].in = ~0;
+      copy.ctx = ctx;
+      copy.array = arrays;
+      copy.prim = &prim[i];
+      copy.nr_prims = this_nr_prims;
+      copy.ib = ib;
+      copy.draw = draw;
+      copy.limits = limits;
 
-   replay_init(&copy);
-   replay_elts(&copy);
-   replay_finish(&copy);
+      /* Clear the vertex cache:
+       */
+      for (i = 0; i < ELT_TABLE_SIZE; i++)
+        copy.vert_cache[i].in = ~0;
+
+      replay_init(&copy);
+      replay_elts(&copy);
+      replay_finish(&copy);
+   }
 }