mesa: change ctx->Color.ColorMask into a 32-bit bitmask
[mesa.git] / src / mesa / swrast / s_clear.c
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 */
42 static void
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
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 const GLubyte colormask[4] = {
191 GET_COLORMASK_BIT(ctx->Color.ColorMask, buf, 0) ? 0xff : 0,
192 GET_COLORMASK_BIT(ctx->Color.ColorMask, buf, 1) ? 0xff : 0,
193 GET_COLORMASK_BIT(ctx->Color.ColorMask, buf, 2) ? 0xff : 0,
194 GET_COLORMASK_BIT(ctx->Color.ColorMask, buf, 3) ? 0xff : 0,
195 };
196 clear_rgba_buffer(ctx, rb, colormask);
197 }
198 }
199
200
201 /**
202 * Called via the device driver's ctx->Driver.Clear() function if the
203 * device driver can't clear one or more of the buffers itself.
204 * \param buffers bitfield of BUFFER_BIT_* values indicating which
205 * renderbuffers are to be cleared.
206 * \param all if GL_TRUE, clear whole buffer, else clear specified region.
207 */
208 void
209 _swrast_Clear(struct gl_context *ctx, GLbitfield buffers)
210 {
211 const GLbitfield BUFFER_DS = BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL;
212
213 #ifdef DEBUG_FOO
214 {
215 const GLbitfield legalBits =
216 BUFFER_BIT_FRONT_LEFT |
217 BUFFER_BIT_FRONT_RIGHT |
218 BUFFER_BIT_BACK_LEFT |
219 BUFFER_BIT_BACK_RIGHT |
220 BUFFER_BIT_DEPTH |
221 BUFFER_BIT_STENCIL |
222 BUFFER_BIT_ACCUM |
223 BUFFER_BIT_AUX0;
224 assert((buffers & (~legalBits)) == 0);
225 }
226 #endif
227
228 if (!_mesa_check_conditional_render(ctx))
229 return; /* don't clear */
230
231 if (SWRAST_CONTEXT(ctx)->NewState)
232 _swrast_validate_derived(ctx);
233
234 if ((buffers & BUFFER_BITS_COLOR)
235 && (ctx->DrawBuffer->_NumColorDrawBuffers > 0)) {
236 clear_color_buffers(ctx);
237 }
238
239 if (buffers & BUFFER_BIT_ACCUM) {
240 _mesa_clear_accum_buffer(ctx);
241 }
242
243 if (buffers & BUFFER_DS) {
244 struct gl_renderbuffer *depthRb =
245 ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
246 struct gl_renderbuffer *stencilRb =
247 ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
248
249 if ((buffers & BUFFER_DS) == BUFFER_DS && depthRb == stencilRb) {
250 /* clear depth and stencil together */
251 _swrast_clear_depth_stencil_buffer(ctx);
252 }
253 else {
254 /* clear depth, stencil separately */
255 if (buffers & BUFFER_BIT_DEPTH) {
256 _swrast_clear_depth_buffer(ctx);
257 }
258 if (buffers & BUFFER_BIT_STENCIL) {
259 _swrast_clear_stencil_buffer(ctx);
260 }
261 }
262 }
263 }