X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Ffbobject.c;h=800f6ee9a31088ff9c12b721913c85a5baf23f2c;hb=eded7f010d344a909cf9c403eb3bdad91804d174;hp=749115a799d33c866782949d25d801991c6d6575;hpb=2e01918b553ad50f6df788bb762f487d618ad37e;p=mesa.git diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c index 749115a799d..800f6ee9a31 100644 --- a/src/mesa/main/fbobject.c +++ b/src/mesa/main/fbobject.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. * @@ -29,13 +29,16 @@ */ +#include "buffers.h" #include "context.h" #include "fbobject.h" #include "framebuffer.h" #include "hash.h" +#include "mipmap.h" #include "renderbuffer.h" #include "state.h" #include "teximage.h" +#include "texobj.h" #include "texstore.h" @@ -66,8 +69,8 @@ static struct gl_renderbuffer DummyRenderbuffer; /** * Helper routine for getting a gl_renderbuffer. */ -static struct gl_renderbuffer * -lookup_renderbuffer(GLcontext *ctx, GLuint id) +struct gl_renderbuffer * +_mesa_lookup_renderbuffer(GLcontext *ctx, GLuint id) { struct gl_renderbuffer *rb; @@ -83,8 +86,8 @@ lookup_renderbuffer(GLcontext *ctx, GLuint id) /** * Helper routine for getting a gl_framebuffer. */ -static struct gl_framebuffer * -lookup_framebuffer(GLcontext *ctx, GLuint id) +struct gl_framebuffer * +_mesa_lookup_framebuffer(GLcontext *ctx, GLuint id) { struct gl_framebuffer *fb; @@ -155,9 +158,7 @@ _mesa_remove_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att) else { /* tell driver that we're done rendering to this texture. */ if (ctx->Driver.FinishRenderTexture) { - ctx->Driver.FinishRenderTexture(ctx, att->Texture, - att->CubeMapFace, - att->TextureLevel); + ctx->Driver.FinishRenderTexture(ctx, att); } } att->Texture = NULL; @@ -165,11 +166,7 @@ _mesa_remove_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att) if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) { ASSERT(att->Renderbuffer); ASSERT(!att->Texture); - att->Renderbuffer->RefCount--; - if (att->Renderbuffer->RefCount == 0) { - att->Renderbuffer->Delete(att->Renderbuffer); - } - att->Renderbuffer = NULL; + _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); } att->Type = GL_NONE; att->Complete = GL_TRUE; @@ -182,6 +179,7 @@ _mesa_remove_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att) */ void _mesa_set_texture_attachment(GLcontext *ctx, + struct gl_framebuffer *fb, struct gl_renderbuffer_attachment *att, struct gl_texture_object *texObj, GLenum texTarget, GLuint level, GLuint zoffset) @@ -208,6 +206,10 @@ _mesa_set_texture_attachment(GLcontext *ctx, } att->Zoffset = zoffset; att->Complete = GL_FALSE; + + if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) { + ctx->Driver.RenderTexture(ctx, fb, att); + } } @@ -220,12 +222,12 @@ _mesa_set_renderbuffer_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att, struct gl_renderbuffer *rb) { + /* XXX check if re-doing same attachment, exit early */ _mesa_remove_attachment(ctx, att); att->Type = GL_RENDERBUFFER_EXT; - att->Renderbuffer = rb; att->Texture = NULL; /* just to be safe */ att->Complete = GL_FALSE; - rb->RefCount++; + _mesa_reference_renderbuffer(&att->Renderbuffer, rb); } @@ -239,15 +241,18 @@ _mesa_framebuffer_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb, { struct gl_renderbuffer_attachment *att; + _glthread_LOCK_MUTEX(fb->Mutex); + att = _mesa_get_attachment(ctx, fb, attachment); ASSERT(att); - if (rb) { _mesa_set_renderbuffer_attachment(ctx, att, rb); } else { _mesa_remove_attachment(ctx, att); } + + _glthread_UNLOCK_MUTEX(fb->Mutex); } @@ -302,7 +307,7 @@ test_attachment_completeness(const GLcontext *ctx, GLenum format, /* OK */ } else if (ctx->Extensions.EXT_packed_depth_stencil && - att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) { + texImage->TexFormat->BaseFormat == GL_DEPTH_STENCIL_EXT) { /* OK */ } else { @@ -317,18 +322,25 @@ test_attachment_completeness(const GLcontext *ctx, GLenum format, } } else if (att->Type == GL_RENDERBUFFER_EXT) { - if (att->Renderbuffer->Width < 1 || att->Renderbuffer->Height < 1) { + ASSERT(att->Renderbuffer); + if (!att->Renderbuffer->InternalFormat || + att->Renderbuffer->Width < 1 || + att->Renderbuffer->Height < 1) { att->Complete = GL_FALSE; return; } if (format == GL_COLOR) { if (att->Renderbuffer->_BaseFormat != GL_RGB && att->Renderbuffer->_BaseFormat != GL_RGBA) { + ASSERT(att->Renderbuffer->RedBits); + ASSERT(att->Renderbuffer->GreenBits); + ASSERT(att->Renderbuffer->BlueBits); att->Complete = GL_FALSE; return; } } else if (format == GL_DEPTH) { + ASSERT(att->Renderbuffer->DepthBits); if (att->Renderbuffer->_BaseFormat == GL_DEPTH_COMPONENT) { /* OK */ } @@ -343,6 +355,7 @@ test_attachment_completeness(const GLcontext *ctx, GLenum format, } else { assert(format == GL_STENCIL); + ASSERT(att->Renderbuffer->StencilBits); if (att->Renderbuffer->_BaseFormat == GL_STENCIL_INDEX) { /* OK */ } @@ -364,6 +377,20 @@ test_attachment_completeness(const GLcontext *ctx, GLenum format, } +/** + * Helpful for debugging + */ +static void +fbo_incomplete(const char *msg, int index) +{ + (void) msg; + (void) index; + /* + _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index); + */ +} + + /** * Test if the given framebuffer object is complete and update its * Status field with the results. @@ -377,6 +404,7 @@ _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb) GLenum intFormat = GL_NONE; GLuint w = 0, h = 0; GLint i; + GLuint j; assert(fb->Name != 0); @@ -394,6 +422,7 @@ _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb) test_attachment_completeness(ctx, GL_DEPTH, att); if (!att->Complete) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; + fbo_incomplete("depth attachment incomplete", -1); return; } } @@ -402,6 +431,7 @@ _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb) test_attachment_completeness(ctx, GL_STENCIL, att); if (!att->Complete) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; + fbo_incomplete("stencil attachment incomplete", -1); return; } } @@ -410,6 +440,7 @@ _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb) test_attachment_completeness(ctx, GL_COLOR, att); if (!att->Complete) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; + fbo_incomplete("color attachment incomplete", i); return; } } @@ -421,9 +452,10 @@ _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb) h = texImg->Height; f = texImg->_BaseFormat; numImages++; - if (f != GL_RGB && f != GL_RGBA && f != GL_DEPTH_COMPONENT) { - /* XXX need GL_DEPTH_STENCIL_EXT test? */ + if (f != GL_RGB && f != GL_RGBA && f != GL_DEPTH_COMPONENT + && f != GL_DEPTH_STENCIL_EXT) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; + fbo_incomplete("texture attachment incomplete", -1); return; } } @@ -449,23 +481,26 @@ _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb) /* check that width, height, format are same */ if (w != width || h != height) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; + fbo_incomplete("width or height mismatch", -1); return; } if (intFormat != GL_NONE && f != intFormat) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; + fbo_incomplete("format mismatch", -1); return; } } } /* Check that all DrawBuffers are present */ - for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { - if (fb->ColorDrawBuffer[i] != GL_NONE) { + for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) { + if (fb->ColorDrawBuffer[j] != GL_NONE) { const struct gl_renderbuffer_attachment *att - = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[i]); + = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]); assert(att); if (att->Type == GL_NONE) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT; + fbo_incomplete("missing drawbuffer", j); return; } } @@ -478,31 +513,14 @@ _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb) assert(att); if (att->Type == GL_NONE) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT; + fbo_incomplete("missing readbuffer", -1); return; } } - /* Check if any renderbuffer is attached more than once. - * Note that there's one exception: a GL_DEPTH_STENCIL renderbuffer can be - * bound to both the stencil and depth attachment points at the same time. - */ - for (i = 0; i < BUFFER_COUNT - 1; i++) { - struct gl_renderbuffer *rb_i = fb->Attachment[i].Renderbuffer; - if (rb_i) { - GLint j; - for (j = i + 1; j < BUFFER_COUNT; j++) { - struct gl_renderbuffer *rb_j = fb->Attachment[j].Renderbuffer; - if (rb_i == rb_j && rb_i->_BaseFormat != GL_DEPTH_STENCIL_EXT) { - fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT; - return; - } - } - } - } - - if (numImages == 0) { fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT; + fbo_incomplete("no attachments", -1); return; } @@ -521,7 +539,7 @@ _mesa_IsRenderbufferEXT(GLuint renderbuffer) GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); if (renderbuffer) { - struct gl_renderbuffer *rb = lookup_renderbuffer(ctx, renderbuffer); + struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); if (rb != NULL && rb != &DummyRenderbuffer) return GL_TRUE; } @@ -532,7 +550,7 @@ _mesa_IsRenderbufferEXT(GLuint renderbuffer) void GLAPIENTRY _mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer) { - struct gl_renderbuffer *newRb, *oldRb; + struct gl_renderbuffer *newRb; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); @@ -544,9 +562,15 @@ _mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer) } FLUSH_VERTICES(ctx, _NEW_BUFFERS); + /* The above doesn't fully flush the drivers in the way that a + * glFlush does, but that is required here: + */ + if (ctx->Driver.Flush) + ctx->Driver.Flush(ctx); + if (renderbuffer) { - newRb = lookup_renderbuffer(ctx, renderbuffer); + newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer); if (newRb == &DummyRenderbuffer) { /* ID was reserved, but no real renderbuffer object made yet */ newRb = NULL; @@ -560,24 +584,16 @@ _mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer) } ASSERT(newRb->AllocStorage); _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb); + newRb->RefCount = 1; /* referenced by hash table */ } - newRb->RefCount++; } else { newRb = NULL; } - oldRb = ctx->CurrentRenderbuffer; - if (oldRb) { - oldRb->RefCount--; - if (oldRb->RefCount == 0) { - oldRb->Delete(oldRb); - } - } - ASSERT(newRb != &DummyRenderbuffer); - ctx->CurrentRenderbuffer = newRb; + _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb); } @@ -593,7 +609,7 @@ _mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) for (i = 0; i < n; i++) { if (renderbuffers[i] > 0) { struct gl_renderbuffer *rb; - rb = lookup_renderbuffer(ctx, renderbuffers[i]); + rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]); if (rb) { /* check if deleting currently bound renderbuffer object */ if (rb == ctx->CurrentRenderbuffer) { @@ -602,17 +618,15 @@ _mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); } - /* remove from hash table immediately, to free the ID */ + /* Remove from hash table immediately, to free the ID. + * But the object will not be freed until it's no longer + * referenced anywhere else. + */ _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]); if (rb != &DummyRenderbuffer) { - /* But the object will not be freed until it's no longer - * bound in any context. - */ - rb->RefCount--; - if (rb->RefCount == 0) { - rb->Delete(rb); - } + /* no longer referenced by hash table */ + _mesa_reference_renderbuffer(&rb, NULL); } } } @@ -653,11 +667,14 @@ _mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers) /** * Given an internal format token for a render buffer, return the * corresponding base format. + * This is very similar to _mesa_base_tex_format() but the set of valid + * internal formats is somewhat different. + * * \return one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT * GL_DEPTH_STENCIL_EXT or zero if error. */ -static GLenum -base_internal_format(GLcontext *ctx, GLenum internalFormat) +GLenum +_mesa_base_fbo_format(GLcontext *ctx, GLenum internalFormat) { switch (internalFormat) { case GL_RGB: @@ -717,19 +734,19 @@ _mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, return; } - baseFormat = base_internal_format(ctx, internalFormat); + baseFormat = _mesa_base_fbo_format(ctx, internalFormat); if (baseFormat == 0) { _mesa_error(ctx, GL_INVALID_ENUM, "glRenderbufferStorageEXT(internalFormat)"); return; } - if (width < 1 || width > ctx->Const.MaxRenderbufferSize) { + if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) { _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(width)"); return; } - if (height < 1 || height > ctx->Const.MaxRenderbufferSize) { + if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) { _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(height)"); return; } @@ -744,21 +761,32 @@ _mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, FLUSH_VERTICES(ctx, _NEW_BUFFERS); if (rb->InternalFormat == internalFormat && - rb->Width == width && - rb->Height == height) { + rb->Width == (GLuint) width && + rb->Height == (GLuint) height) { /* no change in allocation needed */ return; } + /* These MUST get set by the AllocStorage func */ + rb->_ActualFormat = 0; + rb->RedBits = + rb->GreenBits = + rb->BlueBits = + rb->AlphaBits = + rb->IndexBits = + rb->DepthBits = + rb->StencilBits = 0; + /* Now allocate the storage */ ASSERT(rb->AllocStorage); if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) { /* No error - check/set fields now */ - assert(rb->Width == width); - assert(rb->Height == height); - assert(rb->InternalFormat); + assert(rb->_ActualFormat); + assert(rb->Width == (GLuint) width); + assert(rb->Height == (GLuint) height); assert(rb->RedBits || rb->GreenBits || rb->BlueBits || rb->AlphaBits || rb->DepthBits || rb->StencilBits || rb->IndexBits); + rb->InternalFormat = internalFormat; rb->_BaseFormat = baseFormat; } else { @@ -766,6 +794,7 @@ _mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, rb->Width = 0; rb->Height = 0; rb->InternalFormat = GL_NONE; + rb->_ActualFormat = GL_NONE; rb->_BaseFormat = GL_NONE; rb->RedBits = rb->GreenBits = @@ -848,7 +877,7 @@ _mesa_IsFramebufferEXT(GLuint framebuffer) GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); if (framebuffer) { - struct gl_framebuffer *rb = lookup_framebuffer(ctx, framebuffer); + struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer); if (rb != NULL && rb != &DummyFramebuffer) return GL_TRUE; } @@ -856,22 +885,36 @@ _mesa_IsFramebufferEXT(GLuint framebuffer) } +static void +check_begin_texture_render(GLcontext *ctx, struct gl_framebuffer *fb) +{ + GLuint i; + ASSERT(ctx->Driver.RenderTexture); + for (i = 0; i < BUFFER_COUNT; i++) { + struct gl_renderbuffer_attachment *att = fb->Attachment + i; + struct gl_texture_object *texObj = att->Texture; + if (texObj + && att->Texture->Image[att->CubeMapFace][att->TextureLevel]) { + ctx->Driver.RenderTexture(ctx, fb, att); + } + } +} + + /** * Examine all the framebuffer's attachments to see if any are textures. * If so, call ctx->Driver.FinishRenderTexture() for each texture to * notify the device driver that the texture image may have changed. */ static void -check_texture_render(GLcontext *ctx, struct gl_framebuffer *fb) +check_end_texture_render(GLcontext *ctx, struct gl_framebuffer *fb) { if (ctx->Driver.FinishRenderTexture) { GLuint i; for (i = 0; i < BUFFER_COUNT; i++) { struct gl_renderbuffer_attachment *att = fb->Attachment + i; - struct gl_texture_object *texObj = att->Texture; - if (texObj) { - ctx->Driver.FinishRenderTexture(ctx, texObj, att->CubeMapFace, - att->TextureLevel); + if (att->Texture && att->Renderbuffer) { + ctx->Driver.FinishRenderTexture(ctx, att); } } } @@ -881,12 +924,18 @@ check_texture_render(GLcontext *ctx, struct gl_framebuffer *fb) void GLAPIENTRY _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer) { - struct gl_framebuffer *newFb, *oldFb; + struct gl_framebuffer *newFb, *newFbread; GLboolean bindReadBuf, bindDrawBuf; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); + if (!ctx->Extensions.EXT_framebuffer_object) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindFramebufferEXT(unsupported)"); + return; + } + switch (target) { #if FEATURE_EXT_framebuffer_blit case GL_DRAW_FRAMEBUFFER_EXT: @@ -916,10 +965,12 @@ _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer) } FLUSH_VERTICES(ctx, _NEW_BUFFERS); - + if (ctx->Driver.Flush) { + ctx->Driver.Flush(ctx); + } if (framebuffer) { /* Binding a user-created framebuffer object */ - newFb = lookup_framebuffer(ctx, framebuffer); + newFb = _mesa_lookup_framebuffer(ctx, framebuffer); if (newFb == &DummyFramebuffer) { /* ID was reserved, but no real framebuffer object made yet */ newFb = NULL; @@ -933,45 +984,56 @@ _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer) } _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newFb); } - if (bindReadBuf) - newFb->RefCount++; - if (bindDrawBuf) - newFb->RefCount++; + newFbread = newFb; } else { /* Binding the window system framebuffer (which was originally set * with MakeCurrent). */ newFb = ctx->WinSysDrawBuffer; + newFbread = ctx->WinSysReadBuffer; } + ASSERT(newFb); ASSERT(newFb != &DummyFramebuffer); + /* + * XXX check if re-binding same buffer and skip some of this code. + */ + + /* for window-framebuffers, re-initialize the fbo values, as they + could be wrong (makecurrent with a new drawable while still a fbo + was bound will lead to default init fbo values). + note that therefore the context ReadBuffer/DrawBuffer values are not + valid while fbo's are bound!!! */ if (bindReadBuf) { - oldFb = ctx->ReadBuffer; - if (oldFb && oldFb->Name != 0) { - oldFb->RefCount--; - if (oldFb->RefCount == 0) { - oldFb->Delete(oldFb); - } + _mesa_reference_framebuffer(&ctx->ReadBuffer, newFbread); + if (!newFbread->Name) { + _mesa_readbuffer_update_fields(ctx, ctx->Pixel.ReadBuffer); } - ctx->ReadBuffer = newFb; } if (bindDrawBuf) { - oldFb = ctx->DrawBuffer; - if (oldFb && oldFb->Name != 0) { - /* check if old FB had any texture attachments */ - if (ctx->Driver.FinishRenderTexture) { - check_texture_render(ctx, oldFb); - } - /* check if time to delete this framebuffer */ - oldFb->RefCount--; - if (oldFb->RefCount == 0) { - oldFb->Delete(oldFb); + /* check if old FB had any texture attachments */ + check_end_texture_render(ctx, ctx->DrawBuffer); + /* check if time to delete this framebuffer */ + _mesa_reference_framebuffer(&ctx->DrawBuffer, newFb); + if (!newFb->Name) { + GLuint i; + GLenum buffers[MAX_DRAW_BUFFERS]; + for(i = 0; i < ctx->Const.MaxDrawBuffers; i++) { + buffers[i] = ctx->Color.DrawBuffer[i]; } + _mesa_drawbuffers(ctx, ctx->Const.MaxDrawBuffers, buffers, NULL); + } + else { + /* check if newly bound framebuffer has any texture attachments */ + check_begin_texture_render(ctx, newFb); } - ctx->DrawBuffer = newFb; + } + + if (ctx->Driver.BindFramebuffer) { + ctx->Driver.BindFramebuffer(ctx, target, newFb, newFbread); } } @@ -984,11 +1046,16 @@ _mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers) ASSERT_OUTSIDE_BEGIN_END(ctx); FLUSH_VERTICES(ctx, _NEW_BUFFERS); + /* The above doesn't fully flush the drivers in the way that a + * glFlush does, but that is required here: + */ + if (ctx->Driver.Flush) + ctx->Driver.Flush(ctx); for (i = 0; i < n; i++) { if (framebuffers[i] > 0) { struct gl_framebuffer *fb; - fb = lookup_framebuffer(ctx, framebuffers[i]); + fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]); if (fb) { ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]); @@ -1006,10 +1073,7 @@ _mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers) /* But the object will not be freed until it's no longer * bound in any context. */ - fb->RefCount--; - if (fb->RefCount == 0) { - fb->Delete(fb); - } + _mesa_unreference_framebuffer(&fb); } } } @@ -1095,150 +1159,150 @@ _mesa_CheckFramebufferStatusEXT(GLenum target) /** - * Do error checking common to glFramebufferTexture1D/2D/3DEXT. - * \return GL_TRUE if any error, GL_FALSE otherwise + * Common code called by glFramebufferTexture1D/2D/3DEXT(). */ -static GLboolean -error_check_framebuffer_texture(GLcontext *ctx, GLuint dims, - GLenum target, GLenum attachment, - GLenum textarget, GLuint texture, GLint level) +static void +framebuffer_texture(GLcontext *ctx, const char *caller, GLenum target, + GLenum attachment, GLenum textarget, GLuint texture, + GLint level, GLint zoffset) { - ASSERT(dims >= 1 && dims <= 3); + struct gl_renderbuffer_attachment *att; + struct gl_texture_object *texObj = NULL; + struct gl_framebuffer *fb; + + ASSERT_OUTSIDE_BEGIN_END(ctx); if (target != GL_FRAMEBUFFER_EXT) { _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferTexture%dDEXT(target)", dims); - return GL_TRUE; + "glFramebufferTexture%sEXT(target)", caller); + return; } + fb = ctx->DrawBuffer; + ASSERT(fb); + /* check framebuffer binding */ - if (ctx->DrawBuffer->Name == 0) { + if (fb->Name == 0) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferTexture%dDEXT", dims); - return GL_TRUE; + "glFramebufferTexture%sEXT", caller); + return; } - /* only check textarget, level if texture ID is non-zero */ + + /* The textarget, level, and zoffset parameters are only validated if + * texture is non-zero. + */ if (texture) { - if ((dims == 1 && textarget != GL_TEXTURE_1D) || - (dims == 3 && textarget != GL_TEXTURE_3D) || - (dims == 2 && textarget != GL_TEXTURE_2D && - textarget != GL_TEXTURE_RECTANGLE_ARB && - !IS_CUBE_FACE(textarget))) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glFramebufferTexture%dDEXT(textarget)", dims); - return GL_TRUE; + GLboolean err = GL_TRUE; + + texObj = _mesa_lookup_texture(ctx, texture); + if (texObj != NULL) { + if (textarget == 0) { + err = (texObj->Target != GL_TEXTURE_3D) && + (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) && + (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT); + } + else { + err = (texObj->Target == GL_TEXTURE_CUBE_MAP) + ? !IS_CUBE_FACE(textarget) + : (texObj->Target != textarget); + } } - if ((level < 0) || level >= _mesa_max_texture_levels(ctx, textarget)) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glFramebufferTexture%dDEXT(level)", dims); - return GL_TRUE; + if (err) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glFramebufferTexture%sEXT(texture target mismatch)", + caller); + return; } - } - - return GL_FALSE; -} - - -void GLAPIENTRY -_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment, - GLenum textarget, GLuint texture, GLint level) -{ - struct gl_renderbuffer_attachment *att; - struct gl_texture_object *texObj; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); + if (texObj->Target == GL_TEXTURE_3D) { + const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); + if (zoffset < 0 || zoffset >= maxSize) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glFramebufferTexture%sEXT(zoffset)", caller); + return; + } + } + else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) || + (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) { + if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glFramebufferTexture%sEXT(layer)", caller); + return; + } + } - if (error_check_framebuffer_texture(ctx, 1, target, attachment, - textarget, texture, level)) - return; - ASSERT(textarget == GL_TEXTURE_1D); + if ((level < 0) || + (level >= _mesa_max_texture_levels(ctx, texObj->Target))) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glFramebufferTexture%sEXT(level)", caller); + return; + } + } - /* XXX read blit */ - att = _mesa_get_attachment(ctx, ctx->DrawBuffer, attachment); + att = _mesa_get_attachment(ctx, fb, attachment); if (att == NULL) { _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferTexture1DEXT(attachment)"); + "glFramebufferTexture%sEXT(attachment)", caller); return; } FLUSH_VERTICES(ctx, _NEW_BUFFERS); + /* The above doesn't fully flush the drivers in the way that a + * glFlush does, but that is required here: + */ + if (ctx->Driver.Flush) + ctx->Driver.Flush(ctx); - if (texture) { - texObj = (struct gl_texture_object *) - _mesa_HashLookup(ctx->Shared->TexObjects, texture); - if (!texObj) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glFramebufferTexture1DEXT(texture)"); - return; - } - if (texObj->Target != textarget) { - _mesa_error(ctx, GL_INVALID_OPERATION, /* XXX correct error? */ - "glFramebufferTexture1DEXT(texture target)"); - return; - } + _glthread_LOCK_MUTEX(fb->Mutex); + if (texObj) { + _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget, + level, zoffset); } else { - /* remove texture attachment */ - texObj = NULL; + _mesa_remove_attachment(ctx, att); } - ctx->Driver.RenderbufferTexture(ctx, att, texObj, textarget, level, 0); + _glthread_UNLOCK_MUTEX(fb->Mutex); } + void GLAPIENTRY -_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment, +_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) { - struct gl_renderbuffer_attachment *att; - struct gl_texture_object *texObj; GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (error_check_framebuffer_texture(ctx, 2, target, attachment, - textarget, texture, level)) - return; - - ASSERT(textarget == GL_TEXTURE_2D || - textarget == GL_TEXTURE_RECTANGLE_ARB || - IS_CUBE_FACE(textarget)); - - att = _mesa_get_attachment(ctx, ctx->DrawBuffer, attachment); - if (att == NULL) { + if ((texture != 0) && (textarget != GL_TEXTURE_1D)) { _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferTexture2DEXT(attachment)"); + "glFramebufferTexture1DEXT(textarget)"); return; } - FLUSH_VERTICES(ctx, _NEW_BUFFERS); + framebuffer_texture(ctx, "1D", target, attachment, textarget, texture, + level, 0); +} - if (texture) { - texObj = (struct gl_texture_object *) - _mesa_HashLookup(ctx->Shared->TexObjects, texture); - if (!texObj) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glFramebufferTexture2DEXT(texture)"); - return; - } - if ((texObj->Target == GL_TEXTURE_2D && textarget != GL_TEXTURE_2D) || - (texObj->Target == GL_TEXTURE_RECTANGLE_ARB - && textarget != GL_TEXTURE_RECTANGLE_ARB) || - (texObj->Target == GL_TEXTURE_CUBE_MAP - && !IS_CUBE_FACE(textarget))) { - _mesa_error(ctx, GL_INVALID_OPERATION, /* XXX correct error? */ - "glFramebufferTexture2DEXT(texture target)"); - return; - } - } - else { - /* remove texture attachment */ - texObj = NULL; + +void GLAPIENTRY +_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, GLint level) +{ + GET_CURRENT_CONTEXT(ctx); + + if ((texture != 0) && + (textarget != GL_TEXTURE_2D) && + (textarget != GL_TEXTURE_RECTANGLE_ARB) && + (!IS_CUBE_FACE(textarget))) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glFramebufferTexture2DEXT(textarget)"); + return; } - ctx->Driver.RenderbufferTexture(ctx, att, texObj, textarget, level, 0); + + framebuffer_texture(ctx, "2D", target, attachment, textarget, texture, + level, 0); } @@ -1247,53 +1311,27 @@ _mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) { - struct gl_renderbuffer_attachment *att; - struct gl_texture_object *texObj; GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (error_check_framebuffer_texture(ctx, 3, target, attachment, - textarget, texture, level)) - return; - - ASSERT(textarget == GL_TEXTURE_3D); - - att = _mesa_get_attachment(ctx, ctx->DrawBuffer, attachment); - if (att == NULL) { + if ((texture != 0) && (textarget != GL_TEXTURE_3D)) { _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferTexture1DEXT(attachment)"); + "glFramebufferTexture3DEXT(textarget)"); return; } - FLUSH_VERTICES(ctx, _NEW_BUFFERS); + framebuffer_texture(ctx, "3D", target, attachment, textarget, texture, + level, zoffset); +} - if (texture) { - const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); - texObj = (struct gl_texture_object *) - _mesa_HashLookup(ctx->Shared->TexObjects, texture); - if (!texObj) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glFramebufferTexture3DEXT(texture)"); - return; - } - if (texObj->Target != textarget) { - _mesa_error(ctx, GL_INVALID_OPERATION, /* XXX correct error? */ - "glFramebufferTexture3DEXT(texture target)"); - return; - } - if (zoffset < 0 || zoffset >= maxSize) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glFramebufferTexture3DEXT(zoffset)"); - return; - } - } - else { - /* remove texture attachment */ - texObj = NULL; - } - ctx->Driver.RenderbufferTexture(ctx, att, texObj, textarget, - level, zoffset); + +void GLAPIENTRY +_mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment, + GLuint texture, GLint level, GLint layer) +{ + GET_CURRENT_CONTEXT(ctx); + + framebuffer_texture(ctx, "Layer", target, attachment, 0, texture, + level, layer); } @@ -1357,7 +1395,7 @@ _mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment, } if (renderbuffer) { - rb = lookup_renderbuffer(ctx, renderbuffer); + rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); if (!rb) { _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT(renderbuffer)"); @@ -1370,6 +1408,11 @@ _mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment, } FLUSH_VERTICES(ctx, _NEW_BUFFERS); + /* The above doesn't fully flush the drivers in the way that a + * glFlush does, but that is required here: + */ + if (ctx->Driver.Flush) + ctx->Driver.Flush(ctx); assert(ctx->Driver.FramebufferRenderbuffer); ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb); @@ -1433,6 +1476,11 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, } FLUSH_VERTICES(ctx, _NEW_BUFFERS); + /* The above doesn't fully flush the drivers in the way that a + * glFlush does, but that is required here: + */ + if (ctx->Driver.Flush) + ctx->Driver.Flush(ctx); switch (pname) { case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: @@ -1511,7 +1559,9 @@ _mesa_GenerateMipmapEXT(GLenum target) texObj = _mesa_select_tex_object(ctx, texUnit, target); /* XXX this might not handle cube maps correctly */ - _mesa_generate_mipmap(ctx, target, texUnit, texObj); + _mesa_lock_texture(ctx, texObj); + ctx->Driver.GenerateMipmap(ctx, target, texObj); + _mesa_unlock_texture(ctx, texObj); }