Merge branch 'mesa_7_5_branch'
[mesa.git] / src / mesa / main / fbobject.c
index c3cdc110379c5a882a03b7d34f1c45fcc31ff454..825a23090b582d25b2dbbb94f82e3ddd93ce91de 100644 (file)
@@ -302,6 +302,20 @@ _mesa_framebuffer_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb,
 }
 
 
+/**
+ * For debug only.
+ */
+static void
+att_incomplete(const char *msg)
+{
+#if 0
+   _mesa_printf("attachment incomplete: %s\n", msg);
+#else
+   (void) msg;
+#endif
+}
+
+
 /**
  * Test if an attachment point is complete and update its Complete field.
  * \param format if GL_COLOR, this is a color attachment point,
@@ -323,20 +337,26 @@ test_attachment_completeness(const GLcontext *ctx, GLenum format,
       struct gl_texture_image *texImage;
 
       if (!texObj) {
+         att_incomplete("no texobj");
          att->Complete = GL_FALSE;
          return;
       }
 
       texImage = texObj->Image[att->CubeMapFace][att->TextureLevel];
       if (!texImage) {
+         att_incomplete("no teximage");
          att->Complete = GL_FALSE;
          return;
       }
       if (texImage->Width < 1 || texImage->Height < 1) {
+         att_incomplete("teximage width/height=0");
+         _mesa_printf("texobj = %u\n", texObj->Name);
+         _mesa_printf("level = %d\n", att->TextureLevel);
          att->Complete = GL_FALSE;
          return;
       }
       if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) {
+         att_incomplete("bad z offset");
          att->Complete = GL_FALSE;
          return;
       }
@@ -344,6 +364,12 @@ test_attachment_completeness(const GLcontext *ctx, GLenum format,
       if (format == GL_COLOR) {
          if (texImage->TexFormat->BaseFormat != GL_RGB &&
              texImage->TexFormat->BaseFormat != GL_RGBA) {
+            att_incomplete("bad format");
+            att->Complete = GL_FALSE;
+            return;
+         }
+         if (texImage->TexFormat->TexelBytes == 0) {
+            att_incomplete("compressed internalformat");
             att->Complete = GL_FALSE;
             return;
          }
@@ -353,18 +379,30 @@ test_attachment_completeness(const GLcontext *ctx, GLenum format,
             /* OK */
          }
          else if (ctx->Extensions.EXT_packed_depth_stencil &&
+                  ctx->Extensions.ARB_depth_texture &&
                   texImage->TexFormat->BaseFormat == GL_DEPTH_STENCIL_EXT) {
             /* OK */
          }
          else {
             att->Complete = GL_FALSE;
+            att_incomplete("bad depth format");
             return;
          }
       }
       else {
-         /* no such thing as stencil textures */
-         att->Complete = GL_FALSE;
-         return;
+         ASSERT(format == GL_STENCIL);
+         ASSERT(att->Renderbuffer->StencilBits);
+         if (ctx->Extensions.EXT_packed_depth_stencil &&
+             ctx->Extensions.ARB_depth_texture &&
+             att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
+            /* OK */
+         }
+         else {
+            /* no such thing as stencil-only textures */
+            att_incomplete("illegal stencil texture");
+            att->Complete = GL_FALSE;
+            return;
+         }
       }
    }
    else if (att->Type == GL_RENDERBUFFER_EXT) {
@@ -372,45 +410,51 @@ test_attachment_completeness(const GLcontext *ctx, GLenum format,
       if (!att->Renderbuffer->InternalFormat ||
           att->Renderbuffer->Width < 1 ||
           att->Renderbuffer->Height < 1) {
+         att_incomplete("0x0 renderbuffer");
          att->Complete = GL_FALSE;
          return;
       }
       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 {
+            att_incomplete("bad renderbuffer depth format");
             att->Complete = GL_FALSE;
             return;
          }
       }
       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 {
             att->Complete = GL_FALSE;
+            att_incomplete("bad renderbuffer stencil format");
             return;
          }
       }
@@ -665,7 +709,7 @@ _mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
       return;
    }
 
-   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+   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:
     */
@@ -1160,8 +1204,7 @@ _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
       return;
    }
 
-   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
-
+   FLUSH_CURRENT(ctx, _NEW_BUFFERS);
    if (ctx->Driver.Flush) {  
       ctx->Driver.Flush(ctx);
    }
@@ -1202,19 +1245,26 @@ _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
    ASSERT(newFb != &DummyFramebuffer);
 
    /*
-    * XXX check if re-binding same buffer and skip some of this code.
+    * OK, now bind the new Draw/Read framebuffers, if they're changing.
     */
 
    if (bindReadBuf) {
-      _mesa_reference_framebuffer(&ctx->ReadBuffer, newFbread);
+      if (ctx->ReadBuffer == newFbread)
+         bindReadBuf = GL_FALSE; /* no change */
+      else
+         _mesa_reference_framebuffer(&ctx->ReadBuffer, newFbread);
    }
 
    if (bindDrawBuf) {
       /* check if old FB had any texture attachments */
-      check_end_texture_render(ctx, ctx->DrawBuffer);
+      if (ctx->DrawBuffer->Name != 0) {
+         check_end_texture_render(ctx, ctx->DrawBuffer);
+      }
 
-      /* check if time to delete this framebuffer */
-      _mesa_reference_framebuffer(&ctx->DrawBuffer, newFb);
+      if (ctx->DrawBuffer == newFb)
+         bindDrawBuf = GL_FALSE; /* no change */
+      else
+         _mesa_reference_framebuffer(&ctx->DrawBuffer, newFb);
 
       if (newFb->Name != 0) {
          /* check if newly bound framebuffer has any texture attachments */
@@ -1222,7 +1272,7 @@ _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
       }
    }
 
-   if (ctx->Driver.BindFramebuffer) {
+   if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) {
       ctx->Driver.BindFramebuffer(ctx, target, newFb, newFbread);
    }
 }
@@ -1235,7 +1285,7 @@ _mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
    GET_CURRENT_CONTEXT(ctx);
 
    ASSERT_OUTSIDE_BEGIN_END(ctx);
-   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+   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:
     */
@@ -1473,7 +1523,7 @@ framebuffer_texture(GLcontext *ctx, const char *caller, GLenum target,
       }
    }
 
-   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+   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:
     */
@@ -1654,7 +1704,7 @@ _mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
    }
 
 
-   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+   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:
     */
@@ -1735,7 +1785,7 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
       }
    }
 
-   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+   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:
     */
@@ -1990,7 +2040,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;
@@ -2000,7 +2052,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;