mesa: fix a render to texture FBO validation bug
authorBrian Paul <brianp@vmware.com>
Thu, 29 Jan 2009 16:20:18 +0000 (09:20 -0700)
committerBrian Paul <brianp@vmware.com>
Thu, 29 Jan 2009 16:20:18 +0000 (09:20 -0700)
When glTexImage() is called we need to re-validate any FBOs that point to
the texture (i.e. render-to-texture) since changing the texture's size/format
will effect FBO completeness.

We don't keep a list of all FBOs rendering into each texture (which would be
a bit messy) so we check all FBOs in existance.  To optimize this, the
gl_texture_object->_RenderToTexture flag is used to avoid checking textures
that have never been used as renderbuffers.  So, we only walk over all FBOs
(there's usually only a few) when glTexImage() modifies a RTT texture.

Fixes a bug seen in shadowtex.c when toggling packed depth/stencil mode.

src/mesa/main/fbobject.c
src/mesa/main/mtypes.h
src/mesa/main/teximage.c

index 1a191cd288cf2a7699a168049ab95180818d88f3..eec8f1564b6cbf9a09a8f2c5797b0daf4767f976 100644 (file)
@@ -1469,6 +1469,15 @@ framebuffer_texture(GLcontext *ctx, const char *caller, GLenum target,
    if (texObj) {
       _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget,
                                    level, zoffset);
+      /* Set the render-to-texture flag.  We'll check this flag in
+       * glTexImage() and friends to determine if we need to revalidate
+       * any FBOs that might be rendering into this texture.
+       * This flag never gets cleared since it's non-trivial to determine
+       * when all FBOs might be done rendering to this texture.  That's OK
+       * though since it's uncommon to render to a texture then repeatedly
+       * call glTexImage() to change images in the texture.
+       */
+      texObj->_RenderToTexture = GL_TRUE;
    }
    else {
       _mesa_remove_attachment(ctx, att);
index da243eceacf16f6868b35efb05b001ba2f20be66..ad9225e5a973526b85d971b9fe9a4bd3bf42f683 100644 (file)
@@ -1448,6 +1448,7 @@ struct gl_texture_object
    GLuint _Swizzle;             /**< same as Swizzle, but SWIZZLE_* format */
    GLboolean GenerateMipmap;    /**< GL_SGIS_generate_mipmap */
    GLboolean _Complete;                /**< Is texture object complete? */
+   GLboolean _RenderToTexture;  /**< Any rendering to this texture? */
 
    /** Actual texture images, indexed by [cube face] and [mipmap level] */
    struct gl_texture_image *Image[MAX_FACES][MAX_TEXTURE_LEVELS];
index 2f594532cca04644fc46798017f82f79eaf1d293..7b9efb6e41ca9e7bc42011328636a5e76d19a260 100644 (file)
@@ -37,6 +37,7 @@
 #endif
 #include "fbobject.h"
 #include "framebuffer.h"
+#include "hash.h"
 #include "image.h"
 #include "imports.h"
 #include "macros.h"
@@ -2378,23 +2379,33 @@ _mesa_GetTexImage( GLenum target, GLint level, GLenum format,
 }
 
 
+/** Callback info for walking over FBO hash table */
+struct cb_info
+{
+   GLcontext *ctx;
+   struct gl_texture_object *texObj;
+   GLuint level, face;
+};
+
 
 /**
- * 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.
+ * Check render to texture callback.  Called from _mesa_HashWalk().
  */
 static void
-update_fbo_texture(GLcontext *ctx, struct gl_texture_object *texObj,
-                   GLuint face, GLuint level)
+check_rtt_cb(GLuint key, void *data, void *userData)
 {
-   if (ctx->DrawBuffer->Name) {
+   struct gl_framebuffer *fb = (struct gl_framebuffer *) data;
+   const struct cb_info *info = (struct cb_info *) userData;
+   GLcontext *ctx = info->ctx;
+   const struct gl_texture_object *texObj = info->texObj;
+   const GLuint level = info->level, face = info->face;
+
+   /* If this is a user-created FBO */
+   if (fb->Name) {
       GLuint i;
+      /* check if any of the FBO's attachments point to 'texObj' */
       for (i = 0; i < BUFFER_COUNT; i++) {
-         struct gl_renderbuffer_attachment *att = 
-            ctx->DrawBuffer->Attachment + i;
+         struct gl_renderbuffer_attachment *att = fb->Attachment + i;
          if (att->Type == GL_TEXTURE &&
              att->Texture == texObj &&
              att->TextureLevel == level &&
@@ -2402,12 +2413,36 @@ update_fbo_texture(GLcontext *ctx, struct gl_texture_object *texObj,
             ASSERT(att->Texture->Image[att->CubeMapFace][att->TextureLevel]);
             /* Tell driver about the new renderbuffer texture */
             ctx->Driver.RenderTexture(ctx, ctx->DrawBuffer, att);
+            /* Mark fb status as indeterminate to force re-validation */
+            fb->_Status = 0;
          }
       }
    }
 }
 
 
+/**
+ * When a texture image is specified we have to check if it's bound to
+ * any framebuffer objects (render to texture) in order to detect changes
+ * in size or format since that effects FBO completeness.
+ * Any FBOs rendering into the texture must be re-validated.
+ */
+static void
+update_fbo_texture(GLcontext *ctx, struct gl_texture_object *texObj,
+                   GLuint face, GLuint level)
+{
+   /* Only check this texture if it's been marked as RenderToTexture */
+   if (texObj->_RenderToTexture) {
+      struct cb_info info;
+      info.ctx = ctx;
+      info.texObj = texObj;
+      info.level = level;
+      info.face = face;
+      _mesa_HashWalk(ctx->Shared->FrameBuffers, check_rtt_cb, &info);
+   }
+}
+
+
 
 /*
  * Called from the API.  Note that width includes the border.