Rework the GL_READ_BUFFER, GL_DRAW_BUFFER state repairs that Roland previously did.
authorBrian <brian.paul@tungstengraphics.com>
Thu, 16 Aug 2007 17:52:48 +0000 (18:52 +0100)
committerBrian <brian.paul@tungstengraphics.com>
Thu, 16 Aug 2007 17:52:48 +0000 (18:52 +0100)
Basically, in update_framebuffer() (which should be called after an FBO is bound
with MakeCurrent or BindFramebuffer) we check if the FBO is a window-system FBO.
If it is, update the FBO's GL_READ/DRAW_BUFFER state according to the context state.
Old code still in place but disabled with #if 0 / #endif.

src/mesa/main/buffers.c
src/mesa/main/buffers.h
src/mesa/main/context.c
src/mesa/main/fbobject.c
src/mesa/main/framebuffer.c

index 82dd059e4b240d0c60d58c88f2bfe4211a1e472f..94b4be54d503faddc5cff5d7f5ae7fe86dc65635 100644 (file)
@@ -336,6 +336,20 @@ read_buffer_enum_to_index(GLenum buffer)
  * \sa _mesa_DrawBuffersARB
  *
  * \param buffer  buffer token such as GL_LEFT or GL_FRONT_AND_BACK, etc.
+ *
+ * Note that the behaviour of this function depends on whether the
+ * current ctx->DrawBuffer is a window-system framebuffer (Name=0) or
+ * a user-created framebuffer object (Name!=0).
+ *   In the former case, we update the per-context ctx->Color.DrawBuffer
+ *   state var _and_ the FB's ColorDrawBuffer state.
+ *   In the later case, we update the FB's ColorDrawBuffer state only.
+ *
+ * Furthermore, upon a MakeCurrent() or BindFramebuffer() call, if the
+ * new FB is a window system FB, we need to re-update the FB's
+ * ColorDrawBuffer state to match the context.  This is handled in
+ * _mesa_update_framebuffer().
+ *
+ * See the GL_EXT_framebuffer_object spec for more info.
  */
 void GLAPIENTRY
 _mesa_DrawBuffer(GLenum buffer)
@@ -489,10 +503,12 @@ set_color_output(GLcontext *ctx, GLuint output, GLenum buffer,
 
 
 /**
- * Helper routine used by _mesa_DrawBuffer, _mesa_DrawBuffersARB and
- * other places (window fbo fixup) to set fbo (and the old ctx) fields.
+ * Helper function to set the GL_DRAW_BUFFER state in the context and
+ * current FBO.
+ *
  * All error checking will have been done prior to calling this function
  * so nothing should go wrong at this point.
+ *
  * \param ctx  current context
  * \param n    number of color outputs to set
  * \param buffers  array[n] of colorbuffer names, like GL_LEFT.
@@ -532,6 +548,7 @@ _mesa_drawbuffers(GLcontext *ctx, GLuint n, const GLenum *buffers,
 }
 
 
+#if 0
 GLboolean
 _mesa_readbuffer_update_fields(GLcontext *ctx, GLenum buffer)
 {
@@ -563,13 +580,45 @@ _mesa_readbuffer_update_fields(GLcontext *ctx, GLenum buffer)
    }
 
    if (fb->Name == 0) {
+      /* Only update the per-context GL_READ_BUFFER state if we're bound to
+       * a window-system framebuffer.
+       */
       ctx->Pixel.ReadBuffer = buffer;
    }
+
+   /* Set the FBO's GL_READ_BUFFER state */
    fb->ColorReadBuffer = buffer;
    fb->_ColorReadBufferIndex = srcBuffer;
 
    return GL_TRUE;
 }
+#endif
+
+
+/**
+ * Like \sa _mesa_drawbuffers(), this is a helper function for setting
+ * GL_READ_BUFFER state in the context and current FBO.
+ * \param ctx  the rendering context
+ * \param buffer  GL_FRONT, GL_BACK, GL_COLOR_ATTACHMENT0, etc.
+ * \param bufferIndex  the numerical index corresponding to 'buffer'
+ */
+void
+_mesa_readbuffer(GLcontext *ctx, GLenum buffer, GLint bufferIndex)
+{
+   struct gl_framebuffer *fb = ctx->ReadBuffer;
+
+   if (fb->Name == 0) {
+      /* Only update the per-context READ_BUFFER state if we're bound to
+       * a window-system framebuffer.
+       */
+      ctx->Pixel.ReadBuffer = buffer;
+   }
+
+   fb->ColorReadBuffer = buffer;
+   fb->_ColorReadBufferIndex = bufferIndex;
+
+   ctx->NewState |= _NEW_PIXEL;
+}
 
 
 
