0,0 → 1,259 |
/* |
* Mesa 3-D graphics library |
* |
* 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 |
* THE AUTHORS OR COPYRIGHT HOLDERS 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. |
*/ |
|
#include "main/glheader.h" |
#include "main/accum.h" |
#include "main/condrender.h" |
#include "main/format_pack.h" |
#include "main/macros.h" |
#include "main/imports.h" |
#include "main/mtypes.h" |
|
#include "s_context.h" |
#include "s_depth.h" |
#include "s_stencil.h" |
|
|
|
/** |
* Clear an rgba color buffer with masking if needed. |
*/ |
static void |
clear_rgba_buffer(struct gl_context *ctx, struct gl_renderbuffer *rb, |
const GLubyte colorMask[4]) |
{ |
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; |
const GLuint pixelSize = _mesa_get_format_bytes(rb->Format); |
const GLboolean doMasking = (colorMask[0] == 0 || |
colorMask[1] == 0 || |
colorMask[2] == 0 || |
colorMask[3] == 0); |
const GLfloat (*clearColor)[4] = |
(const GLfloat (*)[4]) ctx->Color.ClearColor.f; |
GLbitfield mapMode = GL_MAP_WRITE_BIT; |
GLubyte *map; |
GLint rowStride; |
GLint i, j; |
|
if (doMasking) { |
/* we'll need to read buffer values too */ |
mapMode |= GL_MAP_READ_BIT; |
} |
|
/* map dest buffer */ |
ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, |
mapMode, &map, &rowStride); |
if (!map) { |
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear(color)"); |
return; |
} |
|
/* for 1, 2, 4-byte clearing */ |
#define SIMPLE_TYPE_CLEAR(TYPE) \ |
do { \ |
TYPE pixel, pixelMask; \ |
_mesa_pack_float_rgba_row(rb->Format, 1, clearColor, &pixel); \ |
if (doMasking) { \ |
_mesa_pack_colormask(rb->Format, colorMask, &pixelMask); \ |
pixel &= pixelMask; \ |
pixelMask = ~pixelMask; \ |
} \ |
for (i = 0; i < height; i++) { \ |
TYPE *row = (TYPE *) map; \ |
if (doMasking) { \ |
for (j = 0; j < width; j++) { \ |
row[j] = (row[j] & pixelMask) | pixel; \ |
} \ |
} \ |
else { \ |
for (j = 0; j < width; j++) { \ |
row[j] = pixel; \ |
} \ |
} \ |
map += rowStride; \ |
} \ |
} while (0) |
|
|
/* for 3, 6, 8, 12, 16-byte clearing */ |
#define MULTI_WORD_CLEAR(TYPE, N) \ |
do { \ |
TYPE pixel[N], pixelMask[N]; \ |
GLuint k; \ |
_mesa_pack_float_rgba_row(rb->Format, 1, clearColor, pixel); \ |
if (doMasking) { \ |
_mesa_pack_colormask(rb->Format, colorMask, pixelMask); \ |
for (k = 0; k < N; k++) { \ |
pixel[k] &= pixelMask[k]; \ |
pixelMask[k] = ~pixelMask[k]; \ |
} \ |
} \ |
for (i = 0; i < height; i++) { \ |
TYPE *row = (TYPE *) map; \ |
if (doMasking) { \ |
for (j = 0; j < width; j++) { \ |
for (k = 0; k < N; k++) { \ |
row[j * N + k] = \ |
(row[j * N + k] & pixelMask[k]) | pixel[k]; \ |
} \ |
} \ |
} \ |
else { \ |
for (j = 0; j < width; j++) { \ |
for (k = 0; k < N; k++) { \ |
row[j * N + k] = pixel[k]; \ |
} \ |
} \ |
} \ |
map += rowStride; \ |
} \ |
} while(0) |
|
switch (pixelSize) { |
case 1: |
SIMPLE_TYPE_CLEAR(GLubyte); |
break; |
case 2: |
SIMPLE_TYPE_CLEAR(GLushort); |
break; |
case 3: |
MULTI_WORD_CLEAR(GLubyte, 3); |
break; |
case 4: |
SIMPLE_TYPE_CLEAR(GLuint); |
break; |
case 6: |
MULTI_WORD_CLEAR(GLushort, 3); |
break; |
case 8: |
MULTI_WORD_CLEAR(GLuint, 2); |
break; |
case 12: |
MULTI_WORD_CLEAR(GLuint, 3); |
break; |
case 16: |
MULTI_WORD_CLEAR(GLuint, 4); |
break; |
default: |
_mesa_problem(ctx, "bad pixel size in clear_rgba_buffer()"); |
} |
|
/* unmap buffer */ |
ctx->Driver.UnmapRenderbuffer(ctx, rb); |
} |
|
|
/** |
* 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(struct gl_context *ctx) |
{ |
GLuint buf; |
|
for (buf = 0; buf < ctx->DrawBuffer->_NumColorDrawBuffers; buf++) { |
struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[buf]; |
|
/* If this is an ES2 context or GL_ARB_ES2_compatibility is supported, |
* the framebuffer can be complete with some attachments be missing. In |
* this case the _ColorDrawBuffers pointer will be NULL. |
*/ |
if (rb == NULL) |
continue; |
|
clear_rgba_buffer(ctx, rb, ctx->Color.ColorMask[buf]); |
} |
} |
|
|
/** |
* 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(struct gl_context *ctx, GLbitfield buffers) |
{ |
const GLbitfield BUFFER_DS = BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL; |
ENTER(); |
|
#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; |
assert((buffers & (~legalBits)) == 0); |
} |
#endif |
|
if (!_mesa_check_conditional_render(ctx)) |
return; /* don't clear */ |
|
if (SWRAST_CONTEXT(ctx)->NewState) |
_swrast_validate_derived(ctx); |
|
if ((buffers & BUFFER_BITS_COLOR) |
&& (ctx->DrawBuffer->_NumColorDrawBuffers > 0)) { |
clear_color_buffers(ctx); |
} |
|
if (buffers & BUFFER_BIT_ACCUM) { |
_mesa_clear_accum_buffer(ctx); |
} |
|
if (buffers & BUFFER_DS) { |
struct gl_renderbuffer *depthRb = |
ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; |
struct gl_renderbuffer *stencilRb = |
ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer; |
|
if ((buffers & BUFFER_DS) == BUFFER_DS && depthRb == stencilRb) { |
/* clear depth and stencil together */ |
_swrast_clear_depth_stencil_buffer(ctx); |
} |
else { |
/* clear depth, stencil separately */ |
if (buffers & BUFFER_BIT_DEPTH) { |
_swrast_clear_depth_buffer(ctx); |
} |
if (buffers & BUFFER_BIT_STENCIL) { |
_swrast_clear_stencil_buffer(ctx); |
} |
} |
} |
LEAVE(); |
} |