1/*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25#include "main/glheader.h"
26#include "main/accum.h"
27#include "main/condrender.h"
28#include "main/format_pack.h"
29#include "main/macros.h"
30#include "main/imports.h"
31#include "main/mtypes.h"
32
33#include "s_context.h"
34#include "s_depth.h"
35#include "s_stencil.h"
36
37
38
39/**
40 * Clear an rgba color buffer with masking if needed.
41 */
42static void
43clear_rgba_buffer(struct gl_context *ctx, struct gl_renderbuffer *rb,
44                  const GLubyte colorMask[4])
45{
46   const GLint x = ctx->DrawBuffer->_Xmin;
47   const GLint y = ctx->DrawBuffer->_Ymin;
48   const GLint height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
49   const GLint width  = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
50   const GLuint pixelSize = _mesa_get_format_bytes(rb->Format);
51   const GLboolean doMasking = (colorMask[0] == 0 ||
52                                colorMask[1] == 0 ||
53                                colorMask[2] == 0 ||
54                                colorMask[3] == 0);
55   const GLfloat (*clearColor)[4] =
56      (const GLfloat (*)[4]) ctx->Color.ClearColor.f;
57   GLbitfield mapMode = GL_MAP_WRITE_BIT;
58   GLubyte *map;
59   GLint rowStride;
60   GLint i, j;
61
62   if (doMasking) {
63      /* we'll need to read buffer values too */
64      mapMode |= GL_MAP_READ_BIT;
65   }
66
67   /* map dest buffer */
68   ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height,
69                               mapMode, &map, &rowStride,
70                               ctx->DrawBuffer->FlipY);
71   if (!map) {
72      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear(color)");
73      return;
74   }
75
76   /* for 1, 2, 4-byte clearing */
77#define SIMPLE_TYPE_CLEAR(TYPE)                                         \
78   do {                                                                 \
79      TYPE pixel, pixelMask;                                            \
80      _mesa_pack_float_rgba_row(rb->Format, 1, clearColor, &pixel);     \
81      if (doMasking) {                                                  \
82         _mesa_pack_colormask(rb->Format, colorMask, &pixelMask);       \
83         pixel &= pixelMask;                                            \
84         pixelMask = ~pixelMask;                                        \
85      }                                                                 \
86      for (i = 0; i < height; i++) {                                    \
87         TYPE *row = (TYPE *) map;                                      \
88         if (doMasking) {                                               \
89            for (j = 0; j < width; j++) {                               \
90               row[j] = (row[j] & pixelMask) | pixel;                   \
91            }                                                           \
92         }                                                              \
93         else {                                                         \
94            for (j = 0; j < width; j++) {                               \
95               row[j] = pixel;                                          \
96            }                                                           \
97         }                                                              \
98         map += rowStride;                                              \
99      }                                                                 \
100   } while (0)
101
102
103   /* for 3, 6, 8, 12, 16-byte clearing */
104#define MULTI_WORD_CLEAR(TYPE, N)                                       \
105   do {                                                                 \
106      TYPE pixel[N], pixelMask[N];                                      \
107      GLuint k;                                                         \
108      _mesa_pack_float_rgba_row(rb->Format, 1, clearColor, pixel);      \
109      if (doMasking) {                                                  \
110         _mesa_pack_colormask(rb->Format, colorMask, pixelMask);        \
111         for (k = 0; k < N; k++) {                                      \
112            pixel[k] &= pixelMask[k];                                   \
113            pixelMask[k] = ~pixelMask[k];                               \
114         }                                                              \
115      }                                                                 \
116      for (i = 0; i < height; i++) {                                    \
117         TYPE *row = (TYPE *) map;                                      \
118         if (doMasking) {                                               \
119            for (j = 0; j < width; j++) {                               \
120               for (k = 0; k < N; k++) {                                \
121                  row[j * N + k] =                                      \
122                     (row[j * N + k] & pixelMask[k]) | pixel[k];        \
123               }                                                        \
124            }                                                           \
125         }                                                              \
126         else {                                                         \
127            for (j = 0; j < width; j++) {                               \
128               for (k = 0; k < N; k++) {                                \
129                  row[j * N + k] = pixel[k];                            \
130               }                                                        \
131            }                                                           \
132         }                                                              \
133         map += rowStride;                                              \
134      }                                                                 \
135   } while(0)
136
137   switch (pixelSize) {
138   case 1:
139      SIMPLE_TYPE_CLEAR(GLubyte);
140      break;
141   case 2:
142      SIMPLE_TYPE_CLEAR(GLushort);
143      break;
144   case 3:
145      MULTI_WORD_CLEAR(GLubyte, 3);
146      break;
147   case 4:
148      SIMPLE_TYPE_CLEAR(GLuint);
149      break;
150   case 6:
151      MULTI_WORD_CLEAR(GLushort, 3);
152      break;
153   case 8:
154      MULTI_WORD_CLEAR(GLuint, 2);
155      break;
156   case 12:
157      MULTI_WORD_CLEAR(GLuint, 3);
158      break;
159   case 16:
160      MULTI_WORD_CLEAR(GLuint, 4);
161      break;
162   default:
163      _mesa_problem(ctx, "bad pixel size in clear_rgba_buffer()");
164   }
165
166   /* unmap buffer */
167   ctx->Driver.UnmapRenderbuffer(ctx, rb);
168}
169
170
171/**
172 * Clear the front/back/left/right/aux color buffers.
173 * This function is usually only called if the device driver can't
174 * clear its own color buffers for some reason (such as with masking).
175 */
176static void
177clear_color_buffers(struct gl_context *ctx)
178{
179   GLuint buf;
180
181   for (buf = 0; buf < ctx->DrawBuffer->_NumColorDrawBuffers; buf++) {
182      struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[buf];
183
184      /* If this is an ES2 context or GL_ARB_ES2_compatibility is supported,
185       * the framebuffer can be complete with some attachments be missing.  In
186       * this case the _ColorDrawBuffers pointer will be NULL.
187       */
188      if (rb == NULL)
189	 continue;
190
191      const GLubyte colormask[4] = {
192         GET_COLORMASK_BIT(ctx->Color.ColorMask, buf, 0) ? 0xff : 0,
193         GET_COLORMASK_BIT(ctx->Color.ColorMask, buf, 1) ? 0xff : 0,
194         GET_COLORMASK_BIT(ctx->Color.ColorMask, buf, 2) ? 0xff : 0,
195         GET_COLORMASK_BIT(ctx->Color.ColorMask, buf, 3) ? 0xff : 0,
196      };
197      clear_rgba_buffer(ctx, rb, colormask);
198   }
199}
200
201
202/**
203 * Called via the device driver's ctx->Driver.Clear() function if the
204 * device driver can't clear one or more of the buffers itself.
205 * \param buffers  bitfield of BUFFER_BIT_* values indicating which
206 *                 renderbuffers are to be cleared.
207 * \param all  if GL_TRUE, clear whole buffer, else clear specified region.
208 */
209void
210_swrast_Clear(struct gl_context *ctx, GLbitfield buffers)
211{
212   const GLbitfield BUFFER_DS = BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL;
213
214#ifdef DEBUG_FOO
215   {
216      const GLbitfield legalBits =
217         BUFFER_BIT_FRONT_LEFT |
218	 BUFFER_BIT_FRONT_RIGHT |
219	 BUFFER_BIT_BACK_LEFT |
220	 BUFFER_BIT_BACK_RIGHT |
221	 BUFFER_BIT_DEPTH |
222	 BUFFER_BIT_STENCIL |
223	 BUFFER_BIT_ACCUM |
224         BUFFER_BIT_AUX0;
225      assert((buffers & (~legalBits)) == 0);
226   }
227#endif
228
229   if (!_mesa_check_conditional_render(ctx))
230      return; /* don't clear */
231
232   if (SWRAST_CONTEXT(ctx)->NewState)
233      _swrast_validate_derived(ctx);
234
235   if ((buffers & BUFFER_BITS_COLOR)
236       && (ctx->DrawBuffer->_NumColorDrawBuffers > 0)) {
237      clear_color_buffers(ctx);
238   }
239
240   if (buffers & BUFFER_BIT_ACCUM) {
241      _mesa_clear_accum_buffer(ctx);
242   }
243
244   if (buffers & BUFFER_DS) {
245      struct gl_renderbuffer *depthRb =
246         ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
247      struct gl_renderbuffer *stencilRb =
248         ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
249
250      if ((buffers & BUFFER_DS) == BUFFER_DS && depthRb == stencilRb) {
251         /* clear depth and stencil together */
252         _swrast_clear_depth_stencil_buffer(ctx);
253      }
254      else {
255         /* clear depth, stencil separately */
256         if (buffers & BUFFER_BIT_DEPTH) {
257            _swrast_clear_depth_buffer(ctx);
258         }
259         if (buffers & BUFFER_BIT_STENCIL) {
260            _swrast_clear_stencil_buffer(ctx);
261         }
262      }
263   }
264}
265