mesa: Set correct values for range/precision of shader integer types
[mesa.git] / src / mesa / main / framebuffer.c
index 3e36197d884fbf990a77af87de4376d91a6ef17e..63da71c95b4bd9609173f099e432bed07431da2c 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Mesa 3-D graphics library
- * Version:  6.5.1
+ * Version:  7.2
  *
- * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2008  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"),
@@ -35,6 +35,9 @@
 #include "buffers.h"
 #include "context.h"
 #include "depthstencil.h"
+#include "enums.h"
+#include "formats.h"
+#include "macros.h"
 #include "mtypes.h"
 #include "fbobject.h"
 #include "framebuffer.h"
@@ -69,10 +72,9 @@ compute_depth_max(struct gl_framebuffer *fb)
    fb->_DepthMaxF = (GLfloat) fb->_DepthMax;
 
    /* Minimum resolvable depth value, for polygon offset */
-   fb->_MRD = 1.0 / fb->_DepthMaxF;
+   fb->_MRD = (GLfloat)1.0 / fb->_DepthMaxF;
 }
 
-
 /**
  * Create and initialize a gl_framebuffer object.
  * This is intended for creating _window_system_ framebuffers, not generic
@@ -81,12 +83,12 @@ compute_depth_max(struct gl_framebuffer *fb)
  * \sa _mesa_new_framebuffer
  */
 struct gl_framebuffer *
-_mesa_create_framebuffer(const GLvisual *visual)
+_mesa_create_framebuffer(const struct gl_config *visual)
 {
    struct gl_framebuffer *fb = CALLOC_STRUCT(gl_framebuffer);
    assert(visual);
    if (fb) {
-      _mesa_initialize_framebuffer(fb, visual);
+      _mesa_initialize_window_framebuffer(fb, visual);
    }
    return fb;
 }
@@ -100,20 +102,14 @@ _mesa_create_framebuffer(const GLvisual *visual)
  * \sa _mesa_create_framebuffer
  */
 struct gl_framebuffer *
-_mesa_new_framebuffer(GLcontext *ctx, GLuint name)
+_mesa_new_framebuffer(struct gl_context *ctx, GLuint name)
 {
    struct gl_framebuffer *fb;
    (void) ctx;
    assert(name != 0);
    fb = CALLOC_STRUCT(gl_framebuffer);
    if (fb) {
-      fb->Name = name;
-      fb->RefCount = 1;
-      fb->ColorDrawBuffer[0] = GL_COLOR_ATTACHMENT0_EXT;
-      fb->_ColorDrawBufferMask[0] = BUFFER_BIT_COLOR0;
-      fb->ColorReadBuffer = GL_COLOR_ATTACHMENT0_EXT;
-      fb->_ColorReadBufferIndex = BUFFER_COLOR0;
-      fb->Delete = _mesa_destroy_framebuffer;
+      _mesa_initialize_user_framebuffer(fb, name);
    }
    return fb;
 }
@@ -122,15 +118,16 @@ _mesa_new_framebuffer(GLcontext *ctx, GLuint name)
 /**
  * Initialize a gl_framebuffer object.  Typically used to initialize
  * window system-created framebuffers, not user-created framebuffers.
- * \sa _mesa_create_framebuffer
+ * \sa _mesa_initialize_user_framebuffer
  */
 void
-_mesa_initialize_framebuffer(struct gl_framebuffer *fb, const GLvisual *visual)
+_mesa_initialize_window_framebuffer(struct gl_framebuffer *fb,
+                                    const struct gl_config *visual)
 {
    assert(fb);
    assert(visual);
 
-   _mesa_bzero(fb, sizeof(struct gl_framebuffer));
+   memset(fb, 0, sizeof(struct gl_framebuffer));
 
    _glthread_INIT_MUTEX(fb->Mutex);
 
@@ -141,14 +138,16 @@ _mesa_initialize_framebuffer(struct gl_framebuffer *fb, const GLvisual *visual)
 
    /* Init read/draw renderbuffer state */
    if (visual->doubleBufferMode) {
+      fb->_NumColorDrawBuffers = 1;
       fb->ColorDrawBuffer[0] = GL_BACK;
-      fb->_ColorDrawBufferMask[0] = BUFFER_BIT_BACK_LEFT;
+      fb->_ColorDrawBufferIndexes[0] = BUFFER_BACK_LEFT;
       fb->ColorReadBuffer = GL_BACK;
       fb->_ColorReadBufferIndex = BUFFER_BACK_LEFT;
    }
    else {
+      fb->_NumColorDrawBuffers = 1;
       fb->ColorDrawBuffer[0] = GL_FRONT;
-      fb->_ColorDrawBufferMask[0] = BUFFER_BIT_FRONT_LEFT;
+      fb->_ColorDrawBufferIndexes[0] = BUFFER_FRONT_LEFT;
       fb->ColorReadBuffer = GL_FRONT;
       fb->_ColorReadBufferIndex = BUFFER_FRONT_LEFT;
    }
@@ -160,6 +159,30 @@ _mesa_initialize_framebuffer(struct gl_framebuffer *fb, const GLvisual *visual)
 }
 
 
