diff options
Diffstat (limited to 'src/mesa/main/framebuffer.c')
-rw-r--r-- | src/mesa/main/framebuffer.c | 300 |
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); } |