summaryrefslogtreecommitdiff
path: root/src/mesa/main/framebuffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/main/framebuffer.c')
-rw-r--r--src/mesa/main/framebuffer.c300
1 files changed, 187 insertions, 113 deletions
diff --git a/src/mesa/main/framebuffer.c b/src/mesa/main/framebuffer.c
index 5cea6d1a173..55e9bbc79d6 100644
--- a/src/mesa/main/framebuffer.c
+++ b/src/mesa/main/framebuffer.c
@@ -70,6 +70,48 @@ compute_depth_max(struct gl_framebuffer *fb)
/**
+ * 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.
@@ -127,6 +169,8 @@ _mesa_initialize_framebuffer(struct gl_framebuffer *fb, const GLvisual *visual)
_mesa_bzero(fb, sizeof(struct gl_framebuffer));
+ _glthread_INIT_MUTEX(fb->Mutex);
+
/* save the visual */
fb->Visual = *visual;
@@ -159,6 +203,7 @@ void
_mesa_destroy_framebuffer(struct gl_framebuffer *fb)
{
if (fb) {
+ _glthread_DESTROY_MUTEX(fb->Mutex);
_mesa_free_framebuffer_data(fb);
_mesa_free(fb);
}
@@ -180,7 +225,9 @@ _mesa_free_framebuffer_data(struct gl_framebuffer *fb)
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);
}
@@ -189,22 +236,9 @@ _mesa_free_framebuffer_data(struct gl_framebuffer *fb)
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;
- }
+ /* unbind depth/stencil to decr ref counts */
+ set_depth_renderbuffer(fb, NULL);
+ set_stencil_renderbuffer(fb, NULL);
}
@@ -224,6 +258,10 @@ _mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb,
{
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);
@@ -233,23 +271,42 @@ _mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb,
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)) {
- rb->Width = width;
- rb->Height = 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 */
- if (ctx)
- ctx->NewState |= _NEW_BUFFERS;
+ _mesa_update_draw_buffer_bounds(ctx);
}
@@ -400,80 +457,104 @@ _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.
+ * 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
*/
-static void
-set_depth_renderbuffer(struct gl_framebuffer *fb,
- struct gl_renderbuffer *rb)
+void
+_mesa_update_depth_buffer(GLcontext *ctx,
+ struct gl_framebuffer *fb,
+ GLuint attIndex)
{
- if (fb->_DepthBuffer) {
- fb->_DepthBuffer->RefCount--;
- if (fb->_DepthBuffer->RefCount <= 0) {
- fb->_DepthBuffer->Delete(fb->_DepthBuffer);
+ 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);
}
}
- fb->_DepthBuffer = rb;
- if (rb)
- rb->RefCount++;
+ else {
+ /* depthRb may be null */
+ set_depth_renderbuffer(fb, depthRb);
+ }
}
+
/**
- * \sa set_depth_renderbuffer.
+ * 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
*/
-static void
-set_stencil_renderbuffer(struct gl_framebuffer *fb,
- struct gl_renderbuffer *rb)
+void
+_mesa_update_stencil_buffer(GLcontext *ctx,
+ struct gl_framebuffer *fb,
+ GLuint attIndex)
{
- if (fb->_StencilBuffer) {
- fb->_StencilBuffer->RefCount--;
- if (fb->_StencilBuffer->RefCount <= 0) {
- fb->_StencilBuffer->Delete(fb->_StencilBuffer);
+ 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);
}
}
- fb->_StencilBuffer = rb;
- if (rb)
- rb->RefCount++;
+ else {
+ /* stencilRb may be null */
+ set_stencil_renderbuffer(fb, stencilRb);
+ }
}
/**
- * 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.
+ * Update the list of color drawing renderbuffer pointers.
+ * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers
+ * writing colors.
*/
-void
-_mesa_update_framebuffer(GLcontext *ctx)
+static void
+update_color_draw_buffers(GLcontext *ctx, struct gl_framebuffer *fb)
{
- struct gl_framebuffer *fb = ctx->DrawBuffer;
GLuint output;
- /* Completeness only matters for user-created framebuffers */
- if (fb->Name != 0) {
- _mesa_test_framebuffer_completeness(ctx, fb);
- _mesa_update_framebuffer_visual(fb);
- }
-
/*
- * Update the list of color drawing renderbuffer pointers.
- * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers
- * writing colors. We need the inner loop here because
- * glDrawBuffer(GL_FRONT_AND_BACK) can specify writing to two or four
- * color buffers (for example).
+ * 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) {
@@ -490,11 +571,16 @@ _mesa_update_framebuffer(GLcontext *ctx)
}
fb->_NumColorDrawBuffers[output] = count;
}
+}
- /*
- * Update the color read renderbuffer pointer.
- * Unlike the DrawBuffer, we can only read from one (or zero) color buffers.
- */
+
+/**
+ * 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! */
}
@@ -504,50 +590,38 @@ _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. If either of the DEPTH or STENCIL
- * renderbuffer attachments are GL_DEPTH_STENCIL buffers, we need to set
- * up depth/stencil renderbuffer wrappers.
- */
- {
- 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) {
- /* 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);
- }
- if (stencilRb && stencilRb->_BaseFormat == GL_DEPTH_STENCIL_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 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);
}