+/**
+ * Initialize a user-created gl_framebuffer object.
+ * \sa _mesa_initialize_window_framebuffer
+ */
+void
+_mesa_initialize_user_framebuffer(struct gl_framebuffer *fb, GLuint name)
+{
+   assert(fb);
+   assert(name);
+
+   memset(fb, 0, sizeof(struct gl_framebuffer));
+
+   fb->Name = name;
+   fb->RefCount = 1;
+   fb->_NumColorDrawBuffers = 1;
+   fb->ColorDrawBuffer[0] = GL_COLOR_ATTACHMENT0_EXT;
+   fb->_ColorDrawBufferIndexes[0] = BUFFER_COLOR0;
+   fb->ColorReadBuffer = GL_COLOR_ATTACHMENT0_EXT;
+   fb->_ColorReadBufferIndex = BUFFER_COLOR0;
+   fb->Delete = _mesa_destroy_framebuffer;
+   _glthread_INIT_MUTEX(fb->Mutex);
+}
+
+
 /**
  * Deallocate buffer and everything attached to it.
  * Typically called via the gl_framebuffer->Delete() method.
@@ -169,7 +192,7 @@ _mesa_destroy_framebuffer(struct gl_framebuffer *fb)
 {
    if (fb) {
       _mesa_free_framebuffer_data(fb);
-      _mesa_free(fb);
+      free(fb);
    }
 }
 
@@ -219,45 +242,32 @@ _mesa_reference_framebuffer(struct gl_framebuffer **ptr,
       /* no change */
       return;
    }
-   if (*ptr) {
-      _mesa_unreference_framebuffer(ptr);
-   }
-   assert(!*ptr);
-   assert(fb);
-   _glthread_LOCK_MUTEX(fb->Mutex);
-   fb->RefCount++;
-   _glthread_UNLOCK_MUTEX(fb->Mutex);
-   *ptr = fb;
-}
-
 
-/**
- * Undo/remove a reference to a framebuffer object.
- * Decrement the framebuffer object's reference count and delete it when
- * the refcount hits zero.
- * Note: we pass the address of a pointer and set it to NULL.
- */
-void
-_mesa_unreference_framebuffer(struct gl_framebuffer **fb)
-{
-   assert(fb);
-   if (*fb) {
+   if (*ptr) {
+      /* unreference old renderbuffer */
       GLboolean deleteFlag = GL_FALSE;
+      struct gl_framebuffer *oldFb = *ptr;
 
-      _glthread_LOCK_MUTEX((*fb)->Mutex);
-      ASSERT((*fb)->RefCount > 0);
-      (*fb)->RefCount--;
-      deleteFlag = ((*fb)->RefCount == 0);
-      _glthread_UNLOCK_MUTEX((*fb)->Mutex);
+      _glthread_LOCK_MUTEX(oldFb->Mutex);
+      ASSERT(oldFb->RefCount > 0);
+      oldFb->RefCount--;
+      deleteFlag = (oldFb->RefCount == 0);
+      _glthread_UNLOCK_MUTEX(oldFb->Mutex);
       
       if (deleteFlag)
-         (*fb)->Delete(*fb);
+         oldFb->Delete(oldFb);
 
-      *fb = NULL;
+      *ptr = NULL;
    }
-}
-
+   assert(!*ptr);
 
+   if (fb) {
+      _glthread_LOCK_MUTEX(fb->Mutex);
+      fb->RefCount++;
+      _glthread_UNLOCK_MUTEX(fb->Mutex);
+      *ptr = fb;
+   }
+}
 
 
 /**
@@ -271,7 +281,7 @@ _mesa_unreference_framebuffer(struct gl_framebuffer **fb)
  * without a currently bound rendering context.
  */
 void
