api_validate.c revision e9968ebfa40b4740601c1596950ebd3f168664b0
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 "vbo/vbo.h" 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 */ 56GLuint 57_mesa_max_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 (_mesa_is_bufferobj(elementBuf)) { 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 draw arrays/elements. 100 */ 101static GLboolean 102check_valid_to_render(GLcontext *ctx, const char *function) 103{ 104 if (!_mesa_valid_to_render(ctx, function)) { 105 return GL_FALSE; 106 } 107 108#if FEATURE_es2_glsl 109 /* For ES2, we can draw if any vertex array is enabled (and we should 110 * always have a vertex program/shader). 111 */ 112 if (ctx->Array.ArrayObj->_Enabled == 0x0 || !ctx->VertexProgram._Current) 113 return GL_FALSE; 114#else 115 /* For regular OpenGL, only draw if we have vertex positions (regardless 116 * of whether or not we have a vertex program/shader). 117 */ 118 if (!ctx->Array.ArrayObj->Vertex.Enabled && 119 !ctx->Array.ArrayObj->VertexAttrib[0].Enabled) 120 return GL_FALSE; 121#endif 122 123 return GL_TRUE; 124} 125 126 127/** 128 * Do bounds checking on array element indexes. Check that the vertices 129 * pointed to by the indices don't lie outside buffer object bounds. 130 * \return GL_TRUE if OK, GL_FALSE if any indexed vertex goes is out of bounds 131 */ 132static GLboolean 133check_index_bounds(GLcontext *ctx, GLsizei count, GLenum type, 134 const GLvoid *indices, GLint basevertex) 135{ 136 struct _mesa_prim prim; 137 struct _mesa_index_buffer ib; 138 GLuint min, max; 139 140 /* Only the X Server needs to do this -- otherwise, accessing outside 141 * array/BO bounds allows application termination. 142 */ 143 if (!ctx->Const.CheckArrayBounds) 144 return GL_TRUE; 145 146 memset(&prim, 0, sizeof(prim)); 147 prim.count = count; 148 149 memset(&ib, 0, sizeof(ib)); 150 ib.type = type; 151 ib.ptr = indices; 152 ib.obj = ctx->Array.ElementArrayBufferObj; 153 154 vbo_get_minmax_index(ctx, &prim, &ib, &min, &max); 155 156 if ((int)(min + basevertex) < 0 || 157 max + basevertex > ctx->Array.ArrayObj->_MaxElement) { 158 /* the max element is out of bounds of one or more enabled arrays */ 159 _mesa_warning(ctx, "glDrawElements() index=%u is out of bounds (max=%u)", 160 max, ctx->Array.ArrayObj->_MaxElement); 161 return GL_FALSE; 162 } 163 164 return GL_TRUE; 165} 166 167 168/** 169 * Error checking for glDrawElements(). Includes parameter checking 170 * and VBO bounds checking. 171 * \return GL_TRUE if OK to render, GL_FALSE if error found 172 */ 173GLboolean 174_mesa_validate_DrawElements(GLcontext *ctx, 175 GLenum mode, GLsizei count, GLenum type, 176 const GLvoid *indices, GLint basevertex) 177{ 178 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 179 180 if (count <= 0) { 181 if (count < 0) 182 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawElements(count)" ); 183 return GL_FALSE; 184 } 185 186 if (mode > GL_POLYGON) { 187 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)" ); 188 return GL_FALSE; 189 } 190 191 if (type != GL_UNSIGNED_INT && 192 type != GL_UNSIGNED_BYTE && 193 type != GL_UNSIGNED_SHORT) 194 { 195 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)" ); 196 return GL_FALSE; 197 } 198 199 if (!check_valid_to_render(ctx, "glDrawElements")) 200 return GL_FALSE; 201 202 /* Vertex buffer object tests */ 203 if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) { 204 /* use indices in the buffer object */ 205 /* make sure count doesn't go outside buffer bounds */ 206 if (index_bytes(type, count) > ctx->Array.ElementArrayBufferObj->Size) { 207 _mesa_warning(ctx, "glDrawElements index out of buffer bounds"); 208 return GL_FALSE; 209 } 210 } 211 else { 212 /* not using a VBO */ 213 if (!indices) 214 return GL_FALSE; 215 } 216 217 if (!check_index_bounds(ctx, count, type, indices, basevertex)) 218 return GL_FALSE; 219 220 return GL_TRUE; 221} 222 223 224/** 225 * Error checking for glDrawRangeElements(). Includes parameter checking 226 * and VBO bounds checking. 227 * \return GL_TRUE if OK to render, GL_FALSE if error found 228 */ 229GLboolean 230_mesa_validate_DrawRangeElements(GLcontext *ctx, GLenum mode, 231 GLuint start, GLuint end, 232 GLsizei count, GLenum type, 233 const GLvoid *indices, GLint basevertex) 234{ 235 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 236 237 if (count <= 0) { 238 if (count < 0) 239 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(count)" ); 240 return GL_FALSE; 241 } 242 243 if (mode > GL_POLYGON) { 244 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)" ); 245 return GL_FALSE; 246 } 247 248 if (end < start) { 249 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(end<start)"); 250 return GL_FALSE; 251 } 252 253 if (type != GL_UNSIGNED_INT && 254 type != GL_UNSIGNED_BYTE && 255 type != GL_UNSIGNED_SHORT) { 256 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)" ); 257 return GL_FALSE; 258 } 259 260 if (!check_valid_to_render(ctx, "glDrawRangeElements")) 261 return GL_FALSE; 262 263 /* Vertex buffer object tests */ 264 if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) { 265 /* use indices in the buffer object */ 266 /* make sure count doesn't go outside buffer bounds */ 267 if (index_bytes(type, count) > ctx->Array.ElementArrayBufferObj->Size) { 268 _mesa_warning(ctx, "glDrawRangeElements index out of buffer bounds"); 269 return GL_FALSE; 270 } 271 } 272 else { 273 /* not using a VBO */ 274 if (!indices) 275 return GL_FALSE; 276 } 277 278 if (!check_index_bounds(ctx, count, type, indices, basevertex)) 279 return GL_FALSE; 280 281 return GL_TRUE; 282} 283 284 285/** 286 * Called from the tnl module to error check the function parameters and 287 * verify that we really can draw something. 288 * \return GL_TRUE if OK to render, GL_FALSE if error found 289 */ 290GLboolean 291_mesa_validate_DrawArrays(GLcontext *ctx, 292 GLenum mode, GLint start, GLsizei count) 293{ 294 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 295 296 if (count <= 0) { 297 if (count < 0) 298 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" ); 299 return GL_FALSE; 300 } 301 302 if (mode > GL_POLYGON) { 303 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)" ); 304 return GL_FALSE; 305 } 306 307 if (!check_valid_to_render(ctx, "glDrawArrays")) 308 return GL_FALSE; 309 310 if (ctx->Const.CheckArrayBounds) { 311 if (start + count > (GLint) ctx->Array.ArrayObj->_MaxElement) 312 return GL_FALSE; 313 } 314 315 return GL_TRUE; 316} 317