diff options
Diffstat (limited to 'src/mesa/main/framebuffer.c')
-rw-r--r-- | src/mesa/main/framebuffer.c | 766 |
1 files changed, 766 insertions, 0 deletions
diff --git a/src/mesa/main/framebuffer.c b/src/mesa/main/framebuffer.c new file mode 100644 index 00000000000..a6607387fee --- /dev/null +++ b/src/mesa/main/framebuffer.c @@ -0,0 +1,766 @@ +/* + * 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 framebuffers and renderbuffers. + * Also, routines for reading/writing renderbuffer data as ubytes, + * ushorts, uints, etc. + */ + + +#include "glheader.h" +#include "imports.h" +#include "context.h" +#include "depthstencil.h" +#include "mtypes.h" +#include "fbobject.h" +#include "framebuffer.h" +#include "renderbuffer.h" + + + +/** + * Compute/set the _DepthMax field for the given framebuffer. + * This value depends on the Z buffer resolution. + */ +static void +compute_depth_max(struct gl_framebuffer *fb) +{ + if (fb->Visual.depthBits == 0) { + /* Special case. Even if we don't have a depth buffer we need + * good values for DepthMax for Z vertex transformation purposes + * and for per-fragment fog computation. + */ + fb->_DepthMax = (1 << 16) - 1; + } + else if (fb->Visual.depthBits < 32) { + fb->_DepthMax = (1 << fb->Visual.depthBits) - 1; + } + else { + /* Special case since shift values greater than or equal to the + * number of bits in the left hand expression's type are undefined. + */ + fb->_DepthMax = 0xffffffff; + } + fb->_DepthMaxF = (GLfloat) fb->_DepthMax; + fb->_MRD = 1.0; /* Minimum resolvable depth value, for polygon offset */ +} + + +/** + * Set the framebuffer's _DepthBuffer field, taking 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++; + } +} + + +/** + * Set the framebuffer's _StencilBuffer field, taking care of + * reference counts, etc. + */ +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++; + } +} + + +/** + * Create and initialize a gl_framebuffer object. + * This is intended for creating _window_system_ framebuffers, not generic + * framebuffer objects ala GL_EXT_framebuffer_object. + * + * \sa _mesa_new_framebuffer + */ +struct gl_framebuffer * +_mesa_create_framebuffer(const GLvisual *visual) +{ + struct gl_framebuffer *fb = CALLOC_STRUCT(gl_framebuffer); + assert(visual); + if (fb) { + _mesa_initialize_framebuffer(fb, visual); + } + return fb; +} + + +/** + * Allocate a new gl_framebuffer object. + * This is the default function for ctx->Driver.NewFramebuffer(). + * This is for allocating user-created framebuffers, not window-system + * framebuffers! + * \sa _mesa_create_framebuffer + */ +struct gl_framebuffer * +_mesa_new_framebuffer(GLcontext *ctx, GLuint name) +{ + struct gl_framebuffer *fb; + assert(name != 0); + fb = CALLOC_STRUCT(gl_framebuffer); + if (fb) { + fb->Name = name; + fb->RefCount = 1; + fb->ColorDrawBuffer[0] = GL_COLOR_ATTACHMENT0_EXT; + fb->_ColorDrawBufferMask[0] = BUFFER_BIT_COLOR0; + fb->ColorReadBuffer = GL_COLOR_ATTACHMENT0_EXT; + fb->_ColorReadBufferIndex = BUFFER_COLOR0; + fb->Delete = _mesa_destroy_framebuffer; + } + return fb; +} + + +/** + * Initialize a gl_framebuffer object. Typically used to initialize + * window system-created framebuffers, not user-created framebuffers. + * \sa _mesa_create_framebuffer + */ +void +_mesa_initialize_framebuffer(struct gl_framebuffer *fb, const GLvisual *visual) +{ + assert(fb); + assert(visual); + + _mesa_bzero(fb, sizeof(struct gl_framebuffer)); + + _glthread_INIT_MUTEX(fb->Mutex); + + /* save the visual */ + fb->Visual = *visual; + + /* Init glRead/DrawBuffer state */ + if (visual->doubleBufferMode) { + fb->ColorDrawBuffer[0] = GL_BACK; + fb->_ColorDrawBufferMask[0] = BUFFER_BIT_BACK_LEFT; + fb->ColorReadBuffer = GL_BACK; + fb->_ColorReadBufferIndex = BUFFER_BACK_LEFT; + } + else { + fb->ColorDrawBuffer[0] = GL_FRONT; + fb->_ColorDrawBufferMask[0] = BUFFER_BIT_FRONT_LEFT; + fb->ColorReadBuffer = GL_FRONT; + fb->_ColorReadBufferIndex = BUFFER_FRONT_LEFT; + } + + fb->Delete = _mesa_destroy_framebuffer; + fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT; + + compute_depth_max(fb); +} + + +/** + * Deallocate buffer and everything attached to it. + * Typically called via the gl_framebuffer->Delete() method. + */ +void +_mesa_destroy_framebuffer(struct gl_framebuffer *fb) +{ + if (fb) { + _glthread_DESTROY_MUTEX(fb->Mutex); + _mesa_free_framebuffer_data(fb); + _mesa_free(fb); + } +} + + +/** + * Free all the data hanging off the given gl_framebuffer, but don't free + * the gl_framebuffer object itself. + */ +void +_mesa_free_framebuffer_data(struct gl_framebuffer *fb) +{ + GLuint i; + + assert(fb); + + for (i = 0; i < BUFFER_COUNT; i++) { + struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; + if (att->Renderbuffer) { + struct gl_renderbuffer *rb = att->Renderbuffer; + _glthread_LOCK_MUTEX(rb->Mutex); + rb->RefCount--; + _glthread_UNLOCK_MUTEX(rb->Mutex); + if (rb->RefCount == 0) { + rb->Delete(rb); + } + } + att->Type = GL_NONE; + att->Renderbuffer = NULL; + } + + /* unbind depth/stencil to decr ref counts */ + set_depth_renderbuffer(fb, NULL); + set_stencil_renderbuffer(fb, NULL); +} + + +/** + * 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() 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, + GLuint width, GLuint height) +{ + GLuint i; + + /* XXX I think we could check if the size is not changing + * and return early. + */ + + /* For window system framebuffers, Name is zero */ + assert(fb->Name == 0); + + for (i = 0; i < BUFFER_COUNT; i++) { + struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; + if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) { + struct gl_renderbuffer *rb = att->Renderbuffer; + /* only resize if size is changing */ + if (rb->Width != width || rb->Height != height) { + /* could just as well pass rb->_ActualFormat here */ + if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) { + ASSERT(rb->Width == width); + ASSERT(rb->Height == height); + } + else { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer"); + /* no return */ + } + } + } + } + + if (fb->_DepthBuffer) { + struct gl_renderbuffer *rb = fb->_DepthBuffer; + if (rb->Width != width || rb->Height != height) { + if (!rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer"); + } + } + } + + if (fb->_StencilBuffer) { + struct gl_renderbuffer *rb = fb->_StencilBuffer; + if (rb->Width != width || rb->Height != height) { + if (!rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer"); + } + } + } + + fb->Width = width; + fb->Height = height; + + /* to update scissor / window bounds */ + _mesa_update_draw_buffer_bounds(ctx); +} + + +/** + * Examine all the framebuffer's renderbuffers to update the Width/Height + * fields of the framebuffer. If we have renderbuffers with different + * sizes, set the framebuffer's width and height to zero. + * Note: this is only intended for user-created framebuffers, not + * window-system framebuffes. + */ +static void +update_framebuffer_size(struct gl_framebuffer *fb) +{ + GLboolean haveSize = GL_FALSE; + GLuint i; + + /* user-created framebuffers only */ + assert(fb->Name); + + for (i = 0; i < BUFFER_COUNT; i++) { + struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; + const struct gl_renderbuffer *rb = att->Renderbuffer; + if (rb) { + if (haveSize) { + if (rb->Width != fb->Width && rb->Height != fb->Height) { + /* size mismatch! */ + fb->Width = 0; + fb->Height = 0; + return; + } + } + else { + fb->Width = rb->Width; + fb->Height = rb->Height; + haveSize = GL_TRUE; + } + } + } +} + + +/** + * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields. + * These values are computed from the buffer's width and height and + * the scissor box, if it's enabled. + * \param ctx the GL context. + */ +void +_mesa_update_draw_buffer_bounds(GLcontext *ctx) +{ + struct gl_framebuffer *buffer = ctx->DrawBuffer; + + if (buffer->Name) { + /* user-created framebuffer size depends on the renderbuffers */ + update_framebuffer_size(buffer); + } + + buffer->_Xmin = 0; + buffer->_Ymin = 0; + buffer->_Xmax = buffer->Width; + buffer->_Ymax = buffer->Height; + + if (ctx->Scissor.Enabled) { + if (ctx->Scissor.X > buffer->_Xmin) { + buffer->_Xmin = ctx->Scissor.X; + } + if (ctx->Scissor.Y > buffer->_Ymin) { + buffer->_Ymin = ctx->Scissor.Y; + } + if (ctx->Scissor.X + ctx->Scissor.Width < buffer->_Xmax) { + buffer->_Xmax = ctx->Scissor.X + ctx->Scissor.Width; + } + if (ctx->Scissor.Y + ctx->Scissor.Height < buffer->_Ymax) { + buffer->_Ymax = ctx->Scissor.Y + ctx->Scissor.Height; + } + /* finally, check for empty region */ + if (buffer->_Xmin > buffer->_Xmax) { + buffer->_Xmin = buffer->_Xmax; + } + if (buffer->_Ymin > buffer->_Ymax) { + buffer->_Ymin = buffer->_Ymax; + } + } + + ASSERT(buffer->_Xmin <= buffer->_Xmax); + ASSERT(buffer->_Ymin <= buffer->_Ymax); +} + + +/** + * The glGet queries of the framebuffer red/green/blue size, stencil size, + * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can + * change depending on the renderbuffer bindings. This function updates + * the given framebuffer's Visual from the current renderbuffer bindings. + * This is only intended for user-created framebuffers. + * + * Also note: ctx->DrawBuffer->Visual.depthBits might not equal + * ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits. + * The former one is used to convert floating point depth values into + * integer Z values. + */ +void +_mesa_update_framebuffer_visual(struct gl_framebuffer *fb) +{ + GLuint i; + + assert(fb->Name != 0); + + _mesa_bzero(&fb->Visual, sizeof(fb->Visual)); + fb->Visual.rgbMode = GL_TRUE; /* assume this */ + + /* find first RGB or CI renderbuffer */ + for (i = 0; i < BUFFER_COUNT; i++) { + if (fb->Attachment[i].Renderbuffer) { + const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer; + if (rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB) { + fb->Visual.redBits = rb->RedBits; + fb->Visual.greenBits = rb->GreenBits; + fb->Visual.blueBits = rb->BlueBits; + fb->Visual.alphaBits = rb->AlphaBits; + fb->Visual.rgbBits = fb->Visual.redBits + + fb->Visual.greenBits + fb->Visual.blueBits; + fb->Visual.floatMode = GL_FALSE; + break; + } + else if (rb->_BaseFormat == GL_COLOR_INDEX) { + fb->Visual.indexBits = rb->IndexBits; + fb->Visual.rgbMode = GL_FALSE; + break; + } + } + } + + if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) { + fb->Visual.haveDepthBuffer = GL_TRUE; + fb->Visual.depthBits + = fb->Attachment[BUFFER_DEPTH].Renderbuffer->DepthBits; + } + + if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) { + fb->Visual.haveStencilBuffer = GL_TRUE; + fb->Visual.stencilBits + = fb->Attachment[BUFFER_STENCIL].Renderbuffer->StencilBits; + } + + compute_depth_max(fb); +} + + +/** + * Update the framebuffer's _DepthBuffer field using the renderbuffer + * found at the given attachment index. + * + * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer, + * create and install a depth wrapper/adaptor. + * + * \param fb the framebuffer whose _DepthBuffer field to update + * \param attIndex indicates the renderbuffer to possibly wrap + */ +void +_mesa_update_depth_buffer(GLcontext *ctx, + struct gl_framebuffer *fb, + GLuint attIndex) +{ + struct gl_renderbuffer *depthRb; + + /* only one possiblity for now */ + ASSERT(attIndex == BUFFER_DEPTH); + + depthRb = fb->Attachment[attIndex].Renderbuffer; + + if (depthRb && depthRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) { + /* The attached depth buffer is a GL_DEPTH_STENCIL renderbuffer */ + 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); + } +} + + +/** + * Update the framebuffer's _StencilBuffer field using the renderbuffer + * found at the given attachment index. + * + * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer, + * create and install a stencil wrapper/adaptor. + * + * \param fb the framebuffer whose _StencilBuffer field to update + * \param attIndex indicates the renderbuffer to possibly wrap + */ +void +_mesa_update_stencil_buffer(GLcontext *ctx, + struct gl_framebuffer *fb, + GLuint attIndex) +{ + struct gl_renderbuffer *stencilRb; + + ASSERT(attIndex == BUFFER_DEPTH || + attIndex == BUFFER_STENCIL); + + stencilRb = fb->Attachment[attIndex].Renderbuffer; + + if (stencilRb && stencilRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) { + /* The attached stencil buffer is a GL_DEPTH_STENCIL renderbuffer */ + 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); + } +} + + +/** + * Update the list of color drawing renderbuffer pointers. + * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers + * writing colors. + */ +static void +update_color_draw_buffers(GLcontext *ctx, struct gl_framebuffer *fb) +{ + GLuint output; + + /* + * Fragment programs can write to multiple colorbuffers with + * the GL_ARB_draw_buffers extension. + */ + for (output = 0; output < ctx->Const.MaxDrawBuffers; output++) { + GLbitfield bufferMask = fb->_ColorDrawBufferMask[output]; + GLuint count = 0; + GLuint i; + /* We need the inner loop here because glDrawBuffer(GL_FRONT_AND_BACK) + * can specify writing to two or four color buffers (for example). + */ + for (i = 0; bufferMask && i < BUFFER_COUNT; i++) { + const GLuint bufferBit = 1 << i; + if (bufferBit & bufferMask) { + struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer; + if (rb) { + fb->_ColorDrawBuffers[output][count] = rb; + count++; + } + else { + /*_mesa_warning(ctx, "DrawBuffer names a missing buffer!\n");*/ + } + bufferMask &= ~bufferBit; + } + } + fb->_NumColorDrawBuffers[output] = count; + } +} + + +/** + * Update the color read renderbuffer pointer. + * Unlike the DrawBuffer, we can only read from one (or zero) color buffers. + */ +static void +update_color_read_buffer(GLcontext *ctx, struct gl_framebuffer *fb) +{ + if (fb->_ColorReadBufferIndex == -1) { + fb->_ColorReadBuffer = NULL; /* legal! */ + } + else { + ASSERT(fb->_ColorReadBufferIndex >= 0); + ASSERT(fb->_ColorReadBufferIndex < BUFFER_COUNT); + fb->_ColorReadBuffer + = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer; + } +} + + +/** + * Update state related to the current draw/read framebuffers. + * Specifically, update these framebuffer fields: + * _ColorDrawBuffers + * _NumColorDrawBuffers + * _ColorReadBuffer + * _DepthBuffer + * _StencilBuffer + * If the current framebuffer is user-created, make sure it's complete. + * The following functions can effect this state: glReadBuffer, + * glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT, + * glRenderbufferStorageEXT. + */ +void +_mesa_update_framebuffer(GLcontext *ctx) +{ + struct gl_framebuffer *fb = ctx->DrawBuffer; + + /* Completeness only matters for user-created framebuffers */ + if (fb->Name != 0) { + _mesa_test_framebuffer_completeness(ctx, fb); + _mesa_update_framebuffer_visual(fb); + } + + update_color_draw_buffers(ctx, fb); + update_color_read_buffer(ctx, fb); + _mesa_update_depth_buffer(ctx, fb, BUFFER_DEPTH); + _mesa_update_stencil_buffer(ctx, fb, BUFFER_STENCIL); + + compute_depth_max(fb); +} + + +/** + * Check if the renderbuffer for a read operation (glReadPixels, glCopyPixels, + * glCopyTex[Sub]Image, etc. exists. + * \param format a basic image format such as GL_RGB, GL_RGBA, GL_ALPHA, + * GL_DEPTH_COMPONENT, etc. or GL_COLOR, GL_DEPTH, GL_STENCIL. + * \return GL_TRUE if buffer exists, GL_FALSE otherwise + */ +GLboolean +_mesa_source_buffer_exists(GLcontext *ctx, GLenum format) +{ + const struct gl_renderbuffer_attachment *att + = ctx->ReadBuffer->Attachment; + + if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { + return GL_FALSE; + } + + switch (format) { + case GL_COLOR: + case GL_RED: + case GL_GREEN: + case GL_BLUE: + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + case GL_RGB: + case GL_BGR: + case GL_RGBA: + case GL_BGRA: + case GL_ABGR_EXT: + case GL_COLOR_INDEX: + if (ctx->ReadBuffer->_ColorReadBuffer == NULL) { + return GL_FALSE; + } + /* XXX enable this post 6.5 release: + ASSERT(ctx->ReadBuffer->_ColorReadBuffer->RedBits > 0 || + ctx->ReadBuffer->_ColorReadBuffer->IndexBits > 0); + */ + break; + case GL_DEPTH: + case GL_DEPTH_COMPONENT: + if (!att[BUFFER_DEPTH].Renderbuffer) { + return GL_FALSE; + } + ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0); + break; + case GL_STENCIL: + case GL_STENCIL_INDEX: + if (!att[BUFFER_STENCIL].Renderbuffer) { + return GL_FALSE; + } + ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0); + break; + case GL_DEPTH_STENCIL_EXT: + if (!att[BUFFER_DEPTH].Renderbuffer || + !att[BUFFER_STENCIL].Renderbuffer) { + return GL_FALSE; + } + ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0); + ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0); + break; + default: + _mesa_problem(ctx, + "Unexpected format 0x%x in _mesa_source_buffer_exists", + format); + return GL_FALSE; + } + + /* OK */ + return GL_TRUE; +} + + +/** + * As above, but for drawing operations. + * XXX code do some code merging w/ above function. + */ +GLboolean +_mesa_dest_buffer_exists(GLcontext *ctx, GLenum format) +{ + const struct gl_renderbuffer_attachment *att + = ctx->ReadBuffer->Attachment; + + if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { + return GL_FALSE; + } + + switch (format) { + case GL_COLOR: + case GL_RED: + case GL_GREEN: + case GL_BLUE: + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + case GL_RGB: + case GL_BGR: + case GL_RGBA: + case GL_BGRA: + case GL_ABGR_EXT: + case GL_COLOR_INDEX: + /* nothing special */ + /* Could assert that colorbuffer has RedBits > 0 */ + break; + case GL_DEPTH: + case GL_DEPTH_COMPONENT: + if (!att[BUFFER_DEPTH].Renderbuffer) { + return GL_FALSE; + } + ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0); + break; + case GL_STENCIL: + case GL_STENCIL_INDEX: + if (!att[BUFFER_STENCIL].Renderbuffer) { + return GL_FALSE; + } + ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0); + break; + case GL_DEPTH_STENCIL_EXT: + if (!att[BUFFER_DEPTH].Renderbuffer || + !att[BUFFER_STENCIL].Renderbuffer) { + return GL_FALSE; + } + ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0); + ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0); + break; + default: + _mesa_problem(ctx, + "Unexpected format 0x%x in _mesa_source_buffer_exists", + format); + return GL_FALSE; + } + + /* OK */ + return GL_TRUE; +} |