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