mesa/es: Validate blend function enums in Mesa code rather than the ES wrapper
[mesa.git] / 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 "enums.h"
33 #include "vbo/vbo.h"
34 #include <stdbool.h>
35
36
37 /**
38 * \return number of bytes in array [count] of type.
39 */
40 static GLsizei
41 index_bytes(GLenum type, GLsizei count)
42 {
43 if (type == GL_UNSIGNED_INT) {
44 return count * sizeof(GLuint);
45 }
46 else if (type == GL_UNSIGNED_BYTE) {
47 return count * sizeof(GLubyte);
48 }
49 else {
50 ASSERT(type == GL_UNSIGNED_SHORT);
51 return count * sizeof(GLushort);
52 }
53 }
54
55
56 /**
57 * Find the max index in the given element/index buffer
58 */
59 GLuint
60 _mesa_max_buffer_index(struct gl_context *ctx, GLuint count, GLenum type,
61 const void *indices,
62 struct gl_buffer_object *elementBuf)
63 {
64 const GLubyte *map = NULL;
65 GLuint max = 0;
66 GLuint i;
67
68 if (_mesa_is_bufferobj(elementBuf)) {
69 /* elements are in a user-defined buffer object. need to map it */
70 map = ctx->Driver.MapBufferRange(ctx, 0, elementBuf->Size,
71 GL_MAP_READ_BIT, elementBuf);
72 /* Actual address is the sum of pointers */
73 indices = (const GLvoid *) ADD_POINTERS(map, (const GLubyte *) indices);
74 }
75
76 if (type == GL_UNSIGNED_INT) {
77 for (i = 0; i < count; i++)
78 if (((GLuint *) indices)[i] > max)
79 max = ((GLuint *) indices)[i];
80 }
81 else if (type == GL_UNSIGNED_SHORT) {
82 for (i = 0; i < count; i++)
83 if (((GLushort *) indices)[i] > max)
84 max = ((GLushort *) indices)[i];
85 }
86 else {
87 ASSERT(type == GL_UNSIGNED_BYTE);
88 for (i = 0; i < count; i++)
89 if (((GLubyte *) indices)[i] > max)
90 max = ((GLubyte *) indices)[i];
91 }
92
93 if (map) {
94 ctx->Driver.UnmapBuffer(ctx, elementBuf);
95 }
96
97 return max;
98 }
99
100
101 /**
102 * Check if OK to draw arrays/elements.
103 */
104 static GLboolean
105 check_valid_to_render(struct gl_context *ctx, const char *function)
106 {
107 if (!_mesa_valid_to_render(ctx, function)) {
108 return GL_FALSE;
109 }
110
111 switch (ctx->API) {
112 #if FEATURE_es2_glsl
113 case API_OPENGLES2:
114 /* For ES2, we can draw if any vertex array is enabled (and we
115 * should always have a vertex program/shader). */
116 if (ctx->Array.ArrayObj->_Enabled == 0x0 || !ctx->VertexProgram._Current)
117 return GL_FALSE;
118 break;
119 #endif
120
121 #if FEATURE_ES1
122 case API_OPENGLES:
123 /* For OpenGL ES, only draw if we have vertex positions
124 */
125 if (!ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled)
126 return GL_FALSE;
127 break;
128 #endif
129
130 #if FEATURE_GL
131 case API_OPENGL:
132 case API_OPENGL_CORE:
133 {
134 const struct gl_shader_program *vsProg =
135 ctx->Shader.CurrentVertexProgram;
136 GLboolean haveVertexShader = (vsProg && vsProg->LinkStatus);
137 GLboolean haveVertexProgram = ctx->VertexProgram._Enabled;
138 if (haveVertexShader || haveVertexProgram) {
139 /* Draw regardless of whether or not we have any vertex arrays.
140 * (Ex: could draw a point using a constant vertex pos)
141 */
142 return GL_TRUE;
143 }
144 else {
145 /* Draw if we have vertex positions (GL_VERTEX_ARRAY or generic
146 * array [0]).
147 */
148 return (ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled ||
149 ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_GENERIC0].Enabled);
150 }
151 }
152 break;
153 #endif
154
155 default:
156 ASSERT_NO_FEATURE();
157 }
158
159 return GL_TRUE;
160 }
161
162
163 /**
164 * Do bounds checking on array element indexes. Check that the vertices
165 * pointed to by the indices don't lie outside buffer object bounds.
166 * \return GL_TRUE if OK, GL_FALSE if any indexed vertex goes is out of bounds
167 */
168 static GLboolean
169 check_index_bounds(struct gl_context *ctx, GLsizei count, GLenum type,
170 const GLvoid *indices, GLint basevertex)
171 {
172 struct _mesa_prim prim;
173 struct _mesa_index_buffer ib;
174 GLuint min, max;
175
176 /* Only the X Server needs to do this -- otherwise, accessing outside
177 * array/BO bounds allows application termination.
178 */
179 if (!ctx->Const.CheckArrayBounds)
180 return GL_TRUE;
181
182 memset(&prim, 0, sizeof(prim));
183 prim.count = count;
184
185 memset(&ib, 0, sizeof(ib));
186 ib.type = type;
187 ib.ptr = indices;
188 ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj;
189
190 vbo_get_minmax_indices(ctx, &prim, &ib, &min, &max, 1);
191
192 if ((int)(min + basevertex) < 0 ||
193 max + basevertex >= ctx->Array.ArrayObj->_MaxElement) {
194 /* the max element is out of bounds of one or more enabled arrays */
195 _mesa_warning(ctx, "glDrawElements() index=%u is out of bounds (max=%u)",
196 max, ctx->Array.ArrayObj->_MaxElement);
197 return GL_FALSE;
198 }
199
200 return GL_TRUE;
201 }
202
203
204 /**
205 * Is 'mode' a valid value for glBegin(), glDrawArrays(), glDrawElements(),
206 * etc? The set of legal values depends on whether geometry shaders/programs
207 * are supported.
208 */
209 GLboolean
210 _mesa_valid_prim_mode(struct gl_context *ctx, GLenum mode, const char *name)
211 {
212 if (ctx->Extensions.ARB_geometry_shader4 &&
213 mode > GL_TRIANGLE_STRIP_ADJACENCY_ARB) {
214 _mesa_error(ctx, GL_INVALID_ENUM, "%s(mode=%x)", name, mode);
215 return GL_FALSE;
216 }
217 else if (mode > GL_POLYGON) {
218 _mesa_error(ctx, GL_INVALID_ENUM, "%s(mode=%x)", name, mode);
219 return GL_FALSE;
220 }
221
222 /* From the GL_EXT_transform_feedback spec:
223 *
224 * "The error INVALID_OPERATION is generated if Begin, or any command
225 * that performs an explicit Begin, is called when:
226 *
227 * * a geometry shader is not active and <mode> does not match the
228 * allowed begin modes for the current transform feedback state as
229 * given by table X.1.
230 *
231 * * a geometry shader is active and the output primitive type of the
232 * geometry shader does not match the allowed begin modes for the
233 * current transform feedback state as given by table X.1.
234 *
235 */
236 if (ctx->TransformFeedback.CurrentObject->Active &&
237 !ctx->TransformFeedback.CurrentObject->Paused) {
238 GLboolean pass = GL_TRUE;
239
240 switch (mode) {
241 case GL_POINTS:
242 pass = ctx->TransformFeedback.Mode == GL_POINTS;
243 break;
244 case GL_LINES:
245 case GL_LINE_STRIP:
246 case GL_LINE_LOOP:
247 pass = ctx->TransformFeedback.Mode == GL_LINES;
248 break;
249 default:
250 pass = ctx->TransformFeedback.Mode == GL_TRIANGLES;
251 break;
252 }
253 if (!pass) {
254 _mesa_error(ctx, GL_INVALID_OPERATION,
255 "%s(mode=%s vs transform feedback %s)",
256 name,
257 _mesa_lookup_prim_by_nr(mode),
258 _mesa_lookup_prim_by_nr(ctx->TransformFeedback.Mode));
259 return GL_FALSE;
260 }
261 }
262
263 return GL_TRUE;
264 }
265
266 /**
267 * Verify that the element type is valid.
268 *
269 * Generates \c GL_INVALID_ENUM and returns \c false if it is not.
270 */
271 static bool
272 valid_elements_type(struct gl_context *ctx, GLenum type, const char *name)
273 {
274 switch (type) {
275 case GL_UNSIGNED_BYTE:
276 case GL_UNSIGNED_SHORT:
277 case GL_UNSIGNED_INT:
278 return true;
279
280 default:
281 _mesa_error(ctx, GL_INVALID_ENUM, "%s(type = %s)", name,
282 _mesa_lookup_enum_by_nr(type));
283 return false;
284 }
285 }
286
287 /**
288 * Error checking for glDrawElements(). Includes parameter checking
289 * and VBO bounds checking.
290 * \return GL_TRUE if OK to render, GL_FALSE if error found
291 */
292 GLboolean
293 _mesa_validate_DrawElements(struct gl_context *ctx,
294 GLenum mode, GLsizei count, GLenum type,
295 const GLvoid *indices, GLint basevertex)
296 {
297 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
298 FLUSH_CURRENT(ctx, 0);
299
300 if (count <= 0) {
301 if (count < 0)
302 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawElements(count)" );
303 return GL_FALSE;
304 }
305
306 if (!_mesa_valid_prim_mode(ctx, mode, "glDrawElements")) {
307 return GL_FALSE;
308 }
309
310 if (!valid_elements_type(ctx, type, "glDrawElements"))
311 return GL_FALSE;
312
313 if (!check_valid_to_render(ctx, "glDrawElements"))
314 return GL_FALSE;
315
316 /* Vertex buffer object tests */
317 if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) {
318 /* use indices in the buffer object */
319 /* make sure count doesn't go outside buffer bounds */
320 if (index_bytes(type, count) > ctx->Array.ArrayObj->ElementArrayBufferObj->Size) {
321 _mesa_warning(ctx, "glDrawElements index out of buffer bounds");
322 return GL_FALSE;
323 }
324 }
325 else {
326 /* not using a VBO */
327 if (!indices)
328 return GL_FALSE;
329 }
330
331 if (!check_index_bounds(ctx, count, type, indices, basevertex))
332 return GL_FALSE;
333
334 return GL_TRUE;
335 }
336
337
338 /**
339 * Error checking for glMultiDrawElements(). Includes parameter checking
340 * and VBO bounds checking.
341 * \return GL_TRUE if OK to render, GL_FALSE if error found
342 */
343 GLboolean
344 _mesa_validate_MultiDrawElements(struct gl_context *ctx,
345 GLenum mode, const GLsizei *count,
346 GLenum type, const GLvoid * const *indices,
347 GLuint primcount, const GLint *basevertex)
348 {
349 unsigned i;
350
351 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
352 FLUSH_CURRENT(ctx, 0);
353
354 for (i = 0; i < primcount; i++) {
355 if (count[i] <= 0) {
356 if (count[i] < 0)
357 _mesa_error(ctx, GL_INVALID_VALUE,
358 "glMultiDrawElements(count)" );
359 return GL_FALSE;
360 }
361 }
362
363 if (!_mesa_valid_prim_mode(ctx, mode, "glMultiDrawElements")) {
364 return GL_FALSE;
365 }
366
367 if (!valid_elements_type(ctx, type, "glMultiDrawElements"))
368 return GL_FALSE;
369
370 if (!check_valid_to_render(ctx, "glMultiDrawElements"))
371 return GL_FALSE;
372
373 /* Vertex buffer object tests */
374 if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) {
375 /* use indices in the buffer object */
376 /* make sure count doesn't go outside buffer bounds */
377 for (i = 0; i < primcount; i++) {
378 if (index_bytes(type, count[i]) >
379 ctx->Array.ArrayObj->ElementArrayBufferObj->Size) {
380 _mesa_warning(ctx,
381 "glMultiDrawElements index out of buffer bounds");
382 return GL_FALSE;
383 }
384 }
385 }
386 else {
387 /* not using a VBO */
388 for (i = 0; i < primcount; i++) {
389 if (!indices[i])
390 return GL_FALSE;
391 }
392 }
393
394 for (i = 0; i < primcount; i++) {
395 if (!check_index_bounds(ctx, count[i], type, indices[i],
396 basevertex ? basevertex[i] : 0))
397 return GL_FALSE;
398 }
399
400 return GL_TRUE;
401 }
402
403
404 /**
405 * Error checking for glDrawRangeElements(). Includes parameter checking
406 * and VBO bounds checking.
407 * \return GL_TRUE if OK to render, GL_FALSE if error found
408 */
409 GLboolean
410 _mesa_validate_DrawRangeElements(struct gl_context *ctx, GLenum mode,
411 GLuint start, GLuint end,
412 GLsizei count, GLenum type,
413 const GLvoid *indices, GLint basevertex)
414 {
415 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
416 FLUSH_CURRENT(ctx, 0);
417
418 if (count <= 0) {
419 if (count < 0)
420 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(count)" );
421 return GL_FALSE;
422 }
423
424 if (!_mesa_valid_prim_mode(ctx, mode, "glDrawRangeElements")) {
425 return GL_FALSE;
426 }
427
428 if (end < start) {
429 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(end<start)");
430 return GL_FALSE;
431 }
432
433 if (!valid_elements_type(ctx, type, "glDrawRangeElements"))
434 return GL_FALSE;
435
436 if (!check_valid_to_render(ctx, "glDrawRangeElements"))
437 return GL_FALSE;
438
439 /* Vertex buffer object tests */
440 if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) {
441 /* use indices in the buffer object */
442 /* make sure count doesn't go outside buffer bounds */
443 if (index_bytes(type, count) > ctx->Array.ArrayObj->ElementArrayBufferObj->Size) {
444 _mesa_warning(ctx, "glDrawRangeElements index out of buffer bounds");
445 return GL_FALSE;
446 }
447 }
448 else {
449 /* not using a VBO */
450 if (!indices)
451 return GL_FALSE;
452 }
453
454 if (!check_index_bounds(ctx, count, type, indices, basevertex))
455 return GL_FALSE;
456
457 return GL_TRUE;
458 }
459
460
461 /**
462 * Called from the tnl module to error check the function parameters and
463 * verify that we really can draw something.
464 * \return GL_TRUE if OK to render, GL_FALSE if error found
465 */
466 GLboolean
467 _mesa_validate_DrawArrays(struct gl_context *ctx,
468 GLenum mode, GLint start, GLsizei count)
469 {
470 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
471 FLUSH_CURRENT(ctx, 0);
472
473 if (count <= 0) {
474 if (count < 0)
475 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" );
476 return GL_FALSE;
477 }
478
479 if (!_mesa_valid_prim_mode(ctx, mode, "glDrawArrays")) {
480 return GL_FALSE;
481 }
482
483 if (!check_valid_to_render(ctx, "glDrawArrays"))
484 return GL_FALSE;
485
486 if (ctx->Const.CheckArrayBounds) {
487 if (start + count > (GLint) ctx->Array.ArrayObj->_MaxElement)
488 return GL_FALSE;
489 }
490
491 return GL_TRUE;
492 }
493
494
495 GLboolean
496 _mesa_validate_DrawArraysInstanced(struct gl_context *ctx, GLenum mode, GLint first,
497 GLsizei count, GLsizei numInstances)
498 {
499 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
500 FLUSH_CURRENT(ctx, 0);
501
502 if (count <= 0) {
503 if (count < 0)
504 _mesa_error(ctx, GL_INVALID_VALUE,
505 "glDrawArraysInstanced(count=%d)", count);
506 return GL_FALSE;
507 }
508
509 if (first < 0) {
510 _mesa_error(ctx, GL_INVALID_VALUE,
511 "glDrawArraysInstanced(start=%d)", first);
512 return GL_FALSE;
513 }
514
515 if (!_mesa_valid_prim_mode(ctx, mode, "glDrawArraysInstanced")) {
516 return GL_FALSE;
517 }
518
519 if (numInstances <= 0) {
520 if (numInstances < 0)
521 _mesa_error(ctx, GL_INVALID_VALUE,
522 "glDrawArraysInstanced(numInstances=%d)", numInstances);
523 return GL_FALSE;
524 }
525
526 if (!check_valid_to_render(ctx, "glDrawArraysInstanced(invalid to render)"))
527 return GL_FALSE;
528
529 if (ctx->Const.CheckArrayBounds) {
530 if (first + count > (GLint) ctx->Array.ArrayObj->_MaxElement)
531 return GL_FALSE;
532 }
533
534 return GL_TRUE;
535 }
536
537
538 GLboolean
539 _mesa_validate_DrawElementsInstanced(struct gl_context *ctx,
540 GLenum mode, GLsizei count, GLenum type,
541 const GLvoid *indices, GLsizei numInstances,
542 GLint basevertex)
543 {
544 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
545 FLUSH_CURRENT(ctx, 0);
546
547 if (count <= 0) {
548 if (count < 0)
549 _mesa_error(ctx, GL_INVALID_VALUE,
550 "glDrawElementsInstanced(count=%d)", count);
551 return GL_FALSE;
552 }
553
554 if (!_mesa_valid_prim_mode(ctx, mode, "glDrawElementsInstanced")) {
555 return GL_FALSE;
556 }
557
558 if (!valid_elements_type(ctx, type, "glDrawElementsInstanced"))
559 return GL_FALSE;
560
561 if (numInstances <= 0) {
562 if (numInstances < 0)
563 _mesa_error(ctx, GL_INVALID_VALUE,
564 "glDrawElementsInstanced(numInstances=%d)", numInstances);
565 return GL_FALSE;
566 }
567
568 if (!check_valid_to_render(ctx, "glDrawElementsInstanced"))
569 return GL_FALSE;
570
571 /* Vertex buffer object tests */
572 if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) {
573 /* use indices in the buffer object */
574 /* make sure count doesn't go outside buffer bounds */
575 if (index_bytes(type, count) > ctx->Array.ArrayObj->ElementArrayBufferObj->Size) {
576 _mesa_warning(ctx,
577 "glDrawElementsInstanced index out of buffer bounds");
578 return GL_FALSE;
579 }
580 }
581 else {
582 /* not using a VBO */
583 if (!indices)
584 return GL_FALSE;
585 }
586
587 if (!check_index_bounds(ctx, count, type, indices, basevertex))
588 return GL_FALSE;
589
590 return GL_TRUE;
591 }
592
593
594 #if FEATURE_EXT_transform_feedback
595
596 GLboolean
597 _mesa_validate_DrawTransformFeedback(struct gl_context *ctx,
598 GLenum mode,
599 struct gl_transform_feedback_object *obj,
600 GLuint stream,
601 GLsizei numInstances)
602 {
603 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
604 FLUSH_CURRENT(ctx, 0);
605
606 if (!_mesa_valid_prim_mode(ctx, mode, "glDrawTransformFeedback*(mode)")) {
607 return GL_FALSE;
608 }
609
610 if (!obj) {
611 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawTransformFeedback*(name)");
612 return GL_FALSE;
613 }
614
615 if (!obj->EndedAnytime) {
616 _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawTransformFeedback*");
617 return GL_FALSE;
618 }
619
620 if (stream >= ctx->Const.MaxVertexStreams) {
621 _mesa_error(ctx, GL_INVALID_VALUE,
622 "glDrawTransformFeedbackStream*(index>=MaxVertexStream)");
623 return GL_FALSE;
624 }
625
626 if (numInstances <= 0) {
627 if (numInstances < 0)
628 _mesa_error(ctx, GL_INVALID_VALUE,
629 "glDrawTransformFeedback*Instanced(numInstances=%d)",
630 numInstances);
631 return GL_FALSE;
632 }
633
634 if (!check_valid_to_render(ctx, "glDrawTransformFeedback*")) {
635 return GL_FALSE;
636 }
637
638 return GL_TRUE;
639 }
640
641 #endif