| /* |
| * 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 = _mesa_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->DataType = GL_NONE; |
| rb->RedBits = rb->GreenBits = rb->BlueBits = rb->AlphaBits = 0; |
| rb->IndexBits = 0; |
| rb->DepthBits = 0; |
| rb->StencilBits = 0; |
| 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; |
| } |