api_validate.c revision a3c3bc9ece7e7c55c8832dbc8c50ab1c34f5bfe9
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 33GLboolean 34_mesa_validate_DrawElements(GLcontext *ctx, 35 GLenum mode, GLsizei count, GLenum type, 36 const GLvoid *indices) 37{ 38 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 39 40 if (count <= 0) { 41 if (count < 0) 42 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawElements(count)" ); 43 return GL_FALSE; 44 } 45 46 if (mode > GL_POLYGON) { 47 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)" ); 48 return GL_FALSE; 49 } 50 51 if (type != GL_UNSIGNED_INT && 52 type != GL_UNSIGNED_BYTE && 53 type != GL_UNSIGNED_SHORT) 54 { 55 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)" ); 56 return GL_FALSE; 57 } 58 59 if (ctx->NewState) 60 _mesa_update_state(ctx); 61 62 /* Always need vertex positions */ 63 if (!ctx->Array.ArrayObj->Vertex.Enabled 64 && !(ctx->VertexProgram._Enabled && ctx->Array.ArrayObj->VertexAttrib[0].Enabled)) 65 return GL_FALSE; 66 67 /* Vertex buffer object tests */ 68 if (ctx->Array.ElementArrayBufferObj->Name) { 69 GLuint indexBytes; 70 71 /* use indices in the buffer object */ 72 if (!ctx->Array.ElementArrayBufferObj->Size) { 73 _mesa_warning(ctx, 74 "glDrawElements called with empty array elements buffer"); 75 return GL_FALSE; 76 } 77 78 /* make sure count doesn't go outside buffer bounds */ 79 if (type == GL_UNSIGNED_INT) { 80 indexBytes = count * sizeof(GLuint); 81 } 82 else if (type == GL_UNSIGNED_BYTE) { 83 indexBytes = count * sizeof(GLubyte); 84 } 85 else { 86 ASSERT(type == GL_UNSIGNED_SHORT); 87 indexBytes = count * sizeof(GLushort); 88 } 89 90 if (indexBytes > ctx->Array.ElementArrayBufferObj->Size) { 91 _mesa_warning(ctx, "glDrawElements index out of buffer bounds"); 92 return GL_FALSE; 93 } 94 } 95 else { 96 /* not using a VBO */ 97 if (!indices) 98 return GL_FALSE; 99 } 100 101 if (ctx->Const.CheckArrayBounds) { 102 /* find max array index */ 103 const GLubyte *map; 104 GLuint max = 0; 105 GLint i; 106 107 map = ctx->Driver.MapBuffer(ctx, 108 GL_ELEMENT_ARRAY_BUFFER_ARB, 109 GL_READ_ONLY, 110 ctx->Array.ElementArrayBufferObj); 111 112 /* Actual address is the sum of pointers */ 113 indices = (const GLvoid *) ADD_POINTERS(map, (const GLubyte *) indices); 114 115 if (type == GL_UNSIGNED_INT) { 116 for (i = 0; i < count; i++) 117 if (((GLuint *) indices)[i] > max) 118 max = ((GLuint *) indices)[i]; 119 } 120 else if (type == GL_UNSIGNED_SHORT) { 121 for (i = 0; i < count; i++) 122 if (((GLushort *) indices)[i] > max) 123 max = ((GLushort *) indices)[i]; 124 } 125 else { 126 ASSERT(type == GL_UNSIGNED_BYTE); 127 for (i = 0; i < count; i++) 128 if (((GLubyte *) indices)[i] > max) 129 max = ((GLubyte *) indices)[i]; 130 } 131 132 ctx->Driver.UnmapBuffer(ctx, 133 GL_ELEMENT_ARRAY_BUFFER_ARB, 134 ctx->Array.ElementArrayBufferObj); 135 136 if (max >= ctx->Array._MaxElement) { 137 /* the max element is out of bounds of one or more enabled arrays */ 138 return GL_FALSE; 139 } 140 } 141 142 return GL_TRUE; 143} 144 145 146GLboolean 147_mesa_validate_DrawRangeElements(GLcontext *ctx, GLenum mode, 148 GLuint start, GLuint end, 149 GLsizei count, GLenum type, 150 const GLvoid *indices) 151{ 152 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 153 154 if (count <= 0) { 155 if (count < 0) 156 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(count)" ); 157 return GL_FALSE; 158 } 159 160 if (mode > GL_POLYGON) { 161 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)" ); 162 return GL_FALSE; 163 } 164 165 if (end < start) { 166 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(end<start)"); 167 return GL_FALSE; 168 } 169 170 if (type != GL_UNSIGNED_INT && 171 type != GL_UNSIGNED_BYTE && 172 type != GL_UNSIGNED_SHORT) { 173 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)" ); 174 return GL_FALSE; 175 } 176 177 if (ctx->NewState) 178 _mesa_update_state(ctx); 179 180 /* Always need vertex positions */ 181 if (!ctx->Array.ArrayObj->Vertex.Enabled 182 && !(ctx->VertexProgram._Enabled && ctx->Array.ArrayObj->VertexAttrib[0].Enabled)) 183 return GL_FALSE; 184 185 /* Vertex buffer object tests */ 186 if (ctx->Array.ElementArrayBufferObj->Name) { 187 /* XXX re-use code from above? */ 188 } 189 else { 190 /* not using VBO */ 191 if (!indices) 192 return GL_FALSE; 193 } 194 195 if (ctx->Const.CheckArrayBounds) { 196 /* Find max array index. 197 * We don't trust the user's start and end values. 198 */ 199 GLuint max = 0; 200 GLint i; 201 if (type == GL_UNSIGNED_INT) { 202 for (i = 0; i < count; i++) 203 if (((GLuint *) indices)[i] > max) 204 max = ((GLuint *) indices)[i]; 205 } 206 else if (type == GL_UNSIGNED_SHORT) { 207 for (i = 0; i < count; i++) 208 if (((GLushort *) indices)[i] > max) 209 max = ((GLushort *) indices)[i]; 210 } 211 else { 212 ASSERT(type == GL_UNSIGNED_BYTE); 213 for (i = 0; i < count; i++) 214 if (((GLubyte *) indices)[i] > max) 215 max = ((GLubyte *) indices)[i]; 216 } 217 if (max >= ctx->Array._MaxElement) { 218 /* the max element is out of bounds of one or more enabled arrays */ 219 return GL_FALSE; 220 } 221 } 222 223 return GL_TRUE; 224} 225 226 227/** 228 * Called from the tnl module to error check the function parameters and 229 * verify that we really can draw something. 230 */ 231GLboolean 232_mesa_validate_DrawArrays(GLcontext *ctx, 233 GLenum mode, GLint start, GLsizei count) 234{ 235 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 236 237 if (count < 0) { 238 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" ); 239 return GL_FALSE; 240 } 241 242 if (mode > GL_POLYGON) { 243 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)" ); 244 return GL_FALSE; 245 } 246 247 if (ctx->NewState) 248 _mesa_update_state(ctx); 249 250 /* Always need vertex positions */ 251 if (!ctx->Array.ArrayObj->Vertex.Enabled && !ctx->Array.ArrayObj->VertexAttrib[0].Enabled) 252 return GL_FALSE; 253 254 if (ctx->Const.CheckArrayBounds) { 255 if (start + count > (GLint) ctx->Array._MaxElement) 256 return GL_FALSE; 257 } 258 259 return GL_TRUE; 260} 261