Drop GLcontext typedef and use struct gl_context instead
[mesa.git] / src / mesa / vbo / vbo_exec_array.c
index 774cffc451b861514c9c1c60170ff59a53f2120b..f46ba636fe76fdac438e9e8ce8bc88966c3c530e 100644 (file)
 #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"
 #include "main/macros.h"
-#include "glapi/dispatch.h"
 
 #include "vbo_context.h"
 
 
 /**
- * Compute min and max elements for glDraw[Range]Elements() calls.
+ * Compute min and max elements by scanning the index buffer for
+ * glDraw[Range]Elements() calls.
  */
 void
-vbo_get_minmax_index(GLcontext *ctx,
+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;
-   GLsizei count = prim->count;
+   GLuint count = prim->count;
    const void *indices;
 
    if (_mesa_is_bufferobj(ib->obj)) {
-      const GLvoid *map = ctx->Driver.MapBuffer(ctx,
-                                                GL_ELEMENT_ARRAY_BUFFER_ARB,
-                                                GL_READ_ONLY,
-                                                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);
    } else {
       indices = ib->ptr;
@@ -105,9 +104,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, GL_ELEMENT_ARRAY_BUFFER_ARB, ib->obj);
    }
 }
 
@@ -115,9 +112,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) {
@@ -125,10 +123,9 @@ check_array_data(GLcontext *ctx, struct gl_client_array *array,
       if (_mesa_is_bufferobj(array->BufferObj)) {
          if (!array->BufferObj->Pointer) {
             /* need to map now */
-            array->BufferObj->Pointer = ctx->Driver.MapBuffer(ctx,
-                                                              GL_ARRAY_BUFFER_ARB,
-                                                              GL_READ_ONLY,
-                                                              array->BufferObj);
+            array->BufferObj->Pointer =
+               ctx->Driver.MapBuffer(ctx, GL_ARRAY_BUFFER_ARB,
+                                     GL_READ_ONLY, array->BufferObj);
          }
          data = ADD_POINTERS(data, array->BufferObj->Pointer);
       }
@@ -136,20 +133,20 @@ check_array_data(GLcontext *ctx, struct gl_client_array *array,
       case GL_FLOAT:
          {
             GLfloat *f = (GLfloat *) ((GLubyte *) data + array->StrideB * j);
-            GLuint k;
+            GLint k;
             for (k = 0; k < array->Size; k++) {
                if (IS_INF_OR_NAN(f[k]) ||
                    f[k] >= 1.0e20 || f[k] <= -1.0e10) {
-                  _mesa_printf("Bad array data:\n");
-                  _mesa_printf("  Element[%u].%u = %f\n", j, k, f[k]);
-                  _mesa_printf("  Array %u at %p\n", attrib, (void* ) array);
-                  _mesa_printf("  Type 0x%x, Size %d, Stride %d\n",
-                               array->Type, array->Size, array->Stride);
-                  _mesa_printf("  Address/offset %p in Buffer Object %u\n",
-                               array->Ptr, array->BufferObj->Name);
+                  printf("Bad array data:\n");
+                  printf("  Element[%u].%u = %f\n", j, k, f[k]);
+                  printf("  Array %u at %p\n", attrib, (void* ) array);
+                  printf("  Type 0x%x, Size %d, Stride %d\n",
+                        array->Type, array->Size, array->Stride);
+                  printf("  Address/offset %p in Buffer Object %u\n",
+                        array->Ptr, array->BufferObj->Name);
                   f[k] = 1.0; /* XXX replace the bad value! */
                }
-               //assert(!IS_INF_OR_NAN(f[k]));
+               /*assert(!IS_INF_OR_NAN(f[k]));*/
             }
          }
          break;
@@ -164,23 +161,22 @@ 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, GL_ARRAY_BUFFER_ARB, 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;
@@ -222,13 +218,13 @@ check_draw_elements_data(GLcontext *ctx, GLsizei count, GLenum elemType,
          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],
+                          VERT_ATTRIB_GENERIC0 + k, j);
       }
    }
 
    if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) {
-      ctx->Driver.UnmapBuffer(ctx,
-                             GL_ELEMENT_ARRAY_BUFFER_ARB,
+      ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB,
                              ctx->Array.ElementArrayBufferObj);
    }
 