-_mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb,
+_mesa_resize_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
                          GLuint width, GLuint height)
 {
    GLuint i;
@@ -289,7 +299,6 @@ _mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb,
          struct gl_renderbuffer *rb = att->Renderbuffer;
          /* only resize if size is changing */
          if (rb->Width != width || rb->Height != height) {
-            /* could just as well pass rb->_ActualFormat here */
             if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
                ASSERT(rb->Width == width);
                ASSERT(rb->Height == height);
@@ -334,17 +343,95 @@ _mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb,
 }
 
 
+
+/**
+ * XXX THIS IS OBSOLETE - drivers should take care of detecting window
+ * size changes and act accordingly, likely calling _mesa_resize_framebuffer().
+ *
+ * GL_MESA_resize_buffers extension.
+ *
+ * When this function is called, we'll ask the window system how large
+ * the current window is.  If it's a new size, we'll call the driver's
+ * ResizeBuffers function.  The driver will then resize its color buffers
+ * as needed, and maybe call the swrast's routine for reallocating
+ * swrast-managed depth/stencil/accum/etc buffers.
+ * \note This function should only be called through the GL API, not
+ * from device drivers (as was done in the past).
+ */
+void
+_mesa_resizebuffers( struct gl_context *ctx )
+{
+   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH( ctx );
+
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glResizeBuffersMESA\n");
+
+   if (!ctx->Driver.GetBufferSize) {
+      return;
+   }
+
+   if (ctx->WinSysDrawBuffer) {
+      GLuint newWidth, newHeight;
+      struct gl_framebuffer *buffer = ctx->WinSysDrawBuffer;
+
+      assert(buffer->Name == 0);
+
+      /* ask device driver for size of output buffer */
+      ctx->Driver.GetBufferSize( buffer, &newWidth, &newHeight );
+
+      /* see if size of device driver's color buffer (window) has changed */
+      if (buffer->Width != newWidth || buffer->Height != newHeight) {
+         if (ctx->Driver.ResizeBuffers)
+            ctx->Driver.ResizeBuffers(ctx, buffer, newWidth, newHeight );
+      }
+   }
+
+   if (ctx->WinSysReadBuffer
+       && ctx->WinSysReadBuffer != ctx->WinSysDrawBuffer) {
+      GLuint newWidth, newHeight;
+      struct gl_framebuffer *buffer = ctx->WinSysReadBuffer;
+
+      assert(buffer->Name == 0);
+
+      /* ask device driver for size of read buffer */
+      ctx->Driver.GetBufferSize( buffer, &newWidth, &newHeight );
+
+      /* see if size of device driver's color buffer (window) has changed */
+      if (buffer->Width != newWidth || buffer->Height != newHeight) {
+         if (ctx->Driver.ResizeBuffers)
+            ctx->Driver.ResizeBuffers(ctx, buffer, newWidth, newHeight );
+      }
+   }
+
+   ctx->NewState |= _NEW_BUFFERS;  /* to update scissor / window bounds */
+}
+
+
+/*
+ * XXX THIS IS OBSOLETE
+ */
+void GLAPIENTRY
+_mesa_ResizeBuffersMESA( void )
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (ctx->Extensions.MESA_resize_buffers)
+      _mesa_resizebuffers( ctx );
+}
+
+
+
 /**
  * Examine all the framebuffer's renderbuffers to update the Width/Height
  * fields of the framebuffer.  If we have renderbuffers with different
- * sizes, set the framebuffer's width and height to zero.
+ * sizes, set the framebuffer's width and height to the min size.
  * Note: this is only intended for user-created framebuffers, not
  * window-system framebuffes.
  */
 static void
-update_framebuffer_size(struct gl_framebuffer *fb)
+update_framebuffer_size(struct gl_context *ctx, struct gl_framebuffer *fb)
 {
-   GLboolean haveSize = GL_FALSE;
+   GLuint minWidth = ~0, minHeight = ~0;
    GLuint i;
 
    /* user-created framebuffers only */
@@ -354,21 +441,19 @@ update_framebuffer_size(struct gl_framebuffer *fb)
       struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
       const struct gl_renderbuffer *rb = att->Renderbuffer;
       if (rb) {
-         if (haveSize) {
-            if (rb->Width != fb->Width && rb->Height != fb->Height) {
-               /* size mismatch! */
-               fb->Width = 0;
-               fb->Height = 0;
-               return;
-            }
-         }
-         else {
-            fb->Width = rb->Width;
-            fb->Height = rb->Height;
-            haveSize = GL_TRUE;
-         }
+         minWidth = MIN2(minWidth, rb->Width);
+         minHeight = MIN2(minHeight, rb->Height);
       }
    }
+
+   if (minWidth != ~0) {
+      fb->Width = minWidth;
+      fb->Height = minHeight;
+   }
+   else {
+      fb->Width = 0;
+      fb->Height = 0;
+   }
 }
 
 
@@ -379,7 +464,7 @@ update_framebuffer_size(struct gl_framebuffer *fb)
  * \param ctx  the GL context.
  */
 void
