Implement query object interface.
[mesa.git] / src / mesa / main / api_validate.c
index 931d5c652007c8aced5a81a0cd5cd926699e2c6c..64ab324af2269b02fb1f6d6702c21627f7709d14 100644 (file)
@@ -1,11 +1,8 @@
-
-/* $Id: api_validate.c,v 1.1 2000/12/26 05:09:27 keithw Exp $ */
-
 /*
  * Mesa 3-D graphics library
- * Version:  3.5
+ * Version:  7.0.1
  *
- * Copyright (C) 1999-2000  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  */
 
 #include "glheader.h"
+#include "api_validate.h"
 #include "context.h"
+#include "imports.h"
 #include "mtypes.h"
-#include "api_validate.h"
+#include "state.h"
+
 
 GLboolean
 _mesa_validate_DrawElements(GLcontext *ctx,
-                           GLenum mode, GLsizei count, GLenum type, 
+                           GLenum mode, GLsizei count, GLenum type,
                            const GLvoid *indices)
 {
-   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx,  GL_FALSE); 
+   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx,  GL_FALSE);
 
    if (count <= 0) {
       if (count < 0)
-        gl_error(ctx, GL_INVALID_VALUE, "glDrawElements(count)" );
+        _mesa_error(ctx, GL_INVALID_VALUE, "glDrawElements(count)" );
       return GL_FALSE;
    }
 
-   if (mode < 0 || 
-       mode > GL_POLYGON) {
-      gl_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)" );
+   if (mode > GL_POLYGON) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)" );
       return GL_FALSE;
    }
 
-   if (type != GL_UNSIGNED_INT && 
-       type != GL_UNSIGNED_BYTE && 
+   if (type != GL_UNSIGNED_INT &&
+       type != GL_UNSIGNED_BYTE &&
        type != GL_UNSIGNED_SHORT)
    {
-      gl_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
+      _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
       return GL_FALSE;
    }
 
    if (ctx->NewState)
-      gl_update_state( ctx );
+      _mesa_update_state(ctx);
 
-   if (!ctx->Array.Vertex.Enabled)
+   /* Always need vertex positions */
+   if (!ctx->Array.ArrayObj->Vertex.Enabled
+       && !(ctx->VertexProgram._Enabled && ctx->Array.ArrayObj->VertexAttrib[0].Enabled))
       return GL_FALSE;
 
+   /* Vertex buffer object tests */
+   if (ctx->Array.ElementArrayBufferObj->Name) {
+      GLuint indexBytes;
+
+      /* use indices in the buffer object */
+      if (!ctx->Array.ElementArrayBufferObj->Size) {
+         _mesa_warning(ctx,
+                       "glDrawElements called with empty array elements buffer");
+         return GL_FALSE;
+      }
+
+      /* make sure count doesn't go outside buffer bounds */
+      if (type == GL_UNSIGNED_INT) {
+         indexBytes = count * sizeof(GLuint);
+      }
+      else if (type == GL_UNSIGNED_BYTE) {
+         indexBytes = count * sizeof(GLubyte);
+      }
+      else {
+         ASSERT(type == GL_UNSIGNED_SHORT);
+         indexBytes = count * sizeof(GLushort);
+      }
+
+      if (indexBytes > ctx->Array.ElementArrayBufferObj->Size) {
+         _mesa_warning(ctx, "glDrawElements index out of buffer bounds");
+         return GL_FALSE;
+      }
+   }
+   else {
+      /* not using a VBO */
+      if (!indices)
+         return GL_FALSE;
+   }
+
+   if (ctx->Const.CheckArrayBounds) {
+      /* find max array index */
+      const GLubyte *map;
+      GLuint max = 0;
+      GLint i;
+
+      map = ctx->Driver.MapBuffer(ctx,
+                                  GL_ELEMENT_ARRAY_BUFFER_ARB,
+                                  GL_READ_ONLY,
+                                  ctx->Array.ElementArrayBufferObj);
+
+      /* 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];
+      }
+
+      ctx->Driver.UnmapBuffer(ctx,
+                              GL_ELEMENT_ARRAY_BUFFER_ARB,
+                              ctx->Array.ElementArrayBufferObj);
+
+      if (max >= ctx->Array._MaxElement) {
+         /* the max element is out of bounds of one or more enabled arrays */
+         return GL_FALSE;
+      }
+   }
+
    return GL_TRUE;
 }
 
 
 GLboolean
