mesa: Use VERT_ATTRIB_* indexed array in gl_array_object.
[mesa.git] / src / mesa / vbo / vbo_exec_array.c
index d4dbc8d2562d94b9a6bc2f69a3500fd38fe21a8e..97221a54d4471971701c4d7be1db41ec8acb47b0 100644 (file)
@@ -30,7 +30,6 @@
 #include "main/context.h"
 #include "main/state.h"
 #include "main/api_validate.h"
-#include "main/api_noop.h"
 #include "main/varray.h"
 #include "main/bufferobj.h"
 #include "main/enums.h"
 
 
 /**
- * Compute min and max elements for glDraw[Range]Elements() calls.
+ * All vertex buffers should be in an unmapped state when we're about
+ * to draw.  This debug function checks that.
+ */
+static void
+check_buffers_are_unmapped(const struct gl_client_array **inputs)
+{
+#ifdef DEBUG
+   GLuint i;
+
+   for (i = 0; i < VERT_ATTRIB_MAX; i++) {
+      if (inputs[i]) {
+         struct gl_buffer_object *obj = inputs[i]->BufferObj;
+         assert(!_mesa_bufferobj_mapped(obj));
+         (void) obj;
+      }
+   }
+#endif
+}
+
+
+/**
+ * A debug function that may be called from other parts of Mesa as
+ * needed during debugging.
  */
 void
