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
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