1 /*
2  * Mesa 3-D graphics library
3  * Version:  7.1
4  *
5  * Copyright (C) 1999-2008  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 #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  */
42 static void
clear_rgba_buffer(struct gl_context * ctx,struct gl_renderbuffer * rb,const GLubyte colorMask[4])43 clear_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    if (!map) {
71       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear(color)");
72       return;
73    }
74 
75    /* for 1, 2, 4-byte clearing */
76 #define SIMPLE_TYPE_CLEAR(TYPE)                                         \
77    do {                                                                 \
78       TYPE pixel, pixelMask;                                            \
79       _mesa_pack_float_rgba_row(rb->Format, 1, clearColor, &pixel);     \
80       if (doMasking) {                                                  \
81          _mesa_pack_colormask(rb->Format, colorMask, &pixelMask);       \
82          pixel &= pixelMask;                                            \
83          pixelMask = ~pixelMask;                                        \
84       }                                                                 \
85       for (i = 0; i < height; i++) {                                    \
86          TYPE *row = (TYPE *) map;                                      \
87          if (doMasking) {                                               \
88             for (j = 0; j < width; j++) {                               \
89                row[j] = (row[j] & pixelMask) | pixel;                   \
90             }                                                           \
91          }                                                              \
92          else {                                                         \
93             for (j = 0; j < width; j++) {                               \
94                row[j] = pixel;                                          \
95             }                                                           \
96          }                                                              \
97          map += rowStride;                                              \
98       }                                                                 \
99    } while (0)
100 
101 
102    /* for 3, 6, 8, 12, 16-byte clearing */
103 #define MULTI_WORD_CLEAR(TYPE, N)                                       \
104    do {                                                                 \
105       TYPE pixel[N], pixelMask[N];                                      \
106       GLuint k;                                                         \
107       _mesa_pack_float_rgba_row(rb->Format, 1, clearColor, pixel);      \
108       if (doMasking) {                                                  \
109          _mesa_pack_colormask(rb->Format, colorMask, pixelMask);        \
110          for (k = 0; k < N; k++) {                                      \
111             pixel[k] &= pixelMask[k];                                   \
112             pixelMask[k] = ~pixelMask[k];                               \
113          }                                                              \
114       }                                                                 \
115       for (i = 0; i < height; i++) {                                    \
116          TYPE *row = (TYPE *) map;                                      \
117          if (doMasking) {                                               \
118             for (j = 0; j < width; j++) {                               \
119                for (k = 0; k < N; k++) {                                \
120                   row[j * N + k] =                                      \
121                      (row[j * N + k] & pixelMask[k]) | pixel[k];        \
122                }                                                        \
123             }                                                           \
124          }                                                              \
125          else {                                                         \
126             for (j = 0; j < width; j++) {                               \
127                for (k = 0; k < N; k++) {                                \
128                   row[j * N + k] = pixel[k];                            \
129                }                                                        \
130             }                                                           \
131          }                                                              \
132          map += rowStride;                                              \
133       }                                                                 \
134    } while(0)
135 
136    switch (pixelSize) {
137    case 1:
138       SIMPLE_TYPE_CLEAR(GLubyte);
139       break;
140    case 2:
141       SIMPLE_TYPE_CLEAR(GLushort);
142       break;
143    case 3:
144       MULTI_WORD_CLEAR(GLubyte, 3);
145       break;
146    case 4:
147       SIMPLE_TYPE_CLEAR(GLuint);
148       break;
149    case 6:
150       MULTI_WORD_CLEAR(GLushort, 3);
151       break;
152    case 8:
153       MULTI_WORD_CLEAR(GLuint, 2);
154       break;
155    case 12:
156       MULTI_WORD_CLEAR(GLuint, 3);
157       break;
158    case 16:
159       MULTI_WORD_CLEAR(GLuint, 4);
160       break;
161    default:
162       _mesa_problem(ctx, "bad pixel size in clear_rgba_buffer()");
163    }
164 
165    /* unmap buffer */
166    ctx->Driver.UnmapRenderbuffer(ctx, rb);
167 }
168 
169 
170 /**
171  * Clear the front/back/left/right/aux color buffers.
172  * This function is usually only called if the device driver can't
173  * clear its own color buffers for some reason (such as with masking).
174  */
175 static void
clear_color_buffers(struct gl_context * ctx)176 clear_color_buffers(struct gl_context *ctx)
177 {
178    GLuint buf;
179 
180    for (buf = 0; buf < ctx->DrawBuffer->_NumColorDrawBuffers; buf++) {
181       struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[buf];
182 
183       /* If this is an ES2 context or GL_ARB_ES2_compatibility is supported,
184        * the framebuffer can be complete with some attachments be missing.  In
185        * this case the _ColorDrawBuffers pointer will be NULL.
186        */
187       if (rb == NULL)
188 	 continue;
189 
190       clear_rgba_buffer(ctx, rb, ctx->Color.ColorMask[buf]);
191    }
192 }
193 
194 
195 /**
196  * Called via the device driver's ctx->Driver.Clear() function if the
197  * device driver can't clear one or more of the buffers itself.
198  * \param buffers  bitfield of BUFFER_BIT_* values indicating which
199  *                 renderbuffers are to be cleared.
200  * \param all  if GL_TRUE, clear whole buffer, else clear specified region.
201  */
202 void
_swrast_Clear(struct gl_context * ctx,GLbitfield buffers)203 _swrast_Clear(struct gl_context *ctx, GLbitfield buffers)
204 {
205    const GLbitfield BUFFER_DS = BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL;
206 
207 #ifdef DEBUG_FOO
208    {
209       const GLbitfield legalBits =
210          BUFFER_BIT_FRONT_LEFT |
211 	 BUFFER_BIT_FRONT_RIGHT |
212 	 BUFFER_BIT_BACK_LEFT |
213 	 BUFFER_BIT_BACK_RIGHT |
214 	 BUFFER_BIT_DEPTH |
215 	 BUFFER_BIT_STENCIL |
216 	 BUFFER_BIT_ACCUM |
217          BUFFER_BIT_AUX0;
218       assert((buffers & (~legalBits)) == 0);
219    }
220 #endif
221 
222    if (!_mesa_check_conditional_render(ctx))
223       return; /* don't clear */
224 
225    if (SWRAST_CONTEXT(ctx)->NewState)
226       _swrast_validate_derived(ctx);
227 
228    if ((buffers & BUFFER_BITS_COLOR)
229        && (ctx->DrawBuffer->_NumColorDrawBuffers > 0)) {
230       clear_color_buffers(ctx);
231    }
232 
233    if (buffers & BUFFER_BIT_ACCUM) {
234       _mesa_clear_accum_buffer(ctx);
235    }
236 
237    if (buffers & BUFFER_DS) {
238       struct gl_renderbuffer *depthRb =
239          ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
240       struct gl_renderbuffer *stencilRb =
241          ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
242 
243       if ((buffers & BUFFER_DS) == BUFFER_DS && depthRb == stencilRb) {
244          /* clear depth and stencil together */
245          _swrast_clear_depth_stencil_buffer(ctx);
246       }
247       else {
248          /* clear depth, stencil separately */
249          if (buffers & BUFFER_BIT_DEPTH) {
250             _swrast_clear_depth_buffer(ctx);
251          }
252          if (buffers & BUFFER_BIT_STENCIL) {
253             _swrast_clear_stencil_buffer(ctx);
254          }
255       }
256    }
257 }
258