X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Fapi_validate.c;h=64ab324af2269b02fb1f6d6702c21627f7709d14;hb=09fbb3837b6aa5dfc6c94f41ab5443820177c569;hp=3a0ce52b960c28c4125dfd113ae7e4b4ba793e74;hpb=22144ab7552f0799bcfca506bf4ffa7f70a06649;p=mesa.git diff --git a/src/mesa/main/api_validate.c b/src/mesa/main/api_validate.c index 3a0ce52b960..64ab324af22 100644 --- a/src/mesa/main/api_validate.c +++ b/src/mesa/main/api_validate.c @@ -1,10 +1,8 @@ -/* $Id: api_validate.c,v 1.5 2001/03/12 00:48:37 gareth Exp $ */ - /* * Mesa 3-D graphics library - * Version: 3.5 + * Version: 7.0.1 * - * Copyright (C) 1999-2001 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"), @@ -27,6 +25,7 @@ #include "glheader.h" #include "api_validate.h" #include "context.h" +#include "imports.h" #include "mtypes.h" #include "state.h" @@ -44,9 +43,8 @@ _mesa_validate_DrawElements(GLcontext *ctx, return GL_FALSE; } - if (mode < 0 || - mode > GL_POLYGON) { - _mesa_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)" ); + if (mode > GL_POLYGON) { + _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)" ); return GL_FALSE; } @@ -59,11 +57,88 @@ _mesa_validate_DrawElements(GLcontext *ctx, } if (ctx->NewState) - _mesa_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; } @@ -78,12 +153,12 @@ _mesa_validate_DrawRangeElements(GLcontext *ctx, GLenum mode, if (count <= 0) { if (count < 0) - _mesa_error(ctx, GL_INVALID_VALUE, "glDrawElements(count)" ); + _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(count)" ); return GL_FALSE; } - if (mode < 0 || mode > GL_POLYGON) { - _mesa_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)" ); + if (mode > GL_POLYGON) { + _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)" ); return GL_FALSE; } @@ -94,44 +169,92 @@ _mesa_validate_DrawRangeElements(GLcontext *ctx, GLenum mode, if (type != GL_UNSIGNED_INT && type != GL_UNSIGNED_BYTE && - type != GL_UNSIGNED_SHORT) - { - _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)" ); + type != GL_UNSIGNED_SHORT) { + _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)" ); return GL_FALSE; } if (ctx->NewState) - _mesa_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, GLenum mode, GLint start, GLsizei count) { ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); - if (count<0) { + if (count < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" ); return GL_FALSE; } - if (mode < 0 || mode > GL_POLYGON) { + if (mode > GL_POLYGON) { _mesa_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)" ); return GL_FALSE; } if (ctx->NewState) - _mesa_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; }