@@ -248,36 +244,36 @@ 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, struct vbo_exec_context *exec,
                   GLenum mode, GLint start, GLsizei count)
 {
    int i;
 
-   _mesa_printf("vbo_exec_DrawArrays(mode 0x%x, start %d, count %d):\n",
-                mode, start, count);
+   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;
       GLint stride = exec->array.inputs[i]->Stride;
-      _mesa_printf("attr %2d: size %d stride %d  enabled %d  "
-                   "ptr %p  Bufobj %u\n",
-                   i,
-                   exec->array.inputs[i]->Size,
-                   stride,
-                   /*exec->array.inputs[i]->Enabled,*/
-                   exec->array.legacy_array[i]->Enabled,
-                   exec->array.inputs[i]->Ptr,
-                   bufName);
+      printf("attr %2d: size %d stride %d  enabled %d  "
+            "ptr %p  Bufobj %u\n",
+            i,
+            exec->array.inputs[i]->Size,
+            stride,
+            /*exec->array.inputs[i]->Enabled,*/
+            exec->array.legacy_array[i]->Enabled,
+            exec->array.inputs[i]->Ptr,
+            bufName);
 
       if (bufName) {
          struct gl_buffer_object *buf = _mesa_lookup_bufferobj(ctx, bufName);
@@ -290,9 +286,9 @@ print_draw_arrays(GLcontext *ctx, struct vbo_exec_context *exec,
          int n = (count * stride) / 4;
          if (n > 32)
             n = 32;
-         _mesa_printf("  Data at offset %d:\n", offset);
+         printf("  Data at offset %d:\n", offset);
          for (i = 0; i < n; i++) {
-            _mesa_printf("    float[%d] = 0x%08x %f\n", i, k[i], f[i]);
+            printf("    float[%d] = 0x%08x %f\n", i, k[i], f[i]);
          }
          ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, buf);
       }
@@ -301,10 +297,13 @@ print_draw_arrays(GLcontext *ctx, struct vbo_exec_context *exec,
 
 
 /**
+ * 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;
@@ -340,8 +339,16 @@ bind_array_obj(GLcontext *ctx)
 }
 
 
+/**
+ * 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;
@@ -449,31 +456,25 @@ recalculate_input_bindings(GLcontext *ctx)
 }
 
 
+/**
+ * Examine the enabled vertex arrays to set the exec->array.inputs[] values.
+ * These will point to the arrays to actually use for drawing.  Some will
+ * be user-provided arrays, other will be zero-stride const-valued arrays.
+ * 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)
+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);
-   }
-#else
    bind_array_obj(ctx);
    recalculate_input_bindings(ctx);
-#endif
 }
 
 
 
-/***********************************************************************
- * API functions.
+/**
+ * Called from glDrawArrays when in immediate mode (not display list mode).
  */
-
 static void GLAPIENTRY
 vbo_exec_DrawArrays(GLenum mode, GLint start, GLsizei count)
 {
@@ -482,14 +483,15 @@ vbo_exec_DrawArrays(GLenum mode, GLint start, GLsizei count)
    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",
+                  _mesa_lookup_enum_by_nr(mode), start, count);
+
    if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
       return;
 
    FLUSH_CURRENT( ctx, 0 );
 
-   if (ctx->NewState)
-      _mesa_update_state( ctx );
-      
    if (!_mesa_valid_to_render(ctx, "glDrawArrays")) {
       return;
    }
@@ -519,6 +521,7 @@ vbo_exec_DrawArrays(GLenum mode, GLint start, GLsizei count)
    prim[0].count = count;
    prim[0].indexed = 0;
    prim[0].basevertex = 0;
+   prim[0].num_instances = 1;
 
    vbo->draw_prims( ctx, exec->array.inputs, prim, 1, NULL,
                     GL_TRUE, start, start + count - 1 );
@@ -531,11 +534,72 @@ vbo_exec_DrawArrays(GLenum mode, GLint start, GLsizei 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)
+{
+   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);
+
+   if (!_mesa_validate_DrawArraysInstanced(ctx, mode, start, count, primcount))
+      return;
+
+   FLUSH_CURRENT( ctx, 0 );
+
+   if (!_mesa_valid_to_render(ctx, "glDrawArraysInstanced")) {
+      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;
+
+   vbo->draw_prims( ctx, exec->array.inputs, prim, 1, NULL,
+                    GL_TRUE, start, start + count - 1 );
+
+#if 0 /* debug */
+   print_draw_arrays(ctx, exec, mode, start, count);
+#endif
+}
+
+
 /**
  * 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,
@@ -545,56 +609,60 @@ dump_element_buffer(GLcontext *ctx, GLenum type)
    case GL_UNSIGNED_BYTE:
       {
          const GLubyte *us = (const GLubyte *) map;
-         GLuint i;
+         GLint i;
          for (i = 0; i < ctx->Array.ElementArrayBufferObj->Size; i++) {
-            _mesa_printf("%02x ", us[i]);
+            printf("%02x ", us[i]);
             if (i % 32 == 31)
-               _mesa_printf("\n");
+               printf("\n");
          }
-         _mesa_printf("\n");
+         printf("\n");
       }
       break;
    case GL_UNSIGNED_SHORT:
       {
          const GLushort *us = (const GLushort *) map;
-         GLuint i;
+         GLint i;
          for (i = 0; i < ctx->Array.ElementArrayBufferObj->Size / 2; i++) {
-            _mesa_printf("%04x ", us[i]);
+            printf("%04x ", us[i]);
             if (i % 16 == 15)
-               _mesa_printf("\n");
+               printf("\n");
          }
-         _mesa_printf("\n");
+         printf("\n");
       }
       break;
    case GL_UNSIGNED_INT:
       {
          const GLuint *us = (const GLuint *) map;
-         GLuint i;
+         GLint i;
          for (i = 0; i < ctx->Array.ElementArrayBufferObj->Size / 4; i++) {
-            _mesa_printf("%08x ", us[i]);
+            printf("%08x ", us[i]);
             if (i % 8 == 7)
-               _mesa_printf("\n");
+               printf("\n");
          }
-         _mesa_printf("\n");
+         printf("\n");
       }
       break;
    default:
       ;
    }
 
-   ctx->Driver.UnmapBuffer(ctx,
-                           GL_ELEMENT_ARRAY_BUFFER_ARB,
+   ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB,
                            ctx->Array.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 basevertex, GLint primcount)
 {
    struct vbo_context *vbo = vbo_context(ctx);
    struct vbo_exec_context *exec = &vbo->exec;
@@ -603,18 +671,16 @@ vbo_validated_drawrangeelements(GLcontext *ctx, GLenum mode,
 
    FLUSH_CURRENT( ctx, 0 );
 
-   if (ctx->NewState)
-      _mesa_update_state( ctx );
-
    if (!_mesa_valid_to_render(ctx, "glDraw[Range]Elements")) {
       return;
    }
 
+   bind_arrays( ctx );
+
+   /* check for dirty state again */
    if (ctx->NewState)
       _mesa_update_state( ctx );
 
-   bind_arrays( ctx );
-
    ib.count = count;
    ib.type = type;
    ib.obj = ctx->Array.ElementArrayBufferObj;
@@ -629,6 +695,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;
 
    /* Need to give special consideration to rendering a range of
     * indices starting somewhere above zero.  Typically the
@@ -665,6 +732,10 @@ vbo_validated_drawrangeelements(GLcontext *ctx, GLenum mode,
                    index_bounds_valid, start, end );
 }
 
+
+/**
+ * Called by glDrawRangeElementsBaseVertex() in immediate mode.
+ */
 static void GLAPIENTRY
 vbo_exec_DrawRangeElementsBaseVertex(GLenum mode,
                                     GLuint start, GLuint end,
@@ -675,6 +746,12 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode,
    static GLuint warnCount = 0;
    GET_CURRENT_CONTEXT(ctx);
 
+   if (MESA_VERBOSE & VERBOSE_DRAW)
+      _mesa_debug(ctx,
+                "glDrawRangeElementsBaseVertex(%s, %u, %u, %d, %s, %p, %d)\n",
+                _mesa_lookup_enum_by_nr(mode), start, end, count,
+                _mesa_lookup_enum_by_nr(type), indices, basevertex);
+
    if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count,
                                           type, indices, basevertex ))
       return;
@@ -685,6 +762,16 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode,
     * or we can read/write out of memory in several different places!
     */
 
+   /* Catch/fix some potential user errors */
+   if (type == GL_UNSIGNED_BYTE) {
+      start = MIN2(start, 0xff);
+      end = MIN2(end, 0xff);
+   }
+   else if (type == GL_UNSIGNED_SHORT) {
+      start = MIN2(start, 0xffff);
+      end = MIN2(end, 0xffff);
+   }
+
    if (end >= ctx->Array.ArrayObj->_MaxElement) {
       /* the max element is out of bounds of one or more enabled arrays */
       warnCount++;
@@ -698,7 +785,7 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode,
                        start, end, count, type, indices,
                        ctx->Array.ArrayObj->_MaxElement - 1,
                        ctx->Array.ElementArrayBufferObj->Name,
-                       ctx->Array.ElementArrayBufferObj->Size);
+                       (int) ctx->Array.ElementArrayBufferObj->Size);
       }
 
       if (0)
