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