[MESA]
[reactos.git] / reactos / dll / opengl / mesa / src / mesa / main / api_validate.c
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 "mfeatures.h"
31 #include "mtypes.h"
32 #include "vbo/vbo.h"
33
34
35 /**
36 * \return number of bytes in array [count] of type.
37 */
38 static GLsizei
39 index_bytes(GLenum type, GLsizei count)
40 {
41 if (type == GL_UNSIGNED_INT) {
42 return count * sizeof(GLuint);
43 }
44 else if (type == GL_UNSIGNED_BYTE) {
45 return count * sizeof(GLubyte);
46 }
47 else {
48 ASSERT(type == GL_UNSIGNED_SHORT);
49 return count * sizeof(GLushort);
50 }
51 }
52
53
54 /**
55 * Find the max index in the given element/index buffer
56 */
57 GLuint
58 _mesa_max_buffer_index(struct gl_context *ctx, GLuint count, GLenum type,
59 const void *indices,
60 struct gl_buffer_object *elementBuf)
61 {
62 const GLubyte *map = NULL;
63 GLuint max = 0;
64 GLuint i;
65
66 if (_mesa_is_bufferobj(elementBuf)) {
67 /* elements are in a user-defined buffer object. need to map it */
68 map = ctx->Driver.MapBufferRange(ctx, 0, elementBuf->Size,
69 GL_MAP_READ_BIT, elementBuf);
70 /* Actual address is the sum of pointers */
71 indices = (const GLvoid *) ADD_POINTERS(map, (const GLubyte *) indices);
72 }
73
74 if (type == GL_UNSIGNED_INT) {
75 for (i = 0; i < count; i++)
76 if (((GLuint *) indices)[i] > max)
77 max = ((GLuint *) indices)[i];
78 }
79 else if (type == GL_UNSIGNED_SHORT) {
80 for (i = 0; i < count; i++)
81 if (((GLushort *) indices)[i] > max)
82 max = ((GLushort *) indices)[i];
83 }
84 else {
85 ASSERT(type == GL_UNSIGNED_BYTE);
86 for (i = 0; i < count; i++)
87 if (((GLubyte *) indices)[i] > max)
88 max = ((GLubyte *) indices)[i];
89 }
90
91 if (map) {
92 ctx->Driver.UnmapBuffer(ctx, elementBuf);
93 }
94
95 return max;
96 }
97
98
99 /**
100 * Check if OK to draw arrays/elements.
101 */
102 static GLboolean
103 check_valid_to_render(struct gl_context *ctx, const char *function)
104 {
105 if (!_mesa_valid_to_render(ctx, function)) {
106 return GL_FALSE;
107 }
108
109 {
110 const struct gl_shader_program *vsProg =
111 ctx->Shader.CurrentVertexProgram;
112 GLboolean haveVertexShader = (vsProg && vsProg->LinkStatus);
113 GLboolean haveVertexProgram = ctx->VertexProgram._Enabled;
114 if (haveVertexShader || haveVertexProgram) {
115 /* Draw regardless of whether or not we have any vertex arrays.
116 * (Ex: could draw a point using a constant vertex pos)
117 */
118 return GL_TRUE;
119 }
120 else {
121 /* Draw if we have vertex positions (GL_VERTEX_ARRAY or generic
122 * array [0]).
123 */
124 return (ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled ||
125 ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_GENERIC0].Enabled);
126 }
127 }
128 return GL_TRUE;
129 }
130
131
132 /**
133 * Do bounds checking on array element indexes. Check that the vertices
134 * pointed to by the indices don't lie outside buffer object bounds.
135 * \return GL_TRUE if OK, GL_FALSE if any indexed vertex goes is out of bounds
136 */
137 static GLboolean
138 check_index_bounds(struct gl_context *ctx, GLsizei count, GLenum type,
139 const GLvoid *indices)
140 {
141 struct _mesa_prim prim;
142 struct _mesa_index_buffer ib;
143 GLuint min, max;
144
145 /* Only the X Server needs to do this -- otherwise, accessing outside
146 * array/BO bounds allows application termination.
147 */
148 if (!ctx->Const.CheckArrayBounds)
149 return GL_TRUE;
150
151 memset(&prim, 0, sizeof(prim));
152 prim.count = count;
153
154 memset(&ib, 0, sizeof(ib));
155 ib.type = type;
156 ib.ptr = indices;
157 ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj;
158
159 vbo_get_minmax_index(ctx, &prim, &ib, &min, &max);
160
161 if (max >= ctx->Array.ArrayObj->_MaxElement) {
162 /* the max element is out of bounds of one or more enabled arrays */
163 _mesa_warning(ctx, "glDrawElements() index=%u is out of bounds (max=%u)",
164 max, ctx->Array.ArrayObj->_MaxElement);
165 return GL_FALSE;
166 }
167
168 return GL_TRUE;
169 }
170
171
172 /**
173 * Is 'mode' a valid value for glBegin(), glDrawArrays(), glDrawElements(),
174 * etc? The set of legal values depends on whether geometry shaders/programs
175 * are supported.
176 */
177 GLboolean
178 _mesa_valid_prim_mode(const struct gl_context *ctx, GLenum mode)
179 {
180 if (mode > GL_POLYGON) {
181 return GL_FALSE;
182 }
183 else {
184 return GL_TRUE;
185 }
186 }
187
188
189 /**
190 * Error checking for glDrawElements(). Includes parameter checking
191 * and VBO bounds checking.
192 * \return GL_TRUE if OK to render, GL_FALSE if error found
193 */
194 GLboolean
195 _mesa_validate_DrawElements(struct gl_context *ctx,
196 GLenum mode, GLsizei count, GLenum type,
197 const GLvoid *indices)
198 {
199 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
200
201 if (count <= 0) {
202 if (count < 0)
203 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawElements(count)" );
204 return GL_FALSE;
205 }
206
207 if (!_mesa_valid_prim_mode(ctx, mode)) {
208 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)" );
209 return GL_FALSE;
210 }
211
212 if (type != GL_UNSIGNED_INT &&
213 type != GL_UNSIGNED_BYTE &&
214 type != GL_UNSIGNED_SHORT)
215 {
216 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
217 return GL_FALSE;
218 }
219
220 if (!check_valid_to_render(ctx, "glDrawElements"))
221 return GL_FALSE;
222
223 /* Vertex buffer object tests */
224 if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) {
225 /* use indices in the buffer object */
226 /* make sure count doesn't go outside buffer bounds */
227 if (index_bytes(type, count) > ctx->Array.ArrayObj->ElementArrayBufferObj->Size) {
228 _mesa_warning(ctx, "glDrawElements index out of buffer bounds");
229 return GL_FALSE;
230 }
231 }
232 else {
233 /* not using a VBO */
234 if (!indices)
235 return GL_FALSE;
236 }
237
238 if (!check_index_bounds(ctx, count, type, indices))
239 return GL_FALSE;
240
241 return GL_TRUE;
242 }
243
244
245 /**
246 * Error checking for glDrawRangeElements(). Includes parameter checking
247 * and VBO bounds checking.
248 * \return GL_TRUE if OK to render, GL_FALSE if error found
249 */
250 GLboolean
251 _mesa_validate_DrawRangeElements(struct gl_context *ctx, GLenum mode,
252 GLuint start, GLuint end,
253 GLsizei count, GLenum type,
254 const GLvoid *indices)
255 {
256 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
257
258 if (count <= 0) {
259 if (count < 0)
260 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(count)" );
261 return GL_FALSE;
262 }
263
264 if (!_mesa_valid_prim_mode(ctx, mode)) {
265 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)" );
266 return GL_FALSE;
267 }
268
269 if (end < start) {
270 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(end<start)");
271 return GL_FALSE;
272 }
273
274 if (type != GL_UNSIGNED_INT &&
275 type != GL_UNSIGNED_BYTE &&
276 type != GL_UNSIGNED_SHORT) {
277 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)" );
278 return GL_FALSE;
279 }
280
281 if (!check_valid_to_render(ctx, "glDrawRangeElements"))
282 return GL_FALSE;
283
284 /* Vertex buffer object tests */
285 if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) {
286 /* use indices in the buffer object */
287 /* make sure count doesn't go outside buffer bounds */
288 if (index_bytes(type, count) > ctx->Array.ArrayObj->ElementArrayBufferObj->Size) {
289 _mesa_warning(ctx, "glDrawRangeElements index out of buffer bounds");
290 return GL_FALSE;
291 }
292 }
293 else {
294 /* not using a VBO */
295 if (!indices)
296 return GL_FALSE;
297 }
298
299 if (!check_index_bounds(ctx, count, type, indices))
300 return GL_FALSE;
301
302 return GL_TRUE;
303 }
304
305
306 /**
307 * Called from the tnl module to error check the function parameters and
308 * verify that we really can draw something.
309 * \return GL_TRUE if OK to render, GL_FALSE if error found
310 */
311 GLboolean
312 _mesa_validate_DrawArrays(struct gl_context *ctx,
313 GLenum mode, GLint start, GLsizei count)
314 {
315 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
316
317 if (count <= 0) {
318 if (count < 0)
319 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" );
320 return GL_FALSE;
321 }
322
323 if (!_mesa_valid_prim_mode(ctx, mode)) {
324 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)" );
325 return GL_FALSE;
326 }
327
328 if (!check_valid_to_render(ctx, "glDrawArrays"))
329 return GL_FALSE;
330
331 if (ctx->Const.CheckArrayBounds) {
332 if (start + count > (GLint) ctx->Array.ArrayObj->_MaxElement)
333 return GL_FALSE;
334 }
335
336 return GL_TRUE;
337 }
338
339
340 GLboolean
341 _mesa_validate_DrawArraysInstanced(struct gl_context *ctx, GLenum mode, GLint first,
342 GLsizei count, GLsizei numInstances)
343 {
344 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
345
346 if (count <= 0) {
347 if (count < 0)
348 _mesa_error(ctx, GL_INVALID_VALUE,
349 "glDrawArraysInstanced(count=%d)", count);
350 return GL_FALSE;
351 }
352
353 if (first < 0) {
354 _mesa_error(ctx, GL_INVALID_VALUE,
355 "glDrawArraysInstanced(start=%d)", first);
356 return GL_FALSE;
357 }
358
359 if (!_mesa_valid_prim_mode(ctx, mode)) {
360 _mesa_error(ctx, GL_INVALID_ENUM,
361 "glDrawArraysInstanced(mode=0x%x)", mode);
362 return GL_FALSE;
363 }
364
365 if (numInstances <= 0) {
366 if (numInstances < 0)
367 _mesa_error(ctx, GL_INVALID_VALUE,
368 "glDrawArraysInstanced(numInstances=%d)", numInstances);
369 return GL_FALSE;
370 }
371
372 if (!check_valid_to_render(ctx, "glDrawArraysInstanced(invalid to render)"))
373 return GL_FALSE;
374
375 if (ctx->Const.CheckArrayBounds) {
376 if (first + count > (GLint) ctx->Array.ArrayObj->_MaxElement)
377 return GL_FALSE;
378 }
379
380 return GL_TRUE;
381 }
382
383
384 GLboolean
385 _mesa_validate_DrawElementsInstanced(struct gl_context *ctx,
386 GLenum mode, GLsizei count, GLenum type,
387 const GLvoid *indices, GLsizei numInstances)
388 {
389 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
390
391 if (count <= 0) {
392 if (count < 0)
393 _mesa_error(ctx, GL_INVALID_VALUE,
394 "glDrawElementsInstanced(count=%d)", count);
395 return GL_FALSE;
396 }
397
398 if (!_mesa_valid_prim_mode(ctx, mode)) {
399 _mesa_error(ctx, GL_INVALID_ENUM,
400 "glDrawElementsInstanced(mode = 0x%x)", mode);
401 return GL_FALSE;
402 }
403
404 if (type != GL_UNSIGNED_INT &&
405 type != GL_UNSIGNED_BYTE &&
406 type != GL_UNSIGNED_SHORT) {
407 _mesa_error(ctx, GL_INVALID_ENUM,
408 "glDrawElementsInstanced(type=0x%x)", type);
409 return GL_FALSE;
410 }
411
412 if (numInstances <= 0) {
413 if (numInstances < 0)
414 _mesa_error(ctx, GL_INVALID_VALUE,
415 "glDrawElementsInstanced(numInstances=%d)", numInstances);
416 return GL_FALSE;
417 }
418
419 if (!check_valid_to_render(ctx, "glDrawElementsInstanced"))
420 return GL_FALSE;
421
422 /* Vertex buffer object tests */
423 if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) {
424 /* use indices in the buffer object */
425 /* make sure count doesn't go outside buffer bounds */
426 if (index_bytes(type, count) > ctx->Array.ArrayObj->ElementArrayBufferObj->Size) {
427 _mesa_warning(ctx,
428 "glDrawElementsInstanced index out of buffer bounds");
429 return GL_FALSE;
430 }
431 }
432 else {
433 /* not using a VBO */
434 if (!indices)
435 return GL_FALSE;
436 }
437
438 if (!check_index_bounds(ctx, count, type, indices))
439 return GL_FALSE;
440
441 return GL_TRUE;
442 }
443