@@ -709,8 +796,7 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode,
 
 #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 so, warn
-       * and skip the draw to avoid potential segfault, etc.
+       * indexes to see if any of them are out of bounds.
        */
       {
          GLuint max = _mesa_max_buffer_index(ctx, count, type, indices,
@@ -725,9 +811,8 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode,
                              start, end, count, type, indices, max,
                              ctx->Array.ArrayObj->_MaxElement - 1,
                              ctx->Array.ElementArrayBufferObj->Name,
-                             ctx->Array.ElementArrayBufferObj->Size);
+                             (int) ctx->Array.ElementArrayBufferObj->Size);
             }
-            return;
          }
          /* XXX we could also find the min index and compare to 'start'
           * to see if start is correct.  But it's more likely to get the
@@ -735,14 +820,18 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode,
           */
       }
 #endif
+
+      /* Set 'end' to the max possible legal value */
+      assert(ctx->Array.ArrayObj->_MaxElement >= 1);
+      end = ctx->Array.ArrayObj->_MaxElement - 1;
    }
    else if (0) {
-      _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,
-                  basevertex);
+      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,
+            basevertex);
    }
 
 #if 0
@@ -752,50 +841,105 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode,
 #endif
 
    vbo_validated_drawrangeelements(ctx, mode, GL_TRUE, start, end,
-                                  count, type, indices, basevertex);
+                                  count, type, indices, basevertex, 1);
 }
 