@@ -580,16 +629,43 @@ _mesa_readbuffer_update_fields(GLcontext *ctx, GLenum buffer)
 void GLAPIENTRY
 _mesa_ReadBuffer(GLenum buffer)
 {
+   struct gl_framebuffer *fb;
+   GLbitfield supportedMask;
+   GLint srcBuffer;
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
    if (MESA_VERBOSE & VERBOSE_API)
       _mesa_debug(ctx, "glReadBuffer %s\n", _mesa_lookup_enum_by_nr(buffer));
 
-   if (!_mesa_readbuffer_update_fields(ctx, buffer))
-      return;
+   fb = ctx->ReadBuffer;
 
-   ctx->NewState |= _NEW_PIXEL;
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glReadBuffer %s\n", _mesa_lookup_enum_by_nr(buffer));
+
+   if (fb->Name > 0 && buffer == GL_NONE) {
+      /* This is legal for user-created framebuffer objects */
+      srcBuffer = -1;
+   }
+   else {
+      /* general case / window-system framebuffer */
+      srcBuffer = read_buffer_enum_to_index(buffer);
+      if (srcBuffer == -1) {
+         _mesa_error(ctx, GL_INVALID_ENUM,
+                     "glReadBuffer(buffer=0x%x)", buffer);
+         return;
+      }
+      supportedMask = supported_buffer_bitmask(ctx, fb);
+      if (((1 << srcBuffer) & supportedMask) == 0) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glReadBuffer(buffer=0x%x)", buffer);
+         return;
+      }
+   }
+
+   /* OK, all error checking has been completed now */
+
+   _mesa_readbuffer(ctx, buffer, srcBuffer);
 
    /*
     * Call device driver function.
index 208e7af2b933a9bf9e127c1c6bbbc1e8d092f71f..e7228a6da6b02887d1a836a47600fe6d2eb22f63 100644 (file)
@@ -5,9 +5,9 @@
 
 /*
  * Mesa 3-D graphics library
- * Version:  6.5
+ * Version:  7.1
  *
- * Copyright (C) 1999-2005  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2007  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"),
@@ -56,8 +56,13 @@ extern void
 _mesa_drawbuffers(GLcontext *ctx, GLuint n, const GLenum *buffers,
                   const GLbitfield *destMask);
 
+extern void
+_mesa_readbuffer(GLcontext *ctx, GLenum buffer, GLint bufferIndex);
+
+#if 0
 extern GLboolean
 _mesa_readbuffer_update_fields(GLcontext *ctx, GLenum buffer);
+#endif
 
 extern void GLAPIENTRY
 _mesa_ReadBuffer( GLenum mode );
index f3141fe63e8baccd96e8e3bc59deb2f0d9eaf7fe..9ee7b4bec72b2070c514898367852490a9d132a0 100644 (file)
@@ -1530,6 +1530,7 @@ _mesa_make_current( GLcontext *newCtx, GLframebuffer *drawBuffer,
           */
          if (!newCtx->DrawBuffer || newCtx->DrawBuffer->Name == 0) {
             _mesa_reference_framebuffer(&newCtx->DrawBuffer, drawBuffer);
+#if 000
          /* fix up the fb fields - these will end up wrong otherwise
             if the DRIdrawable changes, and everything relies on them.
             This is a bit messy (same as needed in _mesa_BindFramebufferEXT) */
@@ -1539,12 +1540,18 @@ _mesa_make_current( GLcontext *newCtx, GLframebuffer *drawBuffer,
                buffers[i] = newCtx->Color.DrawBuffer[i];
             }
             _mesa_drawbuffers(newCtx, newCtx->Const.MaxDrawBuffers, buffers, NULL);
+#endif
          }
          if (!newCtx->ReadBuffer || newCtx->ReadBuffer->Name == 0) {
             _mesa_reference_framebuffer(&newCtx->ReadBuffer, readBuffer);
+#if 00
             _mesa_readbuffer_update_fields(newCtx, newCtx->Pixel.ReadBuffer);
+#endif
          }
 
+         /* XXX only set this flag if we're really changing the draw/read
+          * framebuffer bindings.
+          */
         newCtx->NewState |= _NEW_BUFFERS;
 
 #if 1
