Merge branch 'mesa_7_6_branch'
[mesa.git] / src / mesa / main / fbobject.c
index 83301f1e621156369312cddf5fb8e683f84e1631..55709ebf9e32f0057715d2aed59e53accfb6da89 100644 (file)
@@ -34,6 +34,7 @@
 
 #include "buffers.h"
 #include "context.h"
+#include "enums.h"
 #include "fbobject.h"
 #include "framebuffer.h"
 #include "hash.h"
 #include "teximage.h"
 #include "texobj.h"
 #include "texstore.h"
+#include "texstate.h"
+
+
+/** Set this to 1 to help debug FBO incompleteness problems */
+#define DEBUG_FBO 0
+
+/** Set this to 1 to debug/log glBlitFramebuffer() calls */
+#define DEBUG_BLIT 0
 
 
 /**
@@ -234,12 +243,7 @@ _mesa_set_texture_attachment(GLcontext *ctx,
 
    /* always update these fields */
    att->TextureLevel = level;
-   if (IS_CUBE_FACE(texTarget)) {
-      att->CubeMapFace = texTarget - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
-   }
-   else {
-      att->CubeMapFace = 0;
-   }
+   att->CubeMapFace = _mesa_tex_target_to_face(texTarget);
    att->Zoffset = zoffset;
    att->Complete = GL_FALSE;
 
@@ -308,14 +312,31 @@ _mesa_framebuffer_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb,
 static void
 att_incomplete(const char *msg)
 {
-#if 0
-   _mesa_printf("attachment incomplete: %s\n", msg);
+#if DEBUG_FBO
+   _mesa_debug(NULL, "attachment incomplete: %s\n", msg);
+#else
+   (void) msg;
+#endif
+}
+
+
+/**
+ * For debug only.
+ */
+static void
+fbo_incomplete(const char *msg, int index)
+{
+#if DEBUG_FBO
+   _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index);
 #else
    (void) msg;
+   (void) index;
 #endif
 }
 
 
