api_validate.c revision 8d482227915552c414e13743652e6794c4313ae2
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.1 4 * 5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25#include "glheader.h" 26#include "api_validate.h" 27#include "context.h" 28#include "imports.h" 29#include "mtypes.h" 30#include "state.h" 31 32 33 34/** 35 * \return number of bytes in array [count] of type. 36 */ 37static GLsizei 38index_bytes(GLenum type, GLsizei count) 39{ 40 if (type == GL_UNSIGNED_INT) { 41 return count * sizeof(GLuint); 42 } 43 else if (type == GL_UNSIGNED_BYTE) { 44 return count * sizeof(GLubyte); 45 } 46 else { 47 ASSERT(type == GL_UNSIGNED_SHORT); 48 return count * sizeof(GLushort); 49 } 50} 51 52 53/** 54 * Find the max index in the given element/index buffer 55 */ 56static GLuint 57max_buffer_index(GLcontext *ctx, GLuint count, GLenum type, 58 const void *indices, 59 struct gl_buffer_object *elementBuf) 60{ 61 const GLubyte *map = NULL; 62 GLuint max = 0; 63 GLuint i; 64 65 if (elementBuf->Name) { 66 /* elements are in a user-defined buffer object. need to map it */ 67 map = ctx->Driver.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, 68 GL_READ_ONLY, elementBuf); 69 /* Actual address is the sum of pointers */ 70 indices = (const GLvoid *) ADD_POINTERS(map, (const GLubyte *) indices); 71 } 72 73 if (type == GL_UNSIGNED_INT) { 74 for (i = 0; i < count; i++) 75 if (((GLuint *) indices)[i] > max) 76 max = ((GLuint *) indices)[i]; 77 } 78 else if (type == GL_UNSIGNED_SHORT) { 79 for (i = 0; i < count; i++) 80 if (((GLushort *) indices)[i] > max) 81 max = ((GLushort *) indices)[i]; 82 } 83 else { 84 ASSERT(type == GL_UNSIGNED_BYTE); 85 for (i = 0; i < count; i++) 86 if (((GLubyte *) indices)[i] > max) 87 max = ((GLubyte *) indices)[i]; 88 } 89 90 if (map) { 91 ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, elementBuf); 92 } 93 94 return max; 95} 96 97 98/** 99 * Check if OK to render by examining framebuffer status and vertex arrays. 100 */ 101static GLboolean 102check_valid_to_render(GLcontext *ctx, char *function) 103{ 104 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 105 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 106 "glDraw%s(incomplete framebuffer)", function); 107 return GL_FALSE; 108 } 109 110#if FEATURE_es2_glsl 111 /* For ES2, we can draw if any vertex array is enabled (and we should 112 * always have a vertex program/shader). 113 */ 114 if (ctx->Array.ArrayObj->_Enabled == 0x0 || !ctx->VertexProgram._Current) 115 return GL_FALSE; 116#else 117 /* For regular OpenGL, only draw if we have vertex positions (regardless 118 * of whether or not we have a vertex program/shader). 119 */ 120 if (!ctx->Array.ArrayObj->Vertex.Enabled && 121 !ctx->Array.ArrayObj->VertexAttrib[0].Enabled) 122 return GL_FALSE; 123#endif 124 125 return GL_TRUE; 126} 127 128 129/** 130 * Error checking for glDrawElements(). Includes parameter checking 131 * and VBO bounds checking. 132 * \return GL_TRUE if OK to render, GL_FALSE if error found 133 */ 134GLboolean 135_mesa_validate_DrawElements(GLcontext *ctx, 136 GLenum mode, GLsizei count, GLenum type, 137 const GLvoid *indices) 138{ 139 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 140 141 if (count <= 0) { 142 if (count < 0) 143 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawElements(count)" ); 144 return GL_FALSE; 145 } 146 147 if (mode > GL_POLYGON) { 148 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)" ); 149 return GL_FALSE; 150 } 151 152 if (type != GL_UNSIGNED_INT && 153 type != GL_UNSIGNED_BYTE && 154 type != GL_UNSIGNED_SHORT) 155 { 156 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)" ); 157 return GL_FALSE; 158 } 159 160 if (ctx->NewState) 161 _mesa_update_state(ctx); 162 163 if (!check_valid_to_render(ctx, "Elements")) 164 return GL_FALSE; 165 166 /* Vertex buffer object tests */ 167 if (ctx->Array.ElementArrayBufferObj->Name) { 168 /* use indices in the buffer object */ 169 /* make sure count doesn't go outside buffer bounds */ 170 if (index_bytes(type, count) > ctx->Array.ElementArrayBufferObj->Size) { 171 _mesa_warning(ctx, "glDrawElements index out of buffer bounds"); 172 return GL_FALSE; 173 } 174 } 175 else { 176 /* not using a VBO */ 177 if (!indices) 178 return GL_FALSE; 179 } 180 181 if (ctx->Const.CheckArrayBounds) { 182 /* find max array index */ 183 GLuint max = max_buffer_index(ctx, count, type, indices, 184 ctx->Array.ElementArrayBufferObj); 185 if (max >= ctx->Array.ArrayObj->_MaxElement) { 186 /* the max element is out of bounds of one or more enabled arrays */ 187 _mesa_warning(ctx, "glDrawElements() index=%u is " 188 "out of bounds (max=%u)", max, ctx->Array.ArrayObj->_MaxElement); 189 return GL_FALSE; 190 } 191 } 192 193 return GL_TRUE; 194} 195 196 197/** 198 * Error checking for glDrawRangeElements(). Includes parameter checking 199 * and VBO bounds checking. 200 * \return GL_TRUE if OK to render, GL_FALSE if error found 201 */ 202GLboolean 203_mesa_validate_DrawRangeElements(GLcontext *ctx, GLenum mode, 204 GLuint start, GLuint end, 205 GLsizei count, GLenum type, 206 const GLvoid *indices) 207{ 208 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 209 210 if (count <= 0) { 211 if (count < 0) 212 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(count)" ); 213 return GL_FALSE; 214 } 215 216 if (mode > GL_POLYGON) { 217 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)" ); 218 return GL_FALSE; 219 } 220 221 if (end < start) { 222 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(end<start)"); 223 return GL_FALSE; 224 } 225 226 if (type != GL_UNSIGNED_INT && 227 type != GL_UNSIGNED_BYTE && 228 type != GL_UNSIGNED_SHORT) { 229 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)" ); 230 return GL_FALSE; 231 } 232 233 if (ctx->NewState) 234 _mesa_update_state(ctx); 235 236 if (!check_valid_to_render(ctx, "RangeElements")) 237 return GL_FALSE; 238 239 /* Vertex buffer object tests */ 240 if (ctx->Array.ElementArrayBufferObj->Name) { 241 /* use indices in the buffer object */ 242 /* make sure count doesn't go outside buffer bounds */ 243 if (index_bytes(type, count) > ctx->Array.ElementArrayBufferObj->Size) { 244 _mesa_warning(ctx, "glDrawRangeElements index out of buffer bounds"); 245 return GL_FALSE; 246 } 247 } 248 else { 249 /* not using a VBO */ 250 if (!indices) 251 return GL_FALSE; 252 } 253 254 if (ctx->Const.CheckArrayBounds) { 255 GLuint max = max_buffer_index(ctx, count, type, indices, 256 ctx->Array.ElementArrayBufferObj); 257 if (max >= ctx->Array.ArrayObj->_MaxElement) { 258 /* the max element is out of bounds of one or more enabled arrays */ 259 return GL_FALSE; 260 } 261 } 262 263 return GL_TRUE; 264} 265 266 267/** 268 * Called from the tnl module to error check the function parameters and 269 * verify that we really can draw something. 270 * \return GL_TRUE if OK to render, GL_FALSE if error found 271 */ 272GLboolean 273_mesa_validate_DrawArrays(GLcontext *ctx, 274 GLenum mode, GLint start, GLsizei count) 275{ 276 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 277 278 if (count <= 0) { 279 if (count < 0) 280 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" ); 281 return GL_FALSE; 282 } 283 284 if (mode > GL_POLYGON) { 285 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)" ); 286 return GL_FALSE; 287 } 288 289 if (ctx->NewState) 290 _mesa_update_state(ctx); 291 292 if (!check_valid_to_render(ctx, "Arrays")) 293 return GL_FALSE; 294 295 if (ctx->Const.CheckArrayBounds) { 296 if (start + count > (GLint) ctx->Array.ArrayObj->_MaxElement) 297 return GL_FALSE; 298 } 299 300 return GL_TRUE; 301} 302