index fcb620b39d809a81eea0ed199239e9a47b09489c..5cd18d02872a52ffadf09768d2b98ff916c08970 100644 (file)
@@ -962,9 +962,11 @@ _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
    }
 
    FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+
    if (ctx->Driver.Flush) {  
       ctx->Driver.Flush(ctx);
    }
+
    if (framebuffer) {
       /* Binding a user-created framebuffer object */
       newFb = _mesa_lookup_framebuffer(ctx, framebuffer);
@@ -998,34 +1000,43 @@ _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
     * XXX check if re-binding same buffer and skip some of this code.
     */
 
+#if 000
    /* for window-framebuffers, re-initialize the fbo values, as they
       could be wrong (makecurrent with a new drawable while still a fbo
       was bound will lead to default init fbo values).
       note that therefore the context ReadBuffer/DrawBuffer values are not
       valid while fbo's are bound!!! */
+#endif
    if (bindReadBuf) {
       _mesa_reference_framebuffer(&ctx->ReadBuffer, newFbread);
+#if 000
       if (!newFbread->Name) {
          _mesa_readbuffer_update_fields(ctx, ctx->Pixel.ReadBuffer);
       }
+#endif
    }
 
    if (bindDrawBuf) {
       /* check if old FB had any texture attachments */
       check_end_texture_render(ctx, ctx->DrawBuffer);
+
       /* check if time to delete this framebuffer */
       _mesa_reference_framebuffer(&ctx->DrawBuffer, newFb);
-      if (!newFb->Name) {
+
+      if (newFb->Name != 0) {
+         /* check if newly bound framebuffer has any texture attachments */
+         check_begin_texture_render(ctx, newFb);
+      }
+      else {
+         /* XXX try to remove this: */
+#if 000
          GLuint i;
          GLenum buffers[MAX_DRAW_BUFFERS];
          for(i = 0; i < ctx->Const.MaxDrawBuffers; i++) {
             buffers[i] = ctx->Color.DrawBuffer[i];
          }
          _mesa_drawbuffers(ctx, ctx->Const.MaxDrawBuffers, buffers, NULL);
-      }
-      else {
-         /* check if newly bound framebuffer has any texture attachments */
-         check_begin_texture_render(ctx, newFb);
+#endif
       }
    }
 
index 72d85f6f892f357fc672106c6d87d280fbb89447..3e36197d884fbf990a77af87de4376d91a6ef17e 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "glheader.h"
 #include "imports.h"
+#include "buffers.h"
 #include "context.h"
 #include "depthstencil.h"
 #include "mtypes.h"
@@ -583,7 +584,7 @@ _mesa_update_stencil_buffer(GLcontext *ctx,
 
 
 /**
- * Update the list of color drawing renderbuffer pointers.
+ * Update the (derived) list of color drawing renderbuffer pointers.
  * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers
  * writing colors.
  */
@@ -627,7 +628,7 @@ update_color_draw_buffers(GLcontext *ctx, struct gl_framebuffer *fb)
 
 
 /**
- * Update the color read renderbuffer pointer.
+ * Update the (derived) color read renderbuffer pointer.
  * Unlike the DrawBuffer, we can only read from one (or zero) color buffers.
  */
 static void
@@ -668,10 +669,23 @@ update_color_read_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
 static void
 update_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb)
 {
-   /* Completeness only matters for user-created framebuffers */
-   if (fb->Name != 0) {
-      /* XXX: EXT_framebuffer_blit:
-         framebuffer must still be complete wrt read/draw? */
+   if (fb->Name == 0) {
+      /* This is a window-system framebuffer */
+      /* Need to update the FB's GL_DRAW_BUFFER state to match the
+       * context state (GL_READ_BUFFER too).
+       */
+      if (fb->ColorDrawBuffer[0] != ctx->Color.DrawBuffer[0]) {
+         _mesa_drawbuffers(ctx, ctx->Const.MaxDrawBuffers,
+                           ctx->Color.DrawBuffer, NULL);
+      }
+      if (fb->ColorReadBuffer != ctx->Pixel.ReadBuffer) {
+         
+      }
+   }
+   else {
+      /* This is a user-created framebuffer.
+       * Completeness only matters for user-created framebuffers.
+       */
       _mesa_test_framebuffer_completeness(ctx, fb);
       _mesa_update_framebuffer_visual(fb);
    }