-_mesa_update_draw_buffer_bounds(GLcontext *ctx)
+_mesa_update_draw_buffer_bounds(struct gl_context *ctx)
 {
    struct gl_framebuffer *buffer = ctx->DrawBuffer;
 
@@ -388,7 +473,7 @@ _mesa_update_draw_buffer_bounds(GLcontext *ctx)
 
    if (buffer->Name) {
       /* user-created framebuffer size depends on the renderbuffers */
-      update_framebuffer_size(buffer);
+      update_framebuffer_size(ctx, buffer);
    }
 
    buffer->_Xmin = 0;
@@ -437,11 +522,12 @@ _mesa_update_draw_buffer_bounds(GLcontext *ctx)
  * integer Z values.
  */
 void
-_mesa_update_framebuffer_visual(struct gl_framebuffer *fb)
+_mesa_update_framebuffer_visual(struct gl_context *ctx,
+                               struct gl_framebuffer *fb)
 {
    GLuint i;
 
-   _mesa_bzero(&fb->Visual, sizeof(fb->Visual));
+   memset(&fb->Visual, 0, sizeof(fb->Visual));
    fb->Visual.rgbMode = GL_TRUE; /* assume this */
 
 #if 0 /* this _might_ be needed */
@@ -451,50 +537,52 @@ _mesa_update_framebuffer_visual(struct gl_framebuffer *fb)
    }
 #endif
 
-   /* find first RGB or CI renderbuffer */
+   /* find first RGB renderbuffer */
    for (i = 0; i < BUFFER_COUNT; i++) {
       if (fb->Attachment[i].Renderbuffer) {
          const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
-         if (rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB) {
-            fb->Visual.redBits = rb->RedBits;
-            fb->Visual.greenBits = rb->GreenBits;
-            fb->Visual.blueBits = rb->BlueBits;
-            fb->Visual.alphaBits = rb->AlphaBits;
+         const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
+         const gl_format fmt = rb->Format;
+
+         if (_mesa_is_legal_color_format(ctx, baseFormat)) {
+            fb->Visual.redBits = _mesa_get_format_bits(fmt, GL_RED_BITS);
+            fb->Visual.greenBits = _mesa_get_format_bits(fmt, GL_GREEN_BITS);
+            fb->Visual.blueBits = _mesa_get_format_bits(fmt, GL_BLUE_BITS);
+            fb->Visual.alphaBits = _mesa_get_format_bits(fmt, GL_ALPHA_BITS);
             fb->Visual.rgbBits = fb->Visual.redBits
                + fb->Visual.greenBits + fb->Visual.blueBits;
             fb->Visual.floatMode = GL_FALSE;
-            break;
-         }
-         else if (rb->_BaseFormat == GL_COLOR_INDEX) {
-            fb->Visual.indexBits = rb->IndexBits;
-            fb->Visual.rgbMode = GL_FALSE;
+            fb->Visual.samples = rb->NumSamples;
             break;
          }
       }
    }
 
    if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) {
+      const struct gl_renderbuffer *rb =
+         fb->Attachment[BUFFER_DEPTH].Renderbuffer;
+      const gl_format fmt = rb->Format;
       fb->Visual.haveDepthBuffer = GL_TRUE;
-      fb->Visual.depthBits
-         = fb->Attachment[BUFFER_DEPTH].Renderbuffer->DepthBits;
+      fb->Visual.depthBits = _mesa_get_format_bits(fmt, GL_DEPTH_BITS);
    }
 
    if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) {
+      const struct gl_renderbuffer *rb =
+         fb->Attachment[BUFFER_STENCIL].Renderbuffer;
+      const gl_format fmt = rb->Format;
       fb->Visual.haveStencilBuffer = GL_TRUE;
-      fb->Visual.stencilBits
-         = fb->Attachment[BUFFER_STENCIL].Renderbuffer->StencilBits;
+      fb->Visual.stencilBits = _mesa_get_format_bits(fmt, GL_STENCIL_BITS);
    }
 
    if (fb->Attachment[BUFFER_ACCUM].Renderbuffer) {
+      const struct gl_renderbuffer *rb =
+         fb->Attachment[BUFFER_ACCUM].Renderbuffer;
+      const gl_format fmt = rb->Format;
       fb->Visual.haveAccumBuffer = GL_TRUE;
-      fb->Visual.accumRedBits
-         = fb->Attachment[BUFFER_DEPTH].Renderbuffer->RedBits;
-      fb->Visual.accumGreenBits
-         = fb->Attachment[BUFFER_DEPTH].Renderbuffer->GreenBits;
-      fb->Visual.accumBlueBits
-         = fb->Attachment[BUFFER_DEPTH].Renderbuffer->BlueBits;
-      fb->Visual.accumAlphaBits
-         = fb->Attachment[BUFFER_DEPTH].Renderbuffer->AlphaBits;
+      fb->Visual.accumRedBits = _mesa_get_format_bits(fmt, GL_RED_BITS);
+      fb->Visual.accumGreenBits = _mesa_get_format_bits(fmt, GL_GREEN_BITS);
+      fb->Visual.accumBlueBits = _mesa_get_format_bits(fmt, GL_BLUE_BITS);
+      fb->Visual.accumAlphaBits = _mesa_get_format_bits(fmt, GL_ALPHA_BITS);
    }
 
    compute_depth_max(fb);
