mesa: check frambuffer complete status before rendering
[mesa.git] / src / mesa / main / api_validate.c
index 841c6a530263e40984aa8b31421192a2bf5bb237..59c2debb2298f6add27053b9f365d9befd337387 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Mesa 3-D graphics library
- * Version:  7.0.1
+ * Version:  7.1
  *
  * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
  *
 #include "state.h"
 
 
+/**
+ * Find the max index in the given element/index buffer
+ */
+static GLuint
+max_buffer_index(GLcontext *ctx, GLuint count, GLenum type,
+                 const void *indices,
+                 struct gl_buffer_object *elementBuf)
+{
+   const GLubyte *map = NULL;
+   GLuint max = 0;
+   GLint i;
+
+   if (elementBuf->Name) {
+      /* elements are in a user-defined buffer object.  need to map it */
+      map = ctx->Driver.MapBuffer(ctx,
+                                  GL_ELEMENT_ARRAY_BUFFER_ARB,
+                                  GL_READ_ONLY,
+                                  elementBuf);
+      /* Actual address is the sum of pointers */
+      indices = (const GLvoid *) ADD_POINTERS(map, (const GLubyte *) indices);
+   }
+
+   if (type == GL_UNSIGNED_INT) {
+      for (i = 0; i < count; i++)
+         if (((GLuint *) indices)[i] > max)
+            max = ((GLuint *) indices)[i];
+   }
+   else if (type == GL_UNSIGNED_SHORT) {
+      for (i = 0; i < count; i++)
+         if (((GLushort *) indices)[i] > max)
+            max = ((GLushort *) indices)[i];
+   }
+   else {
+      ASSERT(type == GL_UNSIGNED_BYTE);
+      for (i = 0; i < count; i++)
+         if (((GLubyte *) indices)[i] > max)
+            max = ((GLubyte *) indices)[i];
+   }
+
+   if (map) {
+      ctx->Driver.UnmapBuffer(ctx,
+                              GL_ELEMENT_ARRAY_BUFFER_ARB,
+                              ctx->Array.ElementArrayBufferObj);
+   }
+
+   return max;
+}
+
+static GLboolean
+check_valid_to_render(GLcontext *ctx, char *function)
+{
+   if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+      _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
+                  "glDraw%s(incomplete framebuffer)", function);
+      return GL_FALSE;
+   }
+
+   /* Always need vertex positions, unless a vertex program is in use */
+   if (!ctx->VertexProgram._Current &&
+       !ctx->Array.ArrayObj->Vertex.Enabled &&
+       !ctx->Array.ArrayObj->VertexAttrib[0].Enabled)
+      return GL_FALSE;
+
+   return GL_TRUE;
+}
+
 GLboolean
 _mesa_validate_DrawElements(GLcontext *ctx,
                            GLenum mode, GLsizei count, GLenum type,
@@ -59,22 +125,14 @@ _mesa_validate_DrawElements(GLcontext *ctx,
    if (ctx->NewState)
       _mesa_update_state(ctx);
 
-   /* Always need vertex positions */
-   if (!ctx->Array.ArrayObj->Vertex.Enabled
-       && !(ctx->VertexProgram._Enabled && ctx->Array.ArrayObj->VertexAttrib[0].Enabled))
+   if (!check_valid_to_render(ctx, "Elements"))
       return GL_FALSE;
 
    /* Vertex buffer object tests */
    if (ctx->Array.ElementArrayBufferObj->Name) {
-      GLuint indexBytes;
-
       /* use indices in the buffer object */
-      if (!ctx->Array.ElementArrayBufferObj->Data) {
-         _mesa_warning(ctx, "DrawElements with empty vertex elements buffer!");
-         return GL_FALSE;
-      }
+      GLuint indexBytes;
 
-      /* make sure count doesn't go outside buffer bounds */
       if (type == GL_UNSIGNED_INT) {
          indexBytes = count * sizeof(GLuint);
       }
@@ -86,19 +144,11 @@ _mesa_validate_DrawElements(GLcontext *ctx,
          indexBytes = count * sizeof(GLushort);
       }
 
-      if ((GLubyte *) indices + indexBytes >
-          ctx->Array.ElementArrayBufferObj->Data +
-          ctx->Array.ElementArrayBufferObj->Size) {
+      /* make sure count doesn't go outside buffer bounds */
+      if (indexBytes > (GLuint) ctx->Array.ElementArrayBufferObj->Size) {
          _mesa_warning(ctx, "glDrawElements index out of buffer bounds");
          return GL_FALSE;
       }
-
-      /* Actual address is the sum of pointers.  Indices may be used below. */
-      if (ctx->Const.CheckArrayBounds) {
-         indices = (const GLvoid *)
-            ADD_POINTERS(ctx->Array.ElementArrayBufferObj->Data,
-                         (const GLubyte *) indices);
-      }
    }
    else {
       /* not using a VBO */
@@ -108,24 +158,8 @@ _mesa_validate_DrawElements(GLcontext *ctx,
 
    if (ctx->Const.CheckArrayBounds) {
       /* find max array index */
-      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];
-      }
+      GLuint max = max_buffer_index(ctx, count, type, indices,
+                                    ctx->Array.ElementArrayBufferObj);
       if (max >= ctx->Array._MaxElement) {
          /* the max element is out of bounds of one or more enabled arrays */
          return GL_FALSE;
@@ -135,7 +169,6 @@ _mesa_validate_DrawElements(GLcontext *ctx,
    return GL_TRUE;
 }
 
-
 GLboolean
 _mesa_validate_DrawRangeElements(GLcontext *ctx, GLenum mode,
                                 GLuint start, GLuint end,
@@ -170,43 +203,40 @@ _mesa_validate_DrawRangeElements(GLcontext *ctx, GLenum mode,
    if (ctx->NewState)
       _mesa_update_state(ctx);
 
-   /* Always need vertex positions */
-   if (!ctx->Array.ArrayObj->Vertex.Enabled
-       && !(ctx->VertexProgram._Enabled && ctx->Array.ArrayObj->VertexAttrib[0].Enabled))
+   if (!check_valid_to_render(ctx, "RangeElements"))
       return GL_FALSE;
 
    /* Vertex buffer object tests */
    if (ctx->Array.ElementArrayBufferObj->Name) {
-      /* XXX re-use code from above? */
+      /* use indices in the buffer object */
+      GLuint indexBytes;
+
+      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);
+      }
+
+      /* make sure count doesn't go outside buffer bounds */
+      if (indexBytes > ctx->Array.ElementArrayBufferObj->Size) {
+         _mesa_warning(ctx, "glDrawRangeElements index out of buffer bounds");
+         return GL_FALSE;
+      }
    }
    else {
-      /* not using VBO */
+      /* 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];
-      }
+      GLuint max = max_buffer_index(ctx, count, type, indices,
+                                    ctx->Array.ElementArrayBufferObj);
       if (max >= ctx->Array._MaxElement) {
          /* the max element is out of bounds of one or more enabled arrays */
          return GL_FALSE;
@@ -227,8 +257,9 @@ _mesa_validate_DrawArrays(GLcontext *ctx,
 {
    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
 
-   if (count < 0) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" );
+   if (count <= 0) {
+      if (count < 0)
+         _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" );
       return GL_FALSE;
    }
 
@@ -240,8 +271,7 @@ _mesa_validate_DrawArrays(GLcontext *ctx,
    if (ctx->NewState)
       _mesa_update_state(ctx);
 
-   /* Always need vertex positions */
-   if (!ctx->Array.ArrayObj->Vertex.Enabled && !ctx->Array.ArrayObj->VertexAttrib[0].Enabled)
+   if (!check_valid_to_render(ctx, "Arrays"))
       return GL_FALSE;
 
    if (ctx->Const.CheckArrayBounds) {