+
+/**
+ * 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)
+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)
+      _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)
 {
    GET_CURRENT_CONTEXT(ctx);
 
+   if (MESA_VERBOSE & VERBOSE_DRAW)
+      _mesa_debug(ctx, "glDrawElements(%s, %u, %s, %p)\n",
+                  _mesa_lookup_enum_by_nr(mode), count,
+                  _mesa_lookup_enum_by_nr(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);
+                                  count, type, indices, 0, 1);
 }
 
+
+/**
+ * Called by glDrawElementsBaseVertex() in immediate mode.
+ */
 static void GLAPIENTRY
 vbo_exec_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
                                const GLvoid *indices, GLint basevertex)
 {
    GET_CURRENT_CONTEXT(ctx);
 
+   if (MESA_VERBOSE & VERBOSE_DRAW)
+      _mesa_debug(ctx, "glDrawElementsBaseVertex(%s, %d, %s, %p, %d)\n",
+                  _mesa_lookup_enum_by_nr(mode), count,
+                  _mesa_lookup_enum_by_nr(type), indices, basevertex);
+
    if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices,
                                     basevertex ))
       return;
 
    vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
-                                  count, type, indices, basevertex);
+                                  count, type, indices, basevertex, 1);
+}
+
+
+/**
+ * Called by glDrawElementsInstanced() in immediate mode.
+ */
+static void GLAPIENTRY
+vbo_exec_DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
+                               const GLvoid *indices, GLsizei primcount)
+{
+   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);
+
+   if (!_mesa_validate_DrawElementsInstanced(ctx, mode, count, type, indices,
+                                             primcount))
+      return;
+
+   vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
+                                  count, type, indices, 0, primcount);
 }
 
