• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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  * Convert a boolean color mask to a packed color where each channel of
40  * the packed value at dst will be 0 or ~0 depending on the colorMask.
41  */
42 static void
_pack_colormask(mesa_format format,const uint8_t colorMask[4],void * dst)43 _pack_colormask(mesa_format format, const uint8_t colorMask[4], void *dst)
44 {
45    float maskColor[4];
46 
47    switch (_mesa_get_format_datatype(format)) {
48    case GL_UNSIGNED_NORMALIZED:
49       /* simple: 1.0 will convert to ~0 in the right bit positions */
50       maskColor[0] = colorMask[0] ? 1.0f : 0.0f;
51       maskColor[1] = colorMask[1] ? 1.0f : 0.0f;
52       maskColor[2] = colorMask[2] ? 1.0f : 0.0f;
53       maskColor[3] = colorMask[3] ? 1.0f : 0.0f;
54       _mesa_pack_float_rgba_row(format, 1,
55                                 (const float (*)[4]) maskColor, dst);
56       break;
57    case GL_SIGNED_NORMALIZED:
58    case GL_FLOAT:
59       /* These formats are harder because it's hard to know the floating
60        * point values that will convert to ~0 for each color channel's bits.
61        * This solution just generates a non-zero value for each color channel
62        * then fixes up the non-zero values to be ~0.
63        * Note: we'll need to add special case code if we ever have to deal
64        * with formats with unequal color channel sizes, like R11_G11_B10.
65        * We issue a warning below for channel sizes other than 8,16,32.
66        */
67       {
68          uint32_t bits = _mesa_get_format_max_bits(format); /* bits per chan */
69          uint32_t bytes = _mesa_get_format_bytes(format);
70          uint32_t i;
71 
72          /* this should put non-zero values into the channels of dst */
73          maskColor[0] = colorMask[0] ? -1.0f : 0.0f;
74          maskColor[1] = colorMask[1] ? -1.0f : 0.0f;
75          maskColor[2] = colorMask[2] ? -1.0f : 0.0f;
76          maskColor[3] = colorMask[3] ? -1.0f : 0.0f;
77          _mesa_pack_float_rgba_row(format, 1,
78                                    (const float (*)[4]) maskColor, dst);
79 
80          /* fix-up the dst channels by converting non-zero values to ~0 */
81          if (bits == 8) {
82             uint8_t *d = (uint8_t *) dst;
83             for (i = 0; i < bytes; i++) {
84                d[i] = d[i] ? 0xff : 0x0;
85             }
86          }
87          else if (bits == 16) {
88             uint16_t *d = (uint16_t *) dst;
89             for (i = 0; i < bytes / 2; i++) {
90                d[i] = d[i] ? 0xffff : 0x0;
91             }
92          }
93          else if (bits == 32) {
94             uint32_t *d = (uint32_t *) dst;
95             for (i = 0; i < bytes / 4; i++) {
96                d[i] = d[i] ? 0xffffffffU : 0x0;
97             }
98          }
99          else {
100             unreachable("unexpected size in _mesa_pack_colormask()");
101          }
102       }
103       break;
104    default:
105       unreachable("unexpected format data type in gen_color_mask()");
106    }
107 }
108 
109 /**
110  * Clear an rgba color buffer with masking if needed.
111  */
112 static void
clear_rgba_buffer(struct gl_context * ctx,struct gl_renderbuffer * rb,const GLubyte colorMask[4])113 clear_rgba_buffer(struct gl_context *ctx, struct gl_renderbuffer *rb,
114                   const GLubyte colorMask[4])
115 {
116    const GLint x = ctx->DrawBuffer->_Xmin;
117    const GLint y = ctx->DrawBuffer->_Ymin;
118    const GLint height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
119    const GLint width  = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
120    const GLuint pixelSize = _mesa_get_format_bytes(rb->Format);
121    const GLboolean doMasking = (colorMask[0] == 0 ||
122                                 colorMask[1] == 0 ||
123                                 colorMask[2] == 0 ||
124                                 colorMask[3] == 0);
125    const GLfloat (*clearColor)[4] =
126       (const GLfloat (*)[4]) ctx->Color.ClearColor.f;
127    GLbitfield mapMode = GL_MAP_WRITE_BIT;
128    GLubyte *map;
129    GLint rowStride;
130    GLint i, j;
131 
132    if (doMasking) {
133       /* we'll need to read buffer values too */
134       mapMode |= GL_MAP_READ_BIT;
135    }
136 
137    /* map dest buffer */
138    ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height,
139                                mapMode, &map, &rowStride,
140                                ctx->DrawBuffer->FlipY);
141    if (!map) {
142       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear(color)");
143       return;
144    }
145 
146    /* for 1, 2, 4-byte clearing */
147 #define SIMPLE_TYPE_CLEAR(TYPE)                                         \
148    do {                                                                 \
149       TYPE pixel, pixelMask;                                            \
150       _mesa_pack_float_rgba_row(rb->Format, 1, clearColor, &pixel);     \
151       if (doMasking) {                                                  \
152          _pack_colormask(rb->Format, colorMask, &pixelMask);            \
153          pixel &= pixelMask;                                            \
154          pixelMask = ~pixelMask;                                        \
155       }                                                                 \
156       for (i = 0; i < height; i++) {                                    \
157          TYPE *row = (TYPE *) map;                                      \
158          if (doMasking) {                                               \
159             for (j = 0; j < width; j++) {                               \
160                row[j] = (row[j] & pixelMask) | pixel;                   \
161             }                                                           \
162          }                                                              \
163          else {                                                         \
164             for (j = 0; j < width; j++) {                               \
165                row[j] = pixel;                                          \
166             }                                                           \
167          }                                                              \
168          map += rowStride;                                              \
169       }                                                                 \
170    } while (0)
171 
172 
173    /* for 3, 6, 8, 12, 16-byte clearing */
174 #define MULTI_WORD_CLEAR(TYPE, N)                                       \
175    do {                                                                 \
176       TYPE pixel[N], pixelMask[N];                                      \
177       GLuint k;                                                         \
178       _mesa_pack_float_rgba_row(rb->Format, 1, clearColor, pixel);      \
179       if (doMasking) {                                                  \
180          _pack_colormask(rb->Format, colorMask, pixelMask);             \
181          for (k = 0; k < N; k++) {                                      \
182             pixel[k] &= pixelMask[k];                                   \
183             pixelMask[k] = ~pixelMask[k];                               \
184          }                                                              \
185       }                                                                 \
186       for (i = 0; i < height; i++) {                                    \
187          TYPE *row = (TYPE *) map;                                      \
188          if (doMasking) {                                               \
189             for (j = 0; j < width; j++) {                               \
190                for (k = 0; k < N; k++) {                                \
191                   row[j * N + k] =                                      \
192                      (row[j * N + k] & pixelMask[k]) | pixel[k];        \
193                }                                                        \
194             }                                                           \
195          }                                                              \
196          else {                                                         \
197             for (j = 0; j < width; j++) {                               \
198                for (k = 0; k < N; k++) {                                \
199                   row[j * N + k] = pixel[k];                            \
200                }                                                        \
201             }                                                           \
202          }                                                              \
203          map += rowStride;                                              \
204       }                                                                 \
205    } while(0)
206 
207    switch (pixelSize) {
208    case 1:
209       SIMPLE_TYPE_CLEAR(GLubyte);
210       break;
211    case 2:
212       SIMPLE_TYPE_CLEAR(GLushort);
213       break;
214    case 3:
215       MULTI_WORD_CLEAR(GLubyte, 3);
216       break;
217    case 4:
218       SIMPLE_TYPE_CLEAR(GLuint);
219       break;
220    case 6:
221       MULTI_WORD_CLEAR(GLushort, 3);
222       break;
223    case 8:
224       MULTI_WORD_CLEAR(GLuint, 2);
225       break;
226    case 12:
227       MULTI_WORD_CLEAR(GLuint, 3);
228       break;
229    case 16:
230       MULTI_WORD_CLEAR(GLuint, 4);
231       break;
232    default:
233       _mesa_problem(ctx, "bad pixel size in clear_rgba_buffer()");
234    }
235 
236    /* unmap buffer */
237    ctx->Driver.UnmapRenderbuffer(ctx, rb);
238 }
239 
240 
241 /**
242  * Clear the front/back/left/right/aux color buffers.
243  * This function is usually only called if the device driver can't
244  * clear its own color buffers for some reason (such as with masking).
245  */
246 static void
clear_color_buffers(struct gl_context * ctx)247 clear_color_buffers(struct gl_context *ctx)
248 {
249    GLuint buf;
250 
251    for (buf = 0; buf < ctx->DrawBuffer->_NumColorDrawBuffers; buf++) {
252       struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[buf];
253 
254       /* If this is an ES2 context or GL_ARB_ES2_compatibility is supported,
255        * the framebuffer can be complete with some attachments be missing.  In
256        * this case the _ColorDrawBuffers pointer will be NULL.
257        */
258       if (rb == NULL)
259 	 continue;
260 
261       const GLubyte colormask[4] = {
262          GET_COLORMASK_BIT(ctx->Color.ColorMask, buf, 0) ? 0xff : 0,
263          GET_COLORMASK_BIT(ctx->Color.ColorMask, buf, 1) ? 0xff : 0,
264          GET_COLORMASK_BIT(ctx->Color.ColorMask, buf, 2) ? 0xff : 0,
265          GET_COLORMASK_BIT(ctx->Color.ColorMask, buf, 3) ? 0xff : 0,
266       };
267       clear_rgba_buffer(ctx, rb, colormask);
268    }
269 }
270 
271 
272 /**
273  * Called via the device driver's ctx->Driver.Clear() function if the
274  * device driver can't clear one or more of the buffers itself.
275  * \param buffers  bitfield of BUFFER_BIT_* values indicating which
276  *                 renderbuffers are to be cleared.
277  * \param all  if GL_TRUE, clear whole buffer, else clear specified region.
278  */
279 void
_swrast_Clear(struct gl_context * ctx,GLbitfield buffers)280 _swrast_Clear(struct gl_context *ctx, GLbitfield buffers)
281 {
282    const GLbitfield BUFFER_DS = BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL;
283 
284 #ifdef DEBUG_FOO
285    {
286       const GLbitfield legalBits =
287          BUFFER_BIT_FRONT_LEFT |
288 	 BUFFER_BIT_FRONT_RIGHT |
289 	 BUFFER_BIT_BACK_LEFT |
290 	 BUFFER_BIT_BACK_RIGHT |
291 	 BUFFER_BIT_DEPTH |
292 	 BUFFER_BIT_STENCIL |
293 	 BUFFER_BIT_ACCUM;
294       assert((buffers & (~legalBits)) == 0);
295    }
296 #endif
297 
298    if (!_mesa_check_conditional_render(ctx))
299       return; /* don't clear */
300 
301    if (SWRAST_CONTEXT(ctx)->NewState)
302       _swrast_validate_derived(ctx);
303 
304    if ((buffers & BUFFER_BITS_COLOR)
305        && (ctx->DrawBuffer->_NumColorDrawBuffers > 0)) {
306       clear_color_buffers(ctx);
307    }
308 
309    if (buffers & BUFFER_BIT_ACCUM) {
310       _mesa_clear_accum_buffer(ctx);
311    }
312 
313    if (buffers & BUFFER_DS) {
314       struct gl_renderbuffer *depthRb =
315          ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
316       struct gl_renderbuffer *stencilRb =
317          ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
318 
319       if ((buffers & BUFFER_DS) == BUFFER_DS && depthRb == stencilRb) {
320          /* clear depth and stencil together */
321          _swrast_clear_depth_stencil_buffer(ctx);
322       }
323       else {
324          /* clear depth, stencil separately */
325          if (buffers & BUFFER_BIT_DEPTH) {
326             _swrast_clear_depth_buffer(ctx);
327          }
328          if (buffers & BUFFER_BIT_STENCIL) {
329             _swrast_clear_stencil_buffer(ctx);
330          }
331       }
332    }
333 }
334