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:
@@ -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);
|
||||
|
@@ -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];
|
||||
|
@@ -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.
|
||||
|
Reference in New Issue
Block a user