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.
This commit is contained in:
Brian Paul
2006-03-20 18:51:57 +00:00
parent 4991888fa0
commit 519b23b21f
7 changed files with 212 additions and 95 deletions

View File

@@ -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

View File

@@ -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);
}

View File

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

View File

@@ -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;

View File

@@ -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
@@ -578,6 +580,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.
*
@@ -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.
* If so, unbind it and decrement the reference count.
* XXX all RefCount accesses should be protected by a mutex.
/* Check if texture is bound to any framebuffer objects.
* If so, unbind.
* See section 4.4.2.3 of GL_EXT_framebuffer_object.
*/
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_fbo(ctx, delObj);
/* Check if this texture is currently bound to any texture units.
* If so, unbind it and decrement the reference count.
*/
unbind_texobj_from_texunits(ctx, delObj);
ctx->NewState |= _NEW_TEXTURE;
/* The texture _name_ is now free for re-use.

View File

@@ -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)
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);
}
else {
_mesa_remove_attachment(ctx, att);
}
}

View File

@@ -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 */