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