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