+
+
 /**
  * Test if an attachment point is complete and update its Complete field.
  * \param format if GL_COLOR, this is a color attachment point,
@@ -417,21 +438,22 @@ test_attachment_completeness(const GLcontext *ctx, GLenum format,
       if (format == GL_COLOR) {
          if (att->Renderbuffer->_BaseFormat != GL_RGB &&
              att->Renderbuffer->_BaseFormat != GL_RGBA) {
-            ASSERT(att->Renderbuffer->RedBits);
-            ASSERT(att->Renderbuffer->GreenBits);
-            ASSERT(att->Renderbuffer->BlueBits);
             att_incomplete("bad renderbuffer color format");
             att->Complete = GL_FALSE;
             return;
          }
+         ASSERT(att->Renderbuffer->RedBits);
+         ASSERT(att->Renderbuffer->GreenBits);
+         ASSERT(att->Renderbuffer->BlueBits);
       }
       else if (format == GL_DEPTH) {
-         ASSERT(att->Renderbuffer->DepthBits);
          if (att->Renderbuffer->_BaseFormat == GL_DEPTH_COMPONENT) {
+            ASSERT(att->Renderbuffer->DepthBits);
             /* OK */
          }
          else if (ctx->Extensions.EXT_packed_depth_stencil &&
                   att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
+            ASSERT(att->Renderbuffer->DepthBits);
             /* OK */
          }
          else {
@@ -442,12 +464,13 @@ test_attachment_completeness(const GLcontext *ctx, GLenum format,
       }
       else {
          assert(format == GL_STENCIL);
-         ASSERT(att->Renderbuffer->StencilBits);
          if (att->Renderbuffer->_BaseFormat == GL_STENCIL_INDEX) {
+            ASSERT(att->Renderbuffer->StencilBits);
             /* OK */
          }
          else if (ctx->Extensions.EXT_packed_depth_stencil &&
                   att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
+            ASSERT(att->Renderbuffer->StencilBits);
             /* OK */
          }
          else {
@@ -465,20 +488,6 @@ test_attachment_completeness(const GLcontext *ctx, GLenum format,
 }
 
 
-/**
- * Helpful for debugging
- */
-static void
-fbo_incomplete(const char *msg, int index)
-{
-   (void) msg;
-   (void) index;
-   /*
-   _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index);
-   */
-}
-
-
 /**
  * Test if the given framebuffer object is complete and update its
  * Status field with the results.
@@ -708,12 +717,6 @@ _mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
    }
 
    FLUSH_CURRENT(ctx, _NEW_BUFFERS);
-   /* The above doesn't fully flush the drivers in the way that a
-    * glFlush does, but that is required here:
-    */
-   if (ctx->Driver.Flush)
-      ctx->Driver.Flush(ctx);
-
 
    if (renderbuffer) {
       newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
@@ -1125,7 +1128,7 @@ check_begin_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
-          && att->Texture->Image[att->CubeMapFace][att->TextureLevel]) {
+          && texObj->Image[att->CubeMapFace][att->TextureLevel]) {
          ctx->Driver.RenderTexture(ctx, fb, att);
       }
    }
@@ -1203,9 +1206,6 @@ _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
    }
 
    FLUSH_CURRENT(ctx, _NEW_BUFFERS);
-   if (ctx->Driver.Flush) {  
-      ctx->Driver.Flush(ctx);
-   }
 
    if (framebuffer) {
       /* Binding a user-created framebuffer object */
@@ -1284,11 +1284,6 @@ _mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
 
    ASSERT_OUTSIDE_BEGIN_END(ctx);
    FLUSH_CURRENT(ctx, _NEW_BUFFERS);
-   /* The above doesn't fully flush the drivers in the way that a
-    * glFlush does, but that is required here:
-    */
-   if (ctx->Driver.Flush)
-      ctx->Driver.Flush(ctx);
 
    for (i = 0; i < n; i++) {
       if (framebuffers[i] > 0) {
@@ -1509,24 +1504,7 @@ framebuffer_texture(GLcontext *ctx, const char *caller, GLenum target,
       return;
    }
 
-   if (texObj && attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
-      /* the texture format must be depth+stencil */
-      const struct gl_texture_image *texImg;
-      texImg = texObj->Image[0][texObj->BaseLevel];
-      if (!texImg || texImg->_BaseFormat != GL_DEPTH_STENCIL) {
-         _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glFramebufferTexture%sEXT(texture is not"
-                     " DEPTH_STENCIL format)", caller);
-         return;
-      }
-   }
-
    FLUSH_CURRENT(ctx, _NEW_BUFFERS);
-   /* The above doesn't fully flush the drivers in the way that a
-    * glFlush does, but that is required here:
-    */
-   if (ctx->Driver.Flush)
-      ctx->Driver.Flush(ctx);
 
    _glthread_LOCK_MUTEX(fb->Mutex);
    if (texObj) {
@@ -1674,7 +1652,8 @@ _mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
    att = _mesa_get_attachment(ctx, fb, attachment);
    if (att == NULL) {
       _mesa_error(ctx, GL_INVALID_ENUM,
-                 "glFramebufferRenderbufferEXT(attachment)");
+                  "glFramebufferRenderbufferEXT(invalid attachment %s)",
+                  _mesa_lookup_enum_by_nr(attachment));
       return;
    }
 
@@ -1682,7 +1661,8 @@ _mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
       rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
       if (!rb) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
-                    "glFramebufferRenderbufferEXT(renderbuffer)");
+                    "glFramebufferRenderbufferEXT(non-existant"
+                     " renderbuffer %u)", renderbuffer);
         return;
       }
    }
@@ -1703,11 +1683,6 @@ _mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
 
 
    FLUSH_CURRENT(ctx, _NEW_BUFFERS);
-   /* The above doesn't fully flush the drivers in the way that a
-    * glFlush does, but that is required here:
-    */
-   if (ctx->Driver.Flush)
-      ctx->Driver.Flush(ctx);
 
    assert(ctx->Driver.FramebufferRenderbuffer);
    ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
@@ -1784,11 +1759,6 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
    }
 
    FLUSH_CURRENT(ctx, _NEW_BUFFERS);
-   /* The above doesn't fully flush the drivers in the way that a
-    * glFlush does, but that is required here:
-    */
-   if (ctx->Driver.Flush)
-      ctx->Driver.Flush(ctx);
 
    switch (pname) {
    case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
@@ -1946,18 +1916,18 @@ _mesa_GenerateMipmapEXT(GLenum target)
       return;
    }
 