@@ -512,7 +600,7 @@ _mesa_update_framebuffer_visual(struct gl_framebuffer *fb)
  * \param attIndex  indicates the renderbuffer to possibly wrap
  */
 void
-_mesa_update_depth_buffer(GLcontext *ctx,
+_mesa_update_depth_buffer(struct gl_context *ctx,
                           struct gl_framebuffer *fb,
                           GLuint attIndex)
 {
@@ -523,11 +611,11 @@ _mesa_update_depth_buffer(GLcontext *ctx,
 
    depthRb = fb->Attachment[attIndex].Renderbuffer;
 
-   if (depthRb && depthRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) {
+   if (depthRb && _mesa_is_format_packed_depth_stencil(depthRb->Format)) {
       /* The attached depth buffer is a GL_DEPTH_STENCIL renderbuffer */
       if (!fb->_DepthBuffer
           || fb->_DepthBuffer->Wrapped != depthRb
-          || fb->_DepthBuffer->_BaseFormat != GL_DEPTH_COMPONENT) {
+          || _mesa_get_format_base_format(fb->_DepthBuffer->Format) != GL_DEPTH_COMPONENT) {
          /* need to update wrapper */
          struct gl_renderbuffer *wrapper
             = _mesa_new_z24_renderbuffer_wrapper(ctx, depthRb);
@@ -553,7 +641,7 @@ _mesa_update_depth_buffer(GLcontext *ctx,
  * \param attIndex  indicates the renderbuffer to possibly wrap
  */
 void
-_mesa_update_stencil_buffer(GLcontext *ctx,
+_mesa_update_stencil_buffer(struct gl_context *ctx,
                             struct gl_framebuffer *fb,
                             GLuint attIndex)
 {
@@ -564,11 +652,11 @@ _mesa_update_stencil_buffer(GLcontext *ctx,
 
    stencilRb = fb->Attachment[attIndex].Renderbuffer;
 
-   if (stencilRb && stencilRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) {
+   if (stencilRb && _mesa_is_format_packed_depth_stencil(stencilRb->Format)) {
       /* The attached stencil buffer is a GL_DEPTH_STENCIL renderbuffer */
       if (!fb->_StencilBuffer
           || fb->_StencilBuffer->Wrapped != stencilRb
-          || fb->_StencilBuffer->_BaseFormat != GL_STENCIL_INDEX) {
+          || _mesa_get_format_base_format(fb->_StencilBuffer->Format) != GL_STENCIL_INDEX) {
          /* need to update wrapper */
          struct gl_renderbuffer *wrapper
             = _mesa_new_s8_renderbuffer_wrapper(ctx, stencilRb);
@@ -583,46 +671,72 @@ _mesa_update_stencil_buffer(GLcontext *ctx,
 }
 
 
+/*
+ * Example DrawBuffers scenarios:
+ *
+ * 1. glDrawBuffer(GL_FRONT_AND_BACK), fixed-func or shader writes to
+ * "gl_FragColor" or program writes to the "result.color" register:
+ *
+ *   fragment color output   renderbuffer
+ *   ---------------------   ---------------
+ *   color[0]                Front, Back
+ *
+ *
+ * 2. glDrawBuffers(3, [GL_FRONT, GL_AUX0, GL_AUX1]), shader writes to
+ * gl_FragData[i] or program writes to result.color[i] registers:
+ *
+ *   fragment color output   renderbuffer
+ *   ---------------------   ---------------
+ *   color[0]                Front
+ *   color[1]                Aux0
+ *   color[3]                Aux1
+ *
+ *
+ * 3. glDrawBuffers(3, [GL_FRONT, GL_AUX0, GL_AUX1]) and shader writes to
+ * gl_FragColor, or fixed function:
+ *
+ *   fragment color output   renderbuffer
+ *   ---------------------   ---------------
+ *   color[0]                Front, Aux0, Aux1
+ *
+ *
+ * In either case, the list of renderbuffers is stored in the
+ * framebuffer->_ColorDrawBuffers[] array and
+ * framebuffer->_NumColorDrawBuffers indicates the number of buffers.
+ * The renderer (like swrast) has to look at the current fragment shader
+ * to see if it writes to gl_FragColor vs. gl_FragData[i] to determine
+ * how to map color outputs to renderbuffers.
+ *
+ * Note that these two calls are equivalent (for fixed function fragment
+ * shading anyway):
+ *   a)  glDrawBuffer(GL_FRONT_AND_BACK);  (assuming non-stereo framebuffer)
+ *   b)  glDrawBuffers(2, [GL_FRONT_LEFT, GL_BACK_LEFT]);
+ */
+
+
+
+
 /**
  * Update the (derived) list of color drawing renderbuffer pointers.
  * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers
  * writing colors.
  */
 static void
-update_color_draw_buffers(GLcontext *ctx, struct gl_framebuffer *fb)
+update_color_draw_buffers(struct gl_context *ctx, struct gl_framebuffer *fb)
 {
    GLuint output;
 
-   /*
-    * Fragment programs can write to multiple colorbuffers with
-    * the GL_ARB_draw_buffers extension.
-    */
-   for (output = 0; output < ctx->Const.MaxDrawBuffers; output++) {
-      GLbitfield bufferMask = fb->_ColorDrawBufferMask[output];
-      GLuint count = 0;
-      GLuint i;
-      if (!fb->DeletePending) {
-         /* We need the inner loop here because glDrawBuffer(GL_FRONT_AND_BACK)
-          * can specify writing to two or four color buffers (for example).
-          */
-         for (i = 0; bufferMask && i < BUFFER_COUNT; i++) {
-            const GLuint bufferBit = 1 << i;
-            if (bufferBit & bufferMask) {
-               struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
-               if (rb && rb->Width > 0 && rb->Height > 0) {
-                  fb->_ColorDrawBuffers[output][count] = rb;
-                  count++;
-               }
-               else {
-                  /*
-                  _mesa_warning(ctx, "DrawBuffer names a missing buffer!\n");
-                  */
-               }
-               bufferMask &= ~bufferBit;
-            }
-         }
+   /* set 0th buffer to NULL now in case _NumColorDrawBuffers is zero */
+   fb->_ColorDrawBuffers[0] = NULL;
+
+   for (output = 0; output < fb->_NumColorDrawBuffers; output++) {
+      GLint buf = fb->_ColorDrawBufferIndexes[output];
+      if (buf >= 0) {
+         fb->_ColorDrawBuffers[output] = fb->Attachment[buf].Renderbuffer;
+      }
+      else {
+         fb->_ColorDrawBuffers[output] = NULL;
       }
-      fb->_NumColorDrawBuffers[output] = count;
    }
 }
 
@@ -632,7 +746,7 @@ update_color_draw_buffers(GLcontext *ctx, struct gl_framebuffer *fb)
  * Unlike the DrawBuffer, we can only read from one (or zero) color buffers.
  */
 static void
-update_color_read_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
+update_color_read_buffer(struct gl_context *ctx, struct gl_framebuffer *fb)
 {
    (void) ctx;
    if (fb->_ColorReadBufferIndex == -1 ||
@@ -667,7 +781,7 @@ update_color_read_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
  * glRenderbufferStorageEXT.
  */
 static void
-update_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb)
+update_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb)
 {
    if (fb->Name == 0) {
       /* This is a window-system framebuffer */
@@ -686,8 +800,9 @@ update_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb)
       /* This is a user-created framebuffer.
        * Completeness only matters for user-created framebuffers.
        */
-      _mesa_test_framebuffer_completeness(ctx, fb);
-      _mesa_update_framebuffer_visual(fb);
+      if (fb->_Status != GL_FRAMEBUFFER_COMPLETE) {
+         _mesa_test_framebuffer_completeness(ctx, fb);
+      }
    }
 
    /* Strictly speaking, we don't need to update the draw-state
@@ -708,10 +823,14 @@ update_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb)
  * Update state related to the current draw/read framebuffers.
  */
 void
-_mesa_update_framebuffer(GLcontext *ctx)
+_mesa_update_framebuffer(struct gl_context *ctx)
 {
-   struct gl_framebuffer *drawFb = ctx->DrawBuffer;
-   struct gl_framebuffer *readFb = ctx->ReadBuffer;
+   struct gl_framebuffer *drawFb;
+   struct gl_framebuffer *readFb;
+
+   assert(ctx);
+   drawFb = ctx->DrawBuffer;
+   readFb = ctx->ReadBuffer;
 
    update_framebuffer(ctx, drawFb);
    if (readFb != drawFb)
@@ -721,16 +840,20 @@ _mesa_update_framebuffer(GLcontext *ctx)
 
 /**
  * Check if the renderbuffer for a read operation (glReadPixels, glCopyPixels,
- * glCopyTex[Sub]Image, etc. exists.
+ * glCopyTex[Sub]Image, etc) exists.
  * \param format  a basic image format such as GL_RGB, GL_RGBA, GL_ALPHA,
  *                GL_DEPTH_COMPONENT, etc. or GL_COLOR, GL_DEPTH, GL_STENCIL.
  * \return GL_TRUE if buffer exists, GL_FALSE otherwise
  */
 GLboolean
-_mesa_source_buffer_exists(GLcontext *ctx, GLenum format)
+_mesa_source_buffer_exists(struct gl_context *ctx, GLenum format)
 {
-   const struct gl_renderbuffer_attachment *att
-      = ctx->ReadBuffer->Attachment;
+   const struct gl_renderbuffer_attachment *att = ctx->ReadBuffer->Attachment;
+
+   /* If we don't know the framebuffer status, update it now */
+   if (ctx->ReadBuffer->_Status == 0) {
+      _mesa_test_framebuffer_completeness(ctx, ctx->ReadBuffer);
+   }
 
    if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
       return GL_FALSE;
@@ -745,41 +868,53 @@ _mesa_source_buffer_exists(GLcontext *ctx, GLenum format)
    case GL_LUMINANCE:
    case GL_LUMINANCE_ALPHA:
    case GL_INTENSITY:
+   case GL_RG:
    case GL_RGB:
    case GL_BGR:
    case GL_RGBA:
    case GL_BGRA:
    case GL_ABGR_EXT:
    case GL_COLOR_INDEX:
+   case GL_RED_INTEGER_EXT:
+   case GL_GREEN_INTEGER_EXT:
+   case GL_BLUE_INTEGER_EXT:
+   case GL_ALPHA_INTEGER_EXT:
+   case GL_RGB_INTEGER_EXT:
+   case GL_RGBA_INTEGER_EXT:
+   case GL_BGR_INTEGER_EXT:
+   case GL_BGRA_INTEGER_EXT:
+   case GL_LUMINANCE_INTEGER_EXT:
+   case GL_LUMINANCE_ALPHA_INTEGER_EXT:
       if (ctx->ReadBuffer->_ColorReadBuffer == NULL) {
          return GL_FALSE;
       }
-      /* XXX enable this post 6.5 release:
-      ASSERT(ctx->ReadBuffer->_ColorReadBuffer->RedBits > 0 ||
-             ctx->ReadBuffer->_ColorReadBuffer->IndexBits > 0);
-      */
+      ASSERT(_mesa_get_format_bits(ctx->ReadBuffer->_ColorReadBuffer->Format, GL_RED_BITS) > 0 ||
+             _mesa_get_format_bits(ctx->ReadBuffer->_ColorReadBuffer->Format, GL_ALPHA_BITS) > 0 ||
+             _mesa_get_format_bits(ctx->ReadBuffer->_ColorReadBuffer->Format, GL_INDEX_BITS) > 0);
       break;
    case GL_DEPTH:
    case GL_DEPTH_COMPONENT:
       if (!att[BUFFER_DEPTH].Renderbuffer) {
          return GL_FALSE;
       }
-      ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
+      /*ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);*/
       break;
    case GL_STENCIL:
    case GL_STENCIL_INDEX:
       if (!att[BUFFER_STENCIL].Renderbuffer) {
          return GL_FALSE;
       }
-      ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
+      /*ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);*/
       break;
    case GL_DEPTH_STENCIL_EXT:
       if (!att[BUFFER_DEPTH].Renderbuffer ||
           !att[BUFFER_STENCIL].Renderbuffer) {
          return GL_FALSE;
       }
+      /*
       ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
       ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
+      */
       break;
    default:
       _mesa_problem(ctx,
@@ -795,13 +930,17 @@ _mesa_source_buffer_exists(GLcontext *ctx, GLenum format)
 
 /**
  * As above, but for drawing operations.
- * XXX code do some code merging w/ above function.
+ * XXX could do some code merging w/ above function.
  */
 GLboolean
-_mesa_dest_buffer_exists(GLcontext *ctx, GLenum format)
+_mesa_dest_buffer_exists(struct gl_context *ctx, GLenum format)
 {
-   const struct gl_renderbuffer_attachment *att
-      = ctx->ReadBuffer->Attachment;
+   const struct gl_renderbuffer_attachment *att = ctx->DrawBuffer->Attachment;
+
+   /* If we don't know the framebuffer status, update it now */
+   if (ctx->DrawBuffer->_Status == 0) {
+      _mesa_test_framebuffer_completeness(ctx, ctx->DrawBuffer);
+   }
 
    if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
       return GL_FALSE;
@@ -822,7 +961,17 @@ _mesa_dest_buffer_exists(GLcontext *ctx, GLenum format)
    case GL_BGRA:
    case GL_ABGR_EXT:
    case GL_COLOR_INDEX:
-      /* nothing special */
+   case GL_RED_INTEGER_EXT:
+   case GL_GREEN_INTEGER_EXT:
+   case GL_BLUE_INTEGER_EXT:
+   case GL_ALPHA_INTEGER_EXT:
+   case GL_RGB_INTEGER_EXT:
+   case GL_RGBA_INTEGER_EXT:
+   case GL_BGR_INTEGER_EXT:
+   case GL_BGRA_INTEGER_EXT:
+   case GL_LUMINANCE_INTEGER_EXT:
+   case GL_LUMINANCE_ALPHA_INTEGER_EXT:
+      /* Nothing special since GL_DRAW_BUFFER could be GL_NONE. */
       /* Could assert that colorbuffer has RedBits > 0 */
       break;
    case GL_DEPTH:
@@ -830,26 +979,28 @@ _mesa_dest_buffer_exists(GLcontext *ctx, GLenum format)
       if (!att[BUFFER_DEPTH].Renderbuffer) {
          return GL_FALSE;
       }
-      ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
+      /*ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);*/
       break;
    case GL_STENCIL:
    case GL_STENCIL_INDEX:
       if (!att[BUFFER_STENCIL].Renderbuffer) {
          return GL_FALSE;
       }
-      ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
+      /*ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);*/
       break;
    case GL_DEPTH_STENCIL_EXT:
       if (!att[BUFFER_DEPTH].Renderbuffer ||
           !att[BUFFER_STENCIL].Renderbuffer) {
          return GL_FALSE;
       }
+      /*
       ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
       ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
+      */
       break;
    default:
       _mesa_problem(ctx,
-                    "Unexpected format 0x%x in _mesa_source_buffer_exists",
+                    "Unexpected format 0x%x in _mesa_dest_buffer_exists",
                     format);
       return GL_FALSE;
    }
@@ -857,3 +1008,77 @@ _mesa_dest_buffer_exists(GLcontext *ctx, GLenum format)
    /* OK */
    return GL_TRUE;
 }
+
+
+/**
+ * Used to answer the GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES query.
+ */
+GLenum
+_mesa_get_color_read_format(struct gl_context *ctx)
+{
+   switch (ctx->ReadBuffer->_ColorReadBuffer->Format) {
+   case MESA_FORMAT_ARGB8888:
+      return GL_BGRA;
+   case MESA_FORMAT_RGB565:
+      return GL_BGR;
+   default:
+      return GL_RGBA;
+   }
+}
+
+
+/**
+ * Used to answer the GL_IMPLEMENTATION_COLOR_READ_TYPE_OES query.
+ */
+GLenum
+_mesa_get_color_read_type(struct gl_context *ctx)
+{
+   switch (ctx->ReadBuffer->_ColorReadBuffer->Format) {
+   case MESA_FORMAT_ARGB8888:
+      return GL_UNSIGNED_BYTE;
+   case MESA_FORMAT_RGB565:
+      return GL_UNSIGNED_SHORT_5_6_5_REV;
+   default:
+      return GL_UNSIGNED_BYTE;
+   }
+}
+
+
+/**
+ * Print framebuffer info to stderr, for debugging.
+ */
+void
+_mesa_print_framebuffer(const struct gl_framebuffer *fb)
+{
+   GLuint i;
+
+   fprintf(stderr, "Mesa Framebuffer %u at %p\n", fb->Name, (void *) fb);
+   fprintf(stderr, "  Size: %u x %u  Status: %s\n", fb->Width, fb->Height,
+           _mesa_lookup_enum_by_nr(fb->_Status));
+   fprintf(stderr, "  Attachments:\n");
+
+   for (i = 0; i < BUFFER_COUNT; i++) {
+      const struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
+      if (att->Type == GL_TEXTURE) {
+         const struct gl_texture_image *texImage;
+         fprintf(stderr,
+                 "  %2d: Texture %u, level %u, face %u, slice %u, complete %d\n",
+                 i, att->Texture->Name, att->TextureLevel, att->CubeMapFace,
+                 att->Zoffset, att->Complete);
+         texImage = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
+         fprintf(stderr, "       Size: %u x %u x %u  Format %s\n",
+                 texImage->Width, texImage->Height, texImage->Depth,
+                 _mesa_get_format_name(texImage->TexFormat));
+      }
+      else if (att->Type == GL_RENDERBUFFER) {
+         fprintf(stderr, "  %2d: Renderbuffer %u, complete %d\n",
+                 i, att->Renderbuffer->Name, att->Complete);
+         fprintf(stderr, "       Size: %u x %u  Format %s\n",
+                 att->Renderbuffer->Width, att->Renderbuffer->Height,
+                 _mesa_get_format_name(att->Renderbuffer->Format));
+      }
+      else {
+         fprintf(stderr, "  %2d: none\n", i);
+      }
+   }
+}