blob: 6f1d7c39605697225d67a94eebff21bf447a9777 [file] [log] [blame]
/*
* 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;
}