-   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+   texUnit = _mesa_get_current_tex_unit(ctx);
    texObj = _mesa_select_tex_object(ctx, texUnit, target);
 
    _mesa_lock_texture(ctx, texObj);
    if (target == GL_TEXTURE_CUBE_MAP) {
-      int face;
-
+      GLuint face;
       for (face = 0; face < 6; face++)
         ctx->Driver.GenerateMipmap(ctx,
                                    GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face,
                                    texObj);
-   } else {
+   }
+   else {
       ctx->Driver.GenerateMipmap(ctx, target, texObj);
    }
    _mesa_unlock_texture(ctx, texObj);
@@ -1965,6 +1935,20 @@ _mesa_GenerateMipmapEXT(GLenum target)
 
 
 #if FEATURE_EXT_framebuffer_blit
+
+static const struct gl_renderbuffer_attachment *
+find_attachment(const struct gl_framebuffer *fb, const struct gl_renderbuffer *rb)
+{
+   GLuint i;
+   for (i = 0; i < Elements(fb->Attachment); i++) {
+      if (fb->Attachment[i].Renderbuffer == rb)
+         return &fb->Attachment[i];
+   }
+   return NULL;
+}
+
+
+
 /**
  * Blit rectangular region, optionally from one framebuffer to another.
  *
@@ -2038,7 +2022,9 @@ _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
    if (mask & GL_STENCIL_BUFFER_BIT) {
       struct gl_renderbuffer *readRb = readFb->_StencilBuffer;
       struct gl_renderbuffer *drawRb = drawFb->_StencilBuffer;
-      if (readRb->StencilBits != drawRb->StencilBits) {
+      if (!readRb ||
+          !drawRb ||
+          readRb->StencilBits != drawRb->StencilBits) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "glBlitFramebufferEXT(stencil buffer size mismatch");
          return;
@@ -2048,7 +2034,9 @@ _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
    if (mask & GL_DEPTH_BUFFER_BIT) {
       struct gl_renderbuffer *readRb = readFb->_DepthBuffer;
       struct gl_renderbuffer *drawRb = drawFb->_DepthBuffer;
-      if (readRb->DepthBits != drawRb->DepthBits) {
+      if (!readRb ||
+          !drawRb ||
+          readRb->DepthBits != drawRb->DepthBits) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "glBlitFramebufferEXT(depth buffer size mismatch");
          return;
@@ -2088,6 +2076,44 @@ _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
       return;
    }
 
+   /* Debug code */
+   if (DEBUG_BLIT) {
+      _mesa_printf("glBlitFramebuffer(%d, %d, %d, %d,  %d, %d, %d, %d,"
+                   " 0x%x, 0x%x)\n",
+                   srcX0, srcY0, srcX1, srcY1,
+                   dstX0, dstY0, dstX1, dstY1,
+                   mask, filter);
+      if (colorReadRb) {
+         const struct gl_renderbuffer_attachment *att;
+
+         att = find_attachment(readFb, colorReadRb);
+         _mesa_printf("  Src FBO %u  RB %u (%dx%d)  ",
+                      readFb->Name, colorReadRb->Name,
+                      colorReadRb->Width, colorReadRb->Height);
+         if (att && att->Texture) {
+            _mesa_printf("Tex %u  tgt 0x%x  level %u  face %u",
+                         att->Texture->Name,
+                         att->Texture->Target,
+                         att->TextureLevel,
+                         att->CubeMapFace);
+         }
+         _mesa_printf("\n");
+
+         att = find_attachment(drawFb, colorDrawRb);
+         _mesa_printf("  Dst FBO %u  RB %u (%dx%d)  ",
+                      drawFb->Name, colorDrawRb->Name,
+                      colorDrawRb->Width, colorDrawRb->Height);
+         if (att && att->Texture) {
+            _mesa_printf("Tex %u  tgt 0x%x  level %u  face %u",
+                         att->Texture->Name,
+                         att->Texture->Target,
+                         att->TextureLevel,
+                         att->CubeMapFace);
+         }
+         _mesa_printf("\n");
+      }
+   }
+
    ASSERT(ctx->Driver.BlitFramebuffer);
    ctx->Driver.BlitFramebuffer(ctx,
                                srcX0, srcY0, srcX1, srcY1,