diff options
Diffstat (limited to 'mesalib/src/mesa/main/renderbuffer.c')
-rw-r--r-- | mesalib/src/mesa/main/renderbuffer.c | 2209 |
1 files changed, 2209 insertions, 0 deletions
diff --git a/mesalib/src/mesa/main/renderbuffer.c b/mesalib/src/mesa/main/renderbuffer.c new file mode 100644 index 000000000..38be8266e --- /dev/null +++ b/mesalib/src/mesa/main/renderbuffer.c @@ -0,0 +1,2209 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 1999-2006 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. + */ + + +/** + * Functions for allocating/managing renderbuffers. + * Also, routines for reading/writing software-based renderbuffer data as + * ubytes, ushorts, uints, etc. + * + * The 'alpha8' renderbuffer is interesting. It's used to add a software-based + * alpha channel to RGB renderbuffers. This is done by wrapping the RGB + * renderbuffer with the alpha renderbuffer. We can do this because of the + * OO-nature of renderbuffers. + * + * Down the road we'll use this for run-time support of 8, 16 and 32-bit + * color channels. For example, Mesa may use 32-bit/float color channels + * internally (swrast) and use wrapper renderbuffers to convert 32-bit + * values down to 16 or 8-bit values for whatever kind of framebuffer we have. + */ + + +#include "glheader.h" +#include "imports.h" +#include "context.h" +#include "mtypes.h" +#include "fbobject.h" +#include "renderbuffer.h" + +#include "rbadaptors.h" + + +/* 32-bit color index format. Not a public format. */ +#define COLOR_INDEX32 0x424243 + + +/* + * Routines for get/put values in common buffer formats follow. + * Someday add support for arbitrary row stride to make them more + * flexible. + */ + +/********************************************************************** + * Functions for buffers of 1 X GLubyte values. + * Typically stencil. + */ + +static void * +get_pointer_ubyte(GLcontext *ctx, struct gl_renderbuffer *rb, + GLint x, GLint y) +{ + if (!rb->Data) + return NULL; + ASSERT(rb->DataType == GL_UNSIGNED_BYTE); + /* Can't assert _ActualFormat since these funcs may be used for serveral + * different formats (GL_ALPHA8, GL_STENCIL_INDEX8, etc). + */ + return (GLubyte *) rb->Data + y * rb->Width + x; +} + + +static void +get_row_ubyte(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, void *values) +{ + const GLubyte *src = (const GLubyte *) rb->Data + y * rb->Width + x; + ASSERT(rb->DataType == GL_UNSIGNED_BYTE); + _mesa_memcpy(values, src, count * sizeof(GLubyte)); +} + + +static void +get_values_ubyte(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + const GLint x[], const GLint y[], void *values) +{ + GLubyte *dst = (GLubyte *) values; + GLuint i; + ASSERT(rb->DataType == GL_UNSIGNED_BYTE); + for (i = 0; i < count; i++) { + const GLubyte *src = (GLubyte *) rb->Data + y[i] * rb->Width + x[i]; + dst[i] = *src; + } +} + + +static void +put_row_ubyte(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, const void *values, const GLubyte *mask) +{ + const GLubyte *src = (const GLubyte *) values; + GLubyte *dst = (GLubyte *) rb->Data + y * rb->Width + x; + ASSERT(rb->DataType == GL_UNSIGNED_BYTE); + if (mask) { + GLuint i; + for (i = 0; i < count; i++) { + if (mask[i]) { + dst[i] = src[i]; + } + } + } + else { + _mesa_memcpy(dst, values, count * sizeof(GLubyte)); + } +} + + +static void +put_mono_row_ubyte(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, const void *value, const GLubyte *mask) +{ + const GLubyte val = *((const GLubyte *) value); + GLubyte *dst = (GLubyte *) rb->Data + y * rb->Width + x; + ASSERT(rb->DataType == GL_UNSIGNED_BYTE); + if (mask) { + GLuint i; + for (i = 0; i < count; i++) { + if (mask[i]) { + dst[i] = val; + } + } + } + else { + GLuint i; + for (i = 0; i < count; i++) { + dst[i] = val; + } + } +} + + +static void +put_values_ubyte(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + const GLint x[], const GLint y[], + const void *values, const GLubyte *mask) +{ + const GLubyte *src = (const GLubyte *) values; + GLuint i; + ASSERT(rb->DataType == GL_UNSIGNED_BYTE); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + GLubyte *dst = (GLubyte *) rb->Data + y[i] * rb->Width + x[i]; + *dst = src[i]; + } + } +} + + +static void +put_mono_values_ubyte(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + const GLint x[], const GLint y[], + const void *value, const GLubyte *mask) +{ + const GLubyte val = *((const GLubyte *) value); + GLuint i; + ASSERT(rb->DataType == GL_UNSIGNED_BYTE); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + GLubyte *dst = (GLubyte *) rb->Data + y[i] * rb->Width + x[i]; + *dst = val; + } + } +} + + +/********************************************************************** + * Functions for buffers of 1 X GLushort values. + * Typically depth/Z. + */ + +static void * +get_pointer_ushort(GLcontext *ctx, struct gl_renderbuffer *rb, + GLint x, GLint y) +{ + if (!rb->Data) + return NULL; + ASSERT(rb->DataType == GL_UNSIGNED_SHORT); + ASSERT(rb->Width > 0); + return (GLushort *) rb->Data + y * rb->Width + x; +} + + +static void +get_row_ushort(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, void *values) +{ + const void *src = rb->GetPointer(ctx, rb, x, y); + ASSERT(rb->DataType == GL_UNSIGNED_SHORT); + _mesa_memcpy(values, src, count * sizeof(GLushort)); +} + + +static void +get_values_ushort(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + const GLint x[], const GLint y[], void *values) +{ + GLushort *dst = (GLushort *) values; + GLuint i; + ASSERT(rb->DataType == GL_UNSIGNED_SHORT); + for (i = 0; i < count; i++) { + const GLushort *src = (GLushort *) rb->Data + y[i] * rb->Width + x[i]; + dst[i] = *src; + } +} + + +static void +put_row_ushort(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, const void *values, const GLubyte *mask) +{ + const GLushort *src = (const GLushort *) values; + GLushort *dst = (GLushort *) rb->Data + y * rb->Width + x; + ASSERT(rb->DataType == GL_UNSIGNED_SHORT); + if (mask) { + GLuint i; + for (i = 0; i < count; i++) { + if (mask[i]) { + dst[i] = src[i]; + } + } + } + else { + _mesa_memcpy(dst, src, count * sizeof(GLushort)); + } +} + + +static void +put_mono_row_ushort(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, const void *value, const GLubyte *mask) +{ + const GLushort val = *((const GLushort *) value); + GLushort *dst = (GLushort *) rb->Data + y * rb->Width + x; + ASSERT(rb->DataType == GL_UNSIGNED_SHORT); + if (mask) { + GLuint i; + for (i = 0; i < count; i++) { + if (mask[i]) { + dst[i] = val; + } + } + } + else { + GLuint i; + for (i = 0; i < count; i++) { + dst[i] = val; + } + } +} + + +static void +put_values_ushort(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + const GLint x[], const GLint y[], const void *values, + const GLubyte *mask) +{ + const GLushort *src = (const GLushort *) values; + GLuint i; + ASSERT(rb->DataType == GL_UNSIGNED_SHORT); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + GLushort *dst = (GLushort *) rb->Data + y[i] * rb->Width + x[i]; + *dst = src[i]; + } + } +} + + +static void +put_mono_values_ushort(GLcontext *ctx, struct gl_renderbuffer *rb, + GLuint count, const GLint x[], const GLint y[], + const void *value, const GLubyte *mask) +{ + const GLushort val = *((const GLushort *) value); + ASSERT(rb->DataType == GL_UNSIGNED_SHORT); + if (mask) { + GLuint i; + for (i = 0; i < count; i++) { + if (mask[i]) { + GLushort *dst = (GLushort *) rb->Data + y[i] * rb->Width + x[i]; + *dst = val; + } + } + } + else { + GLuint i; + for (i = 0; i < count; i++) { + GLushort *dst = (GLushort *) rb->Data + y[i] * rb->Width + x[i]; + *dst = val; + } + } +} + + +/********************************************************************** + * Functions for buffers of 1 X GLuint values. + * Typically depth/Z or color index. + */ + +static void * +get_pointer_uint(GLcontext *ctx, struct gl_renderbuffer *rb, + GLint x, GLint y) +{ + if (!rb->Data) + return NULL; + ASSERT(rb->DataType == GL_UNSIGNED_INT || + rb->DataType == GL_UNSIGNED_INT_24_8_EXT); + return (GLuint *) rb->Data + y * rb->Width + x; +} + + +static void +get_row_uint(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, void *values) +{ + const void *src = rb->GetPointer(ctx, rb, x, y); + ASSERT(rb->DataType == GL_UNSIGNED_INT || + rb->DataType == GL_UNSIGNED_INT_24_8_EXT); + _mesa_memcpy(values, src, count * sizeof(GLuint)); +} + + +static void +get_values_uint(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + const GLint x[], const GLint y[], void *values) +{ + GLuint *dst = (GLuint *) values; + GLuint i; + ASSERT(rb->DataType == GL_UNSIGNED_INT || + rb->DataType == GL_UNSIGNED_INT_24_8_EXT); + for (i = 0; i < count; i++) { + const GLuint *src = (GLuint *) rb->Data + y[i] * rb->Width + x[i]; + dst[i] = *src; + } +} + + +static void +put_row_uint(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, const void *values, const GLubyte *mask) +{ + const GLuint *src = (const GLuint *) values; + GLuint *dst = (GLuint *) rb->Data + y * rb->Width + x; + ASSERT(rb->DataType == GL_UNSIGNED_INT || + rb->DataType == GL_UNSIGNED_INT_24_8_EXT); + if (mask) { + GLuint i; + for (i = 0; i < count; i++) { + if (mask[i]) { + dst[i] = src[i]; + } + } + } + else { + _mesa_memcpy(dst, src, count * sizeof(GLuint)); + } +} + + +static void +put_mono_row_uint(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, const void *value, const GLubyte *mask) +{ + const GLuint val = *((const GLuint *) value); + GLuint *dst = (GLuint *) rb->Data + y * rb->Width + x; + ASSERT(rb->DataType == GL_UNSIGNED_INT || + rb->DataType == GL_UNSIGNED_INT_24_8_EXT); + if (mask) { + GLuint i; + for (i = 0; i < count; i++) { + if (mask[i]) { + dst[i] = val; + } + } + } + else { + GLuint i; + for (i = 0; i < count; i++) { + dst[i] = val; + } + } +} + + +static void +put_values_uint(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + const GLint x[], const GLint y[], const void *values, + const GLubyte *mask) +{ + const GLuint *src = (const GLuint *) values; + GLuint i; + ASSERT(rb->DataType == GL_UNSIGNED_INT || + rb->DataType == GL_UNSIGNED_INT_24_8_EXT); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + GLuint *dst = (GLuint *) rb->Data + y[i] * rb->Width + x[i]; + *dst = src[i]; + } + } +} + + +static void +put_mono_values_uint(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + const GLint x[], const GLint y[], const void *value, + const GLubyte *mask) +{ + const GLuint val = *((const GLuint *) value); + GLuint i; + ASSERT(rb->DataType == GL_UNSIGNED_INT || + rb->DataType == GL_UNSIGNED_INT_24_8_EXT); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + GLuint *dst = (GLuint *) rb->Data + y[i] * rb->Width + x[i]; + *dst = val; + } + } +} + + +/********************************************************************** + * Functions for buffers of 3 X GLubyte (or GLbyte) values. + * Typically color buffers. + * NOTE: the incoming and outgoing colors are RGBA! We ignore incoming + * alpha values and return 255 for outgoing alpha values. + */ + +static void * +get_pointer_ubyte3(GLcontext *ctx, struct gl_renderbuffer *rb, + GLint x, GLint y) +{ + ASSERT(rb->_ActualFormat == GL_RGB8); + /* No direct access since this buffer is RGB but caller will be + * treating it as if it were RGBA. + */ + return NULL; +} + + +static void +get_row_ubyte3(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, void *values) +{ + const GLubyte *src = (const GLubyte *) rb->Data + 3 * (y * rb->Width + x); + GLubyte *dst = (GLubyte *) values; + GLuint i; + ASSERT(rb->_ActualFormat == GL_RGB8); + ASSERT(rb->DataType == GL_UNSIGNED_BYTE); + for (i = 0; i < count; i++) { + dst[i * 4 + 0] = src[i * 3 + 0]; + dst[i * 4 + 1] = src[i * 3 + 1]; + dst[i * 4 + 2] = src[i * 3 + 2]; + dst[i * 4 + 3] = 255; + } +} + + +static void +get_values_ubyte3(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + const GLint x[], const GLint y[], void *values) +{ + GLubyte *dst = (GLubyte *) values; + GLuint i; + ASSERT(rb->_ActualFormat == GL_RGB8); + ASSERT(rb->DataType == GL_UNSIGNED_BYTE); + for (i = 0; i < count; i++) { + const GLubyte *src + = (GLubyte *) rb->Data + 3 * (y[i] * rb->Width + x[i]); + dst[i * 4 + 0] = src[0]; + dst[i * 4 + 1] = src[1]; + dst[i * 4 + 2] = src[2]; + dst[i * 4 + 3] = 255; + } +} + + +static void +put_row_ubyte3(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, const void *values, const GLubyte *mask) +{ + /* note: incoming values are RGB+A! */ + const GLubyte *src = (const GLubyte *) values; + GLubyte *dst = (GLubyte *) rb->Data + 3 * (y * rb->Width + x); + GLuint i; + ASSERT(rb->_ActualFormat == GL_RGB8); + ASSERT(rb->DataType == GL_UNSIGNED_BYTE); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + dst[i * 3 + 0] = src[i * 4 + 0]; + dst[i * 3 + 1] = src[i * 4 + 1]; + dst[i * 3 + 2] = src[i * 4 + 2]; + } + } +} + + +static void +put_row_rgb_ubyte3(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, const void *values, const GLubyte *mask) +{ + /* note: incoming values are RGB+A! */ + const GLubyte *src = (const GLubyte *) values; + GLubyte *dst = (GLubyte *) rb->Data + 3 * (y * rb->Width + x); + GLuint i; + ASSERT(rb->_ActualFormat == GL_RGB8); + ASSERT(rb->DataType == GL_UNSIGNED_BYTE); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + dst[i * 3 + 0] = src[i * 3 + 0]; + dst[i * 3 + 1] = src[i * 3 + 1]; + dst[i * 3 + 2] = src[i * 3 + 2]; + } + } +} + + +static void +put_mono_row_ubyte3(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, const void *value, const GLubyte *mask) +{ + /* note: incoming value is RGB+A! */ + const GLubyte val0 = ((const GLubyte *) value)[0]; + const GLubyte val1 = ((const GLubyte *) value)[1]; + const GLubyte val2 = ((const GLubyte *) value)[2]; + GLubyte *dst = (GLubyte *) rb->Data + 3 * (y * rb->Width + x); + ASSERT(rb->_ActualFormat == GL_RGB8); + ASSERT(rb->DataType == GL_UNSIGNED_BYTE); + if (!mask && val0 == val1 && val1 == val2) { + /* optimized case */ + _mesa_memset(dst, val0, 3 * count); + } + else { + GLuint i; + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + dst[i * 3 + 0] = val0; + dst[i * 3 + 1] = val1; + dst[i * 3 + 2] = val2; + } + } + } +} + + +static void +put_values_ubyte3(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + const GLint x[], const GLint y[], const void *values, + const GLubyte *mask) +{ + /* note: incoming values are RGB+A! */ + const GLubyte *src = (const GLubyte *) values; + GLuint i; + ASSERT(rb->_ActualFormat == GL_RGB8); + ASSERT(rb->DataType == GL_UNSIGNED_BYTE); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + GLubyte *dst = (GLubyte *) rb->Data + 3 * (y[i] * rb->Width + x[i]); + dst[0] = src[i * 4 + 0]; + dst[1] = src[i * 4 + 1]; + dst[2] = src[i * 4 + 2]; + } + } +} + + +static void +put_mono_values_ubyte3(GLcontext *ctx, struct gl_renderbuffer *rb, + GLuint count, const GLint x[], const GLint y[], + const void *value, const GLubyte *mask) +{ + /* note: incoming value is RGB+A! */ + const GLubyte val0 = ((const GLubyte *) value)[0]; + const GLubyte val1 = ((const GLubyte *) value)[1]; + const GLubyte val2 = ((const GLubyte *) value)[2]; + GLuint i; + ASSERT(rb->_ActualFormat == GL_RGB8); + ASSERT(rb->DataType == GL_UNSIGNED_BYTE); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + GLubyte *dst = (GLubyte *) rb->Data + 3 * (y[i] * rb->Width + x[i]); + dst[0] = val0; + dst[1] = val1; + dst[2] = val2; + } + } +} + + +/********************************************************************** + * Functions for buffers of 4 X GLubyte (or GLbyte) values. + * Typically color buffers. + */ + +static void * +get_pointer_ubyte4(GLcontext *ctx, struct gl_renderbuffer *rb, + GLint x, GLint y) +{ + if (!rb->Data) + return NULL; + ASSERT(rb->DataType == GL_UNSIGNED_BYTE); + ASSERT(rb->_ActualFormat == GL_RGBA8); + return (GLubyte *) rb->Data + 4 * (y * rb->Width + x); +} + + +static void +get_row_ubyte4(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, void *values) +{ + const GLubyte *src = (const GLubyte *) rb->Data + 4 * (y * rb->Width + x); + ASSERT(rb->DataType == GL_UNSIGNED_BYTE); + ASSERT(rb->_ActualFormat == GL_RGBA8); + _mesa_memcpy(values, src, 4 * count * sizeof(GLubyte)); +} + + +static void +get_values_ubyte4(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + const GLint x[], const GLint y[], void *values) +{ + /* treat 4*GLubyte as 1*GLuint */ + GLuint *dst = (GLuint *) values; + GLuint i; + ASSERT(rb->DataType == GL_UNSIGNED_BYTE); + ASSERT(rb->_ActualFormat == GL_RGBA8); + for (i = 0; i < count; i++) { + const GLuint *src = (GLuint *) rb->Data + (y[i] * rb->Width + x[i]); + dst[i] = *src; + } +} + + +static void +put_row_ubyte4(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, const void *values, const GLubyte *mask) +{ + /* treat 4*GLubyte as 1*GLuint */ + const GLuint *src = (const GLuint *) values; + GLuint *dst = (GLuint *) rb->Data + (y * rb->Width + x); + ASSERT(rb->DataType == GL_UNSIGNED_BYTE); + ASSERT(rb->_ActualFormat == GL_RGBA8); + if (mask) { + GLuint i; + for (i = 0; i < count; i++) { + if (mask[i]) { + dst[i] = src[i]; + } + } + } + else { + _mesa_memcpy(dst, src, 4 * count * sizeof(GLubyte)); + } +} + + +static void +put_row_rgb_ubyte4(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, const void *values, const GLubyte *mask) +{ + /* Store RGB values in RGBA buffer */ + const GLubyte *src = (const GLubyte *) values; + GLubyte *dst = (GLubyte *) rb->Data + 4 * (y * rb->Width + x); + GLuint i; + ASSERT(rb->DataType == GL_UNSIGNED_BYTE); + ASSERT(rb->_ActualFormat == GL_RGBA8); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + dst[i * 4 + 0] = src[i * 3 + 0]; + dst[i * 4 + 1] = src[i * 3 + 1]; + dst[i * 4 + 2] = src[i * 3 + 2]; + dst[i * 4 + 3] = 0xff; + } + } +} + + +static void +put_mono_row_ubyte4(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, const void *value, const GLubyte *mask) +{ + /* treat 4*GLubyte as 1*GLuint */ + const GLuint val = *((const GLuint *) value); + GLuint *dst = (GLuint *) rb->Data + (y * rb->Width + x); + ASSERT(rb->DataType == GL_UNSIGNED_BYTE); + ASSERT(rb->_ActualFormat == GL_RGBA8); + if (!mask && val == 0) { + /* common case */ + _mesa_bzero(dst, count * 4 * sizeof(GLubyte)); + } + else { + /* general case */ + if (mask) { + GLuint i; + for (i = 0; i < count; i++) { + if (mask[i]) { + dst[i] = val; + } + } + } + else { + GLuint i; + for (i = 0; i < count; i++) { + dst[i] = val; + } + } + } +} + + +static void +put_values_ubyte4(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + const GLint x[], const GLint y[], const void *values, + const GLubyte *mask) +{ + /* treat 4*GLubyte as 1*GLuint */ + const GLuint *src = (const GLuint *) values; + GLuint i; + ASSERT(rb->DataType == GL_UNSIGNED_BYTE); + ASSERT(rb->_ActualFormat == GL_RGBA8); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + GLuint *dst = (GLuint *) rb->Data + (y[i] * rb->Width + x[i]); + *dst = src[i]; + } + } +} + + +static void +put_mono_values_ubyte4(GLcontext *ctx, struct gl_renderbuffer *rb, + GLuint count, const GLint x[], const GLint y[], + const void *value, const GLubyte *mask) +{ + /* treat 4*GLubyte as 1*GLuint */ + const GLuint val = *((const GLuint *) value); + GLuint i; + ASSERT(rb->DataType == GL_UNSIGNED_BYTE); + ASSERT(rb->_ActualFormat == GL_RGBA8); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + GLuint *dst = (GLuint *) rb->Data + (y[i] * rb->Width + x[i]); + *dst = val; + } + } +} + + +/********************************************************************** + * Functions for buffers of 4 X GLushort (or GLshort) values. + * Typically accum buffer. + */ + +static void * +get_pointer_ushort4(GLcontext *ctx, struct gl_renderbuffer *rb, + GLint x, GLint y) +{ + if (!rb->Data) + return NULL; + ASSERT(rb->DataType == GL_UNSIGNED_SHORT || rb->DataType == GL_SHORT); + return (GLushort *) rb->Data + 4 * (y * rb->Width + x); +} + + +static void +get_row_ushort4(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, void *values) +{ + const GLshort *src = (const GLshort *) rb->Data + 4 * (y * rb->Width + x); + ASSERT(rb->DataType == GL_UNSIGNED_SHORT || rb->DataType == GL_SHORT); + _mesa_memcpy(values, src, 4 * count * sizeof(GLshort)); +} + + +static void +get_values_ushort4(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + const GLint x[], const GLint y[], void *values) +{ + GLushort *dst = (GLushort *) values; + GLuint i; + ASSERT(rb->DataType == GL_UNSIGNED_SHORT || rb->DataType == GL_SHORT); + for (i = 0; i < count; i++) { + const GLushort *src + = (GLushort *) rb->Data + 4 * (y[i] * rb->Width + x[i]); + dst[i] = *src; + } +} + + +static void +put_row_ushort4(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, const void *values, const GLubyte *mask) +{ + const GLushort *src = (const GLushort *) values; + GLushort *dst = (GLushort *) rb->Data + 4 * (y * rb->Width + x); + ASSERT(rb->DataType == GL_UNSIGNED_SHORT || rb->DataType == GL_SHORT); + if (mask) { + GLuint i; + for (i = 0; i < count; i++) { + if (mask[i]) { + dst[i * 4 + 0] = src[i * 4 + 0]; + dst[i * 4 + 1] = src[i * 4 + 1]; + dst[i * 4 + 2] = src[i * 4 + 2]; + dst[i * 4 + 3] = src[i * 4 + 3]; + } + } + } + else { + _mesa_memcpy(dst, src, 4 * count * sizeof(GLushort)); + } +} + + +static void +put_row_rgb_ushort4(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, const void *values, const GLubyte *mask) +{ + /* Put RGB values in RGBA buffer */ + const GLushort *src = (const GLushort *) values; + GLushort *dst = (GLushort *) rb->Data + 4 * (y * rb->Width + x); + ASSERT(rb->DataType == GL_UNSIGNED_SHORT || rb->DataType == GL_SHORT); + if (mask) { + GLuint i; + for (i = 0; i < count; i++) { + if (mask[i]) { + dst[i * 4 + 0] = src[i * 3 + 0]; + dst[i * 4 + 1] = src[i * 3 + 1]; + dst[i * 4 + 2] = src[i * 3 + 2]; + dst[i * 4 + 3] = 0xffff; + } + } + } + else { + _mesa_memcpy(dst, src, 4 * count * sizeof(GLushort)); + } +} + + +static void +put_mono_row_ushort4(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, const void *value, const GLubyte *mask) +{ + const GLushort val0 = ((const GLushort *) value)[0]; + const GLushort val1 = ((const GLushort *) value)[1]; + const GLushort val2 = ((const GLushort *) value)[2]; + const GLushort val3 = ((const GLushort *) value)[3]; + GLushort *dst = (GLushort *) rb->Data + 4 * (y * rb->Width + x); + ASSERT(rb->DataType == GL_UNSIGNED_SHORT || rb->DataType == GL_SHORT); + if (!mask && val0 == 0 && val1 == 0 && val2 == 0 && val3 == 0) { + /* common case for clearing accum buffer */ + _mesa_bzero(dst, count * 4 * sizeof(GLushort)); + } + else { + GLuint i; + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + dst[i * 4 + 0] = val0; + dst[i * 4 + 1] = val1; + dst[i * 4 + 2] = val2; + dst[i * 4 + 3] = val3; + } + } + } +} + + +static void +put_values_ushort4(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count, + const GLint x[], const GLint y[], const void *values, + const GLubyte *mask) +{ + const GLushort *src = (const GLushort *) values; + GLuint i; + ASSERT(rb->DataType == GL_UNSIGNED_SHORT || rb->DataType == GL_SHORT); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + GLushort *dst = (GLushort *) rb->Data + 4 * (y[i] * rb->Width + x[i]); + dst[0] = src[i * 4 + 0]; + dst[1] = src[i * 4 + 1]; + dst[2] = src[i * 4 + 2]; + dst[3] = src[i * 4 + 3]; + } + } +} + + +static void +put_mono_values_ushort4(GLcontext *ctx, struct gl_renderbuffer *rb, + GLuint count, const GLint x[], const GLint y[], + const void *value, const GLubyte *mask) +{ + const GLushort val0 = ((const GLushort *) value)[0]; + const GLushort val1 = ((const GLushort *) value)[1]; + const GLushort val2 = ((const GLushort *) value)[2]; + const GLushort val3 = ((const GLushort *) value)[3]; + GLuint i; + ASSERT(rb->DataType == GL_UNSIGNED_SHORT || rb->DataType == GL_SHORT); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + GLushort *dst = (GLushort *) rb->Data + 4 * (y[i] * rb->Width + x[i]); + dst[0] = val0; + dst[1] = val1; + dst[2] = val2; + dst[3] = val3; + } + } +} + + + +/** + * This is a software fallback for the gl_renderbuffer->AllocStorage + * function. + * Device drivers will typically override this function for the buffers + * which it manages (typically color buffers, Z and stencil). + * Other buffers (like software accumulation and aux buffers) which the driver + * doesn't manage can be handled with this function. + * + * This one multi-purpose function can allocate stencil, depth, accum, color + * or color-index buffers! + * + * This function also plugs in the appropriate GetPointer, Get/PutRow and + * Get/PutValues functions. + */ +GLboolean +_mesa_soft_renderbuffer_storage(GLcontext *ctx, struct gl_renderbuffer *rb, + GLenum internalFormat, + GLuint width, GLuint height) +{ + GLuint pixelSize; + + /* first clear these fields */ + rb->RedBits = + rb->GreenBits = + rb->BlueBits = + rb->AlphaBits = + rb->IndexBits = + rb->DepthBits = + rb->StencilBits = 0; + + switch (internalFormat) { + case GL_RGB: + case GL_R3_G3_B2: + case GL_RGB4: + case GL_RGB5: + case GL_RGB8: + case GL_RGB10: + case GL_RGB12: + case GL_RGB16: + rb->_ActualFormat = GL_RGB8; + rb->_BaseFormat = GL_RGB; + rb->DataType = GL_UNSIGNED_BYTE; + rb->GetPointer = get_pointer_ubyte3; + rb->GetRow = get_row_ubyte3; + rb->GetValues = get_values_ubyte3; + rb->PutRow = put_row_ubyte3; + rb->PutRowRGB = put_row_rgb_ubyte3; + rb->PutMonoRow = put_mono_row_ubyte3; + rb->PutValues = put_values_ubyte3; + rb->PutMonoValues = put_mono_values_ubyte3; + rb->RedBits = 8 * sizeof(GLubyte); + rb->GreenBits = 8 * sizeof(GLubyte); + rb->BlueBits = 8 * sizeof(GLubyte); + rb->AlphaBits = 0; + pixelSize = 3 * sizeof(GLubyte); + break; + case GL_RGBA: + case GL_RGBA2: + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGBA8: + rb->_ActualFormat = GL_RGBA8; + rb->_BaseFormat = GL_RGBA; + rb->DataType = GL_UNSIGNED_BYTE; + rb->GetPointer = get_pointer_ubyte4; + rb->GetRow = get_row_ubyte4; + rb->GetValues = get_values_ubyte4; + rb->PutRow = put_row_ubyte4; + rb->PutRowRGB = put_row_rgb_ubyte4; + rb->PutMonoRow = put_mono_row_ubyte4; + rb->PutValues = put_values_ubyte4; + rb->PutMonoValues = put_mono_values_ubyte4; + rb->RedBits = 8 * sizeof(GLubyte); + rb->GreenBits = 8 * sizeof(GLubyte); + rb->BlueBits = 8 * sizeof(GLubyte); + rb->AlphaBits = 8 * sizeof(GLubyte); + pixelSize = 4 * sizeof(GLubyte); + break; + case GL_RGB10_A2: + case GL_RGBA12: + case GL_RGBA16: + rb->_ActualFormat = GL_RGBA16; + rb->_BaseFormat = GL_RGBA; + rb->DataType = GL_UNSIGNED_SHORT; + rb->GetPointer = get_pointer_ushort4; + rb->GetRow = get_row_ushort4; + rb->GetValues = get_values_ushort4; + rb->PutRow = put_row_ushort4; + rb->PutRowRGB = put_row_rgb_ushort4; + rb->PutMonoRow = put_mono_row_ushort4; + rb->PutValues = put_values_ushort4; + rb->PutMonoValues = put_mono_values_ushort4; + rb->RedBits = 8 * sizeof(GLushort); + rb->GreenBits = 8 * sizeof(GLushort); + rb->BlueBits = 8 * sizeof(GLushort); + rb->AlphaBits = 8 * sizeof(GLushort); + pixelSize = 4 * sizeof(GLushort); + break; +#if 00 + case GL_ALPHA8: + rb->_ActualFormat = GL_ALPHA8; + rb->_BaseFormat = GL_RGBA; /* Yes, not GL_ALPHA! */ + rb->DataType = GL_UNSIGNED_BYTE; + rb->GetPointer = get_pointer_alpha8; + rb->GetRow = get_row_alpha8; + rb->GetValues = get_values_alpha8; + rb->PutRow = put_row_alpha8; + rb->PutRowRGB = NULL; + rb->PutMonoRow = put_mono_row_alpha8; + rb->PutValues = put_values_alpha8; + rb->PutMonoValues = put_mono_values_alpha8; + rb->RedBits = 0; /*red*/ + rb->GreenBits = 0; /*green*/ + rb->BlueBits = 0; /*blue*/ + rb->AlphaBits = 8 * sizeof(GLubyte); + pixelSize = sizeof(GLubyte); + break; +#endif + case GL_STENCIL_INDEX: + case GL_STENCIL_INDEX1_EXT: + case GL_STENCIL_INDEX4_EXT: + case GL_STENCIL_INDEX8_EXT: + rb->_ActualFormat = GL_STENCIL_INDEX8_EXT; + rb->_BaseFormat = GL_STENCIL_INDEX; + rb->DataType = GL_UNSIGNED_BYTE; + rb->GetPointer = get_pointer_ubyte; + rb->GetRow = get_row_ubyte; + rb->GetValues = get_values_ubyte; + rb->PutRow = put_row_ubyte; + rb->PutRowRGB = NULL; + rb->PutMonoRow = put_mono_row_ubyte; + rb->PutValues = put_values_ubyte; + rb->PutMonoValues = put_mono_values_ubyte; + rb->StencilBits = 8 * sizeof(GLubyte); + pixelSize = sizeof(GLubyte); + break; + case GL_STENCIL_INDEX16_EXT: + rb->_ActualFormat = GL_STENCIL_INDEX16_EXT; + rb->_BaseFormat = GL_STENCIL_INDEX; + rb->DataType = GL_UNSIGNED_SHORT; + rb->GetPointer = get_pointer_ushort; + rb->GetRow = get_row_ushort; + rb->GetValues = get_values_ushort; + rb->PutRow = put_row_ushort; + rb->PutRowRGB = NULL; + rb->PutMonoRow = put_mono_row_ushort; + rb->PutValues = put_values_ushort; + rb->PutMonoValues = put_mono_values_ushort; + rb->StencilBits = 8 * sizeof(GLushort); + pixelSize = sizeof(GLushort); + break; + case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT16: + rb->_ActualFormat = GL_DEPTH_COMPONENT16; + rb->_BaseFormat = GL_DEPTH_COMPONENT; + rb->DataType = GL_UNSIGNED_SHORT; + rb->GetPointer = get_pointer_ushort; + rb->GetRow = get_row_ushort; + rb->GetValues = get_values_ushort; + rb->PutRow = put_row_ushort; + rb->PutRowRGB = NULL; + rb->PutMonoRow = put_mono_row_ushort; + rb->PutValues = put_values_ushort; + rb->PutMonoValues = put_mono_values_ushort; + rb->DepthBits = 8 * sizeof(GLushort); + pixelSize = sizeof(GLushort); + break; + case GL_DEPTH_COMPONENT24: + case GL_DEPTH_COMPONENT32: + rb->_BaseFormat = GL_DEPTH_COMPONENT; + rb->DataType = GL_UNSIGNED_INT; + rb->GetPointer = get_pointer_uint; + rb->GetRow = get_row_uint; + rb->GetValues = get_values_uint; + rb->PutRow = put_row_uint; + rb->PutRowRGB = NULL; + rb->PutMonoRow = put_mono_row_uint; + rb->PutValues = put_values_uint; + rb->PutMonoValues = put_mono_values_uint; + if (internalFormat == GL_DEPTH_COMPONENT24) { + rb->_ActualFormat = GL_DEPTH_COMPONENT24; + rb->DepthBits = 24; + } + else { + rb->_ActualFormat = GL_DEPTH_COMPONENT32; + rb->DepthBits = 32; + } + pixelSize = sizeof(GLuint); + break; + case GL_DEPTH_STENCIL_EXT: + case GL_DEPTH24_STENCIL8_EXT: + rb->_ActualFormat = GL_DEPTH24_STENCIL8_EXT; + rb->_BaseFormat = GL_DEPTH_STENCIL_EXT; + rb->DataType = GL_UNSIGNED_INT_24_8_EXT; + rb->GetPointer = get_pointer_uint; + rb->GetRow = get_row_uint; + rb->GetValues = get_values_uint; + rb->PutRow = put_row_uint; + rb->PutRowRGB = NULL; + rb->PutMonoRow = put_mono_row_uint; + rb->PutValues = put_values_uint; + rb->PutMonoValues = put_mono_values_uint; + rb->DepthBits = 24; + rb->StencilBits = 8; + pixelSize = sizeof(GLuint); + break; + case GL_COLOR_INDEX8_EXT: + rb->_ActualFormat = GL_COLOR_INDEX8_EXT; + rb->_BaseFormat = GL_COLOR_INDEX; + rb->DataType = GL_UNSIGNED_BYTE; + rb->GetPointer = get_pointer_ubyte; + rb->GetRow = get_row_ubyte; + rb->GetValues = get_values_ubyte; + rb->PutRow = put_row_ubyte; + rb->PutRowRGB = NULL; + rb->PutMonoRow = put_mono_row_ubyte; + rb->PutValues = put_values_ubyte; + rb->PutMonoValues = put_mono_values_ubyte; + rb->IndexBits = 8 * sizeof(GLubyte); + pixelSize = sizeof(GLubyte); + break; + case GL_COLOR_INDEX16_EXT: + rb->_ActualFormat = GL_COLOR_INDEX16_EXT; + rb->_BaseFormat = GL_COLOR_INDEX; + rb->DataType = GL_UNSIGNED_SHORT; + rb->GetPointer = get_pointer_ushort; + rb->GetRow = get_row_ushort; + rb->GetValues = get_values_ushort; + rb->PutRow = put_row_ushort; + rb->PutRowRGB = NULL; + rb->PutMonoRow = put_mono_row_ushort; + rb->PutValues = put_values_ushort; + rb->PutMonoValues = put_mono_values_ushort; + rb->IndexBits = 8 * sizeof(GLushort); + pixelSize = sizeof(GLushort); + break; + case COLOR_INDEX32: + rb->_ActualFormat = COLOR_INDEX32; + rb->_BaseFormat = GL_COLOR_INDEX; + rb->DataType = GL_UNSIGNED_INT; + rb->GetPointer = get_pointer_uint; + rb->GetRow = get_row_uint; + rb->GetValues = get_values_uint; + rb->PutRow = put_row_uint; + rb->PutRowRGB = NULL; + rb->PutMonoRow = put_mono_row_uint; + rb->PutValues = put_values_uint; + rb->PutMonoValues = put_mono_values_uint; + rb->IndexBits = 8 * sizeof(GLuint); + pixelSize = sizeof(GLuint); + break; + default: + _mesa_problem(ctx, "Bad internalFormat in _mesa_soft_renderbuffer_storage"); + return GL_FALSE; + } + + ASSERT(rb->DataType); + ASSERT(rb->GetPointer); + ASSERT(rb->GetRow); + ASSERT(rb->GetValues); + ASSERT(rb->PutRow); + ASSERT(rb->PutMonoRow); + ASSERT(rb->PutValues); + ASSERT(rb->PutMonoValues); + + /* free old buffer storage */ + if (rb->Data) { + _mesa_free(rb->Data); + rb->Data = NULL; + } + + if (width > 0 && height > 0) { + /* allocate new buffer storage */ + rb->Data = malloc(width * height * pixelSize); + + if (rb->Data == NULL) { + rb->Width = 0; + rb->Height = 0; + _mesa_error(ctx, GL_OUT_OF_MEMORY, + "software renderbuffer allocation (%d x %d x %d)", + width, height, pixelSize); + return GL_FALSE; + } + } + + rb->Width = width; + rb->Height = height; + + return GL_TRUE; +} + + + +/**********************************************************************/ +/**********************************************************************/ +/**********************************************************************/ + + +/** + * Here we utilize the gl_renderbuffer->Wrapper field to put an alpha + * buffer wrapper around an existing RGB renderbuffer (hw or sw). + * + * When PutRow is called (for example), we store the alpha values in + * this buffer, then pass on the PutRow call to the wrapped RGB + * buffer. + */ + + +static GLboolean +alloc_storage_alpha8(GLcontext *ctx, struct gl_renderbuffer *arb, + GLenum internalFormat, GLuint width, GLuint height) +{ + ASSERT(arb != arb->Wrapped); + ASSERT(arb->_ActualFormat == GL_ALPHA8); + + /* first, pass the call to the wrapped RGB buffer */ + if (!arb->Wrapped->AllocStorage(ctx, arb->Wrapped, internalFormat, + width, height)) { + return GL_FALSE; + } + + /* next, resize my alpha buffer */ + if (arb->Data) { + _mesa_free(arb->Data); + } + + arb->Data = _mesa_malloc(width * height * sizeof(GLubyte)); + if (arb->Data == NULL) { + arb->Width = 0; + arb->Height = 0; + _mesa_error(ctx, GL_OUT_OF_MEMORY, "software alpha buffer allocation"); + return GL_FALSE; + } + + arb->Width = width; + arb->Height = height; + + return GL_TRUE; +} + + +/** + * Delete an alpha_renderbuffer object, as well as the wrapped RGB buffer. + */ +static void +delete_renderbuffer_alpha8(struct gl_renderbuffer *arb) +{ + if (arb->Data) { + _mesa_free(arb->Data); + } + ASSERT(arb->Wrapped); + ASSERT(arb != arb->Wrapped); + arb->Wrapped->Delete(arb->Wrapped); + arb->Wrapped = NULL; + _mesa_free(arb); +} + + +static void * +get_pointer_alpha8(GLcontext *ctx, struct gl_renderbuffer *arb, + GLint x, GLint y) +{ + return NULL; /* don't allow direct access! */ +} + + +static void +get_row_alpha8(GLcontext *ctx, struct gl_renderbuffer *arb, GLuint count, + GLint x, GLint y, void *values) +{ + /* NOTE: 'values' is RGBA format! */ + const GLubyte *src = (const GLubyte *) arb->Data + y * arb->Width + x; + GLubyte *dst = (GLubyte *) values; + GLuint i; + ASSERT(arb != arb->Wrapped); + ASSERT(arb->DataType == GL_UNSIGNED_BYTE); + /* first, pass the call to the wrapped RGB buffer */ + arb->Wrapped->GetRow(ctx, arb->Wrapped, count, x, y, values); + /* second, fill in alpha values from this buffer! */ + for (i = 0; i < count; i++) { + dst[i * 4 + 3] = src[i]; + } +} + + +static void +get_values_alpha8(GLcontext *ctx, struct gl_renderbuffer *arb, GLuint count, + const GLint x[], const GLint y[], void *values) +{ + GLubyte *dst = (GLubyte *) values; + GLuint i; + ASSERT(arb != arb->Wrapped); + ASSERT(arb->DataType == GL_UNSIGNED_BYTE); + /* first, pass the call to the wrapped RGB buffer */ + arb->Wrapped->GetValues(ctx, arb->Wrapped, count, x, y, values); + /* second, fill in alpha values from this buffer! */ + for (i = 0; i < count; i++) { + const GLubyte *src = (GLubyte *) arb->Data + y[i] * arb->Width + x[i]; + dst[i * 4 + 3] = *src; + } +} + + +static void +put_row_alpha8(GLcontext *ctx, struct gl_renderbuffer *arb, GLuint count, + GLint x, GLint y, const void *values, const GLubyte *mask) +{ + const GLubyte *src = (const GLubyte *) values; + GLubyte *dst = (GLubyte *) arb->Data + y * arb->Width + x; + GLuint i; + ASSERT(arb != arb->Wrapped); + ASSERT(arb->DataType == GL_UNSIGNED_BYTE); + /* first, pass the call to the wrapped RGB buffer */ + arb->Wrapped->PutRow(ctx, arb->Wrapped, count, x, y, values, mask); + /* second, store alpha in our buffer */ + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + dst[i] = src[i * 4 + 3]; + } + } +} + + +static void +put_row_rgb_alpha8(GLcontext *ctx, struct gl_renderbuffer *arb, GLuint count, + GLint x, GLint y, const void *values, const GLubyte *mask) +{ + const GLubyte *src = (const GLubyte *) values; + GLubyte *dst = (GLubyte *) arb->Data + y * arb->Width + x; + GLuint i; + ASSERT(arb != arb->Wrapped); + ASSERT(arb->DataType == GL_UNSIGNED_BYTE); + /* first, pass the call to the wrapped RGB buffer */ + arb->Wrapped->PutRowRGB(ctx, arb->Wrapped, count, x, y, values, mask); + /* second, store alpha in our buffer */ + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + dst[i] = src[i * 4 + 3]; + } + } +} + + +static void +put_mono_row_alpha8(GLcontext *ctx, struct gl_renderbuffer *arb, GLuint count, + GLint x, GLint y, const void *value, const GLubyte *mask) +{ + const GLubyte val = ((const GLubyte *) value)[3]; + GLubyte *dst = (GLubyte *) arb->Data + y * arb->Width + x; + ASSERT(arb != arb->Wrapped); + ASSERT(arb->DataType == GL_UNSIGNED_BYTE); + /* first, pass the call to the wrapped RGB buffer */ + arb->Wrapped->PutMonoRow(ctx, arb->Wrapped, count, x, y, value, mask); + /* second, store alpha in our buffer */ + if (mask) { + GLuint i; + for (i = 0; i < count; i++) { + if (mask[i]) { + dst[i] = val; + } + } + } + else { + _mesa_memset(dst, val, count); + } +} + + +static void +put_values_alpha8(GLcontext *ctx, struct gl_renderbuffer *arb, GLuint count, + const GLint x[], const GLint y[], + const void *values, const GLubyte *mask) +{ + const GLubyte *src = (const GLubyte *) values; + GLuint i; + ASSERT(arb != arb->Wrapped); + ASSERT(arb->DataType == GL_UNSIGNED_BYTE); + /* first, pass the call to the wrapped RGB buffer */ + arb->Wrapped->PutValues(ctx, arb->Wrapped, count, x, y, values, mask); + /* second, store alpha in our buffer */ + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + GLubyte *dst = (GLubyte *) arb->Data + y[i] * arb->Width + x[i]; + *dst = src[i * 4 + 3]; + } + } +} + + +static void +put_mono_values_alpha8(GLcontext *ctx, struct gl_renderbuffer *arb, + GLuint count, const GLint x[], const GLint y[], + const void *value, const GLubyte *mask) +{ + const GLubyte val = ((const GLubyte *) value)[3]; + GLuint i; + ASSERT(arb != arb->Wrapped); + ASSERT(arb->DataType == GL_UNSIGNED_BYTE); + /* first, pass the call to the wrapped RGB buffer */ + arb->Wrapped->PutValues(ctx, arb->Wrapped, count, x, y, value, mask); + /* second, store alpha in our buffer */ + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + GLubyte *dst = (GLubyte *) arb->Data + y[i] * arb->Width + x[i]; + *dst = val; + } + } +} + + +static void +copy_buffer_alpha8(struct gl_renderbuffer* dst, struct gl_renderbuffer* src) +{ + ASSERT(dst->_ActualFormat == GL_ALPHA8); + ASSERT(src->_ActualFormat == GL_ALPHA8); + ASSERT(dst->Width == src->Width); + ASSERT(dst->Height == src->Height); + + _mesa_memcpy(dst->Data, src->Data, dst->Width * dst->Height * sizeof(GLubyte)); +} + + +/**********************************************************************/ +/**********************************************************************/ +/**********************************************************************/ + + +/** + * Default GetPointer routine. Always return NULL to indicate that + * direct buffer access is not supported. + */ +static void * +nop_get_pointer(GLcontext *ctx, struct gl_renderbuffer *rb, GLint x, GLint y) +{ + return NULL; +} + + +/** + * Initialize the fields of a gl_renderbuffer to default values. + */ +void +_mesa_init_renderbuffer(struct gl_renderbuffer *rb, GLuint name) +{ + _glthread_INIT_MUTEX(rb->Mutex); + + rb->Magic = RB_MAGIC; + rb->ClassID = 0; + rb->Name = name; + rb->RefCount = 0; + rb->Delete = _mesa_delete_renderbuffer; + + /* The rest of these should be set later by the caller of this function or + * the AllocStorage method: + */ + rb->AllocStorage = NULL; + + rb->Width = 0; + rb->Height = 0; + rb->InternalFormat = GL_NONE; + rb->_ActualFormat = GL_NONE; + rb->_BaseFormat = GL_NONE; + + rb->ComponentType = GL_UNSIGNED_NORMALIZED; /* ARB_fbo */ + rb->ColorEncoding = GL_LINEAR; /* ARB_fbo */ + + rb->RedBits = rb->GreenBits = rb->BlueBits = rb->AlphaBits = 0; + rb->IndexBits = 0; + rb->DepthBits = 0; + rb->StencilBits = 0; + + rb->DataType = GL_NONE; + rb->Data = NULL; + + /* Point back to ourself so that we don't have to check for Wrapped==NULL + * all over the drivers. + */ + rb->Wrapped = rb; + + rb->GetPointer = nop_get_pointer; + rb->GetRow = NULL; + rb->GetValues = NULL; + rb->PutRow = NULL; + rb->PutRowRGB = NULL; + rb->PutMonoRow = NULL; + rb->PutValues = NULL; + rb->PutMonoValues = NULL; +} + + +/** + * Allocate a new gl_renderbuffer object. This can be used for user-created + * renderbuffers or window-system renderbuffers. + */ +struct gl_renderbuffer * +_mesa_new_renderbuffer(GLcontext *ctx, GLuint name) +{ + struct gl_renderbuffer *rb = CALLOC_STRUCT(gl_renderbuffer); + if (rb) { + _mesa_init_renderbuffer(rb, name); + } + return rb; +} + + +/** + * Delete a gl_framebuffer. + * This is the default function for renderbuffer->Delete(). + */ +void +_mesa_delete_renderbuffer(struct gl_renderbuffer *rb) +{ + if (rb->Data) { + _mesa_free(rb->Data); + } + _mesa_free(rb); +} + + +/** + * Allocate a software-based renderbuffer. This is called via the + * ctx->Driver.NewRenderbuffer() function when the user creates a new + * renderbuffer. + * This would not be used for hardware-based renderbuffers. + */ +struct gl_renderbuffer * +_mesa_new_soft_renderbuffer(GLcontext *ctx, GLuint name) +{ + struct gl_renderbuffer *rb = _mesa_new_renderbuffer(ctx, name); + if (rb) { + rb->AllocStorage = _mesa_soft_renderbuffer_storage; + /* Normally, one would setup the PutRow, GetRow, etc functions here. + * But we're doing that in the _mesa_soft_renderbuffer_storage() function + * instead. + */ + } + return rb; +} + + +/** + * Add software-based color renderbuffers to the given framebuffer. + * This is a helper routine for device drivers when creating a + * window system framebuffer (not a user-created render/framebuffer). + * Once this function is called, you can basically forget about this + * renderbuffer; core Mesa will handle all the buffer management and + * rendering! + */ +GLboolean +_mesa_add_color_renderbuffers(GLcontext *ctx, struct gl_framebuffer *fb, + GLuint rgbBits, GLuint alphaBits, + GLboolean frontLeft, GLboolean backLeft, + GLboolean frontRight, GLboolean backRight) +{ + GLuint b; + + if (rgbBits > 16 || alphaBits > 16) { + _mesa_problem(ctx, + "Unsupported bit depth in _mesa_add_color_renderbuffers"); + return GL_FALSE; + } + + assert(MAX_COLOR_ATTACHMENTS >= 4); + + for (b = BUFFER_FRONT_LEFT; b <= BUFFER_BACK_RIGHT; b++) { + struct gl_renderbuffer *rb; + + if (b == BUFFER_FRONT_LEFT && !frontLeft) + continue; + else if (b == BUFFER_BACK_LEFT && !backLeft) + continue; + else if (b == BUFFER_FRONT_RIGHT && !frontRight) + continue; + else if (b == BUFFER_BACK_RIGHT && !backRight) + continue; + + assert(fb->Attachment[b].Renderbuffer == NULL); + + rb = _mesa_new_renderbuffer(ctx, 0); + if (!rb) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating color buffer"); + return GL_FALSE; + } + + if (rgbBits <= 8) { + if (alphaBits) + rb->_ActualFormat = GL_RGBA8; + else + rb->_ActualFormat = GL_RGB8; + } + else { + assert(rgbBits <= 16); + if (alphaBits) + rb->_ActualFormat = GL_RGBA16; + else + rb->_ActualFormat = GL_RGBA16; /* don't really have RGB16 yet */ + } + rb->InternalFormat = rb->_ActualFormat; + + rb->AllocStorage = _mesa_soft_renderbuffer_storage; + _mesa_add_renderbuffer(fb, b, rb); + } + + return GL_TRUE; +} + + +/** + * Add software-based color index renderbuffers to the given framebuffer. + * This is a helper routine for device drivers when creating a + * window system framebuffer (not a user-created render/framebuffer). + * Once this function is called, you can basically forget about this + * renderbuffer; core Mesa will handle all the buffer management and + * rendering! + */ +GLboolean +_mesa_add_color_index_renderbuffers(GLcontext *ctx, struct gl_framebuffer *fb, + GLuint indexBits, + GLboolean frontLeft, GLboolean backLeft, + GLboolean frontRight, GLboolean backRight) +{ + GLuint b; + + if (indexBits > 8) { + _mesa_problem(ctx, + "Unsupported bit depth in _mesa_add_color_index_renderbuffers"); + return GL_FALSE; + } + + assert(MAX_COLOR_ATTACHMENTS >= 4); + + for (b = BUFFER_FRONT_LEFT; b <= BUFFER_BACK_RIGHT; b++) { + struct gl_renderbuffer *rb; + + if (b == BUFFER_FRONT_LEFT && !frontLeft) + continue; + else if (b == BUFFER_BACK_LEFT && !backLeft) + continue; + else if (b == BUFFER_FRONT_RIGHT && !frontRight) + continue; + else if (b == BUFFER_BACK_RIGHT && !backRight) + continue; + + assert(fb->Attachment[b].Renderbuffer == NULL); + + rb = _mesa_new_renderbuffer(ctx, 0); + if (!rb) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating color buffer"); + return GL_FALSE; + } + + if (indexBits <= 8) { + /* only support GLuint for now */ + /*rb->InternalFormat = GL_COLOR_INDEX8_EXT;*/ + rb->_ActualFormat = COLOR_INDEX32; + } + else { + rb->_ActualFormat = COLOR_INDEX32; + } + rb->InternalFormat = rb->_ActualFormat; + + rb->AllocStorage = _mesa_soft_renderbuffer_storage; + _mesa_add_renderbuffer(fb, b, rb); + } + + return GL_TRUE; +} + + +/** + * Add software-based alpha renderbuffers to the given framebuffer. + * This is a helper routine for device drivers when creating a + * window system framebuffer (not a user-created render/framebuffer). + * Once this function is called, you can basically forget about this + * renderbuffer; core Mesa will handle all the buffer management and + * rendering! + */ +GLboolean +_mesa_add_alpha_renderbuffers(GLcontext *ctx, struct gl_framebuffer *fb, + GLuint alphaBits, + GLboolean frontLeft, GLboolean backLeft, + GLboolean frontRight, GLboolean backRight) +{ + GLuint b; + + /* for window system framebuffers only! */ + assert(fb->Name == 0); + + if (alphaBits > 8) { + _mesa_problem(ctx, + "Unsupported bit depth in _mesa_add_alpha_renderbuffers"); + return GL_FALSE; + } + + assert(MAX_COLOR_ATTACHMENTS >= 4); + + /* Wrap each of the RGB color buffers with an alpha renderbuffer. + */ + for (b = BUFFER_FRONT_LEFT; b <= BUFFER_BACK_RIGHT; b++) { + struct gl_renderbuffer *arb; + + if (b == BUFFER_FRONT_LEFT && !frontLeft) + continue; + else if (b == BUFFER_BACK_LEFT && !backLeft) + continue; + else if (b == BUFFER_FRONT_RIGHT && !frontRight) + continue; + else if (b == BUFFER_BACK_RIGHT && !backRight) + continue; + + /* the RGB buffer to wrap must already exist!! */ + assert(fb->Attachment[b].Renderbuffer); + + /* only GLubyte supported for now */ + assert(fb->Attachment[b].Renderbuffer->DataType == GL_UNSIGNED_BYTE); + + /* allocate alpha renderbuffer */ + arb = _mesa_new_renderbuffer(ctx, 0); + if (!arb) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating alpha buffer"); + return GL_FALSE; + } + + /* wrap the alpha renderbuffer around the RGB renderbuffer */ + arb->Wrapped = fb->Attachment[b].Renderbuffer; + + /* Set up my alphabuffer fields and plug in my functions. + * The functions will put/get the alpha values from/to RGBA arrays + * and then call the wrapped buffer's functions to handle the RGB + * values. + */ + arb->InternalFormat = arb->Wrapped->InternalFormat; + arb->_ActualFormat = GL_ALPHA8; + arb->_BaseFormat = arb->Wrapped->_BaseFormat; + arb->DataType = arb->Wrapped->DataType; + arb->AllocStorage = alloc_storage_alpha8; + arb->Delete = delete_renderbuffer_alpha8; + arb->GetPointer = get_pointer_alpha8; + arb->GetRow = get_row_alpha8; + arb->GetValues = get_values_alpha8; + arb->PutRow = put_row_alpha8; + arb->PutRowRGB = put_row_rgb_alpha8; + arb->PutMonoRow = put_mono_row_alpha8; + arb->PutValues = put_values_alpha8; + arb->PutMonoValues = put_mono_values_alpha8; + + /* clear the pointer to avoid assertion/sanity check failure later */ + fb->Attachment[b].Renderbuffer = NULL; + + /* plug the alpha renderbuffer into the colorbuffer attachment */ + _mesa_add_renderbuffer(fb, b, arb); + } + + return GL_TRUE; +} + + +/** + * For framebuffers that use a software alpha channel wrapper + * created by _mesa_add_alpha_renderbuffer or _mesa_add_soft_renderbuffers, + * copy the back buffer alpha channel into the front buffer alpha channel. + */ +void +_mesa_copy_soft_alpha_renderbuffers(GLcontext *ctx, struct gl_framebuffer *fb) +{ + if (fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer && + fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer) + copy_buffer_alpha8(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer, + fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer); + + + if (fb->Attachment[BUFFER_FRONT_RIGHT].Renderbuffer && + fb->Attachment[BUFFER_BACK_RIGHT].Renderbuffer) + copy_buffer_alpha8(fb->Attachment[BUFFER_FRONT_RIGHT].Renderbuffer, + fb->Attachment[BUFFER_BACK_RIGHT].Renderbuffer); +} + + +/** + * Add a software-based depth renderbuffer to the given framebuffer. + * This is a helper routine for device drivers when creating a + * window system framebuffer (not a user-created render/framebuffer). + * Once this function is called, you can basically forget about this + * renderbuffer; core Mesa will handle all the buffer management and + * rendering! + */ +GLboolean +_mesa_add_depth_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb, + GLuint depthBits) +{ + struct gl_renderbuffer *rb; + + if (depthBits > 32) { + _mesa_problem(ctx, + "Unsupported depthBits in _mesa_add_depth_renderbuffer"); + return GL_FALSE; + } + + assert(fb->Attachment[BUFFER_DEPTH].Renderbuffer == NULL); + + rb = _mesa_new_renderbuffer(ctx, 0); + if (!rb) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating depth buffer"); + return GL_FALSE; + } + + if (depthBits <= 16) { + rb->_ActualFormat = GL_DEPTH_COMPONENT16; + } + else if (depthBits <= 24) { + rb->_ActualFormat = GL_DEPTH_COMPONENT24; + } + else { + rb->_ActualFormat = GL_DEPTH_COMPONENT32; + } + rb->InternalFormat = rb->_ActualFormat; + + rb->AllocStorage = _mesa_soft_renderbuffer_storage; + _mesa_add_renderbuffer(fb, BUFFER_DEPTH, rb); + + return GL_TRUE; +} + + +/** + * Add a software-based stencil renderbuffer to the given framebuffer. + * This is a helper routine for device drivers when creating a + * window system framebuffer (not a user-created render/framebuffer). + * Once this function is called, you can basically forget about this + * renderbuffer; core Mesa will handle all the buffer management and + * rendering! + */ +GLboolean +_mesa_add_stencil_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb, + GLuint stencilBits) +{ + struct gl_renderbuffer *rb; + + if (stencilBits > 16) { + _mesa_problem(ctx, + "Unsupported stencilBits in _mesa_add_stencil_renderbuffer"); + return GL_FALSE; + } + + assert(fb->Attachment[BUFFER_STENCIL].Renderbuffer == NULL); + + rb = _mesa_new_renderbuffer(ctx, 0); + if (!rb) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating stencil buffer"); + return GL_FALSE; + } + + if (stencilBits <= 8) { + rb->_ActualFormat = GL_STENCIL_INDEX8_EXT; + } + else { + /* not really supported (see s_stencil.c code) */ + rb->_ActualFormat = GL_STENCIL_INDEX16_EXT; + } + rb->InternalFormat = rb->_ActualFormat; + + rb->AllocStorage = _mesa_soft_renderbuffer_storage; + _mesa_add_renderbuffer(fb, BUFFER_STENCIL, rb); + + return GL_TRUE; +} + + +/** + * Add a software-based accumulation renderbuffer to the given framebuffer. + * This is a helper routine for device drivers when creating a + * window system framebuffer (not a user-created render/framebuffer). + * Once this function is called, you can basically forget about this + * renderbuffer; core Mesa will handle all the buffer management and + * rendering! + */ +GLboolean +_mesa_add_accum_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb, + GLuint redBits, GLuint greenBits, + GLuint blueBits, GLuint alphaBits) +{ + struct gl_renderbuffer *rb; + + if (redBits > 16 || greenBits > 16 || blueBits > 16 || alphaBits > 16) { + _mesa_problem(ctx, + "Unsupported accumBits in _mesa_add_accum_renderbuffer"); + return GL_FALSE; + } + + assert(fb->Attachment[BUFFER_ACCUM].Renderbuffer == NULL); + + rb = _mesa_new_renderbuffer(ctx, 0); + if (!rb) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating accum buffer"); + return GL_FALSE; + } + + rb->_ActualFormat = GL_RGBA16; + rb->InternalFormat = GL_RGBA16; + rb->AllocStorage = _mesa_soft_renderbuffer_storage; + _mesa_add_renderbuffer(fb, BUFFER_ACCUM, rb); + + return GL_TRUE; +} + + + +/** + * Add a software-based accumulation renderbuffer to the given framebuffer. + * This is a helper routine for device drivers when creating a + * window system framebuffer (not a user-created render/framebuffer). + * Once this function is called, you can basically forget about this + * renderbuffer; core Mesa will handle all the buffer management and + * rendering! + * + * NOTE: color-index aux buffers not supported. + */ +GLboolean +_mesa_add_aux_renderbuffers(GLcontext *ctx, struct gl_framebuffer *fb, + GLuint colorBits, GLuint numBuffers) +{ + GLuint i; + + if (colorBits > 16) { + _mesa_problem(ctx, + "Unsupported accumBits in _mesa_add_aux_renderbuffers"); + return GL_FALSE; + } + + assert(numBuffers < MAX_AUX_BUFFERS); + + for (i = 0; i < numBuffers; i++) { + struct gl_renderbuffer *rb = _mesa_new_renderbuffer(ctx, 0); + + assert(fb->Attachment[BUFFER_AUX0 + i].Renderbuffer == NULL); + + if (!rb) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating accum buffer"); + return GL_FALSE; + } + + if (colorBits <= 8) { + rb->_ActualFormat = GL_RGBA8; + } + else { + rb->_ActualFormat = GL_RGBA16; + } + rb->InternalFormat = rb->_ActualFormat; + + rb->AllocStorage = _mesa_soft_renderbuffer_storage; + _mesa_add_renderbuffer(fb, BUFFER_AUX0 + i, rb); + } + return GL_TRUE; +} + + +/** + * Create/attach software-based renderbuffers to the given framebuffer. + * This is a helper routine for device drivers. Drivers can just as well + * call the individual _mesa_add_*_renderbuffer() routines directly. + */ +void +_mesa_add_soft_renderbuffers(struct gl_framebuffer *fb, + GLboolean color, + GLboolean depth, + GLboolean stencil, + GLboolean accum, + GLboolean alpha, + GLboolean aux) +{ + GLboolean frontLeft = GL_TRUE; + GLboolean backLeft = fb->Visual.doubleBufferMode; + GLboolean frontRight = fb->Visual.stereoMode; + GLboolean backRight = fb->Visual.stereoMode && fb->Visual.doubleBufferMode; + + if (color) { + if (fb->Visual.rgbMode) { + assert(fb->Visual.redBits == fb->Visual.greenBits); + assert(fb->Visual.redBits == fb->Visual.blueBits); + _mesa_add_color_renderbuffers(NULL, fb, + fb->Visual.redBits, + fb->Visual.alphaBits, + frontLeft, backLeft, + frontRight, backRight); + } + else { + _mesa_add_color_index_renderbuffers(NULL, fb, + fb->Visual.indexBits, + frontLeft, backLeft, + frontRight, backRight); + } + } + + if (depth) { + assert(fb->Visual.depthBits > 0); + _mesa_add_depth_renderbuffer(NULL, fb, fb->Visual.depthBits); + } + + if (stencil) { + assert(fb->Visual.stencilBits > 0); + _mesa_add_stencil_renderbuffer(NULL, fb, fb->Visual.stencilBits); + } + + if (accum) { + assert(fb->Visual.rgbMode); + assert(fb->Visual.accumRedBits > 0); + assert(fb->Visual.accumGreenBits > 0); + assert(fb->Visual.accumBlueBits > 0); + _mesa_add_accum_renderbuffer(NULL, fb, + fb->Visual.accumRedBits, + fb->Visual.accumGreenBits, + fb->Visual.accumBlueBits, + fb->Visual.accumAlphaBits); + } + + if (aux) { + assert(fb->Visual.rgbMode); + assert(fb->Visual.numAuxBuffers > 0); + _mesa_add_aux_renderbuffers(NULL, fb, fb->Visual.redBits, + fb->Visual.numAuxBuffers); + } + + if (alpha) { + assert(fb->Visual.rgbMode); + assert(fb->Visual.alphaBits > 0); + _mesa_add_alpha_renderbuffers(NULL, fb, fb->Visual.alphaBits, + frontLeft, backLeft, + frontRight, backRight); + } + +#if 0 + if (multisample) { + /* maybe someday */ + } +#endif +} + + +/** + * Attach a renderbuffer to a framebuffer. + */ +void +_mesa_add_renderbuffer(struct gl_framebuffer *fb, + GLuint bufferName, struct gl_renderbuffer *rb) +{ + assert(fb); + assert(rb); + assert(bufferName < BUFFER_COUNT); + + /* There should be no previous renderbuffer on this attachment point, + * with the exception of depth/stencil since the same renderbuffer may + * be used for both. + */ + assert(bufferName == BUFFER_DEPTH || + bufferName == BUFFER_STENCIL || + fb->Attachment[bufferName].Renderbuffer == NULL); + + /* winsys vs. user-created buffer cross check */ + if (fb->Name) { + assert(rb->Name); + } + else { + assert(!rb->Name); + } + + /* If Mesa's compiled with deep color channels (16 or 32 bits / channel) + * and the device driver is expecting 8-bit values (GLubyte), we can + * use a "renderbuffer adaptor/wrapper" to do the necessary conversions. + */ + if (rb->_BaseFormat == GL_RGBA) { + if (CHAN_BITS == 16 && rb->DataType == GL_UNSIGNED_BYTE) { + GET_CURRENT_CONTEXT(ctx); + rb = _mesa_new_renderbuffer_16wrap8(ctx, rb); + } + else if (CHAN_BITS == 32 && rb->DataType == GL_UNSIGNED_BYTE) { + GET_CURRENT_CONTEXT(ctx); + rb = _mesa_new_renderbuffer_32wrap8(ctx, rb); + } + else if (CHAN_BITS == 32 && rb->DataType == GL_UNSIGNED_SHORT) { + GET_CURRENT_CONTEXT(ctx); + rb = _mesa_new_renderbuffer_32wrap16(ctx, rb); + } + } + + fb->Attachment[bufferName].Type = GL_RENDERBUFFER_EXT; + fb->Attachment[bufferName].Complete = GL_TRUE; + _mesa_reference_renderbuffer(&fb->Attachment[bufferName].Renderbuffer, rb); +} + + +/** + * Remove the named renderbuffer from the given framebuffer. + */ +void +_mesa_remove_renderbuffer(struct gl_framebuffer *fb, GLuint bufferName) +{ + struct gl_renderbuffer *rb; + + assert(bufferName < BUFFER_COUNT); + + rb = fb->Attachment[bufferName].Renderbuffer; + if (!rb) + return; + + _mesa_reference_renderbuffer(&rb, NULL); + + fb->Attachment[bufferName].Renderbuffer = NULL; +} + + +/** + * Set *ptr to point to rb. If *ptr points to another renderbuffer, + * dereference that buffer first. The new renderbuffer's refcount will + * be incremented. The old renderbuffer's refcount will be decremented. + */ +void +_mesa_reference_renderbuffer(struct gl_renderbuffer **ptr, + struct gl_renderbuffer *rb) +{ + assert(ptr); + if (*ptr == rb) { + /* no change */ + return; + } + + if (*ptr) { + /* Unreference the old renderbuffer */ + GLboolean deleteFlag = GL_FALSE; + struct gl_renderbuffer *oldRb = *ptr; + + assert(oldRb->Magic == RB_MAGIC); + _glthread_LOCK_MUTEX(oldRb->Mutex); + assert(oldRb->Magic == RB_MAGIC); + ASSERT(oldRb->RefCount > 0); + oldRb->RefCount--; + /*printf("RB DECR %p (%d) to %d\n", (void*) oldRb, oldRb->Name, oldRb->RefCount);*/ + deleteFlag = (oldRb->RefCount == 0); + _glthread_UNLOCK_MUTEX(oldRb->Mutex); + + if (deleteFlag) { + oldRb->Magic = 0; /* now invalid memory! */ + oldRb->Delete(oldRb); + } + + *ptr = NULL; + } + assert(!*ptr); + + if (rb) { + assert(rb->Magic == RB_MAGIC); + /* reference new renderbuffer */ + _glthread_LOCK_MUTEX(rb->Mutex); + rb->RefCount++; + /*printf("RB INCR %p (%d) to %d\n", (void*) rb, rb->Name, rb->RefCount);*/ + _glthread_UNLOCK_MUTEX(rb->Mutex); + *ptr = rb; + } +} + + +/** + * Create a new combined depth/stencil renderbuffer for implementing + * the GL_EXT_packed_depth_stencil extension. + * \return new depth/stencil renderbuffer + */ +struct gl_renderbuffer * +_mesa_new_depthstencil_renderbuffer(GLcontext *ctx, GLuint name) +{ + struct gl_renderbuffer *dsrb; + + dsrb = _mesa_new_renderbuffer(ctx, name); + if (!dsrb) + return NULL; + + /* init fields not covered by _mesa_new_renderbuffer() */ + dsrb->InternalFormat = GL_DEPTH24_STENCIL8_EXT; + dsrb->_ActualFormat = GL_DEPTH24_STENCIL8_EXT; + dsrb->AllocStorage = _mesa_soft_renderbuffer_storage; + + return dsrb; +} |