From 519b23b21f9cd6945fd17cdb26e7a6f531cdeec0 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Mon, 20 Mar 2006 18:51:57 +0000 Subject: [PATCH] Lots of changes/fixes for rendering to framebuffer objects. - When deleting texture objects, unbind from FBOs if necessary. - Changed driver hooks for starting/ending render to texture. - Now properly handle case where gl[Copy]TexImage() is called after glFramebufferTexture[123]D(). That didn't work before. --- src/mesa/main/dd.h | 8 ++- src/mesa/main/fbobject.c | 44 +++++++-------- src/mesa/main/fbobject.h | 1 + src/mesa/main/teximage.c | 65 +++++++++++++++++++--- src/mesa/main/texobj.c | 133 +++++++++++++++++++++++++++++++--------------- src/mesa/main/texrender.c | 49 +++++++++++------ src/mesa/main/texrender.h | 5 +- 7 files changed, 211 insertions(+), 94 deletions(-) diff --git a/src/mesa/main/dd.h b/src/mesa/main/dd.h index 6af304fe26a..4b2764979d8 100644 --- a/src/mesa/main/dd.h +++ b/src/mesa/main/dd.h @@ -808,12 +808,10 @@ struct dd_function_table { GLenum attachment, struct gl_renderbuffer *rb); void (*RenderbufferTexture)(GLcontext *ctx, - struct gl_renderbuffer_attachment *att, - struct gl_texture_object *texObj, - GLenum texTarget, GLuint level, GLuint zoffset); + struct gl_framebuffer *fb, + struct gl_renderbuffer_attachment *att); void (*FinishRenderTexture)(GLcontext *ctx, - struct gl_texture_object *texObj, - GLuint face, GLuint level); + struct gl_renderbuffer_attachment *att); /*@}*/ #endif #if FEATURE_EXT_framebuffer_blit diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c index a83ed56069d..53c4d27e81a 100644 --- a/src/mesa/main/fbobject.c +++ b/src/mesa/main/fbobject.c @@ -155,9 +155,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; @@ -182,6 +180,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 +207,10 @@ _mesa_set_texture_attachment(GLcontext *ctx, } att->Zoffset = zoffset; att->Complete = GL_FALSE; + + if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) { + ctx->Driver.RenderbufferTexture(ctx, fb, att); + } } @@ -903,8 +906,7 @@ check_texture_render(GLcontext *ctx, struct gl_framebuffer *fb) 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); + ctx->Driver.FinishRenderTexture(ctx, att); } } } @@ -1178,12 +1180,15 @@ error_check_framebuffer_texture(GLcontext *ctx, GLuint dims, } +/** + * XXX The code in _mesa_FramebufferTexture1/2/3DEXT could be probably + * be combined into one function. + */ 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); @@ -1205,7 +1210,7 @@ _mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment, FLUSH_VERTICES(ctx, _NEW_BUFFERS); if (texture) { - texObj = (struct gl_texture_object *) + struct gl_texture_object *texObj = (struct gl_texture_object *) _mesa_HashLookup(ctx->Shared->TexObjects, texture); if (!texObj) { _mesa_error(ctx, GL_INVALID_VALUE, @@ -1217,12 +1222,12 @@ _mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment, "glFramebufferTexture1DEXT(texture target)"); return; } + _mesa_set_texture_attachment(ctx, ctx->DrawBuffer, att, + texObj, textarget, level, 0); } else { - /* remove texture attachment */ - texObj = NULL; + _mesa_remove_attachment(ctx, att); } - ctx->Driver.RenderbufferTexture(ctx, att, texObj, textarget, level, 0); } @@ -1231,7 +1236,6 @@ _mesa_FramebufferTexture2DEXT(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); @@ -1254,7 +1258,7 @@ _mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment, FLUSH_VERTICES(ctx, _NEW_BUFFERS); if (texture) { - texObj = (struct gl_texture_object *) + struct gl_texture_object *texObj = (struct gl_texture_object *) _mesa_HashLookup(ctx->Shared->TexObjects, texture); if (!texObj) { _mesa_error(ctx, GL_INVALID_VALUE, @@ -1270,12 +1274,12 @@ _mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment, "glFramebufferTexture2DEXT(texture target)"); return; } + _mesa_set_texture_attachment(ctx, ctx->DrawBuffer, att, + texObj, textarget, level, 0); } else { - /* remove texture attachment */ - texObj = NULL; + _mesa_remove_attachment(ctx, att); } - ctx->Driver.RenderbufferTexture(ctx, att, texObj, textarget, level, 0); } @@ -1285,7 +1289,6 @@ _mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment, GLint level, GLint zoffset) { struct gl_renderbuffer_attachment *att; - struct gl_texture_object *texObj; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); @@ -1307,7 +1310,7 @@ _mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment, if (texture) { const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); - texObj = (struct gl_texture_object *) + struct gl_texture_object *texObj = (struct gl_texture_object *) _mesa_HashLookup(ctx->Shared->TexObjects, texture); if (!texObj) { _mesa_error(ctx, GL_INVALID_VALUE, @@ -1324,13 +1327,12 @@ _mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment, "glFramebufferTexture3DEXT(zoffset)"); return; } + _mesa_set_texture_attachment(ctx, ctx->DrawBuffer, att, + texObj, textarget, level,zoffset); } else { - /* remove texture attachment */ - texObj = NULL; + _mesa_remove_attachment(ctx, att); } - ctx->Driver.RenderbufferTexture(ctx, att, texObj, textarget, - level, zoffset); } diff --git a/src/mesa/main/fbobject.h b/src/mesa/main/fbobject.h index 3171aa7b1b9..c16f628a092 100644 --- a/src/mesa/main/fbobject.h +++ b/src/mesa/main/fbobject.h @@ -38,6 +38,7 @@ _mesa_remove_attachment(GLcontext *ctx, extern 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); diff --git a/src/mesa/main/teximage.c b/src/mesa/main/teximage.c index edfe82adcf7..15a12ee4dcc 100644 --- a/src/mesa/main/teximage.c +++ b/src/mesa/main/teximage.c @@ -551,6 +551,18 @@ is_compressed_format(GLcontext *ctx, GLenum internalFormat) } +static GLuint +texture_face(GLenum target) +{ + if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB && + target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) + return (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X; + else + return 0; +} + + + /** * Store a gl_texture_image pointer in a gl_texture_object structure * according to the target and level parameters. @@ -2135,6 +2147,36 @@ _mesa_GetTexImage( GLenum target, GLint level, GLenum format, +/** + * Check if the given texture image is bound to any framebuffer objects + * and update/invalidate them. + * XXX We're only checking the currently bound framebuffer object for now. + * In the future, perhaps struct gl_texture_image should have a pointer (or + * list of pointers (yikes)) to the gl_framebuffer(s) which it's bound to. + */ +static void +update_fbo_texture(GLcontext *ctx, struct gl_texture_object *texObj, + GLuint face, GLuint level) +{ + if (ctx->DrawBuffer->Name) { + GLuint i; + for (i = 0; i < BUFFER_COUNT; i++) { + struct gl_renderbuffer_attachment *att = + ctx->DrawBuffer->Attachment + i; + if (att->Type == GL_TEXTURE && + att->Texture == texObj && + att->TextureLevel == level && + att->CubeMapFace == face) { + ASSERT(att->Texture->Image[att->CubeMapFace][att->TextureLevel]); + /* Tell driver about the new renderbuffer texture */ + ctx->Driver.RenderbufferTexture(ctx, ctx->DrawBuffer, att); + } + } + } +} + + + /* * Called from the API. Note that width includes the border. */ @@ -2156,6 +2198,7 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat, struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; struct gl_texture_image *texImage; + const GLuint face = texture_face(target); if (texture_error_check(ctx, target, level, internalFormat, format, type, 1, postConvWidth, 1, 1, border)) { @@ -2191,6 +2234,8 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat, ASSERT(texImage->TexFormat); + update_fbo_texture(ctx, texObj, face, level); + /* state update */ texObj->Complete = GL_FALSE; ctx->NewState |= _NEW_TEXTURE; @@ -2247,6 +2292,7 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat, struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; struct gl_texture_image *texImage; + const GLuint face = texture_face(target); if (texture_error_check(ctx, target, level, internalFormat, format, type, 2, postConvWidth, postConvHeight, @@ -2280,14 +2326,10 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat, width, height, border, format, type, pixels, &ctx->Unpack, texObj, texImage); - /* - * XXX if this texture image is currently bound to a user-created - * framebuffer object, we have to invalidate that framebuffer's - * completeness state. - */ - ASSERT(texImage->TexFormat); + update_fbo_texture(ctx, texObj, face, level); + /* state update */ texObj->Complete = GL_FALSE; ctx->NewState |= _NEW_TEXTURE; @@ -2337,10 +2379,11 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat, ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); if (target == GL_TEXTURE_3D) { + /* non-proxy target */ struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; struct gl_texture_image *texImage; - /* non-proxy target */ + const GLuint face = texture_face(target); if (texture_error_check(ctx, target, level, (GLint) internalFormat, format, type, 3, width, height, depth, border)) { @@ -2375,6 +2418,8 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat, ASSERT(texImage->TexFormat); + update_fbo_texture(ctx, texObj, face, level); + /* state update */ texObj->Complete = GL_FALSE; ctx->NewState |= _NEW_TEXTURE; @@ -2565,6 +2610,7 @@ _mesa_CopyTexImage1D( GLenum target, GLint level, struct gl_texture_object *texObj; struct gl_texture_image *texImage; GLsizei postConvWidth = width; + const GLuint face = texture_face(target); GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); @@ -2602,6 +2648,8 @@ _mesa_CopyTexImage1D( GLenum target, GLint level, ASSERT(texImage->TexFormat); + update_fbo_texture(ctx, texObj, face, level); + /* state update */ texObj->Complete = GL_FALSE; ctx->NewState |= _NEW_TEXTURE; @@ -2618,6 +2666,7 @@ _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat, struct gl_texture_object *texObj; struct gl_texture_image *texImage; GLsizei postConvWidth = width, postConvHeight = height; + const GLuint face = texture_face(target); GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); @@ -2656,6 +2705,8 @@ _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat, ASSERT(texImage->TexFormat); + update_fbo_texture(ctx, texObj, face, level); + /* state update */ texObj->Complete = GL_FALSE; ctx->NewState |= _NEW_TEXTURE; diff --git a/src/mesa/main/texobj.c b/src/mesa/main/texobj.c index 0f320fea6a5..59a1d9375ff 100644 --- a/src/mesa/main/texobj.c +++ b/src/mesa/main/texobj.c @@ -5,9 +5,9 @@ /* * Mesa 3-D graphics library - * Version: 6.3 + * Version: 6.5 * - * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. + * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -32,6 +32,7 @@ #include "colortab.h" #include "context.h" #include "enums.h" +#include "fbobject.h" #include "hash.h" #include "imports.h" #include "macros.h" @@ -40,6 +41,7 @@ #include "texobj.h" #include "mtypes.h" + #ifdef __VMS #define _mesa_sprintf sprintf #endif @@ -579,6 +581,82 @@ _mesa_GenTextures( GLsizei n, GLuint *textures ) /** + * Check if the given texture object is bound to the current draw or + * read framebuffer. If so, Unbind it. + */ +static void +unbind_texobj_from_fbo(GLcontext *ctx, struct gl_texture_object *texObj) +{ + const GLuint n = (ctx->DrawBuffer == ctx->ReadBuffer) ? 1 : 2; + GLuint i; + + for (i = 0; i < n; i++) { + struct gl_framebuffer *fb = (i == 0) ? ctx->DrawBuffer : ctx->ReadBuffer; + if (fb->Name) { + GLuint j; + for (j = 0; j < BUFFER_COUNT; j++) { + if (fb->Attachment[j].Type == GL_TEXTURE && + fb->Attachment[j].Texture == texObj) { + _mesa_remove_attachment(ctx, fb->Attachment + j); + } + } + } + } +} + + +/** + * Check if the given texture object is bound to any texture image units and + * unbind it if so. + * XXX all RefCount accesses should be protected by a mutex. + */ +static void +unbind_texobj_from_texunits(GLcontext *ctx, struct gl_texture_object *texObj) +{ + GLuint u; + + for (u = 0; u < MAX_TEXTURE_IMAGE_UNITS; u++) { + struct gl_texture_unit *unit = &ctx->Texture.Unit[u]; + if (texObj == unit->Current1D) { + unit->Current1D = ctx->Shared->Default1D; + ctx->Shared->Default1D->RefCount++; + texObj->RefCount--; + if (texObj == unit->_Current) + unit->_Current = unit->Current1D; + } + else if (texObj == unit->Current2D) { + unit->Current2D = ctx->Shared->Default2D; + ctx->Shared->Default2D->RefCount++; + texObj->RefCount--; + if (texObj == unit->_Current) + unit->_Current = unit->Current2D; + } + else if (texObj == unit->Current3D) { + unit->Current3D = ctx->Shared->Default3D; + ctx->Shared->Default3D->RefCount++; + texObj->RefCount--; + if (texObj == unit->_Current) + unit->_Current = unit->Current3D; + } + else if (texObj == unit->CurrentCubeMap) { + unit->CurrentCubeMap = ctx->Shared->DefaultCubeMap; + ctx->Shared->DefaultCubeMap->RefCount++; + texObj->RefCount--; + if (texObj == unit->_Current) + unit->_Current = unit->CurrentCubeMap; + } + else if (texObj == unit->CurrentRect) { + unit->CurrentRect = ctx->Shared->DefaultRect; + ctx->Shared->DefaultRect->RefCount++; + texObj->RefCount--; + if (texObj == unit->_Current) + unit->_Current = unit->CurrentRect; + } + } +} + + +/** * Delete named textures. * * \param n number of textures to be deleted. @@ -607,49 +685,18 @@ _mesa_DeleteTextures( GLsizei n, const GLuint *textures) struct gl_texture_object *delObj = (struct gl_texture_object *) _mesa_HashLookup(ctx->Shared->TexObjects, textures[i]); if (delObj) { - /* First check if this texture is currently bound. + + /* Check if texture is bound to any framebuffer objects. + * If so, unbind. + * See section 4.4.2.3 of GL_EXT_framebuffer_object. + */ + unbind_texobj_from_fbo(ctx, delObj); + + /* Check if this texture is currently bound to any texture units. * If so, unbind it and decrement the reference count. - * XXX all RefCount accesses should be protected by a mutex. */ - GLuint u; - for (u = 0; u < MAX_TEXTURE_IMAGE_UNITS; u++) { - struct gl_texture_unit *unit = &ctx->Texture.Unit[u]; - if (delObj == unit->Current1D) { - unit->Current1D = ctx->Shared->Default1D; - ctx->Shared->Default1D->RefCount++; - delObj->RefCount--; - if (delObj == unit->_Current) - unit->_Current = unit->Current1D; - } - else if (delObj == unit->Current2D) { - unit->Current2D = ctx->Shared->Default2D; - ctx->Shared->Default2D->RefCount++; - delObj->RefCount--; - if (delObj == unit->_Current) - unit->_Current = unit->Current2D; - } - else if (delObj == unit->Current3D) { - unit->Current3D = ctx->Shared->Default3D; - ctx->Shared->Default3D->RefCount++; - delObj->RefCount--; - if (delObj == unit->_Current) - unit->_Current = unit->Current3D; - } - else if (delObj == unit->CurrentCubeMap) { - unit->CurrentCubeMap = ctx->Shared->DefaultCubeMap; - ctx->Shared->DefaultCubeMap->RefCount++; - delObj->RefCount--; - if (delObj == unit->_Current) - unit->_Current = unit->CurrentCubeMap; - } - else if (delObj == unit->CurrentRect) { - unit->CurrentRect = ctx->Shared->DefaultRect; - ctx->Shared->DefaultRect->RefCount++; - delObj->RefCount--; - if (delObj == unit->_Current) - unit->_Current = unit->CurrentRect; - } - } + unbind_texobj_from_texunits(ctx, delObj); + ctx->NewState |= _NEW_TEXTURE; /* The texture _name_ is now free for re-use. diff --git a/src/mesa/main/texrender.c b/src/mesa/main/texrender.c index a4efe640382..dca93a1c04a 100644 --- a/src/mesa/main/texrender.c +++ b/src/mesa/main/texrender.c @@ -200,25 +200,44 @@ wrap_texture(GLcontext *ctx, struct gl_renderbuffer_attachment *att) /** - * Software fallback for ctx->Driver.RenderbufferTexture. - * This is called via the glRenderbufferTexture1D/2D/3D() functions. - * If we're unbinding a texture, texObj will be NULL. - * The framebuffer of interest is ctx->DrawBuffer. + * Called when rendering to a texture image begins. + * This is a fallback routine for software render-to-texture. + * + * Called via the glRenderbufferTexture1D/2D/3D() functions + * and elsewhere (such as glTexImage2D). + * + * The image we're rendering into is + * att->Texture->Image[att->CubeMapFace][att->TextureLevel]; + * It'll never be NULL. + * + * \param fb the framebuffer object the texture is being bound to + * \param att the fb attachment point of the texture + * * \sa _mesa_framebuffer_renderbuffer */ void _mesa_renderbuffer_texture(GLcontext *ctx, - struct gl_renderbuffer_attachment *att, - struct gl_texture_object *texObj, - GLenum texTarget, GLuint level, GLuint zoffset) + struct gl_framebuffer *fb, + struct gl_renderbuffer_attachment *att) { - if (texObj) { - _mesa_set_texture_attachment(ctx, att, texObj, - texTarget, level, zoffset); - if (!att->Renderbuffer) - wrap_texture(ctx, att); - } - else { - _mesa_remove_attachment(ctx, att); + struct gl_texture_image *newImage + = att->Texture->Image[att->CubeMapFace][att->TextureLevel]; + struct texture_renderbuffer *trb + = (struct texture_renderbuffer *) att->Renderbuffer; + struct gl_texture_image *oldImage = trb ? trb->TexImage : NULL; + + (void) fb; + + ASSERT(newImage); + + if (oldImage != newImage) { + if (trb) { + /* get rid of old wrapper */ + /* XXX also if Zoffset changes? */ + trb->Base.Delete(&trb->Base); + } + wrap_texture(ctx, att); } } + + diff --git a/src/mesa/main/texrender.h b/src/mesa/main/texrender.h index 6d8bc964141..1e11e505130 100644 --- a/src/mesa/main/texrender.h +++ b/src/mesa/main/texrender.h @@ -4,9 +4,8 @@ extern void _mesa_renderbuffer_texture(GLcontext *ctx, - struct gl_renderbuffer_attachment *att, - struct gl_texture_object *texObj, - GLenum texTarget, GLuint level, GLuint zoffset); + struct gl_framebuffer *fb, + struct gl_renderbuffer_attachment *att); #endif /* TEXRENDER_H */ -- 2.11.0