mesa/es: Validate glClear mask in Mesa code rather than the ES wrapper
[mesa.git] / src / mesa / main / clear.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
26 /**
27 * \file clear.c
28 * glClearColor, glClearIndex, glClear() functions.
29 */
30
31
32
33 #include "glheader.h"
34 #include "clear.h"
35 #include "context.h"
36 #include "colormac.h"
37 #include "enums.h"
38 #include "macros.h"
39 #include "mtypes.h"
40 #include "state.h"
41
42
43
44 #if _HAVE_FULL_GL
45 void GLAPIENTRY
46 _mesa_ClearIndex( GLfloat c )
47 {
48 GET_CURRENT_CONTEXT(ctx);
49 ASSERT_OUTSIDE_BEGIN_END(ctx);
50
51 if (ctx->Color.ClearIndex == (GLuint) c)
52 return;
53
54 FLUSH_VERTICES(ctx, _NEW_COLOR);
55 ctx->Color.ClearIndex = (GLuint) c;
56 }
57 #endif
58
59
60 /**
61 * Specify the clear values for the color buffers.
62 *
63 * \param red red color component.
64 * \param green green color component.
65 * \param blue blue color component.
66 * \param alpha alpha component.
67 *
68 * \sa glClearColor().
69 *
70 * Clamps the parameters and updates gl_colorbuffer_attrib::ClearColor. On a
71 * change, flushes the vertices and notifies the driver via the
72 * dd_function_table::ClearColor callback.
73 */
74 void GLAPIENTRY
75 _mesa_ClearColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha )
76 {
77 GLfloat tmp[4];
78 GET_CURRENT_CONTEXT(ctx);
79 ASSERT_OUTSIDE_BEGIN_END(ctx);
80
81 tmp[0] = red;
82 tmp[1] = green;
83 tmp[2] = blue;
84 tmp[3] = alpha;
85
86 if (TEST_EQ_4V(tmp, ctx->Color.ClearColor.f))
87 return; /* no change */
88
89 FLUSH_VERTICES(ctx, _NEW_COLOR);
90 COPY_4V(ctx->Color.ClearColor.f, tmp);
91 }
92
93
94 /**
95 * GL_EXT_texture_integer
96 */
97 void GLAPIENTRY
98 _mesa_ClearColorIiEXT(GLint r, GLint g, GLint b, GLint a)
99 {
100 GLint tmp[4];
101 GET_CURRENT_CONTEXT(ctx);
102 ASSERT_OUTSIDE_BEGIN_END(ctx);
103
104 tmp[0] = r;
105 tmp[1] = g;
106 tmp[2] = b;
107 tmp[3] = a;
108
109 if (TEST_EQ_4V(tmp, ctx->Color.ClearColor.i))
110 return; /* no change */
111
112 FLUSH_VERTICES(ctx, _NEW_COLOR);
113 COPY_4V(ctx->Color.ClearColor.i, tmp);
114 }
115
116
117 /**
118 * GL_EXT_texture_integer
119 */
120 void GLAPIENTRY
121 _mesa_ClearColorIuiEXT(GLuint r, GLuint g, GLuint b, GLuint a)
122 {
123 GLuint tmp[4];
124 GET_CURRENT_CONTEXT(ctx);
125 ASSERT_OUTSIDE_BEGIN_END(ctx);
126
127 tmp[0] = r;
128 tmp[1] = g;
129 tmp[2] = b;
130 tmp[3] = a;
131
132 if (TEST_EQ_4V(tmp, ctx->Color.ClearColor.ui))
133 return; /* no change */
134
135 FLUSH_VERTICES(ctx, _NEW_COLOR);
136 COPY_4V(ctx->Color.ClearColor.ui, tmp);
137 }
138
139
140 /**
141 * Clear buffers.
142 *
143 * \param mask bit-mask indicating the buffers to be cleared.
144 *
145 * Flushes the vertices and verifies the parameter. If __struct gl_contextRec::NewState
146 * is set then calls _mesa_update_state() to update gl_frame_buffer::_Xmin,
147 * etc. If the rasterization mode is set to GL_RENDER then requests the driver
148 * to clear the buffers, via the dd_function_table::Clear callback.
149 */
150 void GLAPIENTRY
151 _mesa_Clear( GLbitfield mask )
152 {
153 GET_CURRENT_CONTEXT(ctx);
154 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
155
156 FLUSH_CURRENT(ctx, 0);
157
158 if (MESA_VERBOSE & VERBOSE_API)
159 _mesa_debug(ctx, "glClear 0x%x\n", mask);
160
161 if (mask & ~(GL_COLOR_BUFFER_BIT |
162 GL_DEPTH_BUFFER_BIT |
163 GL_STENCIL_BUFFER_BIT |
164 GL_ACCUM_BUFFER_BIT)) {
165 /* invalid bit set */
166 _mesa_error( ctx, GL_INVALID_VALUE, "glClear(0x%x)", mask);
167 return;
168 }
169
170 /* Accumulation buffers were removed in core contexts, and they never
171 * existed in OpenGL ES.
172 */
173 if ((mask & GL_ACCUM_BUFFER_BIT) != 0
174 && (ctx->API == API_OPENGL_CORE || _mesa_is_gles(ctx))) {
175 _mesa_error( ctx, GL_INVALID_VALUE, "glClear(GL_ACCUM_BUFFER_BIT)");
176 return;
177 }
178
179 if (ctx->NewState) {
180 _mesa_update_state( ctx ); /* update _Xmin, etc */
181 }
182
183 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
184 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
185 "glClear(incomplete framebuffer)");
186 return;
187 }
188
189 if (ctx->DrawBuffer->Width == 0 || ctx->DrawBuffer->Height == 0 ||
190 ctx->DrawBuffer->_Xmin >= ctx->DrawBuffer->_Xmax ||
191 ctx->DrawBuffer->_Ymin >= ctx->DrawBuffer->_Ymax)
192 return;
193
194 if (ctx->RasterDiscard)
195 return;
196
197 if (ctx->RenderMode == GL_RENDER) {
198 GLbitfield bufferMask;
199
200 /* don't clear depth buffer if depth writing disabled */
201 if (!ctx->Depth.Mask)
202 mask &= ~GL_DEPTH_BUFFER_BIT;
203
204 /* Build the bitmask to send to device driver's Clear function.
205 * Note that the GL_COLOR_BUFFER_BIT flag will expand to 0, 1, 2 or 4
206 * of the BUFFER_BIT_FRONT/BACK_LEFT/RIGHT flags, or one of the
207 * BUFFER_BIT_COLORn flags.
208 */
209 bufferMask = 0;
210 if (mask & GL_COLOR_BUFFER_BIT) {
211 GLuint i;
212 for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
213 bufferMask |= (1 << ctx->DrawBuffer->_ColorDrawBufferIndexes[i]);
214 }
215 }
216
217 if ((mask & GL_DEPTH_BUFFER_BIT)
218 && ctx->DrawBuffer->Visual.haveDepthBuffer) {
219 bufferMask |= BUFFER_BIT_DEPTH;
220 }
221
222 if ((mask & GL_STENCIL_BUFFER_BIT)
223 && ctx->DrawBuffer->Visual.haveStencilBuffer) {
224 bufferMask |= BUFFER_BIT_STENCIL;
225 }
226
227 if ((mask & GL_ACCUM_BUFFER_BIT)
228 && ctx->DrawBuffer->Visual.haveAccumBuffer) {
229 bufferMask |= BUFFER_BIT_ACCUM;
230 }
231
232 ASSERT(ctx->Driver.Clear);
233 ctx->Driver.Clear(ctx, bufferMask);
234 }
235 }
236
237
238 /** Returned by make_color_buffer_mask() for errors */
239 #define INVALID_MASK ~0x0
240
241
242 /**
243 * Convert the glClearBuffer 'drawbuffer' parameter into a bitmask of
244 * BUFFER_BIT_x values.
245 * Return INVALID_MASK if the drawbuffer value is invalid.
246 */
247 static GLbitfield
248 make_color_buffer_mask(struct gl_context *ctx, GLint drawbuffer)
249 {
250 const struct gl_renderbuffer_attachment *att = ctx->DrawBuffer->Attachment;
251 GLbitfield mask = 0x0;
252
253 switch (drawbuffer) {
254 case GL_FRONT:
255 if (att[BUFFER_FRONT_LEFT].Renderbuffer)
256 mask |= BUFFER_BIT_FRONT_LEFT;
257 if (att[BUFFER_FRONT_RIGHT].Renderbuffer)
258 mask |= BUFFER_BIT_FRONT_RIGHT;
259 break;
260 case GL_BACK:
261 if (att[BUFFER_BACK_LEFT].Renderbuffer)
262 mask |= BUFFER_BIT_BACK_LEFT;
263 if (att[BUFFER_BACK_RIGHT].Renderbuffer)
264 mask |= BUFFER_BIT_BACK_RIGHT;
265 break;
266 case GL_LEFT:
267 if (att[BUFFER_FRONT_LEFT].Renderbuffer)
268 mask |= BUFFER_BIT_FRONT_LEFT;
269 if (att[BUFFER_BACK_LEFT].Renderbuffer)
270 mask |= BUFFER_BIT_BACK_LEFT;
271 break;
272 case GL_RIGHT:
273 if (att[BUFFER_FRONT_RIGHT].Renderbuffer)
274 mask |= BUFFER_BIT_FRONT_RIGHT;
275 if (att[BUFFER_BACK_RIGHT].Renderbuffer)
276 mask |= BUFFER_BIT_BACK_RIGHT;
277 break;
278 case GL_FRONT_AND_BACK:
279 if (att[BUFFER_FRONT_LEFT].Renderbuffer)
280 mask |= BUFFER_BIT_FRONT_LEFT;
281 if (att[BUFFER_BACK_LEFT].Renderbuffer)
282 mask |= BUFFER_BIT_BACK_LEFT;
283 if (att[BUFFER_FRONT_RIGHT].Renderbuffer)
284 mask |= BUFFER_BIT_FRONT_RIGHT;
285 if (att[BUFFER_BACK_RIGHT].Renderbuffer)
286 mask |= BUFFER_BIT_BACK_RIGHT;
287 break;
288 default:
289 if (drawbuffer < 0 || drawbuffer >= (GLint)ctx->Const.MaxDrawBuffers) {
290 mask = INVALID_MASK;
291 }
292 else if (att[BUFFER_COLOR0 + drawbuffer].Renderbuffer) {
293 mask |= (BUFFER_BIT_COLOR0 << drawbuffer);
294 }
295 }
296
297 return mask;
298 }
299
300
301
302 /**
303 * New in GL 3.0
304 * Clear signed integer color buffer or stencil buffer (not depth).
305 */
306 void GLAPIENTRY
307 _mesa_ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *value)
308 {
309 GET_CURRENT_CONTEXT(ctx);
310 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
311
312 FLUSH_CURRENT(ctx, 0);
313
314 if (ctx->NewState) {
315 _mesa_update_state( ctx );
316 }
317
318 switch (buffer) {
319 case GL_STENCIL:
320 /* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
321 *
322 * "ClearBuffer generates an INVALID VALUE error if buffer is
323 * COLOR and drawbuffer is less than zero, or greater than the
324 * value of MAX DRAW BUFFERS minus one; or if buffer is DEPTH,
325 * STENCIL, or DEPTH STENCIL and drawbuffer is not zero."
326 */
327 if (drawbuffer != 0) {
328 _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferiv(drawbuffer=%d)",
329 drawbuffer);
330 return;
331 }
332 else if (ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer && !ctx->RasterDiscard) {
333 /* Save current stencil clear value, set to 'value', do the
334 * stencil clear and restore the clear value.
335 * XXX in the future we may have a new ctx->Driver.ClearBuffer()
336 * hook instead.
337 */
338 const GLuint clearSave = ctx->Stencil.Clear;
339 ctx->Stencil.Clear = *value;
340 ctx->Driver.Clear(ctx, BUFFER_BIT_STENCIL);
341 ctx->Stencil.Clear = clearSave;
342 }
343 break;
344 case GL_COLOR:
345 {
346 const GLbitfield mask = make_color_buffer_mask(ctx, drawbuffer);
347 if (mask == INVALID_MASK) {
348 _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferiv(drawbuffer=%d)",
349 drawbuffer);
350 return;
351 }
352 else if (mask && !ctx->RasterDiscard) {
353 union gl_color_union clearSave;
354
355 /* save color */
356 clearSave = ctx->Color.ClearColor;
357 /* set color */
358 COPY_4V(ctx->Color.ClearColor.i, value);
359 /* clear buffer(s) */
360 ctx->Driver.Clear(ctx, mask);
361 /* restore color */
362 ctx->Color.ClearColor = clearSave;
363 }
364 }
365 break;
366 case GL_DEPTH:
367 /* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
368 *
369 * "The result of ClearBuffer is undefined if no conversion between
370 * the type of the specified value and the type of the buffer being
371 * cleared is defined (for example, if ClearBufferiv is called for a
372 * fixed- or floating-point buffer, or if ClearBufferfv is called
373 * for a signed or unsigned integer buffer). This is not an error."
374 *
375 * In this case we take "undefined" and "not an error" to mean "ignore."
376 * Note that we still need to generate an error for the invalid
377 * drawbuffer case (see the GL_STENCIL case above).
378 */
379 if (drawbuffer != 0) {
380 _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferiv(drawbuffer=%d)",
381 drawbuffer);
382 return;
383 }
384 return;
385 default:
386 _mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferiv(buffer=%s)",
387 _mesa_lookup_enum_by_nr(buffer));
388 return;
389 }
390 }
391
392
393 /**
394 * New in GL 3.0
395 * Clear unsigned integer color buffer (not depth, not stencil).
396 */
397 void GLAPIENTRY
398 _mesa_ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *value)
399 {
400 GET_CURRENT_CONTEXT(ctx);
401 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
402
403 FLUSH_CURRENT(ctx, 0);
404
405 if (ctx->NewState) {
406 _mesa_update_state( ctx );
407 }
408
409 switch (buffer) {
410 case GL_COLOR:
411 {
412 const GLbitfield mask = make_color_buffer_mask(ctx, drawbuffer);
413 if (mask == INVALID_MASK) {
414 _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferuiv(drawbuffer=%d)",
415 drawbuffer);
416 return;
417 }
418 else if (mask && !ctx->RasterDiscard) {
419 union gl_color_union clearSave;
420
421 /* save color */
422 clearSave = ctx->Color.ClearColor;
423 /* set color */
424 COPY_4V(ctx->Color.ClearColor.ui, value);
425 /* clear buffer(s) */
426 ctx->Driver.Clear(ctx, mask);
427 /* restore color */
428 ctx->Color.ClearColor = clearSave;
429 }
430 }
431 break;
432 case GL_DEPTH:
433 case GL_STENCIL:
434 /* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
435 *
436 * "The result of ClearBuffer is undefined if no conversion between
437 * the type of the specified value and the type of the buffer being
438 * cleared is defined (for example, if ClearBufferiv is called for a
439 * fixed- or floating-point buffer, or if ClearBufferfv is called
440 * for a signed or unsigned integer buffer). This is not an error."
441 *
442 * In this case we take "undefined" and "not an error" to mean "ignore."
443 * Even though we could do something sensible for GL_STENCIL, page 263
444 * (page 279 of the PDF) says:
445 *
446 * "Only ClearBufferiv should be used to clear stencil buffers."
447 *
448 * Note that we still need to generate an error for the invalid
449 * drawbuffer case (see the GL_STENCIL case in _mesa_ClearBufferiv).
450 */
451 if (drawbuffer != 0) {
452 _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferuiv(drawbuffer=%d)",
453 drawbuffer);
454 return;
455 }
456 return;
457 default:
458 _mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferuiv(buffer=%s)",
459 _mesa_lookup_enum_by_nr(buffer));
460 return;
461 }
462 }
463
464
465 /**
466 * New in GL 3.0
467 * Clear fixed-pt or float color buffer or depth buffer (not stencil).
468 */
469 void GLAPIENTRY
470 _mesa_ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value)
471 {
472 GET_CURRENT_CONTEXT(ctx);
473 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
474
475 FLUSH_CURRENT(ctx, 0);
476
477 if (ctx->NewState) {
478 _mesa_update_state( ctx );
479 }
480
481 switch (buffer) {
482 case GL_DEPTH:
483 /* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
484 *
485 * "ClearBuffer generates an INVALID VALUE error if buffer is
486 * COLOR and drawbuffer is less than zero, or greater than the
487 * value of MAX DRAW BUFFERS minus one; or if buffer is DEPTH,
488 * STENCIL, or DEPTH STENCIL and drawbuffer is not zero."
489 */
490 if (drawbuffer != 0) {
491 _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferfv(drawbuffer=%d)",
492 drawbuffer);
493 return;
494 }
495 else if (ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer && !ctx->RasterDiscard) {
496 /* Save current depth clear value, set to 'value', do the
497 * depth clear and restore the clear value.
498 * XXX in the future we may have a new ctx->Driver.ClearBuffer()
499 * hook instead.
500 */
501 const GLclampd clearSave = ctx->Depth.Clear;
502 ctx->Depth.Clear = *value;
503 ctx->Driver.Clear(ctx, BUFFER_BIT_DEPTH);
504 ctx->Depth.Clear = clearSave;
505 }
506 /* clear depth buffer to value */
507 break;
508 case GL_COLOR:
509 {
510 const GLbitfield mask = make_color_buffer_mask(ctx, drawbuffer);
511 if (mask == INVALID_MASK) {
512 _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferfv(drawbuffer=%d)",
513 drawbuffer);
514 return;
515 }
516 else if (mask && !ctx->RasterDiscard) {
517 union gl_color_union clearSave;
518
519 /* save color */
520 clearSave = ctx->Color.ClearColor;
521 /* set color */
522 COPY_4V(ctx->Color.ClearColor.f, value);
523 /* clear buffer(s) */
524 ctx->Driver.Clear(ctx, mask);
525 /* restore color */
526 ctx->Color.ClearColor = clearSave;
527 }
528 }
529 break;
530 case GL_STENCIL:
531 /* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
532 *
533 * "The result of ClearBuffer is undefined if no conversion between
534 * the type of the specified value and the type of the buffer being
535 * cleared is defined (for example, if ClearBufferiv is called for a
536 * fixed- or floating-point buffer, or if ClearBufferfv is called
537 * for a signed or unsigned integer buffer). This is not an error."
538 *
539 * In this case we take "undefined" and "not an error" to mean "ignore."
540 * Note that we still need to generate an error for the invalid
541 * drawbuffer case (see the GL_DEPTH case above).
542 */
543 if (drawbuffer != 0) {
544 _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferfv(drawbuffer=%d)",
545 drawbuffer);
546 return;
547 }
548 return;
549 default:
550 _mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferfv(buffer=%s)",
551 _mesa_lookup_enum_by_nr(buffer));
552 return;
553 }
554 }
555
556
557 /**
558 * New in GL 3.0
559 * Clear depth/stencil buffer only.
560 */
561 void GLAPIENTRY
562 _mesa_ClearBufferfi(GLenum buffer, GLint drawbuffer,
563 GLfloat depth, GLint stencil)
564 {
565 GET_CURRENT_CONTEXT(ctx);
566 GLbitfield mask = 0;
567
568 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
569
570 FLUSH_CURRENT(ctx, 0);
571
572 if (buffer != GL_DEPTH_STENCIL) {
573 _mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferfi(buffer=%s)",
574 _mesa_lookup_enum_by_nr(buffer));
575 return;
576 }
577
578 /* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
579 *
580 * "ClearBuffer generates an INVALID VALUE error if buffer is
581 * COLOR and drawbuffer is less than zero, or greater than the
582 * value of MAX DRAW BUFFERS minus one; or if buffer is DEPTH,
583 * STENCIL, or DEPTH STENCIL and drawbuffer is not zero."
584 */
585 if (drawbuffer != 0) {
586 _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferfi(drawbuffer=%d)",
587 drawbuffer);
588 return;
589 }
590
591 if (ctx->RasterDiscard)
592 return;
593
594 if (ctx->NewState) {
595 _mesa_update_state( ctx );
596 }
597
598 if (ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer)
599 mask |= BUFFER_BIT_DEPTH;
600 if (ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer)
601 mask |= BUFFER_BIT_STENCIL;
602
603 if (mask) {
604 /* save current clear values */
605 const GLclampd clearDepthSave = ctx->Depth.Clear;
606 const GLuint clearStencilSave = ctx->Stencil.Clear;
607
608 /* set new clear values */
609 ctx->Depth.Clear = depth;
610 ctx->Stencil.Clear = stencil;
611
612 /* clear buffers */
613 ctx->Driver.Clear(ctx, mask);
614
615 /* restore */
616 ctx->Depth.Clear = clearDepthSave;
617 ctx->Stencil.Clear = clearStencilSave;
618 }
619 }