-vbo_get_minmax_index(GLcontext *ctx,
+vbo_check_buffers_are_unmapped(struct gl_context *ctx)
+{
+   struct vbo_context *vbo = vbo_context(ctx);
+   struct vbo_exec_context *exec = &vbo->exec;
+   /* check the current vertex arrays */
+   check_buffers_are_unmapped(exec->array.inputs);
+   /* check the current glBegin/glVertex/glEnd-style VBO */
+   assert(!_mesa_bufferobj_mapped(exec->vtx.bufferobj));
+}
+
+
+
+/**
+ * Compute min and max elements by scanning the index buffer for
+ * glDraw[Range]Elements() calls.
+ * If primitive restart is enabled, we need to ignore restart
+ * indexes when computing min/max.
+ */
+void
+vbo_get_minmax_index(struct gl_context *ctx,
                     const struct _mesa_prim *prim,
                     const struct _mesa_index_buffer *ib,
                     GLuint *min_index, GLuint *max_index)
 {
-   GLuint i;
-   GLuint count = prim->count;
+   const GLboolean restart = ctx->Array.PrimitiveRestart;
+   const GLuint restartIndex = ctx->Array.RestartIndex;
+   const GLuint count = prim->count;
    const void *indices;
+   GLuint i;
 
    if (_mesa_is_bufferobj(ib->obj)) {
-      const GLvoid *map =
-         ctx->Driver.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB,
-                               GL_READ_ONLY, ib->obj);
-      indices = ADD_POINTERS(map, ib->ptr);
+      unsigned map_size;
+
+      switch (ib->type) {
+      case GL_UNSIGNED_INT:
+        map_size = count * sizeof(GLuint);
+        break;
+      case GL_UNSIGNED_SHORT:
+        map_size = count * sizeof(GLushort);
+        break;
+      case GL_UNSIGNED_BYTE:
+        map_size = count * sizeof(GLubyte);
+        break;
+      default:
+        assert(0);
+        map_size = 0;
+      }
+
+      indices = ctx->Driver.MapBufferRange(ctx, (GLsizeiptr) ib->ptr, map_size,
+                                          GL_MAP_READ_BIT, ib->obj);
    } else {
       indices = ib->ptr;
    }
@@ -64,11 +121,21 @@ vbo_get_minmax_index(GLcontext *ctx,
    switch (ib->type) {
    case GL_UNSIGNED_INT: {
       const GLuint *ui_indices = (const GLuint *)indices;
-      GLuint max_ui = ui_indices[count-1];
-      GLuint min_ui = ui_indices[0];
-      for (i = 0; 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];
+      GLuint max_ui = 0;
+      GLuint min_ui = ~0U;
+      if (restart) {
+         for (i = 0; i < count; i++) {
+            if (ui_indices[i] != restartIndex) {
+               if (ui_indices[i] > max_ui) max_ui = ui_indices[i];
+               if (ui_indices[i] < min_ui) min_ui = ui_indices[i];
+            }
+         }
+      }
+      else {
+         for (i = 0; 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;
@@ -76,11 +143,21 @@ vbo_get_minmax_index(GLcontext *ctx,
    }
    case GL_UNSIGNED_SHORT: {
       const GLushort *us_indices = (const GLushort *)indices;
-      GLuint max_us = us_indices[count-1];
-      GLuint min_us = us_indices[0];
-      for (i = 0; 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];
+      GLuint max_us = 0;
+      GLuint min_us = ~0U;
+      if (restart) {
+         for (i = 0; i < count; i++) {
+            if (us_indices[i] != restartIndex) {
+               if (us_indices[i] > max_us) max_us = us_indices[i];
+               if (us_indices[i] < min_us) min_us = us_indices[i];
+            }
+         }
+      }
+      else {
+         for (i = 0; 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;
@@ -88,11 +165,21 @@ vbo_get_minmax_index(GLcontext *ctx,
    }
    case GL_UNSIGNED_BYTE: {
       const GLubyte *ub_indices = (const GLubyte *)indices;
-      GLuint max_ub = ub_indices[count-1];
-      GLuint min_ub = ub_indices[0];
-      for (i = 0; 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];
+      GLuint max_ub = 0;
+      GLuint min_ub = ~0U;
+      if (restart) {
+         for (i = 0; i < count; i++) {
+            if (ub_indices[i] != restartIndex) {
+               if (ub_indices[i] > max_ub) max_ub = ub_indices[i];
+               if (ub_indices[i] < min_ub) min_ub = ub_indices[i];
+            }
+         }
+      }
+      else {
+         for (i = 0; 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;
@@ -104,7 +191,7 @@ vbo_get_minmax_index(GLcontext *ctx,
    }
 
    if (_mesa_is_bufferobj(ib->obj)) {
-      ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, ib->obj);
+      ctx->Driver.UnmapBuffer(ctx, ib->obj);
    }
 }
 
@@ -112,9 +199,10 @@ vbo_get_minmax_index(GLcontext *ctx,
 /**
  * Check that element 'j' of the array has reasonable data.
  * Map VBO if needed.
+ * For debugging purposes; not normally used.
  */
 static void
-check_array_data(GLcontext *ctx, struct gl_client_array *array,
+check_array_data(struct gl_context *ctx, struct gl_client_array *array,
                  GLuint attrib, GLuint j)
 {
    if (array->Enabled) {
@@ -123,8 +211,8 @@ check_array_data(GLcontext *ctx, struct gl_client_array *array,
          if (!array->BufferObj->Pointer) {
             /* need to map now */
             array->BufferObj->Pointer =
-               ctx->Driver.MapBuffer(ctx, GL_ARRAY_BUFFER_ARB,
-                                     GL_READ_ONLY, array->BufferObj);
+               ctx->Driver.MapBufferRange(ctx, 0, array->BufferObj->Size,
+                                         GL_MAP_READ_BIT, array->BufferObj);
          }
          data = ADD_POINTERS(data, array->BufferObj->Pointer);
       }
@@ -160,32 +248,33 @@ check_array_data(GLcontext *ctx, struct gl_client_array *array,
  * Unmap the buffer object referenced by given array, if mapped.
  */
 static void
-unmap_array_buffer(GLcontext *ctx, struct gl_client_array *array)
+unmap_array_buffer(struct gl_context *ctx, struct gl_client_array *array)
 {
    if (array->Enabled &&
        _mesa_is_bufferobj(array->BufferObj) &&
        _mesa_bufferobj_mapped(array->BufferObj)) {
-      ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, array->BufferObj);
+      ctx->Driver.UnmapBuffer(ctx, array->BufferObj);
    }
 }
 
 
 /**
  * Examine the array's data for NaNs, etc.
+ * For debug purposes; not normally used.
  */
 static void
-check_draw_elements_data(GLcontext *ctx, GLsizei count, GLenum elemType,
+check_draw_elements_data(struct gl_context *ctx, GLsizei count, GLenum elemType,
                          const void *elements, GLint basevertex)
 {
    struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
    const void *elemMap;
    GLint i, k;
 
-   if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) {
-      elemMap = ctx->Driver.MapBuffer(ctx,
-                                      GL_ELEMENT_ARRAY_BUFFER_ARB,
-                                      GL_READ_ONLY,
-                                      ctx->Array.ElementArrayBufferObj);
+   if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) {
+      elemMap = ctx->Driver.MapBufferRange(ctx, 0,
+                                          ctx->Array.ArrayObj->ElementArrayBufferObj->Size,
+                                          GL_MAP_READ_BIT,
+                                          ctx->Array.ArrayObj->ElementArrayBufferObj);
       elements = ADD_POINTERS(elements, elemMap);
    }
 
@@ -208,30 +297,15 @@ check_draw_elements_data(GLcontext *ctx, GLsizei count, GLenum elemType,
       }
 
       /* check element j of each enabled array */
-      check_array_data(ctx, &arrayObj->Vertex, VERT_ATTRIB_POS, j);
-      check_array_data(ctx, &arrayObj->Normal, VERT_ATTRIB_NORMAL, j);
-      check_array_data(ctx, &arrayObj->Color, VERT_ATTRIB_COLOR0, j);
-      check_array_data(ctx, &arrayObj->SecondaryColor, VERT_ATTRIB_COLOR1, j);
-      for (k = 0; k < Elements(arrayObj->TexCoord); k++) {
-         check_array_data(ctx, &arrayObj->TexCoord[k], VERT_ATTRIB_TEX0 + k, j);
-      }
       for (k = 0; k < Elements(arrayObj->VertexAttrib); k++) {
-         check_array_data(ctx, &arrayObj->VertexAttrib[k],
-                          VERT_ATTRIB_GENERIC0 + k, j);
+         check_array_data(ctx, &arrayObj->VertexAttrib[k], k, j);
       }
    }
 
-   if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) {
-      ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB,
-                             ctx->Array.ElementArrayBufferObj);
+   if (_mesa_is_bufferobj(arrayObj->ElementArrayBufferObj)) {
+      ctx->Driver.UnmapBuffer(ctx, ctx->Array.ArrayObj->ElementArrayBufferObj);
    }
 
-   unmap_array_buffer(ctx, &arrayObj->Vertex);
-   unmap_array_buffer(ctx, &arrayObj->Normal);
-   unmap_array_buffer(ctx, &arrayObj->Color);
-   for (k = 0; k < Elements(arrayObj->TexCoord); k++) {
-      unmap_array_buffer(ctx, &arrayObj->TexCoord[k]);
-   }
    for (k = 0; k < Elements(arrayObj->VertexAttrib); k++) {
       unmap_array_buffer(ctx, &arrayObj->VertexAttrib[k]);
    }
@@ -242,26 +316,29 @@ check_draw_elements_data(GLcontext *ctx, GLsizei count, GLenum elemType,
  * Check array data, looking for NaNs, etc.
  */
 static void
-check_draw_arrays_data(GLcontext *ctx, GLint start, GLsizei count)
+check_draw_arrays_data(struct gl_context *ctx, GLint start, GLsizei count)
 {
    /* TO DO */
 }
 
 
 /**
- * Print info/data for glDrawArrays().
+ * Print info/data for glDrawArrays(), for debugging.
  */
 static void
-print_draw_arrays(GLcontext *ctx, struct vbo_exec_context *exec,
+print_draw_arrays(struct gl_context *ctx,
                   GLenum mode, GLint start, GLsizei count)
 {
+   struct vbo_context *vbo = vbo_context(ctx);
+   struct vbo_exec_context *exec = &vbo->exec;
    int i;
 
    printf("vbo_exec_DrawArrays(mode 0x%x, start %d, count %d):\n",
          mode, start, count);
 
    for (i = 0; i < 32; i++) {
-      GLuint bufName = exec->array.inputs[i]->BufferObj->Name;
+      struct gl_buffer_object *bufObj = exec->array.inputs[i]->BufferObj;
+      GLuint bufName = bufObj->Name;
       GLint stride = exec->array.inputs[i]->Stride;
       printf("attr %2d: size %d stride %d  enabled %d  "
             "ptr %p  Bufobj %u\n",
@@ -274,9 +351,8 @@ print_draw_arrays(GLcontext *ctx, struct vbo_exec_context *exec,
             bufName);
 
       if (bufName) {
-         struct gl_buffer_object *buf = _mesa_lookup_bufferobj(ctx, bufName);
-         GLubyte *p = ctx->Driver.MapBuffer(ctx, GL_ARRAY_BUFFER_ARB,
-                                            GL_READ_ONLY_ARB, buf);
+         GLubyte *p = ctx->Driver.MapBufferRange(ctx, 0, bufObj->Size,
+                                                GL_MAP_READ_BIT, bufObj);
          int offset = (int) (GLintptr) exec->array.inputs[i]->Ptr;
          float *f = (float *) (p + offset);
          int *k = (int *) f;
@@ -288,92 +364,89 @@ print_draw_arrays(GLcontext *ctx, struct vbo_exec_context *exec,
          for (i = 0; i < n; i++) {
             printf("    float[%d] = 0x%08x %f\n", i, k[i], f[i]);
          }
-         ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, buf);
+         ctx->Driver.UnmapBuffer(ctx, bufObj);
       }
    }
 }
 
 
 /**
+ * Bind the VBO executor to the current vertex array object prior
+ * to drawing.
+ *
  * Just translate the arrayobj into a sane layout.
  */
 static void
-bind_array_obj(GLcontext *ctx)
+bind_array_obj(struct gl_context *ctx)
 {
    struct vbo_context *vbo = vbo_context(ctx);
    struct vbo_exec_context *exec = &vbo->exec;
    struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
    GLuint i;
 
-   /* TODO: Fix the ArrayObj struct to keep legacy arrays in an array
-    * rather than as individual named arrays.  Then this function can
-    * go away.
-    */
-   exec->array.legacy_array[VERT_ATTRIB_POS] = &arrayObj->Vertex;
-   exec->array.legacy_array[VERT_ATTRIB_WEIGHT] = &arrayObj->Weight;
-   exec->array.legacy_array[VERT_ATTRIB_NORMAL] = &arrayObj->Normal;
-   exec->array.legacy_array[VERT_ATTRIB_COLOR0] = &arrayObj->Color;
-   exec->array.legacy_array[VERT_ATTRIB_COLOR1] = &arrayObj->SecondaryColor;
-   exec->array.legacy_array[VERT_ATTRIB_FOG] = &arrayObj->FogCoord;
-   exec->array.legacy_array[VERT_ATTRIB_COLOR_INDEX] = &arrayObj->Index;
-   if (arrayObj->PointSize.Enabled) {
-      /* this aliases COLOR_INDEX */
-      exec->array.legacy_array[VERT_ATTRIB_POINT_SIZE] = &arrayObj->PointSize;
-   }
-   exec->array.legacy_array[VERT_ATTRIB_EDGEFLAG] = &arrayObj->EdgeFlag;
+   for (i = 0; i < VERT_ATTRIB_FF_MAX; i++)
+      exec->array.legacy_array[i] = &arrayObj->VertexAttrib[VERT_ATTRIB_FF(i)];
 
-   for (i = 0; i < Elements(arrayObj->TexCoord); i++)
-      exec->array.legacy_array[VERT_ATTRIB_TEX0 + i] = &arrayObj->TexCoord[i];
-
-   for (i = 0; i < Elements(arrayObj->VertexAttrib); i++) {
+   for (i = 0; i < VERT_ATTRIB_GENERIC_MAX; i++) {
       assert(i < Elements(exec->array.generic_array));
-      exec->array.generic_array[i] = &arrayObj->VertexAttrib[i];
+      exec->array.generic_array[i] = &arrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(i)];
    }
-   
-   exec->array.array_obj = arrayObj->Name;
 }
 
 
+/**
+ * Set the vbo->exec->inputs[] pointers to point to the enabled
+ * vertex arrays.  This depends on the current vertex program/shader
+ * being executed because of whether or not generic vertex arrays
+ * alias the conventional vertex arrays.
+ * For arrays that aren't enabled, we set the input[attrib] pointer
+ * to point at a zero-stride current value "array".
+ */
 static void
-recalculate_input_bindings(GLcontext *ctx)
+recalculate_input_bindings(struct gl_context *ctx)
 {
    struct vbo_context *vbo = vbo_context(ctx);
    struct vbo_exec_context *exec = &vbo->exec;
    const struct gl_client_array **inputs = &exec->array.inputs[0];
-   GLbitfield const_inputs = 0x0;
+   GLbitfield64 const_inputs = 0x0;
    GLuint i;
 
-   exec->array.program_mode = get_program_mode(ctx);
-   exec->array.enabled_flags = ctx->Array.ArrayObj->_Enabled;
-
-   switch (exec->array.program_mode) {
+   switch (get_program_mode(ctx)) {
    case VP_NONE:
       /* When no vertex program is active (or the vertex program is generated
        * from fixed-function state).  We put the material values into the
        * generic slots.  This is the only situation where material values
        * are available as per-vertex attributes.
        */
-      for (i = 0; i <= VERT_ATTRIB_TEX7; i++) {
+      for (i = 0; i < VERT_ATTRIB_FF_MAX; i++) {
         if (exec->array.legacy_array[i]->Enabled)
            inputs[i] = exec->array.legacy_array[i];
         else {
            inputs[i] = &vbo->legacy_currval[i];
-            const_inputs |= 1 << i;
+            const_inputs |= VERT_BIT(i);
          }
       }
 
       for (i = 0; i < MAT_ATTRIB_MAX; i++) {
-        inputs[VERT_ATTRIB_GENERIC0 + i] = &vbo->mat_currval[i];
-         const_inputs |= 1 << (VERT_ATTRIB_GENERIC0 + i);
+        inputs[VERT_ATTRIB_GENERIC(i)] = &vbo->mat_currval[i];
+         const_inputs |= VERT_BIT_GENERIC(i);
       }
 
       /* Could use just about anything, just to fill in the empty
        * slots:
        */
-      for (i = MAT_ATTRIB_MAX; i < VERT_ATTRIB_MAX - VERT_ATTRIB_GENERIC0; i++) {
-        inputs[VERT_ATTRIB_GENERIC0 + i] = &vbo->generic_currval[i];
-         const_inputs |= 1 << (VERT_ATTRIB_GENERIC0 + i);
+      for (i = MAT_ATTRIB_MAX; i < VERT_ATTRIB_GENERIC_MAX; i++) {
+        inputs[VERT_ATTRIB_GENERIC(i)] = &vbo->generic_currval[i];
+         const_inputs |= VERT_BIT_GENERIC(i);
       }
+
+      /* There is no need to make _NEW_ARRAY dirty here for the TnL program,
+       * because it already takes care of invalidating the state necessary
+       * to revalidate vertex arrays. Not marking the state as dirty also
+       * improves performance (quite significantly in some apps).
+       */
+      if (!ctx->VertexProgram._MaintainTnlProgram)
+         ctx->NewState |= _NEW_ARRAY;
       break;
 
    case VP_NV:
@@ -381,24 +454,27 @@ recalculate_input_bindings(GLcontext *ctx)
        * conventional, legacy arrays.  No materials, and the generic
        * slots are vacant.
        */
-      for (i = 0; i <= VERT_ATTRIB_TEX7; i++) {
-        if (exec->array.generic_array[i]->Enabled)
+      for (i = 0; i < VERT_ATTRIB_FF_MAX; i++) {
+        if (i < VERT_ATTRIB_GENERIC_MAX
+             && exec->array.generic_array[i]->Enabled)
            inputs[i] = exec->array.generic_array[i];
         else if (exec->array.legacy_array[i]->Enabled)
            inputs[i] = exec->array.legacy_array[i];
         else {
            inputs[i] = &vbo->legacy_currval[i];
-            const_inputs |= 1 << i;
+            const_inputs |= VERT_BIT_FF(i);
          }
       }
 
       /* Could use just about anything, just to fill in the empty
        * slots:
        */
-      for (i = VERT_ATTRIB_GENERIC0; i < VERT_ATTRIB_MAX; i++) {
-        inputs[i] = &vbo->generic_currval[i - VERT_ATTRIB_GENERIC0];
-         const_inputs |= 1 << i;
+      for (i = 0; i < VERT_ATTRIB_GENERIC_MAX; i++) {
+        inputs[VERT_ATTRIB_GENERIC(i)] = &vbo->generic_currval[i];
+         const_inputs |= VERT_BIT_GENERIC(i);
       }
+
+      ctx->NewState |= _NEW_ARRAY;
       break;
 
    case VP_ARB:
@@ -415,31 +491,33 @@ recalculate_input_bindings(GLcontext *ctx)
         inputs[0] = exec->array.legacy_array[0];
       else {
         inputs[0] = &vbo->legacy_currval[0];
-         const_inputs |= 1 << 0;
+         const_inputs |= VERT_BIT_POS;
       }
 
-      for (i = 1; i <= VERT_ATTRIB_TEX7; i++) {
+      for (i = 1; i < VERT_ATTRIB_FF_MAX; i++) {
         if (exec->array.legacy_array[i]->Enabled)
            inputs[i] = exec->array.legacy_array[i];
         else {
            inputs[i] = &vbo->legacy_currval[i];
-            const_inputs |= 1 << i;
+            const_inputs |= VERT_BIT_FF(i);
          }
       }
 
-      for (i = 0; i < MAX_VERTEX_GENERIC_ATTRIBS; i++) {
+      for (i = 1; i < VERT_ATTRIB_GENERIC_MAX; i++) {
         if (exec->array.generic_array[i]->Enabled)
-           inputs[VERT_ATTRIB_GENERIC0 + i] = exec->array.generic_array[i];
+           inputs[VERT_ATTRIB_GENERIC(i)] = exec->array.generic_array[i];
         else {
-           inputs[VERT_ATTRIB_GENERIC0 + i] = &vbo->generic_currval[i];
-            const_inputs |= 1 << (VERT_ATTRIB_GENERIC0 + i);
+           inputs[VERT_ATTRIB_GENERIC(i)] = &vbo->generic_currval[i];
+            const_inputs |= VERT_BIT_GENERIC(i);
          }
-
       }
+
+      inputs[VERT_ATTRIB_GENERIC0] = inputs[0];
+      ctx->NewState |= _NEW_ARRAY;
       break;
    }
 
-   _mesa_set_varying_vp_inputs( ctx, ~const_inputs );
+   _mesa_set_varying_vp_inputs( ctx, VERT_BIT_ALL & (~const_inputs) );
 }
 
 
@@ -450,37 +528,109 @@ recalculate_input_bindings(GLcontext *ctx)
  * Note that this might set the _NEW_ARRAY dirty flag so state validation
  * must be done after this call.
  */
-static void
-bind_arrays(GLcontext *ctx)
+void
+vbo_bind_arrays(struct gl_context *ctx)
 {
-#if 0
-   if (ctx->Array.ArrayObj.Name != exec->array.array_obj) {
-      bind_array_obj(ctx);
-      recalculate_input_bindings(ctx);
-   }
-   else if (exec->array.program_mode != get_program_mode(ctx) ||
-           exec->array.enabled_flags != ctx->Array.ArrayObj->_Enabled) {
-      recalculate_input_bindings(ctx);
+   if (!ctx->Array.RebindArrays) {
+      return;
    }
-#else
+
    bind_array_obj(ctx);
    recalculate_input_bindings(ctx);
-#endif
+   ctx->Array.RebindArrays = GL_FALSE;
 }
 
 
-
-/***********************************************************************
- * API functions.
+/**
+ * Helper function called by the other DrawArrays() functions below.
+ * This is where we handle primitive restart for drawing non-indexed
+ * arrays.  If primitive restart is enabled, it typically means
+ * splitting one DrawArrays() into two.
  */
+static void
+vbo_draw_arrays(struct gl_context *ctx, GLenum mode, GLint start,
+                GLsizei count, GLuint numInstances)
+{
+   struct vbo_context *vbo = vbo_context(ctx);
+   struct vbo_exec_context *exec = &vbo->exec;
+   struct _mesa_prim prim[2];
+
+   vbo_bind_arrays(ctx);
+
+   /* Again... because we may have changed the bitmask of per-vertex varying
+    * attributes.  If we regenerate the fixed-function vertex program now
+    * we may be able to prune down the number of vertex attributes which we
+    * need in the shader.
+    */
+   if (ctx->NewState)
+      _mesa_update_state(ctx);
+
+   /* init most fields to zero */
+   memset(prim, 0, sizeof(prim));
+   prim[0].begin = 1;
+   prim[0].end = 1;
+   prim[0].mode = mode;
+   prim[0].num_instances = numInstances;
+
+   /* Implement the primitive restart index */
+   if (ctx->Array.PrimitiveRestart && ctx->Array.RestartIndex < count) {
+      GLuint primCount = 0;
+
+      if (ctx->Array.RestartIndex == start) {
+         /* special case: RestartIndex at beginning */
+         if (count > 1) {
+            prim[0].start = start + 1;
+            prim[0].count = count - 1;
+            primCount = 1;
+         }
+      }
+      else if (ctx->Array.RestartIndex == start + count - 1) {
+         /* special case: RestartIndex at end */
+         if (count > 1) {
+            prim[0].start = start;
+            prim[0].count = count - 1;
+            primCount = 1;
+         }
+      }
+      else {
+         /* general case: RestartIndex in middle, split into two prims */
+         prim[0].start = start;
+         prim[0].count = ctx->Array.RestartIndex - start;
+
+         prim[1] = prim[0];
+         prim[1].start = ctx->Array.RestartIndex + 1;
+         prim[1].count = count - prim[1].start;
+
+         primCount = 2;
+      }
+
+      if (primCount > 0) {
+         /* draw one or two prims */
+         check_buffers_are_unmapped(exec->array.inputs);
+         vbo->draw_prims(ctx, exec->array.inputs, prim, primCount, NULL,
+                         GL_TRUE, start, start + count - 1);
+      }
+   }
+   else {
+      /* no prim restart */
+      prim[0].start = start;
+      prim[0].count = count;
+
+      check_buffers_are_unmapped(exec->array.inputs);
+      vbo->draw_prims(ctx, exec->array.inputs, prim, 1, NULL,
+                      GL_TRUE, start, start + count - 1);
+   }
+}
 
+
+
+/**
+ * Called from glDrawArrays when in immediate mode (not display list mode).
+ */
 static void GLAPIENTRY
 vbo_exec_DrawArrays(GLenum mode, GLint start, GLsizei count)
 {
    GET_CURRENT_CONTEXT(ctx);
-   struct vbo_context *vbo = vbo_context(ctx);
-   struct vbo_exec_context *exec = &vbo->exec;
-   struct _mesa_prim prim[1];
 
    if (MESA_VERBOSE & VERBOSE_DRAW)
       _mesa_debug(ctx, "glDrawArrays(%s, %d, %d)\n",
@@ -495,58 +645,31 @@ vbo_exec_DrawArrays(GLenum mode, GLint start, GLsizei count)
       return;
    }
 
-#if 0
-   check_draw_arrays_data(ctx, start, count);
-#else
-   (void) check_draw_arrays_data;
-#endif
-
-   bind_arrays( ctx );
-
-   /* Again... because we may have changed the bitmask of per-vertex varying
-    * attributes.  If we regenerate the fixed-function vertex program now
-    * we may be able to prune down the number of vertex attributes which we
-    * need in the shader.
-    */
-   if (ctx->NewState)
-      _mesa_update_state( ctx );
-
-   prim[0].begin = 1;
-   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;
-   prim[0].basevertex = 0;
-   prim[0].num_instances = 1;
+   if (0)
+      check_draw_arrays_data(ctx, start, count);
 
-   vbo->draw_prims( ctx, exec->array.inputs, prim, 1, NULL,
-                    GL_TRUE, start, start + count - 1 );
+   vbo_draw_arrays(ctx, mode, start, count, 1);
 
-#if 0
-   print_draw_arrays(ctx, exec, mode, start, count);
-#else
-   (void) print_draw_arrays;
-#endif
+   if (0)
+      print_draw_arrays(ctx, mode, start, count);
 }
 
 
+/**
+ * Called from glDrawArraysInstanced when in immediate mode (not
+ * display list mode).
+ */
 static void GLAPIENTRY
 vbo_exec_DrawArraysInstanced(GLenum mode, GLint start, GLsizei count,
-                             GLsizei primcount)
+                             GLsizei numInstances)
 {
    GET_CURRENT_CONTEXT(ctx);
-   struct vbo_context *vbo = vbo_context(ctx);
-   struct vbo_exec_context *exec = &vbo->exec;
-   struct _mesa_prim prim[1];
 
    if (MESA_VERBOSE & VERBOSE_DRAW)
       _mesa_debug(ctx, "glDrawArraysInstanced(%s, %d, %d, %d)\n",
-                  _mesa_lookup_enum_by_nr(mode), start, count, primcount);
+                  _mesa_lookup_enum_by_nr(mode), start, count, numInstances);
 
-   if (!_mesa_validate_DrawArraysInstanced(ctx, mode, start, count, primcount))
+   if (!_mesa_validate_DrawArraysInstanced(ctx, mode, start, count, numInstances))
       return;
 
    FLUSH_CURRENT( ctx, 0 );
@@ -555,56 +678,34 @@ vbo_exec_DrawArraysInstanced(GLenum mode, GLint start, GLsizei count,
       return;
    }
 
-#if 0 /* debug */
-   check_draw_arrays_data(ctx, start, count);
-#endif
-
-   bind_arrays( ctx );
-
-   /* Again... because we may have changed the bitmask of per-vertex varying
-    * attributes.  If we regenerate the fixed-function vertex program now
-    * we may be able to prune down the number of vertex attributes which we
-    * need in the shader.
-    */
-   if (ctx->NewState)
-      _mesa_update_state( ctx );
-
-   prim[0].begin = 1;
-   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;
-   prim[0].basevertex = 0;
-   prim[0].num_instances = primcount;
+   if (0)
+      check_draw_arrays_data(ctx, start, count);
 
-   vbo->draw_prims( ctx, exec->array.inputs, prim, 1, NULL,
-                    GL_TRUE, start, start + count - 1 );
+   vbo_draw_arrays(ctx, mode, start, count, numInstances);
 
-#if 0 /* debug */
-   print_draw_arrays(ctx, exec, mode, start, count);
-#endif
+   if (0)
+      print_draw_arrays(ctx, mode, start, count);
 }
 
 
 /**
  * Map GL_ELEMENT_ARRAY_BUFFER and print contents.
+ * For debugging.
  */
 static void
-dump_element_buffer(GLcontext *ctx, GLenum type)
+dump_element_buffer(struct gl_context *ctx, GLenum type)
 {
-   const GLvoid *map = ctx->Driver.MapBuffer(ctx,
-                                             GL_ELEMENT_ARRAY_BUFFER_ARB,
-                                             GL_READ_ONLY,
-                                             ctx->Array.ElementArrayBufferObj);
+   const GLvoid *map =
+      ctx->Driver.MapBufferRange(ctx, 0,
+                                ctx->Array.ArrayObj->ElementArrayBufferObj->Size,
+                                GL_MAP_READ_BIT,
+                                ctx->Array.ArrayObj->ElementArrayBufferObj);
    switch (type) {
    case GL_UNSIGNED_BYTE:
       {
          const GLubyte *us = (const GLubyte *) map;
          GLint i;
-         for (i = 0; i < ctx->Array.ElementArrayBufferObj->Size; i++) {
+         for (i = 0; i < ctx->Array.ArrayObj->ElementArrayBufferObj->Size; i++) {
             printf("%02x ", us[i]);
             if (i % 32 == 31)
                printf("\n");
@@ -616,7 +717,7 @@ dump_element_buffer(GLcontext *ctx, GLenum type)
       {
          const GLushort *us = (const GLushort *) map;
          GLint i;
-         for (i = 0; i < ctx->Array.ElementArrayBufferObj->Size / 2; i++) {
+         for (i = 0; i < ctx->Array.ArrayObj->ElementArrayBufferObj->Size / 2; i++) {
             printf("%04x ", us[i]);
             if (i % 16 == 15)
                printf("\n");
@@ -628,7 +729,7 @@ dump_element_buffer(GLcontext *ctx, GLenum type)
       {
          const GLuint *us = (const GLuint *) map;
          GLint i;
-         for (i = 0; i < ctx->Array.ElementArrayBufferObj->Size / 4; i++) {
+         for (i = 0; i < ctx->Array.ArrayObj->ElementArrayBufferObj->Size / 4; i++) {
             printf("%08x ", us[i]);
             if (i % 8 == 7)
                printf("\n");
@@ -640,19 +741,22 @@ dump_element_buffer(GLcontext *ctx, GLenum type)
       ;
    }
 
-   ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB,
-                           ctx->Array.ElementArrayBufferObj);
+   ctx->Driver.UnmapBuffer(ctx, ctx->Array.ArrayObj->ElementArrayBufferObj);
 }
 
 
-/* Inner support for both _mesa_DrawElements and _mesa_DrawRangeElements */
+/**
+ * Inner support for both _mesa_DrawElements and _mesa_DrawRangeElements.
+ * Do the rendering for a glDrawElements or glDrawRangeElements call after
+ * we've validated buffer bounds, etc.
+ */
 static void
-vbo_validated_drawrangeelements(GLcontext *ctx, GLenum mode,
+vbo_validated_drawrangeelements(struct gl_context *ctx, GLenum mode,
                                GLboolean index_bounds_valid,
                                GLuint start, GLuint end,
                                GLsizei count, GLenum type,
                                const GLvoid *indices,
-                               GLint basevertex, GLint primcount)
+                               GLint basevertex, GLint numInstances)
 {
    struct vbo_context *vbo = vbo_context(ctx);
    struct vbo_exec_context *exec = &vbo->exec;
@@ -665,7 +769,7 @@ vbo_validated_drawrangeelements(GLcontext *ctx, GLenum mode,
       return;
    }
 
-   bind_arrays( ctx );
+   vbo_bind_arrays( ctx );
 
    /* check for dirty state again */
    if (ctx->NewState)
@@ -673,7 +777,7 @@ vbo_validated_drawrangeelements(GLcontext *ctx, GLenum mode,
 
    ib.count = count;
    ib.type = type;
-   ib.obj = ctx->Array.ElementArrayBufferObj;
+   ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj;
    ib.ptr = indices;
 
    prim[0].begin = 1;
@@ -685,7 +789,7 @@ vbo_validated_drawrangeelements(GLcontext *ctx, GLenum mode,
    prim[0].count = count;
    prim[0].indexed = 1;
    prim[0].basevertex = basevertex;
-   prim[0].num_instances = primcount;
+   prim[0].num_instances = numInstances;
 
    /* Need to give special consideration to rendering a range of
     * indices starting somewhere above zero.  Typically the
@@ -718,10 +822,15 @@ vbo_validated_drawrangeelements(GLcontext *ctx, GLenum mode,
     * for the latter case elsewhere.
     */
 
+   check_buffers_are_unmapped(exec->array.inputs);
    vbo->draw_prims( ctx, exec->array.inputs, prim, 1, &ib,
                    index_bounds_valid, start, end );
 }
 
+
+/**
+ * Called by glDrawRangeElementsBaseVertex() in immediate mode.
+ */
 static void GLAPIENTRY
 vbo_exec_DrawRangeElementsBaseVertex(GLenum mode,
                                     GLuint start, GLuint end,
@@ -770,8 +879,8 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode,
                        "\tThis should probably be fixed in the application.",
                        start, end, count, type, indices,
                        ctx->Array.ArrayObj->_MaxElement - 1,
-                       ctx->Array.ElementArrayBufferObj->Name,
-                       ctx->Array.ElementArrayBufferObj->Size);
+                       ctx->Array.ArrayObj->ElementArrayBufferObj->Name,
+                       (int) ctx->Array.ArrayObj->ElementArrayBufferObj->Size);
       }
 
       if (0)
@@ -780,13 +889,12 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode,
       if (0)
          _mesa_print_arrays(ctx);
 
-#ifdef DEBUG
       /* 'end' was out of bounds, but now let's check the actual array
        * indexes to see if any of them are out of bounds.
        */
-      {
+      if (0) {
          GLuint max = _mesa_max_buffer_index(ctx, count, type, indices,
-                                             ctx->Array.ElementArrayBufferObj);
+                                             ctx->Array.ArrayObj->ElementArrayBufferObj);
          if (max >= ctx->Array.ArrayObj->_MaxElement) {
             if (warnCount < 10) {
                _mesa_warning(ctx, "glDraw[Range]Elements(start %u, end %u, "
@@ -796,8 +904,8 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode,
                              "\tSkipping the glDrawRangeElements() call",
                              start, end, count, type, indices, max,
                              ctx->Array.ArrayObj->_MaxElement - 1,
-                             ctx->Array.ElementArrayBufferObj->Name,
-                             ctx->Array.ElementArrayBufferObj->Size);
+                             ctx->Array.ArrayObj->ElementArrayBufferObj->Name,
+                             (int) ctx->Array.ArrayObj->ElementArrayBufferObj->Size);
             }
          }
          /* XXX we could also find the min index and compare to 'start'
@@ -805,18 +913,22 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode,
           * upper bound wrong.
           */
       }
-#endif
 
       /* Set 'end' to the max possible legal value */
       assert(ctx->Array.ArrayObj->_MaxElement >= 1);
       end = ctx->Array.ArrayObj->_MaxElement - 1;
+
+      if (end < start) {
+         return;
+      }
    }
-   else if (0) {
+
+   if (0) {
       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.ArrayObj->ElementArrayBufferObj->Name,
             basevertex);
    }
 
@@ -831,23 +943,29 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode,
 }
 
 
+/**
+ * Called by glDrawRangeElements() in immediate mode.
+ */
 static void GLAPIENTRY
 vbo_exec_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
                            GLsizei count, GLenum type, const GLvoid *indices)
 {
-   GET_CURRENT_CONTEXT(ctx);
-
-   if (MESA_VERBOSE & VERBOSE_DRAW)
+   if (MESA_VERBOSE & VERBOSE_DRAW) {
+      GET_CURRENT_CONTEXT(ctx);
       _mesa_debug(ctx,
                   "glDrawRangeElements(%s, %u, %u, %d, %s, %p)\n",
                   _mesa_lookup_enum_by_nr(mode), start, end, count,
                   _mesa_lookup_enum_by_nr(type), indices);
+   }
 
    vbo_exec_DrawRangeElementsBaseVertex(mode, start, end, count, type,
                                        indices, 0);
 }
 
 
+/**
+ * Called by glDrawElements() in immediate mode.
+ */
 static void GLAPIENTRY
 vbo_exec_DrawElements(GLenum mode, GLsizei count, GLenum type,
                       const GLvoid *indices)
@@ -867,6 +985,9 @@ vbo_exec_DrawElements(GLenum mode, GLsizei count, GLenum type,
 }
 
 
+/**
+ * Called by glDrawElementsBaseVertex() in immediate mode.
+ */
 static void GLAPIENTRY
 vbo_exec_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
                                const GLvoid *indices, GLint basevertex)
@@ -887,29 +1008,60 @@ vbo_exec_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
 }
 
 
+/**
+ * Called by glDrawElementsInstanced() in immediate mode.
+ */
 static void GLAPIENTRY
 vbo_exec_DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
-                               const GLvoid *indices, GLsizei primcount)
+                               const GLvoid *indices, GLsizei numInstances)
 {
    GET_CURRENT_CONTEXT(ctx);
 
    if (MESA_VERBOSE & VERBOSE_DRAW)
       _mesa_debug(ctx, "glDrawElementsInstanced(%s, %d, %s, %p, %d)\n",
                   _mesa_lookup_enum_by_nr(mode), count,
-                  _mesa_lookup_enum_by_nr(type), indices, primcount);
+                  _mesa_lookup_enum_by_nr(type), indices, numInstances);
 
    if (!_mesa_validate_DrawElementsInstanced(ctx, mode, count, type, indices,
-                                             primcount))
+                                             numInstances, 0))
       return;
 
    vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
-                                  count, type, indices, 0, primcount);
+                                  count, type, indices, 0, numInstances);
+}
+
+/**
+ * Called by glDrawElementsInstancedBaseVertex() in immediate mode.
+ */
+static void GLAPIENTRY
+vbo_exec_DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type,
+                               const GLvoid *indices, GLsizei numInstances,
+                               GLint basevertex)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (MESA_VERBOSE & VERBOSE_DRAW)
+      _mesa_debug(ctx, "glDrawElementsInstancedBaseVertex(%s, %d, %s, %p, %d; %d)\n",
+                  _mesa_lookup_enum_by_nr(mode), count,
+                  _mesa_lookup_enum_by_nr(type), indices,
+                  numInstances, basevertex);
+
+   if (!_mesa_validate_DrawElementsInstanced(ctx, mode, count, type, indices,
+                                             numInstances, basevertex))
+      return;
+
+   vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
+                                  count, type, indices, basevertex, numInstances);
 }
 
 
-/** Inner support for both _mesa_DrawElements and _mesa_DrawRangeElements */
+/**
+ * Inner support for both _mesa_MultiDrawElements() and
+ * _mesa_MultiDrawRangeElements().
+ * This does the actual rendering after we've checked array indexes, etc.
+ */
 static void
-vbo_validated_multidrawelements(GLcontext *ctx, GLenum mode,
+vbo_validated_multidrawelements(struct gl_context *ctx, GLenum mode,
                                const GLsizei *count, GLenum type,
                                const GLvoid **indices, GLsizei primcount,
                                const GLint *basevertex)
@@ -939,9 +1091,10 @@ vbo_validated_multidrawelements(GLcontext *ctx, GLenum mode,
    }
 
    /* Decide if we can do this all as one set of primitives sharing the
-    * same index buffer, or if we have to reset the index pointer per primitive.
+    * same index buffer, or if we have to reset the index pointer per
+    * primitive.
     */
-   bind_arrays( ctx );
+   vbo_bind_arrays( ctx );
 
    /* check for dirty state again */
    if (ctx->NewState)
@@ -972,6 +1125,8 @@ vbo_validated_multidrawelements(GLcontext *ctx, GLenum mode,
    /* Check if we can handle this thing as a bunch of index offsets from the
     * same index pointer.  If we can't, then we have to fall back to doing
     * a draw_prims per primitive.
+    * Check that the difference between each prim's indexes is a multiple of
+    * the index/element size.
     */
    if (index_type_size != 1) {
       for (i = 0; i < primcount; i++) {
@@ -986,13 +1141,13 @@ vbo_validated_multidrawelements(GLcontext *ctx, GLenum mode,
     * subranges of the index buffer as one large index buffer may lead to
     * us reading unmapped memory.
     */
-   if (!_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj))
+   if (!_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj))
       fallback = GL_TRUE;
 
    if (!fallback) {
       ib.count = (max_index_ptr - min_index_ptr) / index_type_size;
       ib.type = type;
-      ib.obj = ctx->Array.ElementArrayBufferObj;
+      ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj;
       ib.ptr = (void *)min_index_ptr;
 
       for (i = 0; i < primcount; i++) {
@@ -1011,6 +1166,7 @@ vbo_validated_multidrawelements(GLcontext *ctx, GLenum mode,
            prim[i].basevertex = 0;
       }
 
+      check_buffers_are_unmapped(exec->array.inputs);
       vbo->draw_prims(ctx, exec->array.inputs, prim, primcount, &ib,
                      GL_FALSE, ~0, ~0);
    } else {
@@ -1018,7 +1174,7 @@ vbo_validated_multidrawelements(GLcontext *ctx, GLenum mode,
       for (i = 0; i < primcount; i++) {
         ib.count = count[i];
         ib.type = type;
-        ib.obj = ctx->Array.ElementArrayBufferObj;
+        ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj;
         ib.ptr = indices[i];
 
         prim[0].begin = 1;
@@ -1035,6 +1191,7 @@ vbo_validated_multidrawelements(GLcontext *ctx, GLenum mode,
         else
            prim[0].basevertex = 0;
 
+         check_buffers_are_unmapped(exec->array.inputs);
          vbo->draw_prims(ctx, exec->array.inputs, prim, 1, &ib,
                          GL_FALSE, ~0, ~0);
       }
@@ -1089,14 +1246,13 @@ vbo_exec_MultiDrawElementsBaseVertex(GLenum mode,
 }
 
 
-/***********************************************************************
- * Initialization
+/**
+ * Plug in the immediate-mode vertex array drawing commands into the
+ * givven vbo_exec_context object.
  */
-
 void
 vbo_exec_array_init( struct vbo_exec_context *exec )
 {
-#if 1
    exec->vtxfmt.DrawArrays = vbo_exec_DrawArrays;
    exec->vtxfmt.DrawElements = vbo_exec_DrawElements;
    exec->vtxfmt.DrawRangeElements = vbo_exec_DrawRangeElements;
@@ -1106,15 +1262,7 @@ vbo_exec_array_init( struct vbo_exec_context *exec )
    exec->vtxfmt.MultiDrawElementsBaseVertex = vbo_exec_MultiDrawElementsBaseVertex;
    exec->vtxfmt.DrawArraysInstanced = vbo_exec_DrawArraysInstanced;
    exec->vtxfmt.DrawElementsInstanced = vbo_exec_DrawElementsInstanced;
-#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
+   exec->vtxfmt.DrawElementsInstancedBaseVertex = vbo_exec_DrawElementsInstancedBaseVertex;
 }
 
 
@@ -1125,7 +1273,13 @@ vbo_exec_array_destroy( struct vbo_exec_context *exec )
 }
 
 
-/* This API entrypoint is not ordinarily used */
+
+/**
+ * The following functions are only used for OpenGL ES 1/2 support.
+ * And some aren't even supported (yet) in ES 1/2.
+ */
+
+
 void GLAPIENTRY
 _mesa_DrawArrays(GLenum mode, GLint first, GLsizei count)
 {
@@ -1133,7 +1287,6 @@ _mesa_DrawArrays(GLenum mode, GLint first, GLsizei count)
 }
 
 
-/* This API entrypoint is not ordinarily used */
 void GLAPIENTRY
 _mesa_DrawElements(GLenum mode, GLsizei count, GLenum type,
                    const GLvoid *indices)
@@ -1141,6 +1294,7 @@ _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)
@@ -1149,7 +1303,6 @@ _mesa_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
 }
 
 
-/* This API entrypoint is not ordinarily used */
 void GLAPIENTRY
 _mesa_DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count,
                         GLenum type, const GLvoid *indices)
@@ -1168,7 +1321,6 @@ _mesa_DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end,
 }
 
 
-/* GL_EXT_multi_draw_arrays */
 void GLAPIENTRY
 _mesa_MultiDrawElementsEXT(GLenum mode, const GLsizei *count, GLenum type,
                           const GLvoid **indices, GLsizei primcount)