mesa: minor error string changes
[mesa.git] / src / mesa / main / fbobject.c
index c16ac0f0093d31998de895a7ad88fcdc4d855be5..ab91fbc4de901d0c4d3a96b80b8711ec405dca85 100644 (file)
@@ -193,7 +193,7 @@ _mesa_remove_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att)
    if (att->Type == GL_TEXTURE) {
       ASSERT(att->Texture);
       if (ctx->Driver.FinishRenderTexture) {
-         /* tell driver we're done rendering to this texobj */
+         /* tell driver that we're done rendering to this texture. */
          ctx->Driver.FinishRenderTexture(ctx, att);
       }
       _mesa_reference_texobj(&att->Texture, NULL); /* unbind */
@@ -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,6 +410,7 @@ 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;
       }
@@ -381,6 +420,7 @@ test_attachment_completeness(const GLcontext *ctx, GLenum format,
             ASSERT(att->Renderbuffer->RedBits);
             ASSERT(att->Renderbuffer->GreenBits);
             ASSERT(att->Renderbuffer->BlueBits);
+            att_incomplete("bad renderbuffer color format");
             att->Complete = GL_FALSE;
             return;
          }
@@ -395,6 +435,7 @@ test_attachment_completeness(const GLcontext *ctx, GLenum format,
             /* OK */
          }
          else {
+            att_incomplete("bad renderbuffer depth format");
             att->Complete = GL_FALSE;
             return;
          }
@@ -411,6 +452,7 @@ test_attachment_completeness(const GLcontext *ctx, GLenum format,
          }
          else {
             att->Complete = GL_FALSE;
+            att_incomplete("bad renderbuffer stencil format");
             return;
          }
       }
@@ -630,6 +672,9 @@ _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb)
        */
       fb->Width = minWidth;
       fb->Height = minHeight;
+
+      /* finally, update the visual info for the framebuffer */
+      _mesa_update_framebuffer_visual(fb);
    }
 }
 
@@ -662,7 +707,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:
     */
@@ -1157,8 +1202,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);
    }
@@ -1199,19 +1243,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 */
@@ -1219,7 +1270,7 @@ _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
       }
    }
 
-   if (ctx->Driver.BindFramebuffer) {
+   if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) {
       ctx->Driver.BindFramebuffer(ctx, target, newFb, newFbread);
    }
 }
@@ -1232,7 +1283,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:
     */
@@ -1265,7 +1316,7 @@ _mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
                /* But the object will not be freed until it's no longer
                 * bound in any context.
                 */
-               _mesa_unreference_framebuffer(&fb);
+               _mesa_reference_framebuffer(&fb, NULL);
            }
         }
       }
@@ -1364,16 +1415,31 @@ framebuffer_texture(GLcontext *ctx, const char *caller, GLenum target,
    struct gl_renderbuffer_attachment *att;
    struct gl_texture_object *texObj = NULL;
    struct gl_framebuffer *fb;
+   GLboolean error = GL_FALSE;
 
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
-   if (target != GL_FRAMEBUFFER_EXT) {
+   switch (target) {
+   case GL_READ_FRAMEBUFFER_EXT:
+      error = !ctx->Extensions.EXT_framebuffer_blit;
+      fb = ctx->ReadBuffer;
+      break;
+   case GL_DRAW_FRAMEBUFFER_EXT:
+      error = !ctx->Extensions.EXT_framebuffer_blit;
+      /* fall-through */
+   case GL_FRAMEBUFFER_EXT:
+      fb = ctx->DrawBuffer;
+      break;
+   default:
+      error = GL_TRUE;
+   }
+
+   if (error) {
       _mesa_error(ctx, GL_INVALID_ENUM,
-                  "glFramebufferTexture%sEXT(target)", caller);
+                  "glFramebufferTexture%sEXT(target=0x%x)", caller, target);
       return;
    }
 
-   fb = ctx->DrawBuffer;
    ASSERT(fb);
 
    /* check framebuffer binding */
@@ -1455,7 +1521,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:
     */
@@ -1466,6 +1532,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);
@@ -1506,7 +1581,7 @@ _mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
        (textarget != GL_TEXTURE_RECTANGLE_ARB) &&
        (!IS_CUBE_FACE(textarget))) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "glFramebufferTexture2DEXT(textarget)");
+                  "glFramebufferTexture2DEXT(textarget=0x%x)", textarget);
       return;
    }
 
@@ -1627,7 +1702,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:
     */
@@ -1708,7 +1783,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:
     */
@@ -1963,7 +2038,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;
@@ -1973,7 +2050,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;