api_validate.c revision 97dd2ddbd97ba95e8bc8ab572ec05e8081556e1e
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, 48 GL_ELEMENT_ARRAY_BUFFER_ARB, 49 GL_READ_ONLY, 50 elementBuf); 51 /* Actual address is the sum of pointers */ 52 indices = (const GLvoid *) ADD_POINTERS(map, (const GLubyte *) indices); 53 } 54 55 if (type == GL_UNSIGNED_INT) { 56 for (i = 0; i < count; i++) 57 if (((GLuint *) indices)[i] > max) 58 max = ((GLuint *) indices)[i]; 59 } 60 else if (type == GL_UNSIGNED_SHORT) { 61 for (i = 0; i < count; i++) 62 if (((GLushort *) indices)[i] > max) 63 max = ((GLushort *) indices)[i]; 64 } 65 else { 66 ASSERT(type == GL_UNSIGNED_BYTE); 67 for (i = 0; i < count; i++) 68 if (((GLubyte *) indices)[i] > max) 69 max = ((GLubyte *) indices)[i]; 70 } 71 72 if (map) { 73 ctx->Driver.UnmapBuffer(ctx, 74 GL_ELEMENT_ARRAY_BUFFER_ARB, 75 ctx->Array.ElementArrayBufferObj); 76 } 77 78 return max; 79} 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 108GLboolean 109_mesa_validate_DrawElements(GLcontext *ctx, 110 GLenum mode, GLsizei count, GLenum type, 111 const GLvoid *indices) 112{ 113 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 114 115 if (count <= 0) { 116 if (count < 0) 117 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawElements(count)" ); 118 return GL_FALSE; 119 } 120 121 if (mode > GL_POLYGON) { 122 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)" ); 123 return GL_FALSE; 124 } 125 126 if (type != GL_UNSIGNED_INT && 127 type != GL_UNSIGNED_BYTE && 128 type != GL_UNSIGNED_SHORT) 129 { 130 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)" ); 131 return GL_FALSE; 132 } 133 134 if (ctx->NewState) 135 _mesa_update_state(ctx); 136 137 if (!check_valid_to_render(ctx, "Elements")) 138 return GL_FALSE; 139 140 /* Vertex buffer object tests */ 141 if (ctx->Array.ElementArrayBufferObj->Name) { 142 /* use indices in the buffer object */ 143 GLuint indexBytes; 144 145 if (!ctx->Array.ElementArrayBufferObj->Size) { 146 _mesa_warning(ctx, 147 "glDrawElements called with empty array elements buffer"); 148 return GL_FALSE; 149 } 150 151 if (type == GL_UNSIGNED_INT) { 152 indexBytes = count * sizeof(GLuint); 153 } 154 else if (type == GL_UNSIGNED_BYTE) { 155 indexBytes = count * sizeof(GLubyte); 156 } 157 else { 158 ASSERT(type == GL_UNSIGNED_SHORT); 159 indexBytes = count * sizeof(GLushort); 160 } 161 162 /* make sure count doesn't go outside buffer bounds */ 163 if (indexBytes > (GLuint) ctx->Array.ElementArrayBufferObj->Size) { 164 _mesa_warning(ctx, "glDrawElements index out of buffer bounds"); 165 return GL_FALSE; 166 } 167 } 168 else { 169 /* not using a VBO */ 170 if (!indices) 171 return GL_FALSE; 172 } 173 174 if (ctx->Const.CheckArrayBounds) { 175 /* find max array index */ 176 GLuint max = max_buffer_index(ctx, count, type, indices, 177 ctx->Array.ElementArrayBufferObj); 178 if (max >= ctx->Array._MaxElement) { 179 /* the max element is out of bounds of one or more enabled arrays */ 180 return GL_FALSE; 181 } 182 } 183 184 return GL_TRUE; 185} 186 187GLboolean 188_mesa_validate_DrawRangeElements(GLcontext *ctx, GLenum mode, 189 GLuint start, GLuint end, 190 GLsizei count, GLenum type, 191 const GLvoid *indices) 192{ 193 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 194 195 if (count <= 0) { 196 if (count < 0) 197 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(count)" ); 198 return GL_FALSE; 199 } 200 201 if (mode > GL_POLYGON) { 202 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)" ); 203 return GL_FALSE; 204 } 205 206 if (end < start) { 207 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(end<start)"); 208 return GL_FALSE; 209 } 210 211 if (type != GL_UNSIGNED_INT && 212 type != GL_UNSIGNED_BYTE && 213 type != GL_UNSIGNED_SHORT) { 214 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)" ); 215 return GL_FALSE; 216 } 217 218 if (ctx->NewState) 219 _mesa_update_state(ctx); 220 221 if (!check_valid_to_render(ctx, "RangeElements")) 222 return GL_FALSE; 223 224 /* Vertex buffer object tests */ 225 if (ctx->Array.ElementArrayBufferObj->Name) { 226 /* use indices in the buffer object */ 227 GLuint indexBytes; 228 229 if (type == GL_UNSIGNED_INT) { 230 indexBytes = count * sizeof(GLuint); 231 } 232 else if (type == GL_UNSIGNED_BYTE) { 233 indexBytes = count * sizeof(GLubyte); 234 } 235 else { 236 ASSERT(type == GL_UNSIGNED_SHORT); 237 indexBytes = count * sizeof(GLushort); 238 } 239 240 /* make sure count doesn't go outside buffer bounds */ 241 if (indexBytes > ctx->Array.ElementArrayBufferObj->Size) { 242 _mesa_warning(ctx, "glDrawRangeElements index out of buffer bounds"); 243 return GL_FALSE; 244 } 245 } 246 else { 247 /* not using a VBO */ 248 if (!indices) 249 return GL_FALSE; 250 } 251 252 if (ctx->Const.CheckArrayBounds) { 253 GLuint max = max_buffer_index(ctx, count, type, indices, 254 ctx->Array.ElementArrayBufferObj); 255 if (max >= ctx->Array._MaxElement) { 256 /* the max element is out of bounds of one or more enabled arrays */ 257 return GL_FALSE; 258 } 259 } 260 261 return GL_TRUE; 262} 263 264 265/** 266 * Called from the tnl module to error check the function parameters and 267 * verify that we really can draw something. 268 */ 269GLboolean 270_mesa_validate_DrawArrays(GLcontext *ctx, 271 GLenum mode, GLint start, GLsizei count) 272{ 273 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 274 275 if (count <= 0) { 276 if (count < 0) 277 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" ); 278 return GL_FALSE; 279 } 280 281 if (mode > GL_POLYGON) { 282 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)" ); 283 return GL_FALSE; 284 } 285 286 if (ctx->NewState) 287 _mesa_update_state(ctx); 288 289 if (!check_valid_to_render(ctx, "Arrays")) 290 return GL_FALSE; 291 292 if (ctx->Const.CheckArrayBounds) { 293 if (start + count > (GLint) ctx->Array._MaxElement) 294 return GL_FALSE; 295 } 296 297 return GL_TRUE; 298} 299