-/* 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)
@@ -814,27 +958,26 @@ vbo_validated_multidrawelements(GLcontext *ctx, GLenum mode,
 
    FLUSH_CURRENT( ctx, 0 );
 
-   if (ctx->NewState)
-      _mesa_update_state( ctx );
-
    if (!_mesa_valid_to_render(ctx, "glMultiDrawElements")) {
       return;
    }
 
-   if (ctx->NewState)
-      _mesa_update_state( ctx );
-
-   prim = _mesa_calloc(primcount * sizeof(*prim));
+   prim = calloc(1, primcount * sizeof(*prim));
    if (prim == NULL) {
       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMultiDrawElements");
       return;
    }
 
    /* 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 );
 
+   /* check for dirty state again */
+   if (ctx->NewState)
+      _mesa_update_state( ctx );
+
    switch (type) {
    case GL_UNSIGNED_INT:
       index_type_size = 4;
@@ -892,6 +1035,7 @@ 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;
+         prim[i].num_instances = 1;
         if (basevertex != NULL)
            prim[i].basevertex = basevertex[i];
         else
@@ -901,13 +1045,13 @@ vbo_validated_multidrawelements(GLcontext *ctx, GLenum mode,
       vbo->draw_prims(ctx, exec->array.inputs, prim, primcount, &ib,
                      GL_FALSE, ~0, ~0);
    } else {
+      /* render one prim at a time */
       for (i = 0; i < primcount; i++) {
         ib.count = count[i];
         ib.type = type;
         ib.obj = ctx->Array.ElementArrayBufferObj;
         ib.ptr = indices[i];
 
-
         prim[0].begin = 1;
         prim[0].end = 1;
         prim[0].weak = 0;
@@ -916,18 +1060,21 @@ vbo_validated_multidrawelements(GLcontext *ctx, GLenum mode,
         prim[0].start = 0;
         prim[0].count = count[i];
         prim[0].indexed = 1;
+         prim[0].num_instances = 1;
         if (basevertex != NULL)
            prim[0].basevertex = basevertex[i];
         else
            prim[0].basevertex = 0;
-      }
 
-      vbo->draw_prims(ctx, exec->array.inputs, prim, 1, &ib,
-                     GL_FALSE, ~0, ~0);
+         vbo->draw_prims(ctx, exec->array.inputs, prim, 1, &ib,
+                         GL_FALSE, ~0, ~0);
+      }
    }
-   _mesa_free(prim);
+
+   free(prim);
 }
 
+
 static void GLAPIENTRY
 vbo_exec_MultiDrawElements(GLenum mode,
                           const GLsizei *count, GLenum type,
@@ -949,6 +1096,7 @@ vbo_exec_MultiDrawElements(GLenum mode,
                                   NULL);
 }
 
+
 static void GLAPIENTRY
 vbo_exec_MultiDrawElementsBaseVertex(GLenum mode,
                                     const GLsizei *count, GLenum type,
@@ -972,14 +1120,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;
@@ -987,15 +1134,8 @@ vbo_exec_array_init( struct vbo_exec_context *exec )
    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
+   exec->vtxfmt.DrawArraysInstanced = vbo_exec_DrawArraysInstanced;
+   exec->vtxfmt.DrawElementsInstanced = vbo_exec_DrawElementsInstanced;
 }
 
 
@@ -1006,7 +1146,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)
 {
@@ -1014,7 +1160,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)
@@ -1022,6 +1167,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)
@@ -1030,7 +1176,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)
@@ -1038,6 +1183,7 @@ _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,
@@ -1047,7 +1193,7 @@ _mesa_DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end,
                                        indices, basevertex);
 }
 
-/* GL_EXT_multi_draw_arrays */
+
 void GLAPIENTRY
 _mesa_MultiDrawElementsEXT(GLenum mode, const GLsizei *count, GLenum type,
                           const GLvoid **indices, GLsizei primcount)
@@ -1055,6 +1201,7 @@ _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,