clear.c revision a0bc8eeb3224eec1e713fb9885f5d02c21b30c14
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
44void 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 */
73void 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 */
101void 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 */
132void 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 */
170void 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 */
255static GLbitfield
256make_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 */
314void 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 */
390void 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, "glClearBufferiv(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 */
444void 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 */
517void 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}
567