diff options
author | Brian Paul <brian.paul@tungstengraphics.com> | 2005-11-16 04:05:54 +0000 |
---|---|---|
committer | Brian Paul <brian.paul@tungstengraphics.com> | 2005-11-16 04:05:54 +0000 |
commit | 847160466cb7d1af55f294578c328b01fb3fd3d3 (patch) | |
tree | 7a85fe8a10af86caf7c94eb193572d08da4eb80e | |
parent | 06185363ddcbd53a7b8b60350e71d9725a1632d5 (diff) |
Support for combined depth/stencil renderbuffers (GL_EXT_packed_depth_stencil).
depthstencil.c provides wrappers for treating depth/stencil buffers either
as regular depth or stencil renderbuffers.
-rw-r--r-- | src/mesa/main/dd.h | 3 | ||||
-rw-r--r-- | src/mesa/main/depthstencil.c | 549 | ||||
-rw-r--r-- | src/mesa/main/depthstencil.h | 55 | ||||
-rw-r--r-- | src/mesa/main/fbobject.c | 36 | ||||
-rw-r--r-- | src/mesa/main/fbobject.h | 10 | ||||
-rw-r--r-- | src/mesa/main/framebuffer.c | 105 | ||||
-rw-r--r-- | src/mesa/main/mtypes.h | 5 |
7 files changed, 740 insertions, 23 deletions
diff --git a/src/mesa/main/dd.h b/src/mesa/main/dd.h index f150cf99e2..1e7a93e939 100644 --- a/src/mesa/main/dd.h +++ b/src/mesa/main/dd.h @@ -802,7 +802,8 @@ struct dd_function_table { struct gl_framebuffer * (*NewFramebuffer)(GLcontext *ctx, GLuint name); struct gl_renderbuffer * (*NewRenderbuffer)(GLcontext *ctx, GLuint name); void (*FramebufferRenderbuffer)(GLcontext *ctx, - struct gl_renderbuffer_attachment *att, + struct gl_framebuffer *fb, + GLenum attachment, struct gl_renderbuffer *rb); void (*RenderbufferTexture)(GLcontext *ctx, struct gl_renderbuffer_attachment *att, diff --git a/src/mesa/main/depthstencil.c b/src/mesa/main/depthstencil.c new file mode 100644 index 0000000000..90e434118e --- /dev/null +++ b/src/mesa/main/depthstencil.c @@ -0,0 +1,549 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 1999-2005 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. + */ + +#include "glheader.h" +#include "imports.h" +#include "context.h" +#include "fbobject.h" +#include "mtypes.h" +#include "depthstencil.h" +#include "renderbuffer.h" + + +/** + * Adaptor/wrappers for GL_DEPTH_STENCIL renderbuffers. + * + * The problem with a GL_DEPTH_STENCIL renderbuffer is that sometimes we + * want to treat it as a stencil buffer, other times we want to treat it + * as a depth/z buffer and still other times when we want to treat it as + * a combined Z+stencil buffer! That implies we need three different sets + * of Get/Put functions. + * + * We solve this by wrapping the Z24_S8 renderbuffer with depth and stencil + * adaptors, each with the right kind of depth/stencil Get/Put functions. + */ + + +static void * +nop_get_pointer(GLcontext *ctx, struct gl_renderbuffer *rb, GLint x, GLint y) +{ + return NULL; +} + + +/** + * Delete a depth or stencil renderbuffer. + */ +static void +delete_wrapper(struct gl_renderbuffer *rb) +{ + struct gl_renderbuffer *dsrb = rb->Wrapped; + assert(dsrb); + assert(rb->InternalFormat == GL_DEPTH_COMPONENT24 || + rb->InternalFormat == GL_STENCIL_INDEX8_EXT); + /* decrement refcount on the wrapped buffer and delete it if necessary */ + dsrb->RefCount--; + if (dsrb->RefCount <= 0) { + dsrb->Delete(dsrb); + } + _mesa_free(rb); +} + + +/*====================================================================== + * Depth wrapper around depth/stencil renderbuffer + */ + +static void +get_row_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb, GLuint count, + GLint x, GLint y, void *values) +{ + struct gl_renderbuffer *dsrb = z24rb->Wrapped; + GLuint temp[MAX_WIDTH], i; + GLuint *dst = (GLuint *) values; + const GLuint *src = (const GLuint *) dsrb->GetPointer(ctx, dsrb, x, y); + ASSERT(z24rb->DataType == GL_UNSIGNED_INT); + ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT); + if (!src) { + dsrb->GetRow(ctx, dsrb, count, x, y, temp); + src = temp; + } + for (i = 0; i < count; i++) { + dst[i] = src[i] >> 8; + } +} + +static void +get_values_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb, GLuint count, + const GLint x[], const GLint y[], void *values) +{ + struct gl_renderbuffer *dsrb = z24rb->Wrapped; + GLuint temp[MAX_WIDTH], i; + GLuint *dst = (GLuint *) values; + ASSERT(z24rb->DataType == GL_UNSIGNED_INT); + ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT); + ASSERT(count <= MAX_WIDTH); + /* don't bother trying direct access */ + dsrb->GetValues(ctx, dsrb, count, x, y, temp); + for (i = 0; i < count; i++) { + dst[i] = temp[i] >> 8; + } +} + +static void +put_row_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb, GLuint count, + GLint x, GLint y, const void *values, const GLubyte *mask) +{ + struct gl_renderbuffer *dsrb = z24rb->Wrapped; + const GLuint *src = (const GLuint *) values; + GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x, y); + ASSERT(z24rb->DataType == GL_UNSIGNED_INT); + ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT); + if (dst) { + /* direct access */ + GLuint i; + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + dst[i] = (src[i] << 8) | (dst[i] & 0xff); + } + } + } + else { + /* get, modify, put */ + GLuint temp[MAX_WIDTH], i; + dsrb->GetRow(ctx, dsrb, count, x, y, temp); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + temp[i] = (src[i] << 8) | (temp[i] & 0xff); + } + } + dsrb->PutRow(ctx, dsrb, count, x, y, temp, mask); + } +} + +static void +put_mono_row_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb, GLuint count, + GLint x, GLint y, const void *value, const GLubyte *mask) +{ + struct gl_renderbuffer *dsrb = z24rb->Wrapped; + const GLuint shiftedVal = *((GLuint *) value) << 8; + GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x, y); + ASSERT(z24rb->DataType == GL_UNSIGNED_INT); + ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT); + if (dst) { + /* direct access */ + GLuint i; + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + dst[i] = shiftedVal | (dst[i] & 0xff); + } + } + } + else { + /* get, modify, put */ + GLuint temp[MAX_WIDTH], i; + dsrb->GetRow(ctx, dsrb, count, x, y, temp); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + temp[i] = shiftedVal | (temp[i] & 0xff); + } + } + dsrb->PutRow(ctx, dsrb, count, x, y, temp, mask); + } +} + +static void +put_values_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb, GLuint count, + const GLint x[], const GLint y[], + const void *values, const GLubyte *mask) +{ + struct gl_renderbuffer *dsrb = z24rb->Wrapped; + const GLubyte *src = (const GLubyte *) values; + ASSERT(z24rb->DataType == GL_UNSIGNED_INT); + ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT); + if (dsrb->GetPointer(ctx, dsrb, 0, 0)) { + /* direct access */ + GLuint i; + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x[i], y[i]); + *dst = (src[i] << 8) | (*dst & 0xff); + } + } + } + else { + /* get, modify, put */ + GLuint temp[MAX_WIDTH], i; + dsrb->GetValues(ctx, dsrb, count, x, y, temp); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + temp[i] = (src[i] << 8) | (temp[i] & 0xff); + } + } + dsrb->PutValues(ctx, dsrb, count, x, y, temp, mask); + } +} + +static void +put_mono_values_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb, + GLuint count, const GLint x[], const GLint y[], + const void *value, const GLubyte *mask) +{ + struct gl_renderbuffer *dsrb = z24rb->Wrapped; + GLuint temp[MAX_WIDTH], i; + const GLuint shiftedVal = *((GLuint *) value) << 8; + /* get, modify, put */ + dsrb->GetValues(ctx, dsrb, count, x, y, temp); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + temp[i] = shiftedVal | (temp[i] & 0xff); + } + } + dsrb->PutValues(ctx, dsrb, count, x, y, temp, mask); +} + + +/** + * Wrap the given GL_DEPTH_STENCIL renderbuffer so that it acts like + * a depth renderbuffer. + * \return new depth renderbuffer + */ +struct gl_renderbuffer * +_mesa_new_z24_renderbuffer_wrapper(GLcontext *ctx, + struct gl_renderbuffer *dsrb) +{ + struct gl_renderbuffer *z24rb; + + ASSERT(dsrb->_BaseFormat == GL_DEPTH_STENCIL_EXT); + ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT); + + z24rb = _mesa_new_renderbuffer(ctx, 0); + if (!z24rb) + return NULL; + + z24rb->Wrapped = dsrb; + z24rb->Name = dsrb->Name; + z24rb->RefCount = 1; + z24rb->Width = dsrb->Width; + z24rb->Height = dsrb->Height; + z24rb->InternalFormat = GL_DEPTH_COMPONENT24_ARB; + z24rb->_BaseFormat = GL_DEPTH_COMPONENT; + z24rb->DataType = GL_UNSIGNED_INT; + z24rb->DepthBits = 24; + z24rb->Data = NULL; + z24rb->Delete = delete_wrapper; + z24rb->GetPointer = nop_get_pointer; + z24rb->GetRow = get_row_z24; + z24rb->GetValues = get_values_z24; + z24rb->PutRow = put_row_z24; + z24rb->PutRowRGB = NULL; + z24rb->PutMonoRow = put_mono_row_z24; + z24rb->PutValues = put_values_z24; + z24rb->PutMonoValues = put_mono_values_z24; + + return z24rb; +} + + +/*====================================================================== + * Stencil wrapper around depth/stencil renderbuffer + */ + +static void +get_row_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count, + GLint x, GLint y, void *values) +{ + struct gl_renderbuffer *dsrb = s8rb->Wrapped; + GLuint temp[MAX_WIDTH], i; + GLubyte *dst = (GLubyte *) values; + const GLuint *src = (const GLuint *) dsrb->GetPointer(ctx, dsrb, x, y); + ASSERT(s8rb->DataType == GL_UNSIGNED_BYTE); + ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT); + if (!src) { + dsrb->GetRow(ctx, dsrb, count, x, y, temp); + src = temp; + } + for (i = 0; i < count; i++) { + dst[i] = src[i] & 0xff; + } +} + +static void +get_values_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count, + const GLint x[], const GLint y[], void *values) +{ + struct gl_renderbuffer *dsrb = s8rb->Wrapped; + GLuint temp[MAX_WIDTH], i; + GLubyte *dst = (GLubyte *) values; + ASSERT(s8rb->DataType == GL_UNSIGNED_BYTE); + ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT); + ASSERT(count <= MAX_WIDTH); + /* don't bother trying direct access */ + dsrb->GetValues(ctx, dsrb, count, x, y, temp); + for (i = 0; i < count; i++) { + dst[i] = temp[i] & 0xff; + } +} + +static void +put_row_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count, + GLint x, GLint y, const void *values, const GLubyte *mask) +{ + struct gl_renderbuffer *dsrb = s8rb->Wrapped; + const GLubyte *src = (const GLubyte *) values; + GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x, y); + ASSERT(s8rb->DataType == GL_UNSIGNED_BYTE); + ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT); + if (dst) { + /* direct access */ + GLuint i; + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + dst[i] = (dst[i] & 0xffffff00) | src[i]; + } + } + } + else { + /* get, modify, put */ + GLuint temp[MAX_WIDTH], i; + dsrb->GetRow(ctx, dsrb, count, x, y, temp); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + temp[i] = (temp[i] & 0xffffff00) | src[i]; + } + } + dsrb->PutRow(ctx, dsrb, count, x, y, temp, mask); + } +} + +static void +put_mono_row_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count, + GLint x, GLint y, const void *value, const GLubyte *mask) +{ + struct gl_renderbuffer *dsrb = s8rb->Wrapped; + const GLubyte val = *((GLubyte *) value); + GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x, y); + ASSERT(s8rb->DataType == GL_UNSIGNED_BYTE); + ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT); + if (dst) { + /* direct access */ + GLuint i; + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + dst[i] = (dst[i] & 0xffffff00) | val; + } + } + } + else { + /* get, modify, put */ + GLuint temp[MAX_WIDTH], i; + dsrb->GetRow(ctx, dsrb, count, x, y, temp); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + temp[i] = (temp[i] & 0xffffff00) | val; + } + } + dsrb->PutRow(ctx, dsrb, count, x, y, temp, mask); + } +} + +static void +put_values_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count, + const GLint x[], const GLint y[], + const void *values, const GLubyte *mask) +{ + struct gl_renderbuffer *dsrb = s8rb->Wrapped; + const GLubyte *src = (const GLubyte *) values; + ASSERT(s8rb->DataType == GL_UNSIGNED_BYTE); + ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT); + if (dsrb->GetPointer(ctx, dsrb, 0, 0)) { + /* direct access */ + GLuint i; + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x[i], y[i]); + *dst = (*dst & 0xffffff00) | src[i]; + } + } + } + else { + /* get, modify, put */ + GLuint temp[MAX_WIDTH], i; + dsrb->GetValues(ctx, dsrb, count, x, y, temp); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + temp[i] = (temp[i] & 0xffffff00) | src[i]; + } + } + dsrb->PutValues(ctx, dsrb, count, x, y, temp, mask); + } +} + +static void +put_mono_values_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count, + const GLint x[], const GLint y[], + const void *value, const GLubyte *mask) +{ + struct gl_renderbuffer *dsrb = s8rb->Wrapped; + GLuint temp[MAX_WIDTH], i; + const GLubyte val = *((GLubyte *) value); + /* get, modify, put */ + dsrb->GetValues(ctx, dsrb, count, x, y, temp); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + temp[i] = (temp[i] & 0xffffff) | val; + } + } + dsrb->PutValues(ctx, dsrb, count, x, y, temp, mask); +} + + +/** + * Wrap the given GL_DEPTH_STENCIL renderbuffer so that it acts like + * a stencil renderbuffer. + * \return new stencil renderbuffer + */ +struct gl_renderbuffer * +_mesa_new_s8_renderbuffer_wrapper(GLcontext *ctx, struct gl_renderbuffer *dsrb) +{ + struct gl_renderbuffer *s8rb; + + ASSERT(dsrb->_BaseFormat == GL_DEPTH_STENCIL_EXT); + ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT); + + s8rb = _mesa_new_renderbuffer(ctx, 0); + if (!s8rb) + return NULL; + + s8rb->Wrapped = dsrb; + s8rb->Name = dsrb->Name; + s8rb->RefCount = 1; + s8rb->Width = dsrb->Width; + s8rb->Height = dsrb->Height; + s8rb->InternalFormat = GL_STENCIL_INDEX8_EXT; + s8rb->_BaseFormat = GL_STENCIL_INDEX; + s8rb->DataType = GL_UNSIGNED_BYTE; + s8rb->StencilBits = 8; + s8rb->Data = NULL; + s8rb->Delete = delete_wrapper; + s8rb->GetPointer = nop_get_pointer; + s8rb->GetRow = get_row_s8; + s8rb->GetValues = get_values_s8; + s8rb->PutRow = put_row_s8; + s8rb->PutRowRGB = NULL; + s8rb->PutMonoRow = put_mono_row_s8; + s8rb->PutValues = put_values_s8; + s8rb->PutMonoValues = put_mono_values_s8; + + return s8rb; +} + + +/** + * Merge data from a depth renderbuffer and a stencil renderbuffer into a + * combined depth/stencil renderbuffer. + */ +void +_mesa_merge_depth_stencil_buffers(GLcontext *ctx, + struct gl_renderbuffer *dest, + struct gl_renderbuffer *depth, + struct gl_renderbuffer *stencil) +{ + GLuint depthVals[MAX_WIDTH]; + GLubyte stencilVals[MAX_WIDTH]; + GLuint combined[MAX_WIDTH]; + GLuint row, width; + + ASSERT(dest); + ASSERT(depth); + ASSERT(stencil); + + ASSERT(dest->InternalFormat == GL_DEPTH24_STENCIL8_EXT); + ASSERT(dest->DataType == GL_UNSIGNED_INT_24_8_EXT); + ASSERT(depth->InternalFormat == GL_DEPTH_COMPONENT24); + ASSERT(depth->DataType == GL_UNSIGNED_INT); + ASSERT(stencil->InternalFormat == GL_STENCIL_INDEX8_EXT); + ASSERT(stencil->DataType == GL_UNSIGNED_BYTE); + + ASSERT(dest->Width == depth->Width); + ASSERT(dest->Height == depth->Height); + ASSERT(dest->Width == stencil->Width); + ASSERT(dest->Height == stencil->Height); + + width = dest->Width; + for (row = 0; row < dest->Height; row++) { + GLuint i; + depth->GetRow(ctx, depth, width, 0, row, depthVals); + stencil->GetRow(ctx, stencil, width, 0, row, stencilVals); + for (i = 0; i < width; i++) { + combined[i] = (depthVals[i] << 8) | stencilVals[i]; + } + dest->PutRow(ctx, dest, width, 0, row, combined, NULL); + } +} + + +/** + * Split combined depth/stencil renderbuffer data into separate depth/stencil + * buffers. + */ +void +_mesa_split_depth_stencil_buffer(GLcontext *ctx, + struct gl_renderbuffer *source, + struct gl_renderbuffer *depth, + struct gl_renderbuffer *stencil) +{ + GLuint depthVals[MAX_WIDTH]; + GLubyte stencilVals[MAX_WIDTH]; + GLuint combined[MAX_WIDTH]; + GLuint row, width; + + ASSERT(source); + ASSERT(depth); + ASSERT(stencil); + + ASSERT(source->InternalFormat == GL_DEPTH24_STENCIL8_EXT); + ASSERT(source->DataType == GL_UNSIGNED_INT_24_8_EXT); + ASSERT(depth->InternalFormat == GL_DEPTH_COMPONENT24); + ASSERT(depth->DataType == GL_UNSIGNED_INT); + ASSERT(stencil->InternalFormat == GL_STENCIL_INDEX8_EXT); + ASSERT(stencil->DataType == GL_UNSIGNED_BYTE); + + ASSERT(source->Width == depth->Width); + ASSERT(source->Height == depth->Height); + ASSERT(source->Width == stencil->Width); + ASSERT(source->Height == stencil->Height); + + width = source->Width; + for (row = 0; row < source->Height; row++) { + GLuint i; + source->GetRow(ctx, source, width, 0, row, combined); + for (i = 0; i < width; i++) { + depthVals[i] = combined[i] >> 8; + stencilVals[i] = combined[i] & 0xff; + } + depth->PutRow(ctx, depth, width, 0, row, depthVals, NULL); + stencil->PutRow(ctx, stencil, width, 0, row, stencilVals, NULL); + } +} diff --git a/src/mesa/main/depthstencil.h b/src/mesa/main/depthstencil.h new file mode 100644 index 0000000000..76b75a0e36 --- /dev/null +++ b/src/mesa/main/depthstencil.h @@ -0,0 +1,55 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 1999-2005 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. + */ + + +#ifndef DEPTHSTENCIL_H +#define DEPTHSTENCIL_H + + +extern struct gl_renderbuffer * +_mesa_new_z24_renderbuffer_wrapper(GLcontext *ctx, + struct gl_renderbuffer *dsrb); + + +extern struct gl_renderbuffer * +_mesa_new_s8_renderbuffer_wrapper(GLcontext *ctx, + struct gl_renderbuffer *dsrb); + + +extern void +_mesa_merge_depth_stencil_buffers(GLcontext *ctx, + struct gl_renderbuffer *dest, + struct gl_renderbuffer *depth, + struct gl_renderbuffer *stencil); + + +extern void +_mesa_split_depth_stencil_buffer(GLcontext *ctx, + struct gl_renderbuffer *source, + struct gl_renderbuffer *depth, + struct gl_renderbuffer *stencil); + + + +#endif /* DEPTHSTENCIL_H */ diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c index dc32caae15..ecf54a5a79 100644 --- a/src/mesa/main/fbobject.c +++ b/src/mesa/main/fbobject.c @@ -38,7 +38,6 @@ #include "texstore.h" - /* XXX temporarily here */ #define GL_READ_FRAMEBUFFER_EXT 0x90 #define GL_DRAW_FRAMEBUFFER_EXT 0x9a @@ -108,8 +107,9 @@ lookup_framebuffer(GLcontext *ctx, GLuint id) * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding * gl_renderbuffer_attachment object. */ -static struct gl_renderbuffer_attachment * -get_attachment(GLcontext *ctx, struct gl_framebuffer *fb, GLenum attachment) +struct gl_renderbuffer_attachment * +_mesa_get_attachment(GLcontext *ctx, struct gl_framebuffer *fb, + GLenum attachment) { GLuint i; @@ -232,15 +232,17 @@ _mesa_set_renderbuffer_attachment(GLcontext *ctx, /** * Fallback for ctx->Driver.FramebufferRenderbuffer() - * Sets a framebuffer attachment to a particular renderbuffer. - * The framebuffer in question is ctx->DrawBuffer. - * \sa _mesa_renderbuffer_texture + * Attach a renderbuffer object to a framebuffer object. */ void -_mesa_framebuffer_renderbuffer(GLcontext *ctx, - struct gl_renderbuffer_attachment *att, - struct gl_renderbuffer *rb) +_mesa_framebuffer_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb, + GLenum attachment, struct gl_renderbuffer *rb) { + struct gl_renderbuffer_attachment *att; + + att = _mesa_get_attachment(ctx, fb, attachment); + ASSERT(att); + if (rb) { _mesa_set_renderbuffer_attachment(ctx, att, rb); } @@ -461,7 +463,7 @@ _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb) for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { if (fb->ColorDrawBuffer[i] != GL_NONE) { const struct gl_renderbuffer_attachment *att - = get_attachment(ctx, fb, fb->ColorDrawBuffer[i]); + = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[i]); assert(att); if (att->Type == GL_NONE) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT; @@ -473,7 +475,7 @@ _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb) /* Check that the ReadBuffer is present */ if (fb->ColorReadBuffer != GL_NONE) { const struct gl_renderbuffer_attachment *att - = get_attachment(ctx, fb, fb->ColorReadBuffer); + = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer); assert(att); if (att->Type == GL_NONE) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT; @@ -1151,7 +1153,7 @@ _mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment, ASSERT(textarget == GL_TEXTURE_1D); /* XXX read blit */ - att = get_attachment(ctx, ctx->DrawBuffer, attachment); + att = _mesa_get_attachment(ctx, ctx->DrawBuffer, attachment); if (att == NULL) { _mesa_error(ctx, GL_INVALID_ENUM, "glFramebufferTexture1DEXT(attachment)"); @@ -1200,7 +1202,7 @@ _mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment, textarget == GL_TEXTURE_RECTANGLE_ARB || IS_CUBE_FACE(textarget)); - att = get_attachment(ctx, ctx->DrawBuffer, attachment); + att = _mesa_get_attachment(ctx, ctx->DrawBuffer, attachment); if (att == NULL) { _mesa_error(ctx, GL_INVALID_ENUM, "glFramebufferTexture2DEXT(attachment)"); @@ -1252,7 +1254,7 @@ _mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment, ASSERT(textarget == GL_TEXTURE_3D); - att = get_attachment(ctx, ctx->DrawBuffer, attachment); + att = _mesa_get_attachment(ctx, ctx->DrawBuffer, attachment); if (att == NULL) { _mesa_error(ctx, GL_INVALID_ENUM, "glFramebufferTexture1DEXT(attachment)"); @@ -1342,7 +1344,7 @@ _mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment, return; } - att = get_attachment(ctx, fb, attachment); + att = _mesa_get_attachment(ctx, fb, attachment); if (att == NULL) { _mesa_error(ctx, GL_INVALID_ENUM, "glFramebufferRenderbufferEXT(attachment)"); @@ -1365,7 +1367,7 @@ _mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment, FLUSH_VERTICES(ctx, _NEW_BUFFERS); assert(ctx->Driver.FramebufferRenderbuffer); - ctx->Driver.FramebufferRenderbuffer(ctx, att, rb); + ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb); } @@ -1413,7 +1415,7 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, return; } - att = get_attachment(ctx, buffer, attachment); + att = _mesa_get_attachment(ctx, buffer, attachment); if (att == NULL) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetFramebufferAttachmentParameterivEXT(attachment)"); diff --git a/src/mesa/main/fbobject.h b/src/mesa/main/fbobject.h index 59214ce81d..71517adfd8 100644 --- a/src/mesa/main/fbobject.h +++ b/src/mesa/main/fbobject.h @@ -27,6 +27,11 @@ #define FBOBJECT_H +extern struct gl_renderbuffer_attachment * +_mesa_get_attachment(GLcontext *ctx, struct gl_framebuffer *fb, + GLenum attachment); + + extern void _mesa_remove_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att); @@ -43,9 +48,8 @@ _mesa_set_renderbuffer_attachment(GLcontext *ctx, struct gl_renderbuffer *rb); extern void -_mesa_framebuffer_renderbuffer(GLcontext *ctx, - struct gl_renderbuffer_attachment *att, - struct gl_renderbuffer *rb); +_mesa_framebuffer_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb, + GLenum attachment, struct gl_renderbuffer *rb); extern void _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb); diff --git a/src/mesa/main/framebuffer.c b/src/mesa/main/framebuffer.c index 956527efbc..4fef9066c8 100644 --- a/src/mesa/main/framebuffer.c +++ b/src/mesa/main/framebuffer.c @@ -33,6 +33,7 @@ #include "glheader.h" #include "imports.h" #include "context.h" +#include "depthstencil.h" #include "mtypes.h" #include "fbobject.h" #include "framebuffer.h" @@ -159,7 +160,7 @@ _mesa_destroy_framebuffer(struct gl_framebuffer *fb) { if (fb) { _mesa_free_framebuffer_data(fb); - FREE(fb); + _mesa_free(fb); } } @@ -187,6 +188,23 @@ _mesa_free_framebuffer_data(struct gl_framebuffer *fb) att->Type = GL_NONE; att->Renderbuffer = NULL; } + + if (fb->_DepthBuffer) { + struct gl_renderbuffer *rb = fb->_DepthBuffer; + rb->RefCount--; + if (rb->RefCount <= 0) { + rb->Delete(rb); + } + fb->_DepthBuffer = NULL; + } + if (fb->_StencilBuffer) { + struct gl_renderbuffer *rb = fb->_StencilBuffer; + rb->RefCount--; + if (rb->RefCount <= 0) { + rb->Delete(rb); + } + fb->_StencilBuffer = NULL; + } } @@ -194,7 +212,11 @@ _mesa_free_framebuffer_data(struct gl_framebuffer *fb) * Resize the given framebuffer's renderbuffers to the new width and height. * This should only be used for window-system framebuffers, not * user-created renderbuffers (i.e. made with GL_EXT_framebuffer_object). - * This will typically be called via ctx->Driver.ResizeBuffers() + * This will typically be called via ctx->Driver.ResizeBuffers() or directly + * from a device driver. + * + * \note it's possible for ctx to be null since a window can be resized + * without a currently bound rendering context. */ void _mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb, @@ -378,6 +400,45 @@ _mesa_update_framebuffer_visual(struct gl_framebuffer *fb) /** + * Helper function for _mesa_update_framebuffer(). + * Set the actual depth renderbuffer for the given framebuffer. + * Take care of reference counts, etc. + */ +static void +set_depth_renderbuffer(struct gl_framebuffer *fb, + struct gl_renderbuffer *rb) +{ + if (fb->_DepthBuffer) { + fb->_DepthBuffer->RefCount--; + if (fb->_DepthBuffer->RefCount <= 0) { + fb->_DepthBuffer->Delete(fb->_DepthBuffer); + } + } + fb->_DepthBuffer = rb; + if (rb) + rb->RefCount++; +} + +/** + * \sa set_depth_renderbuffer. + */ +static void +set_stencil_renderbuffer(struct gl_framebuffer *fb, + struct gl_renderbuffer *rb) +{ + if (fb->_StencilBuffer) { + fb->_StencilBuffer->RefCount--; + if (fb->_StencilBuffer->RefCount <= 0) { + fb->_StencilBuffer->Delete(fb->_StencilBuffer); + } + } + fb->_StencilBuffer = rb; + if (rb) + rb->RefCount++; +} + + +/** * Update state related to the current draw/read framebuffers. * Specifically, update these framebuffer fields: * _ColorDrawBuffers @@ -440,5 +501,45 @@ _mesa_update_framebuffer(GLcontext *ctx) fb->_ColorReadBuffer = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer; } + + /* + * Deal with GL_DEPTH_STENCIL renderbuffer(s) attached to the depth + * and/or stencil attachment points. + */ + { + struct gl_renderbuffer *depthRb + = fb->Attachment[BUFFER_DEPTH].Renderbuffer; + struct gl_renderbuffer *stencilRb + = fb->Attachment[BUFFER_STENCIL].Renderbuffer; + + if (depthRb && depthRb->_BaseFormat == GL_DEPTH_STENCIL_EXT) { + if (!fb->_DepthBuffer || fb->_DepthBuffer->Wrapped != depthRb) { + /* need to update wrapper */ + struct gl_renderbuffer *wrapper + = _mesa_new_z24_renderbuffer_wrapper(ctx, depthRb); + set_depth_renderbuffer(fb, wrapper); + assert(fb->_DepthBuffer->Wrapped == depthRb); + } + } + else { + /* depthRb may be null */ + set_depth_renderbuffer(fb, depthRb); + } + + if (stencilRb && stencilRb->_BaseFormat == GL_DEPTH_STENCIL_EXT) { + if (!fb->_StencilBuffer || fb->_StencilBuffer->Wrapped != stencilRb) { + /* need to update wrapper */ + struct gl_renderbuffer *wrapper + = _mesa_new_s8_renderbuffer_wrapper(ctx, stencilRb); + set_stencil_renderbuffer(fb, wrapper); + assert(fb->_StencilBuffer->Wrapped == stencilRb); + } + } + else { + /* stencilRb may be null */ + set_stencil_renderbuffer(fb, stencilRb); + } + } + compute_depth_max(fb); } diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 17978e7135..32ce91c50e 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -2243,6 +2243,11 @@ struct gl_framebuffer struct gl_renderbuffer *_ColorDrawBuffers[MAX_DRAW_BUFFERS][4]; struct gl_renderbuffer *_ColorReadBuffer; + /** The Actual depth/stencil buffers to use. May be wrappers around the + * depth/stencil buffers attached above. */ + struct gl_renderbuffer *_DepthBuffer; + struct gl_renderbuffer *_StencilBuffer; + /** Delete this framebuffer */ void (*Delete)(struct gl_framebuffer *fb); }; |