api_validate.c revision 434ec3ada841915a00ffc23f699401eb3e7b37ee
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 "bufferobj.h" 28#include "context.h" 29#include "imports.h" 30#include "mtypes.h" 31#include "state.h" 32 33 34 35/** 36 * \return number of bytes in array [count] of type. 37 */ 38static GLsizei 39index_bytes(GLenum type, GLsizei count) 40{ 41 if (type == GL_UNSIGNED_INT) { 42 return count * sizeof(GLuint); 43 } 44 else if (type == GL_UNSIGNED_BYTE) { 45 return count * sizeof(GLubyte); 46 } 47 else { 48 ASSERT(type == GL_UNSIGNED_SHORT); 49 return count * sizeof(GLushort); 50 } 51} 52 53 54/** 55 * Find the max index in the given element/index buffer 56 */ 57static GLuint 58max_buffer_index(GLcontext *ctx, GLuint count, GLenum type, 59 const void *indices, 60 struct gl_buffer_object *elementBuf) 61{ 62 const GLubyte *map = NULL; 63 GLuint max = 0; 64 GLuint i; 65 66 if (_mesa_is_bufferobj(elementBuf)) { 67 /* elements are in a user-defined buffer object. need to map it */ 68 map = ctx->Driver.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, 69 GL_READ_ONLY, elementBuf); 70 /* Actual address is the sum of pointers */ 71 indices = (const GLvoid *) ADD_POINTERS(map, (const GLubyte *) indices); 72 } 73 74 if (type == GL_UNSIGNED_INT) { 75 for (i = 0; i < count; i++) 76 if (((GLuint *) indices)[i] > max) 77 max = ((GLuint *) indices)[i]; 78 } 79 else if (type == GL_UNSIGNED_SHORT) { 80 for (i = 0; i < count; i++) 81 if (((GLushort *) indices)[i] > max) 82 max = ((GLushort *) indices)[i]; 83 } 84 else { 85 ASSERT(type == GL_UNSIGNED_BYTE); 86 for (i = 0; i < count; i++) 87 if (((GLubyte *) indices)[i] > max) 88 max = ((GLubyte *) indices)[i]; 89 } 90 91 if (map) { 92 ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, elementBuf); 93 } 94 95 return max; 96} 97 98 99/** 100 * Check if OK to render by examining framebuffer status and vertex arrays. 101 */ 102static GLboolean 103check_valid_to_render(GLcontext *ctx, char *function) 104{ 105 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 106 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 107 "glDraw%s(incomplete framebuffer)", function); 108 return GL_FALSE; 109 } 110 111#if FEATURE_es2_glsl 112 /* For ES2, we can draw if any vertex array is enabled (and we should 113 * always have a vertex program/shader). 114 */ 115 if (ctx->Array.ArrayObj->_Enabled == 0x0 || !ctx->VertexProgram._Current) 116 return GL_FALSE; 117#else 118 /* For regular OpenGL, only draw if we have vertex positions (regardless 119 * of whether or not we have a vertex program/shader). 120 */ 121 if (!ctx->Array.ArrayObj->Vertex.Enabled && 122 !ctx->Array.ArrayObj->VertexAttrib[0].Enabled) 123 return GL_FALSE; 124#endif 125 126 return GL_TRUE; 127} 128 129 130/** 131 * Error checking for glDrawElements(). Includes parameter checking 132 * and VBO bounds checking. 133 * \return GL_TRUE if OK to render, GL_FALSE if error found 134 */ 135GLboolean 136_mesa_validate_DrawElements(GLcontext *ctx, 137 GLenum mode, GLsizei count, GLenum type, 138 const GLvoid *indices) 139{ 140 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 141 142 if (count <= 0) { 143 if (count < 0) 144 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawElements(count)" ); 145 return GL_FALSE; 146 } 147 148 if (mode > GL_POLYGON) { 149 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)" ); 150 return GL_FALSE; 151 } 152 153 if (type != GL_UNSIGNED_INT && 154 type != GL_UNSIGNED_BYTE && 155 type != GL_UNSIGNED_SHORT) 156 { 157 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)" ); 158 return GL_FALSE; 159 } 160 161 if (ctx->NewState) 162 _mesa_update_state(ctx); 163 164 if (!check_valid_to_render(ctx, "Elements")) 165 return GL_FALSE; 166 167 /* Vertex buffer object tests */ 168 if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) { 169 /* use indices in the buffer object */ 170 /* make sure count doesn't go outside buffer bounds */ 171 if (index_bytes(type, count) > ctx->Array.ElementArrayBufferObj->Size) { 172 _mesa_warning(ctx, "glDrawElements index out of buffer bounds"); 173 return GL_FALSE; 174 } 175 } 176 else { 177 /* not using a VBO */ 178 if (!indices) 179 return GL_FALSE; 180 } 181 182 if (ctx->Const.CheckArrayBounds) { 183 /* find max array index */ 184 GLuint max = max_buffer_index(ctx, count, type, indices, 185 ctx->Array.ElementArrayBufferObj); 186 if (max >= ctx->Array.ArrayObj->_MaxElement) { 187 /* the max element is out of bounds of one or more enabled arrays */ 188 _mesa_warning(ctx, "glDrawElements() index=%u is " 189 "out of bounds (max=%u)", max, ctx->Array.ArrayObj->_MaxElement); 190 return GL_FALSE; 191 } 192 } 193 194 return GL_TRUE; 195} 196 197 198/** 199 * Error checking for glDrawRangeElements(). Includes parameter checking 200 * and VBO bounds checking. 201 * \return GL_TRUE if OK to render, GL_FALSE if error found 202 */ 203GLboolean 204_mesa_validate_DrawRangeElements(GLcontext *ctx, GLenum mode, 205 GLuint start, GLuint end, 206 GLsizei count, GLenum type, 207 const GLvoid *indices) 208{ 209 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 210 211 if (count <= 0) { 212 if (count < 0) 213 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(count)" ); 214 return GL_FALSE; 215 } 216 217 if (mode > GL_POLYGON) { 218 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)" ); 219 return GL_FALSE; 220 } 221 222 if (end < start) { 223 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(end<start)"); 224 return GL_FALSE; 225 } 226 227 if (type != GL_UNSIGNED_INT && 228 type != GL_UNSIGNED_BYTE && 229 type != GL_UNSIGNED_SHORT) { 230 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)" ); 231 return GL_FALSE; 232 } 233 234 if (ctx->NewState) 235 _mesa_update_state(ctx); 236 237 if (!check_valid_to_render(ctx, "RangeElements")) 238 return GL_FALSE; 239 240 /* Vertex buffer object tests */ 241 if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) { 242 /* use indices in the buffer object */ 243 /* make sure count doesn't go outside buffer bounds */ 244 if (index_bytes(type, count) > ctx->Array.ElementArrayBufferObj->Size) { 245 _mesa_warning(ctx, "glDrawRangeElements index out of buffer bounds"); 246 return GL_FALSE; 247 } 248 } 249 else { 250 /* not using a VBO */ 251 if (!indices) 252 return GL_FALSE; 253 } 254 255 if (ctx->Const.CheckArrayBounds) { 256 GLuint max = max_buffer_index(ctx, count, type, indices, 257 ctx->Array.ElementArrayBufferObj); 258 if (max >= ctx->Array.ArrayObj->_MaxElement) { 259 /* the max element is out of bounds of one or more enabled arrays */ 260 return GL_FALSE; 261 } 262 } 263 264 return GL_TRUE; 265} 266 267 268/** 269 * Called from the tnl module to error check the function parameters and 270 * verify that we really can draw something. 271 * \return GL_TRUE if OK to render, GL_FALSE if error found 272 */ 273GLboolean 274_mesa_validate_DrawArrays(GLcontext *ctx, 275 GLenum mode, GLint start, GLsizei count) 276{ 277 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 278 279 if (count <= 0) { 280 if (count < 0) 281 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" ); 282 return GL_FALSE; 283 } 284 285 if (mode > GL_POLYGON) { 286 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)" ); 287 return GL_FALSE; 288 } 289 290 if (ctx->NewState) 291 _mesa_update_state(ctx); 292 293 if (!check_valid_to_render(ctx, "Arrays")) 294 return GL_FALSE; 295 296 if (ctx->Const.CheckArrayBounds) { 297 if (start + count > (GLint) ctx->Array.ArrayObj->_MaxElement) 298 return GL_FALSE; 299 } 300 301 return GL_TRUE; 302} 303