/*
* Mesa 3-D graphics library
- * Version: 6.5
+ * Version: 6.5.1
*
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
*
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++;
- }
+ /* Minimum resolvable depth value, for polygon offset */
+ fb->_MRD = 1.0 / fb->_DepthMaxF;
}
_mesa_new_framebuffer(GLcontext *ctx, GLuint name)
{
struct gl_framebuffer *fb;
+ (void) ctx;
assert(name != 0);
fb = CALLOC_STRUCT(gl_framebuffer);
if (fb) {
_glthread_INIT_MUTEX(fb->Mutex);
+ fb->RefCount = 1;
+
/* save the visual */
fb->Visual = *visual;
_mesa_destroy_framebuffer(struct gl_framebuffer *fb)
{
if (fb) {
- _glthread_DESTROY_MUTEX(fb->Mutex);
_mesa_free_framebuffer_data(fb);
_mesa_free(fb);
}
GLuint i;
assert(fb);
+ assert(fb->RefCount == 0);
+
+ _glthread_DESTROY_MUTEX(fb->Mutex);
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);
+ _mesa_reference_renderbuffer(&att->Renderbuffer, NULL);
+ }
+ if (att->Texture) {
+ /* render to texture */
+ att->Texture->RefCount--;
+ if (att->Texture->RefCount == 0) {
+ GET_CURRENT_CONTEXT(ctx);
+ if (ctx) {
+ ctx->Driver.DeleteTexture(ctx, att->Texture);
+ }
}
}
att->Type = GL_NONE;
- att->Renderbuffer = NULL;
+ att->Texture = NULL;
}
- /* unbind depth/stencil to decr ref counts */
- set_depth_renderbuffer(fb, NULL);
- set_stencil_renderbuffer(fb, NULL);
+ /* unbind _Depth/_StencilBuffer to decr ref counts */
+ _mesa_reference_renderbuffer(&fb->_DepthBuffer, NULL);
+ _mesa_reference_renderbuffer(&fb->_StencilBuffer, NULL);
+}
+
+
+/**
+ * Set *ptr to point to fb, with refcounting and locking.
+ */
+void
+_mesa_reference_framebuffer(struct gl_framebuffer **ptr,
+ struct gl_framebuffer *fb)
+{
+ assert(ptr);
+ if (*ptr == fb) {
+ /* no change */
+ return;
+ }
+ if (*ptr) {
+ _mesa_unreference_framebuffer(ptr);
+ }
+ assert(!*ptr);
+ assert(fb);
+ _glthread_LOCK_MUTEX(fb->Mutex);
+ fb->RefCount++;
+ _glthread_UNLOCK_MUTEX(fb->Mutex);
+ *ptr = fb;
}
+/**
+ * Undo/remove a reference to a framebuffer object.
+ * Decrement the framebuffer object's reference count and delete it when
+ * the refcount hits zero.
+ * Note: we pass the address of a pointer and set it to NULL.
+ */
+void
+_mesa_unreference_framebuffer(struct gl_framebuffer **fb)
+{
+ assert(fb);
+ if (*fb) {
+ GLboolean deleteFlag = GL_FALSE;
+
+ _glthread_LOCK_MUTEX((*fb)->Mutex);
+ ASSERT((*fb)->RefCount > 0);
+ (*fb)->RefCount--;
+ deleteFlag = ((*fb)->RefCount == 0);
+ _glthread_UNLOCK_MUTEX((*fb)->Mutex);
+
+ if (deleteFlag)
+ (*fb)->Delete(*fb);
+
+ *fb = NULL;
+ }
+}
+
+
+
+
/**
* Resize the given framebuffer's renderbuffers to the new width and height.
* This should only be used for window-system framebuffers, not
fb->Width = width;
fb->Height = height;
- /* to update scissor / window bounds */
- _mesa_update_draw_buffer_bounds(ctx);
+ if (ctx) {
+ /* update scissor / window bounds */
+ _mesa_update_draw_buffer_bounds(ctx);
+ /* Signal new buffer state so that swrast will update its clipping
+ * info (the CLIP_BIT flag).
+ */
+ ctx->NewState |= _NEW_BUFFERS;
+ }
}
{
struct gl_framebuffer *buffer = ctx->DrawBuffer;
+ if (!buffer)
+ return;
+
if (buffer->Name) {
/* user-created framebuffer size depends on the renderbuffers */
update_framebuffer_size(buffer);
* 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.
+ *
+ * This may apply to user-created framebuffers or window system framebuffers.
*
* Also note: ctx->DrawBuffer->Visual.depthBits might not equal
* ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits.
{
GLuint i;
- assert(fb->Name != 0);
-
_mesa_bzero(&fb->Visual, sizeof(fb->Visual));
fb->Visual.rgbMode = GL_TRUE; /* assume this */
+#if 0 /* this _might_ be needed */
+ if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+ /* leave visual fields zero'd */
+ return;
+ }
+#endif
+
/* find first RGB or CI renderbuffer */
for (i = 0; i < BUFFER_COUNT; i++) {
if (fb->Attachment[i].Renderbuffer) {
= fb->Attachment[BUFFER_STENCIL].Renderbuffer->StencilBits;
}
+ if (fb->Attachment[BUFFER_ACCUM].Renderbuffer) {
+ fb->Visual.haveAccumBuffer = GL_TRUE;
+ fb->Visual.accumRedBits
+ = fb->Attachment[BUFFER_DEPTH].Renderbuffer->RedBits;
+ fb->Visual.accumGreenBits
+ = fb->Attachment[BUFFER_DEPTH].Renderbuffer->GreenBits;
+ fb->Visual.accumBlueBits
+ = fb->Attachment[BUFFER_DEPTH].Renderbuffer->BlueBits;
+ fb->Visual.accumAlphaBits
+ = fb->Attachment[BUFFER_DEPTH].Renderbuffer->AlphaBits;
+ }
+
compute_depth_max(fb);
}
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) {
+ if (!fb->_DepthBuffer
+ || fb->_DepthBuffer->Wrapped != depthRb
+ || fb->_DepthBuffer->_BaseFormat != GL_DEPTH_COMPONENT) {
/* need to update wrapper */
struct gl_renderbuffer *wrapper
= _mesa_new_z24_renderbuffer_wrapper(ctx, depthRb);
- set_depth_renderbuffer(fb, wrapper);
+ _mesa_reference_renderbuffer(&fb->_DepthBuffer, wrapper);
ASSERT(fb->_DepthBuffer->Wrapped == depthRb);
}
}
else {
/* depthRb may be null */
- set_depth_renderbuffer(fb, depthRb);
+ _mesa_reference_renderbuffer(&fb->_DepthBuffer, depthRb);
}
}
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) {
+ if (!fb->_StencilBuffer
+ || fb->_StencilBuffer->Wrapped != stencilRb
+ || fb->_StencilBuffer->_BaseFormat != GL_STENCIL_INDEX) {
/* need to update wrapper */
struct gl_renderbuffer *wrapper
= _mesa_new_s8_renderbuffer_wrapper(ctx, stencilRb);
- set_stencil_renderbuffer(fb, wrapper);
+ _mesa_reference_renderbuffer(&fb->_StencilBuffer, wrapper);
ASSERT(fb->_StencilBuffer->Wrapped == stencilRb);
}
}
else {
/* stencilRb may be null */
- set_stencil_renderbuffer(fb, stencilRb);
+ _mesa_reference_renderbuffer(&fb->_StencilBuffer, stencilRb);
}
}
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++;
+ if (!fb->DeletePending) {
+ /* 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 && rb->Width > 0 && rb->Height > 0) {
+ fb->_ColorDrawBuffers[output][count] = rb;
+ count++;
+ }
+ else {
+ /*
+ _mesa_warning(ctx, "DrawBuffer names a missing buffer!\n");
+ */
+ }
+ bufferMask &= ~bufferBit;
}
- else {
- /*_mesa_warning(ctx, "DrawBuffer names a missing buffer!\n");*/
- }
- bufferMask &= ~bufferBit;
}
}
fb->_NumColorDrawBuffers[output] = count;
static void
update_color_read_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
{
- if (fb->_ColorReadBufferIndex == -1) {
+ (void) ctx;
+ if (fb->_ColorReadBufferIndex == -1 ||
+ fb->DeletePending ||
+ fb->Width == 0 ||
+ fb->Height == 0) {
fb->_ColorReadBuffer = NULL; /* legal! */
}
else {
}
+static void
+update_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb)
+{
+ /* Completeness only matters for user-created framebuffers */
+ if (fb->Name != 0) {
+ /* XXX: EXT_framebuffer_blit:
+ framebuffer must still be complete wrt read/draw? */
+ _mesa_test_framebuffer_completeness(ctx, fb);
+ _mesa_update_framebuffer_visual(fb);
+ }
+
+ /* update_color_draw/read_buffers not needed for
+ read/draw only fb, but shouldn't hurt ??? */
+ 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);
+}
+
/**
* Update state related to the current draw/read framebuffers.
* Specifically, update these framebuffer fields:
_mesa_update_framebuffer(GLcontext *ctx)
{
struct gl_framebuffer *fb = ctx->DrawBuffer;
+ struct gl_framebuffer *fbread = ctx->ReadBuffer;
- /* 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);
+ update_framebuffer(ctx, fb);
+ if (fbread != fb)
+ update_framebuffer(ctx, fbread);
}