Merge branch 'mesa_7_7_branch'
[mesa.git] / src / mesa / vbo / vbo_exec_array.c
index b9550d6106cfd3f519621d19133ab6dd62760bfd..bd2fccdba1456fb5a8b79f48d26cb8c9e5b84718 100644 (file)
@@ -33,8 +33,8 @@
 #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"
 
@@ -53,10 +53,9 @@ vbo_get_minmax_index(GLcontext *ctx,
    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);
    }
 }
 
@@ -125,10 +122,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);
       }
@@ -149,7 +145,7 @@ check_array_data(GLcontext *ctx, struct gl_client_array *array,
                                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;
@@ -169,9 +165,7 @@ unmap_array_buffer(GLcontext *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);
    }
 }
 
@@ -222,13 +216,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);
    }
 
@@ -459,7 +453,6 @@ bind_arrays(GLcontext *ctx)
    }
    else if (exec->array.program_mode != get_program_mode(ctx) ||
            exec->array.enabled_flags != ctx->Array.ArrayObj->_Enabled) {
-      
       recalculate_input_bindings(ctx);
    }
 #else
@@ -482,6 +475,10 @@ 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;
 
@@ -582,11 +579,11 @@ dump_element_buffer(GLcontext *ctx, GLenum type)
       ;
    }
 
-   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 */
 static void
 vbo_validated_drawrangeelements(GLcontext *ctx, GLenum mode,
@@ -672,29 +669,89 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode,
                                     const GLvoid *indices,
                                     GLint basevertex)
 {
+   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;
 
+   /* NOTE: It's important that 'end' is a reasonable value.
+    * in _tnl_draw_prims(), we use end to determine how many vertices
+    * to transform.  If it's too large, we can unnecessarily split prims
+    * 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 */
-      _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, basevertex,
-                    ctx->Array.ArrayObj->_MaxElement - 1,
-                    ctx->Array.ElementArrayBufferObj->Name,
-                    ctx->Array.ElementArrayBufferObj->Size);
+      warnCount++;
+
+      if (warnCount < 10) {
+         _mesa_warning(ctx, "glDraw[Range]Elements(start %u, end %u, count %d, "
+                       "type 0x%x, indices=%p)\n"
+                       "\tend is out of bounds (max=%u)  "
+                       "Element Buffer %u (size %d)\n"
+                       "\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);
+      }
 
       if (0)
          dump_element_buffer(ctx, type);
 
       if (0)
          _mesa_print_arrays(ctx);
-      return;
+
+#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.
+       */
+      {
+         GLuint max = _mesa_max_buffer_index(ctx, count, type, indices,
+                                             ctx->Array.ElementArrayBufferObj);
+         if (max >= ctx->Array.ArrayObj->_MaxElement) {
+            if (warnCount < 10) {
+               _mesa_warning(ctx, "glDraw[Range]Elements(start %u, end %u, "
+                             "count %d, type 0x%x, indices=%p)\n"
+                             "\tindex=%u is out of bounds (max=%u)  "
+                             "Element Buffer %u (size %d)\n"
+                             "\tSkipping the glDrawRangeElements() call",
+                             start, end, count, type, indices, max,
+                             ctx->Array.ArrayObj->_MaxElement - 1,
+                             ctx->Array.ElementArrayBufferObj->Name,
+                             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
+          * upper bound wrong.
+          */
+      }
+#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}"
@@ -715,12 +772,19 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode,
                                   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_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);
 }
@@ -732,6 +796,11 @@ vbo_exec_DrawElements(GLenum mode, GLsizei count, GLenum type,
 {
    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;
 
@@ -739,12 +808,18 @@ vbo_exec_DrawElements(GLenum mode, GLsizei count, GLenum type,
                                   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_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;
@@ -753,7 +828,8 @@ vbo_exec_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
                                   count, type, indices, basevertex);
 }
 
-/* Inner support for both _mesa_DrawElements and _mesa_DrawRangeElements */
+
+/** Inner support for both _mesa_DrawElements and _mesa_DrawRangeElements */
 static void
 vbo_validated_multidrawelements(GLcontext *ctx, GLenum mode,
                                const GLsizei *count, GLenum type,
@@ -888,6 +964,7 @@ vbo_validated_multidrawelements(GLcontext *ctx, GLenum mode,
    _mesa_free(prim);
 }
 
+
 static void GLAPIENTRY
 vbo_exec_MultiDrawElements(GLenum mode,
                           const GLsizei *count, GLenum type,
@@ -909,6 +986,7 @@ vbo_exec_MultiDrawElements(GLenum mode,
                                   NULL);
 }
 
+
 static void GLAPIENTRY
 vbo_exec_MultiDrawElementsBaseVertex(GLenum mode,
                                     const GLsizei *count, GLenum type,
@@ -998,6 +1076,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,
@@ -1007,6 +1086,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,
@@ -1015,6 +1095,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,