mesa: fix a render to texture FBO validation bug

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.
This commit is contained in:
Brian Paul
2009-01-29 09:20:18 -07:00
parent 425c803c03
commit 2897cee99f
3 changed files with 55 additions and 10 deletions

View 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);

View 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];

View 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.