X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Fframebuffer.c;h=c9b30d3252829993b796366dcf096f7928f441c3;hb=e0a26b046764ae80748b347395ab1b27de83651e;hp=26e72da3f7c70c7f6074718a3f2d23b1896e8cd1;hpb=7275d4d097f97a2154dfe8fa573dc193cb5b4bf1;p=mesa.git diff --git a/src/mesa/main/framebuffer.c b/src/mesa/main/framebuffer.c index 26e72da3f7c..c9b30d32528 100644 --- a/src/mesa/main/framebuffer.c +++ b/src/mesa/main/framebuffer.c @@ -1,6 +1,6 @@ /* * Mesa 3-D graphics library - * Version: 6.5 + * Version: 6.5.1 * * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. * @@ -65,7 +65,9 @@ compute_depth_max(struct gl_framebuffer *fb) fb->_DepthMax = 0xffffffff; } fb->_DepthMaxF = (GLfloat) fb->_DepthMax; - fb->_MRD = 1.0; /* Minimum resolvable depth value, for polygon offset */ + + /* Minimum resolvable depth value, for polygon offset */ + fb->_MRD = 1.0 / fb->_DepthMaxF; } @@ -99,6 +101,7 @@ struct gl_framebuffer * _mesa_new_framebuffer(GLcontext *ctx, GLuint name) { struct gl_framebuffer *fb; + (void) ctx; assert(name != 0); fb = CALLOC_STRUCT(gl_framebuffer); if (fb) { @@ -127,6 +130,10 @@ _mesa_initialize_framebuffer(struct gl_framebuffer *fb, const GLvisual *visual) _mesa_bzero(fb, sizeof(struct gl_framebuffer)); + _glthread_INIT_MUTEX(fb->Mutex); + + fb->RefCount = 1; + /* save the visual */ fb->Visual = *visual; @@ -175,39 +182,88 @@ _mesa_free_framebuffer_data(struct gl_framebuffer *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->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) { - struct gl_renderbuffer *rb = att->Renderbuffer; - rb->RefCount--; - if (rb->RefCount == 0) { - rb->Delete(rb); + if (att->Renderbuffer) { + _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; } - if (fb->_DepthBuffer) { - struct gl_renderbuffer *rb = fb->_DepthBuffer; - rb->RefCount--; - if (rb->RefCount <= 0) { - rb->Delete(rb); - } - fb->_DepthBuffer = 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 (fb->_StencilBuffer) { - struct gl_renderbuffer *rb = fb->_StencilBuffer; - rb->RefCount--; - if (rb->RefCount <= 0) { - rb->Delete(rb); - } - fb->_StencilBuffer = NULL; + 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 @@ -224,6 +280,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 +293,48 @@ _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) + 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; + } } @@ -302,6 +387,9 @@ _mesa_update_draw_buffer_bounds(GLcontext *ctx) { struct gl_framebuffer *buffer = ctx->DrawBuffer; + if (!buffer) + return; + if (buffer->Name) { /* user-created framebuffer size depends on the renderbuffers */ update_framebuffer_size(buffer); @@ -344,7 +432,8 @@ _mesa_update_draw_buffer_bounds(GLcontext *ctx) * 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. @@ -356,11 +445,16 @@ _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 */ +#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) { @@ -395,107 +489,160 @@ _mesa_update_framebuffer_visual(struct gl_framebuffer *fb) = 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); } /** - * 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 + || fb->_DepthBuffer->_BaseFormat != GL_DEPTH_COMPONENT) { + /* need to update wrapper */ + struct gl_renderbuffer *wrapper + = _mesa_new_z24_renderbuffer_wrapper(ctx, depthRb); + _mesa_reference_renderbuffer(&fb->_DepthBuffer, wrapper); + ASSERT(fb->_DepthBuffer->Wrapped == depthRb); } } - fb->_DepthBuffer = rb; - if (rb) - rb->RefCount++; + else { + /* depthRb may be null */ + _mesa_reference_renderbuffer(&fb->_DepthBuffer, 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 + || fb->_StencilBuffer->_BaseFormat != GL_STENCIL_INDEX) { + /* need to update wrapper */ + struct gl_renderbuffer *wrapper + = _mesa_new_s8_renderbuffer_wrapper(ctx, stencilRb); + _mesa_reference_renderbuffer(&fb->_StencilBuffer, wrapper); + ASSERT(fb->_StencilBuffer->Wrapped == stencilRb); } } - fb->_StencilBuffer = rb; - if (rb) - rb->RefCount++; + else { + /* stencilRb may be null */ + _mesa_reference_renderbuffer(&fb->_StencilBuffer, 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; - 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 the color read renderbuffer pointer. - * Unlike the DrawBuffer, we can only read from one (or zero) color buffers. - */ - if (fb->_ColorReadBufferIndex == -1) { + +/** + * 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) +{ + (void) ctx; + if (fb->_ColorReadBufferIndex == -1 || + fb->DeletePending || + fb->Width == 0 || + fb->Height == 0) { fb->_ColorReadBuffer = NULL; /* legal! */ } else { @@ -504,53 +651,54 @@ _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); - } +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: + * _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; + struct gl_framebuffer *fbread = ctx->ReadBuffer; + + update_framebuffer(ctx, fb); + if (fbread != fb) + update_framebuffer(ctx, fbread); +} + /** * Check if the renderbuffer for a read operation (glReadPixels, glCopyPixels, @@ -571,16 +719,26 @@ _mesa_source_buffer_exists(GLcontext *ctx, GLenum format) 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: @@ -606,7 +764,8 @@ _mesa_source_buffer_exists(GLcontext *ctx, GLenum format) break; default: _mesa_problem(ctx, - "Unexpected format 0x%x in _mesa_source_buffer_exists"); + "Unexpected format 0x%x in _mesa_source_buffer_exists", + format); return GL_FALSE; } @@ -631,14 +790,21 @@ _mesa_dest_buffer_exists(GLcontext *ctx, GLenum format) 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: @@ -664,7 +830,8 @@ _mesa_dest_buffer_exists(GLcontext *ctx, GLenum format) break; default: _mesa_problem(ctx, - "Unexpected format 0x%x in _mesa_source_buffer_exists"); + "Unexpected format 0x%x in _mesa_source_buffer_exists", + format); return GL_FALSE; }