-_mesa_validate_DrawRangeElements(GLcontext *ctx, GLenum mode, 
-                                GLuint start, GLuint end, 
-                                GLsizei count, GLenum type, 
+_mesa_validate_DrawRangeElements(GLcontext *ctx, GLenum mode,
+                                GLuint start, GLuint end,
+                                GLsizei count, GLenum type,
                                 const GLvoid *indices)
 {
-   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 
+   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
 
    if (count <= 0) {
       if (count < 0)
-        gl_error(ctx, GL_INVALID_VALUE, "glDrawElements(count)" );
+        _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(count)" );
       return GL_FALSE;
    }
 
-   if (mode < 0 || mode > GL_POLYGON) {
-      gl_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)" );
+   if (mode > GL_POLYGON) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)" );
       return GL_FALSE;
    }
 
    if (end < start) {
-      gl_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(end<start)");
+      _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(end<start)");
       return GL_FALSE;
    }
 
-   if (type != GL_UNSIGNED_INT && 
-       type != GL_UNSIGNED_BYTE && 
-       type != GL_UNSIGNED_SHORT)
-   {
-      gl_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
+   if (type != GL_UNSIGNED_INT &&
+       type != GL_UNSIGNED_BYTE &&
+       type != GL_UNSIGNED_SHORT) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)" );
       return GL_FALSE;
    }
 
    if (ctx->NewState)
-      gl_update_state( ctx );
+      _mesa_update_state(ctx);
 
-   if (!ctx->Array.Vertex.Enabled)
+   /* Always need vertex positions */
+   if (!ctx->Array.ArrayObj->Vertex.Enabled
+       && !(ctx->VertexProgram._Enabled && ctx->Array.ArrayObj->VertexAttrib[0].Enabled))
       return GL_FALSE;
 
+   /* Vertex buffer object tests */
+   if (ctx->Array.ElementArrayBufferObj->Name) {
+      /* XXX re-use code from above? */
+   }
+   else {
+      /* not using VBO */
+      if (!indices)
+         return GL_FALSE;
+   }
+
+   if (ctx->Const.CheckArrayBounds) {
+      /* Find max array index.
+       * We don't trust the user's start and end values.
+       */
+      GLuint max = 0;
+      GLint i;
+      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 (max >= ctx->Array._MaxElement) {
+         /* the max element is out of bounds of one or more enabled arrays */
+         return GL_FALSE;
+      }
+   }
+
    return GL_TRUE;
 }
 
 
-
+/**
+ * Called from the tnl module to error check the function parameters and
+ * verify that we really can draw something.
+ */
 GLboolean
-_mesa_validate_DrawArrays(GLcontext *ctx, 
+_mesa_validate_DrawArrays(GLcontext *ctx,
                          GLenum mode, GLint start, GLsizei count)
 {
-   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 
+   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
 
-   if (count<0) {
-      gl_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" );
+   if (count < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" );
       return GL_FALSE;
    }
 
-   if (mode < 0 || mode > GL_POLYGON) {
-      gl_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)" );
+   if (mode > GL_POLYGON) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)" );
       return GL_FALSE;
    }
 
    if (ctx->NewState)
-      gl_update_state( ctx );
+      _mesa_update_state(ctx);
 
-   if (!ctx->Array.Vertex.Enabled) 
+   /* Always need vertex positions */
+   if (!ctx->Array.ArrayObj->Vertex.Enabled && !ctx->Array.ArrayObj->VertexAttrib[0].Enabled)
       return GL_FALSE;
 
+   if (ctx->Const.CheckArrayBounds) {
+      if (start + count > (GLint) ctx->Array._MaxElement)
+         return GL_FALSE;
+   }
+
    return GL_TRUE;
 }
-