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) {
- _mesa_dereference_renderbuffer(&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) {
- _mesa_dereference_renderbuffer(&fb->_StencilBuffer);
- }
- fb->_StencilBuffer = rb;
- if (rb) {
- rb->RefCount++;
- }
+ /* Minimum resolvable depth value, for polygon offset */
+ fb->_MRD = 1.0 / fb->_DepthMaxF;
}
_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;
- /* remove framebuffer's reference to renderbuffer */
- _mesa_dereference_renderbuffer(&rb);
- if (rb && rb->Name == 0) {
- /* delete window system renderbuffer */
- _mesa_dereference_renderbuffer(&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;
}
/**
- * Decrement the reference count on a framebuffer and delete it when
+ * 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 if we delete it.
+ * Note: we pass the address of a pointer and set it to NULL.
*/
void
-_mesa_dereference_framebuffer(struct gl_framebuffer **fb)
+_mesa_unreference_framebuffer(struct gl_framebuffer **fb)
{
- GLboolean deleteFlag = GL_FALSE;
+ assert(fb);
+ if (*fb) {
+ GLboolean deleteFlag = GL_FALSE;
- _glthread_LOCK_MUTEX((*fb)->Mutex);
- {
+ _glthread_LOCK_MUTEX((*fb)->Mutex);
ASSERT((*fb)->RefCount > 0);
(*fb)->RefCount--;
deleteFlag = ((*fb)->RefCount == 0);
- }
- _glthread_UNLOCK_MUTEX((*fb)->Mutex);
+ _glthread_UNLOCK_MUTEX((*fb)->Mutex);
+
+ if (deleteFlag)
+ (*fb)->Delete(*fb);
- if (deleteFlag) {
- (*fb)->Delete(*fb);
*fb = NULL;
}
}
/* 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);
}
}
/* 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;
update_color_read_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
{
(void) ctx;
- if (fb->_ColorReadBufferIndex == -1) {
+ 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);
}