OSDN Git Service

Lots of changes/fixes for rendering to framebuffer objects.
authorBrian Paul <brian.paul@tungstengraphics.com>
Mon, 20 Mar 2006 18:51:57 +0000 (18:51 +0000)
committerBrian Paul <brian.paul@tungstengraphics.com>
Mon, 20 Mar 2006 18:51:57 +0000 (18:51 +0000)
- 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
src/mesa/main/fbobject.c
src/mesa/main/fbobject.h
src/mesa/main/teximage.c
src/mesa/main/texobj.c
src/mesa/main/texrender.c
src/mesa/main/texrender.h

index 6af304f..4b27649 100644 (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
index a83ed56..53c4d27 100644 (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);
 }
 
 
index 3171aa7..c16f628 100644 (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);
index edfe82a..15a12ee 100644 (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;
index 0f320fe..59a1d93 100644 (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
@@ -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.
index a4efe64..dca93a1 100644 (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)
-         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);
    }
 }
+
+
index 6d8bc96..1e11e50 100644 (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 */