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