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