| /* |
| * Mesa 3-D graphics library |
| * Version: 7.1 |
| * |
| * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included |
| * in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
| * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| |
| /** XXX This file should be named s_clear.c */ |
| |
| #include "glheader.h" |
| #include "colormac.h" |
| #include "macros.h" |
| #include "imports.h" |
| #include "mtypes.h" |
| |
| #include "s_accum.h" |
| #include "s_context.h" |
| #include "s_depth.h" |
| #include "s_masking.h" |
| #include "s_stencil.h" |
| |
| |
| /** |
| * Clear the color buffer when glColorMask is in effect. |
| */ |
| static void |
| clear_rgba_buffer_with_masking(GLcontext *ctx, struct gl_renderbuffer *rb) |
| { |
| const GLint x = ctx->DrawBuffer->_Xmin; |
| const GLint y = ctx->DrawBuffer->_Ymin; |
| const GLint height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin; |
| const GLint width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; |
| SWspan span; |
| GLint i; |
| |
| ASSERT(ctx->Visual.rgbMode); |
| ASSERT(rb->PutRow); |
| |
| /* Initialize color span with clear color */ |
| /* XXX optimize for clearcolor == black/zero (bzero) */ |
| INIT_SPAN(span, GL_BITMAP); |
| span.end = width; |
| span.arrayMask = SPAN_RGBA; |
| span.array->ChanType = rb->DataType; |
| if (span.array->ChanType == GL_UNSIGNED_BYTE) { |
| GLubyte clearColor[4]; |
| UNCLAMPED_FLOAT_TO_UBYTE(clearColor[RCOMP], ctx->Color.ClearColor[0]); |
| UNCLAMPED_FLOAT_TO_UBYTE(clearColor[GCOMP], ctx->Color.ClearColor[1]); |
| UNCLAMPED_FLOAT_TO_UBYTE(clearColor[BCOMP], ctx->Color.ClearColor[2]); |
| UNCLAMPED_FLOAT_TO_UBYTE(clearColor[ACOMP], ctx->Color.ClearColor[3]); |
| for (i = 0; i < width; i++) { |
| COPY_4UBV(span.array->rgba[i], clearColor); |
| } |
| } |
| else if (span.array->ChanType == GL_UNSIGNED_SHORT) { |
| GLushort clearColor[4]; |
| UNCLAMPED_FLOAT_TO_USHORT(clearColor[RCOMP], ctx->Color.ClearColor[0]); |
| UNCLAMPED_FLOAT_TO_USHORT(clearColor[GCOMP], ctx->Color.ClearColor[1]); |
| UNCLAMPED_FLOAT_TO_USHORT(clearColor[BCOMP], ctx->Color.ClearColor[2]); |
| UNCLAMPED_FLOAT_TO_USHORT(clearColor[ACOMP], ctx->Color.ClearColor[3]); |
| for (i = 0; i < width; i++) { |
| COPY_4V(span.array->rgba[i], clearColor); |
| } |
| } |
| else { |
| ASSERT(span.array->ChanType == GL_FLOAT); |
| for (i = 0; i < width; i++) { |
| CLAMPED_FLOAT_TO_CHAN(span.array->rgba[i][0], ctx->Color.ClearColor[0]); |
| CLAMPED_FLOAT_TO_CHAN(span.array->rgba[i][1], ctx->Color.ClearColor[1]); |
| CLAMPED_FLOAT_TO_CHAN(span.array->rgba[i][2], ctx->Color.ClearColor[2]); |
| CLAMPED_FLOAT_TO_CHAN(span.array->rgba[i][3], ctx->Color.ClearColor[3]); |
| } |
| } |
| |
| /* Note that masking will change the color values, but only the |
| * channels for which the write mask is GL_FALSE. The channels |
| * which which are write-enabled won't get modified. |
| */ |
| for (i = 0; i < height; i++) { |
| span.x = x; |
| span.y = y + i; |
| _swrast_mask_rgba_span(ctx, rb, &span); |
| /* write masked row */ |
| rb->PutRow(ctx, rb, width, x, y + i, span.array->rgba, NULL); |
| } |
| } |
| |
| |
| /** |
| * Clear color index buffer with masking. |
| */ |
| static void |
| clear_ci_buffer_with_masking(GLcontext *ctx, struct gl_renderbuffer *rb) |
| { |
| const GLint x = ctx->DrawBuffer->_Xmin; |
| const GLint y = ctx->DrawBuffer->_Ymin; |
| const GLint height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin; |
| const GLint width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; |
| SWspan span; |
| GLint i; |
| |
| ASSERT(!ctx->Visual.rgbMode); |
| ASSERT(rb->PutRow); |
| ASSERT(rb->DataType == GL_UNSIGNED_INT); |
| |
| /* Initialize index span with clear index */ |
| INIT_SPAN(span, GL_BITMAP); |
| span.end = width; |
| span.arrayMask = SPAN_INDEX; |
| for (i = 0; i < width;i++) { |
| span.array->index[i] = ctx->Color.ClearIndex; |
| } |
| |
| /* Note that masking will change the color indexes, but only the |
| * bits for which the write mask is GL_FALSE. The bits |
| * which are write-enabled won't get modified. |
| */ |
| for (i = 0; i < height;i++) { |
| span.x = x; |
| span.y = y + i; |
| _swrast_mask_ci_span(ctx, rb, &span); |
| /* write masked row */ |
| rb->PutRow(ctx, rb, width, x, y + i, span.array->index, NULL); |
| } |
| } |
| |
| |
| /** |
| * Clear an rgba color buffer without channel masking. |
| */ |
| static void |
| clear_rgba_buffer(GLcontext *ctx, struct gl_renderbuffer *rb) |
| { |
| const GLint x = ctx->DrawBuffer->_Xmin; |
| const GLint y = ctx->DrawBuffer->_Ymin; |
| const GLint height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin; |
| const GLint width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; |
| GLubyte clear8[4]; |
| GLushort clear16[4]; |
| GLvoid *clearVal; |
| GLint i; |
| |
| ASSERT(ctx->Visual.rgbMode); |
| |
| ASSERT(ctx->Color.ColorMask[0] && |
| ctx->Color.ColorMask[1] && |
| ctx->Color.ColorMask[2] && |
| ctx->Color.ColorMask[3]); |
| |
| ASSERT(rb->PutMonoRow); |
| |
| switch (rb->DataType) { |
| case GL_UNSIGNED_BYTE: |
| UNCLAMPED_FLOAT_TO_UBYTE(clear8[0], ctx->Color.ClearColor[0]); |
| UNCLAMPED_FLOAT_TO_UBYTE(clear8[1], ctx->Color.ClearColor[1]); |
| UNCLAMPED_FLOAT_TO_UBYTE(clear8[2], ctx->Color.ClearColor[2]); |
| UNCLAMPED_FLOAT_TO_UBYTE(clear8[3], ctx->Color.ClearColor[3]); |
| clearVal = clear8; |
| break; |
| case GL_UNSIGNED_SHORT: |
| UNCLAMPED_FLOAT_TO_USHORT(clear16[0], ctx->Color.ClearColor[0]); |
| UNCLAMPED_FLOAT_TO_USHORT(clear16[1], ctx->Color.ClearColor[1]); |
| UNCLAMPED_FLOAT_TO_USHORT(clear16[2], ctx->Color.ClearColor[2]); |
| UNCLAMPED_FLOAT_TO_USHORT(clear16[3], ctx->Color.ClearColor[3]); |
| clearVal = clear16; |
| break; |
| case GL_FLOAT: |
| clearVal = ctx->Color.ClearColor; |
| break; |
| default: |
| _mesa_problem(ctx, "Bad rb DataType in clear_color_buffer"); |
| return; |
| } |
| |
| for (i = 0; i < height; i++) { |
| rb->PutMonoRow(ctx, rb, width, x, y + i, clearVal, NULL); |
| } |
| } |
| |
| |
| /** |
| * Clear color index buffer without masking. |
| */ |
| static void |
| clear_ci_buffer(GLcontext *ctx, struct gl_renderbuffer *rb) |
| { |
| const GLint x = ctx->DrawBuffer->_Xmin; |
| const GLint y = ctx->DrawBuffer->_Ymin; |
| const GLint height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin; |
| const GLint width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; |
| GLubyte clear8; |
| GLushort clear16; |
| GLuint clear32; |
| GLvoid *clearVal; |
| GLint i; |
| |
| ASSERT(!ctx->Visual.rgbMode); |
| |
| ASSERT((ctx->Color.IndexMask & ((1 << rb->IndexBits) - 1)) |
| == (GLuint) ((1 << rb->IndexBits) - 1)); |
| |
| ASSERT(rb->PutMonoRow); |
| |
| /* setup clear value */ |
| switch (rb->DataType) { |
| case GL_UNSIGNED_BYTE: |
| clear8 = (GLubyte) ctx->Color.ClearIndex; |
| clearVal = &clear8; |
| break; |
| case GL_UNSIGNED_SHORT: |
| clear16 = (GLushort) ctx->Color.ClearIndex; |
| clearVal = &clear16; |
| break; |
| case GL_UNSIGNED_INT: |
| clear32 = ctx->Color.ClearIndex; |
| clearVal = &clear32; |
| break; |
| default: |
| _mesa_problem(ctx, "Bad rb DataType in clear_color_buffer"); |
| return; |
| } |
| |
| for (i = 0; i < height; i++) |
| rb->PutMonoRow(ctx, rb, width, x, y + i, clearVal, NULL); |
| } |
| |
| |
| /** |
| * Clear the front/back/left/right/aux color buffers. |
| * This function is usually only called if the device driver can't |
| * clear its own color buffers for some reason (such as with masking). |
| */ |
| static void |
| clear_color_buffers(GLcontext *ctx) |
| { |
| GLboolean masking; |
| GLuint buf; |
| |
| if (ctx->Visual.rgbMode) { |
| if (ctx->Color.ColorMask[0] && |
| ctx->Color.ColorMask[1] && |
| ctx->Color.ColorMask[2] && |
| ctx->Color.ColorMask[3]) { |
| masking = GL_FALSE; |
| } |
| else { |
| masking = GL_TRUE; |
| } |
| } |
| else { |
| struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0]; |
| const GLuint indexBits = (1 << rb->IndexBits) - 1; |
| if ((ctx->Color.IndexMask & indexBits) == indexBits) { |
| masking = GL_FALSE; |
| } |
| else { |
| masking = GL_TRUE; |
| } |
| } |
| |
| for (buf = 0; buf < ctx->DrawBuffer->_NumColorDrawBuffers; buf++) { |
| struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[buf]; |
| if (ctx->Visual.rgbMode) { |
| if (masking) { |
| clear_rgba_buffer_with_masking(ctx, rb); |
| } |
| else { |
| clear_rgba_buffer(ctx, rb); |
| } |
| } |
| else { |
| if (masking) { |
| clear_ci_buffer_with_masking(ctx, rb); |
| } |
| else { |
| clear_ci_buffer(ctx, rb); |
| } |
| } |
| } |
| } |
| |
| |
| /** |
| * Called via the device driver's ctx->Driver.Clear() function if the |
| * device driver can't clear one or more of the buffers itself. |
| * \param buffers bitfield of BUFFER_BIT_* values indicating which |
| * renderbuffers are to be cleared. |
| * \param all if GL_TRUE, clear whole buffer, else clear specified region. |
| */ |
| void |
| _swrast_Clear(GLcontext *ctx, GLbitfield buffers) |
| { |
| SWcontext *swrast = SWRAST_CONTEXT(ctx); |
| |
| #ifdef DEBUG_FOO |
| { |
| const GLbitfield legalBits = |
| BUFFER_BIT_FRONT_LEFT | |
| BUFFER_BIT_FRONT_RIGHT | |
| BUFFER_BIT_BACK_LEFT | |
| BUFFER_BIT_BACK_RIGHT | |
| BUFFER_BIT_DEPTH | |
| BUFFER_BIT_STENCIL | |
| BUFFER_BIT_ACCUM | |
| BUFFER_BIT_AUX0 | |
| BUFFER_BIT_AUX1 | |
| BUFFER_BIT_AUX2 | |
| BUFFER_BIT_AUX3; |
| assert((buffers & (~legalBits)) == 0); |
| } |
| #endif |
| |
| RENDER_START(swrast,ctx); |
| |
| /* do software clearing here */ |
| if (buffers) { |
| if ((buffers & BUFFER_BITS_COLOR) |
| && (ctx->DrawBuffer->_NumColorDrawBuffers > 0)) { |
| clear_color_buffers(ctx); |
| } |
| if (buffers & BUFFER_BIT_DEPTH) { |
| _swrast_clear_depth_buffer(ctx, ctx->DrawBuffer->_DepthBuffer); |
| } |
| if (buffers & BUFFER_BIT_ACCUM) { |
| _swrast_clear_accum_buffer(ctx, |
| ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer); |
| } |
| if (buffers & BUFFER_BIT_STENCIL) { |
| _swrast_clear_stencil_buffer(ctx, ctx->DrawBuffer->_StencilBuffer); |
| } |
| } |
| |
| RENDER_FINISH(swrast,ctx); |
| } |