Rework the GL_READ_BUFFER, GL_DRAW_BUFFER state repairs that Roland previously did.
[mesa.git] / src / mesa / main / context.c
index cc29f2cb992e423f1b97e7250e245b7d42732346..9ee7b4bec72b2070c514898367852490a9d132a0 100644 (file)
@@ -6,9 +6,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"),
@@ -79,6 +79,7 @@
 #include "glheader.h"
 #include "imports.h"
 #include "accum.h"
+#include "arrayobj.h"
 #include "attrib.h"
 #include "blend.h"
 #include "buffers.h"
@@ -94,9 +95,8 @@
 #include "fbobject.h"
 #include "feedback.h"
 #include "fog.h"
+#include "framebuffer.h"
 #include "get.h"
-#include "glthread.h"
-#include "glapioffsets.h"
 #include "histogram.h"
 #include "hint.h"
 #include "hash.h"
 #include "lines.h"
 #include "macros.h"
 #include "matrix.h"
-#include "occlude.h"
 #include "pixel.h"
 #include "points.h"
 #include "polygon.h"
-#if FEATURE_NV_vertex_program || FEATURE_NV_fragment_program
-#include "program.h"
-#endif
+#include "queryobj.h"
 #include "rastpos.h"
 #include "simple_list.h"
 #include "state.h"
 #include "varray.h"
 #include "version.h"
 #include "vtxfmt.h"
+#include "glapi/glthread.h"
+#include "glapi/glapioffsets.h"
+#if FEATURE_NV_vertex_program || FEATURE_NV_fragment_program
+#include "shader/program.h"
+#endif
+#include "shader/shader_api.h"
+#include "shader/atifragshader.h"
 #if _HAVE_FULL_GL
 #include "math/m_translate.h"
 #include "math/m_matrix.h"
 #include "math/m_xform.h"
 #include "math/mathmod.h"
 #endif
-#include "shaderobjects.h"
 
 #ifdef USE_SPARC_ASM
 #include "sparc/sparc.h"
@@ -151,171 +154,6 @@ static void
 free_shared_state( GLcontext *ctx, struct gl_shared_state *ss );
 
 
-/**********************************************************************/
-/** \name OpenGL SI-style interface (new in Mesa 3.5)
- *
- * \if subset
- * \note Most of these functions are never called in the Mesa subset.
- * \endif
- */
-/*@{*/
-
-/**
- * Destroy context callback.
- * 
- * \param gc context.
- * \return GL_TRUE on success, or GL_FALSE on failure.
- * 
- * \ifnot subset
- * Called by window system/device driver (via __GLexports::destroyCurrent) when
- * the rendering context is to be destroyed.
- * \endif
- *
- * Frees the context data and the context structure.
- */
-GLboolean
-_mesa_destroyContext(__GLcontext *gc)
-{
-   if (gc) {
-      _mesa_free_context_data(gc);
-      _mesa_free(gc);
-   }
-   return GL_TRUE;
-}
-
-/**
- * Unbind context callback.
- * 
- * \param gc context.
- * \return GL_TRUE on success, or GL_FALSE on failure.
- *
- * \ifnot subset
- * Called by window system/device driver (via __GLexports::loseCurrent)
- * when the rendering context is made non-current.
- * \endif
- *
- * No-op
- */
-GLboolean
-_mesa_loseCurrent(__GLcontext *gc)
-{
-   /* XXX unbind context from thread */
-   (void) gc;
-   return GL_TRUE;
-}
-
-/**
- * Bind context callback.
- * 
- * \param gc context.
- * \return GL_TRUE on success, or GL_FALSE on failure.
- *
- * \ifnot subset
- * Called by window system/device driver (via __GLexports::makeCurrent)
- * when the rendering context is made current.
- * \endif
- *
- * No-op
- */
-GLboolean
-_mesa_makeCurrent(__GLcontext *gc)
-{
-   /* XXX bind context to thread */
-   (void) gc;
-   return GL_TRUE;
-}
-
-/**
- * Share context callback.
- * 
- * \param gc context.
- * \param gcShare shared context.
- * \return GL_TRUE on success, or GL_FALSE on failure.
- *
- * \ifnot subset
- * Called by window system/device driver (via __GLexports::shareContext)
- * \endif
- *
- * Update the shared context reference count, gl_shared_state::RefCount.
- */
-GLboolean
-_mesa_shareContext(__GLcontext *gc, __GLcontext *gcShare)
-{
-   if (gc && gcShare && gc->Shared && gcShare->Shared) {
-      gc->Shared->RefCount--;
-      if (gc->Shared->RefCount == 0) {
-         free_shared_state(gc, gc->Shared);
-      }
-      gc->Shared = gcShare->Shared;
-      gc->Shared->RefCount++;
-      return GL_TRUE;
-   }
-   else {
-      return GL_FALSE;
-   }
-}
-
-
-#if _HAVE_FULL_GL
-/**
- * Copy context callback.
- */
-GLboolean
-_mesa_copyContext(__GLcontext *dst, const __GLcontext *src, GLuint mask)
-{
-   if (dst && src) {
-      _mesa_copy_context( src, dst, mask );
-      return GL_TRUE;
-   }
-   else {
-      return GL_FALSE;
-   }
-}
-#endif
-
-/** No-op */
-GLboolean
-_mesa_forceCurrent(__GLcontext *gc)
-{
-   (void) gc;
-   return GL_TRUE;
-}
-
-/**
- * Windows/buffer resizing notification callback.
- *
- * \param gc GL context.
- * \return GL_TRUE on success, or GL_FALSE on failure.
- */
-GLboolean
-_mesa_notifyResize(__GLcontext *gc)
-{
-   GLint x, y;
-   GLuint width, height;
-   __GLdrawablePrivate *d = gc->imports.getDrawablePrivate(gc);
-   if (!d || !d->getDrawableSize)
-      return GL_FALSE;
-   d->getDrawableSize( d, &x, &y, &width, &height );
-   /* update viewport, resize software buffers, etc. */
-   return GL_TRUE;
-}
-
-/**
- * Window/buffer destruction notification callback.
- *
- * \param gc GL context.
- * 
- * Called when the context's window/buffer is going to be destroyed. 
- *
- * No-op
- */
-void
-_mesa_notifyDestroy(__GLcontext *gc)
-{
-   /* Unbind from it. */
-   (void) gc;
-}
-
 /**
  * Swap buffers notification callback.
  * 
@@ -330,105 +168,6 @@ _mesa_notifySwapBuffers(__GLcontext *gc)
    FLUSH_VERTICES( gc, 0 );
 }
 
-/** No-op */
-struct __GLdispatchStateRec *
-_mesa_dispatchExec(__GLcontext *gc)
-{
-   (void) gc;
-   return NULL;
-}
-
-/** No-op */
-void
-_mesa_beginDispatchOverride(__GLcontext *gc)
-{
-   (void) gc;
-}
-
-/** No-op */
-void
-_mesa_endDispatchOverride(__GLcontext *gc)
-{
-   (void) gc;
-}
-
-/**
- * \ifnot subset
- * Setup the exports.  
- *
- * The window system will call these functions when it needs Mesa to do
- * something.
- * 
- * \note Device drivers should override these functions!  For example,
- * the Xlib driver should plug in the XMesa*-style functions into this
- * structure.  The XMesa-style functions should then call the _mesa_*
- * version of these functions.  This is an approximation to OO design
- * (inheritance and virtual functions).
- * \endif
- *
- * \if subset
- * No-op.
- * 
- * \endif
- */
-static void
-_mesa_init_default_exports(__GLexports *exports)
-{
-#if _HAVE_FULL_GL
-    exports->destroyContext = _mesa_destroyContext;
-    exports->loseCurrent = _mesa_loseCurrent;
-    exports->makeCurrent = _mesa_makeCurrent;
-    exports->shareContext = _mesa_shareContext;
-    exports->copyContext = _mesa_copyContext;
-    exports->forceCurrent = _mesa_forceCurrent;
-    exports->notifyResize = _mesa_notifyResize;
-    exports->notifyDestroy = _mesa_notifyDestroy;
-    exports->notifySwapBuffers = _mesa_notifySwapBuffers;
-    exports->dispatchExec = _mesa_dispatchExec;
-    exports->beginDispatchOverride = _mesa_beginDispatchOverride;
-    exports->endDispatchOverride = _mesa_endDispatchOverride;
-#else
-    (void) exports;
-#endif
-}
-
-/**
- * Exported OpenGL SI interface.
- */
-__GLcontext *
-__glCoreCreateContext(__GLimports *imports, __GLcontextModes *modes)
-{
-    GLcontext *ctx;
-
-    ctx = (GLcontext *) (*imports->calloc)(NULL, 1, sizeof(GLcontext));
-    if (ctx == NULL) {
-       return NULL;
-    }
-
-    /* XXX doesn't work at this time */
-    _mesa_initialize_context(ctx, modes, NULL, NULL, NULL);
-    ctx->imports = *imports;
-
-    return ctx;
-}
-
-/**
- * Exported OpenGL SI interface.
- */
-void
-__glCoreNopDispatch(void)
-{
-#if 0
-   /* SI */
-   __gl_dispatch = __glNopDispatchState;
-#else
-   /* Mesa */
-   _glapi_set_dispatch(NULL);
-#endif
-}
-
-/*@}*/
-
 
 /**********************************************************************/
 /** \name GL Visual allocation/destruction                            */
@@ -477,7 +216,7 @@ _mesa_create_visual( GLboolean rgbFlag,
                      GLint accumAlphaBits,
                      GLint numSamples )
 {
-   GLvisual *vis = (GLvisual *) CALLOC( sizeof(GLvisual) );
+   GLvisual *vis = (GLvisual *) _mesa_calloc(sizeof(GLvisual));
    if (vis) {
       if (!_mesa_initialize_visual(vis, rgbFlag, dbFlag, stereoFlag,
                                    redBits, greenBits, blueBits, alphaBits,
@@ -485,7 +224,7 @@ _mesa_create_visual( GLboolean rgbFlag,
                                    accumRedBits, accumGreenBits,
                                    accumBlueBits, accumAlphaBits,
                                    numSamples)) {
-         FREE(vis);
+         _mesa_free(vis);
          return NULL;
       }
    }
@@ -527,18 +266,10 @@ _mesa_initialize_visual( GLvisual *vis,
    if (stencilBits < 0 || stencilBits > STENCIL_BITS) {
       return GL_FALSE;
    }
-   if (accumRedBits < 0 || accumRedBits > ACCUM_BITS) {
-      return GL_FALSE;
-   }
-   if (accumGreenBits < 0 || accumGreenBits > ACCUM_BITS) {
-      return GL_FALSE;
-   }
-   if (accumBlueBits < 0 || accumBlueBits > ACCUM_BITS) {
-      return GL_FALSE;
-   }
-   if (accumAlphaBits < 0 || accumAlphaBits > ACCUM_BITS) {
-      return GL_FALSE;
-   }
+   assert(accumRedBits >= 0);
+   assert(accumGreenBits >= 0);
+   assert(accumBlueBits >= 0);
+   assert(accumAlphaBits >= 0);
 
    vis->rgbMode          = rgbFlag;
    vis->doubleBufferMode = dbFlag;
@@ -583,7 +314,7 @@ _mesa_initialize_visual( GLvisual *vis,
 void
 _mesa_destroy_visual( GLvisual *vis )
 {
-   FREE(vis);
+   _mesa_free(vis);
 }
 
 /*@}*/
@@ -612,7 +343,7 @@ _glthread_DECLARE_STATIC_MUTEX(OneTimeLock);
  * and sets the glapi callbacks if the \c MESA_DEBUG environment variable is
  * defined.
  *
- * \sa _mesa_init_lists(), _math_init().
+ * \sa _math_init().
  */
 static void
 one_time_init( GLcontext *ctx )
@@ -631,7 +362,7 @@ one_time_init( GLcontext *ctx )
       assert( sizeof(GLint) == 4 );
       assert( sizeof(GLuint) == 4 );
 
-      _mesa_init_lists();
+      _mesa_init_sqrt_table();
 
 #if _HAVE_FULL_GL
       _math_init();
@@ -700,14 +431,21 @@ alloc_shared_state( GLcontext *ctx )
       goto cleanup;
 #endif
 #if FEATURE_ATI_fragment_shader
-   ss->DefaultFragmentShader = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_SHADER_ATI, 0);
+   ss->ATIShaders = _mesa_NewHashTable();
+   ss->DefaultFragmentShader = _mesa_new_ati_fragment_shader(ctx, 0);
    if (!ss->DefaultFragmentShader)
       goto cleanup;
 #endif
 
+#if FEATURE_ARB_vertex_buffer_object || FEATURE_ARB_pixel_buffer_object
    ss->BufferObjects = _mesa_NewHashTable();
+#endif
 
-   ss->GL2Objects = _mesa_NewHashTable ();
+   ss->ArrayObjects = _mesa_NewHashTable();
+
+#if FEATURE_ARB_shader_objects
+   ss->ShaderObjects = _mesa_NewHashTable();
+#endif
 
    ss->Default1D = (*ctx->Driver.NewTextureObject)(ctx, 0, GL_TEXTURE_1D);
    if (!ss->Default1D)
@@ -729,12 +467,19 @@ alloc_shared_state( GLcontext *ctx )
    if (!ss->DefaultRect)
       goto cleanup;
 
-   /* Effectively bind the default textures to all texture units */
-   ss->Default1D->RefCount += MAX_TEXTURE_IMAGE_UNITS;
-   ss->Default2D->RefCount += MAX_TEXTURE_IMAGE_UNITS;
-   ss->Default3D->RefCount += MAX_TEXTURE_IMAGE_UNITS;
-   ss->DefaultCubeMap->RefCount += MAX_TEXTURE_IMAGE_UNITS;
-   ss->DefaultRect->RefCount += MAX_TEXTURE_IMAGE_UNITS;
+   ss->Default1DArray = (*ctx->Driver.NewTextureObject)(ctx, 0, GL_TEXTURE_1D_ARRAY_EXT);
+   if (!ss->Default1DArray)
+      goto cleanup;
+
+   ss->Default2DArray = (*ctx->Driver.NewTextureObject)(ctx, 0, GL_TEXTURE_2D_ARRAY_EXT);
+   if (!ss->Default2DArray)
+      goto cleanup;
+
+   /* sanity check */
+   assert(ss->Default1D->RefCount == 1);
+
+   _glthread_INIT_MUTEX(ss->TexMutex);
+   ss->TextureStateStamp = 0;
 
 #if FEATURE_EXT_framebuffer_object
    ss->FrameBuffers = _mesa_NewHashTable();
@@ -745,10 +490,9 @@ alloc_shared_state( GLcontext *ctx )
       goto cleanup;
 #endif
 
-
    return GL_TRUE;
 
- cleanup:
+cleanup:
    /* Ran out of memory at some point.  Free everything and return NULL */
    if (ss->DisplayList)
       _mesa_DeleteHashTable(ss->DisplayList);
@@ -768,15 +512,20 @@ alloc_shared_state( GLcontext *ctx )
 #endif
 #if FEATURE_ATI_fragment_shader
    if (ss->DefaultFragmentShader)
-      ctx->Driver.DeleteProgram(ctx, ss->DefaultFragmentShader);
+      _mesa_delete_ati_fragment_shader(ctx, ss->DefaultFragmentShader);
 #endif
-#if FEATURE_ARB_vertex_buffer_object
+#if FEATURE_ARB_vertex_buffer_object || FEATURE_ARB_pixel_buffer_object
    if (ss->BufferObjects)
       _mesa_DeleteHashTable(ss->BufferObjects);
 #endif
 
-   if (ss->GL2Objects)
-      _mesa_DeleteHashTable (ss->GL2Objects);
+   if (ss->ArrayObjects)
+      _mesa_DeleteHashTable (ss->ArrayObjects);
+
+#if FEATURE_ARB_shader_objects
+   if (ss->ShaderObjects)
+      _mesa_DeleteHashTable (ss->ShaderObjects);
+#endif
 
 #if FEATURE_EXT_framebuffer_object
    if (ss->FrameBuffers)
@@ -795,13 +544,132 @@ alloc_shared_state( GLcontext *ctx )
       (*ctx->Driver.DeleteTexture)(ctx, ss->DefaultCubeMap);
    if (ss->DefaultRect)
       (*ctx->Driver.DeleteTexture)(ctx, ss->DefaultRect);
+   if (ss->Default1DArray)
+      (*ctx->Driver.DeleteTexture)(ctx, ss->Default1DArray);
+   if (ss->Default2DArray)
+      (*ctx->Driver.DeleteTexture)(ctx, ss->Default2DArray);
    if (ss)
       _mesa_free(ss);
    return GL_FALSE;
 }
 
+
 /**
- * Deallocate a shared state context and all children structures.
+ * Callback for deleting a display list.  Called by _mesa_HashDeleteAll().
+ */
+static void
+delete_displaylist_cb(GLuint id, void *data, void *userData)
+{
+   struct mesa_display_list *list = (struct mesa_display_list *) data;
+   GLcontext *ctx = (GLcontext *) userData;
+   _mesa_delete_list(ctx, list);
+}
+
+/**
+ * Callback for deleting a texture object.  Called by _mesa_HashDeleteAll().
+ */
+static void
+delete_texture_cb(GLuint id, void *data, void *userData)
+{
+   struct gl_texture_object *texObj = (struct gl_texture_object *) data;
+   GLcontext *ctx = (GLcontext *) userData;
+   ctx->Driver.DeleteTexture(ctx, texObj);
+}
+
+/**
+ * Callback for deleting a program object.  Called by _mesa_HashDeleteAll().
+ */
+static void
+delete_program_cb(GLuint id, void *data, void *userData)
+{
+   struct gl_program *prog = (struct gl_program *) data;
+   GLcontext *ctx = (GLcontext *) userData;
+   ctx->Driver.DeleteProgram(ctx, prog);
+}
+
+/**
+ * Callback for deleting an ATI fragment shader object.
+ * Called by _mesa_HashDeleteAll().
+ */
+static void
+delete_fragshader_cb(GLuint id, void *data, void *userData)
+{
+   struct ati_fragment_shader *shader = (struct ati_fragment_shader *) data;
+   GLcontext *ctx = (GLcontext *) userData;
+   _mesa_delete_ati_fragment_shader(ctx, shader);
+}
+
+/**
+ * Callback for deleting a buffer object.  Called by _mesa_HashDeleteAll().
+ */
+static void
+delete_bufferobj_cb(GLuint id, void *data, void *userData)
+{
+   struct gl_buffer_object *bufObj = (struct gl_buffer_object *) data;
+   GLcontext *ctx = (GLcontext *) userData;
+   ctx->Driver.DeleteBuffer(ctx, bufObj);
+}
+
+/**
+ * Callback for deleting an array object.  Called by _mesa_HashDeleteAll().
+ */
+static void
+delete_arrayobj_cb(GLuint id, void *data, void *userData)
+{
+   struct gl_array_object *arrayObj = (struct gl_array_object *) data;
+   GLcontext *ctx = (GLcontext *) userData;
+   _mesa_delete_array_object(ctx, arrayObj);
+}
+
+/**
+ * Callback for deleting shader and shader programs objects.
+ * Called by _mesa_HashDeleteAll().
+ */
+static void
+delete_shader_cb(GLuint id, void *data, void *userData)
+{
+   GLcontext *ctx = (GLcontext *) userData;
+   struct gl_shader *sh = (struct gl_shader *) data;
+   if (sh->Type == GL_FRAGMENT_SHADER || sh->Type == GL_VERTEX_SHADER) {
+      _mesa_free_shader(ctx, sh);
+   }
+   else {
+      struct gl_shader_program *shProg = (struct gl_shader_program *) data;
+      ASSERT(shProg->Type == GL_SHADER_PROGRAM_MESA);
+      _mesa_free_shader_program(ctx, shProg);
+   }
+}
+
+/**
+ * Callback for deleting a framebuffer object.  Called by _mesa_HashDeleteAll()
+ */
+static void
+delete_framebuffer_cb(GLuint id, void *data, void *userData)
+{
+   struct gl_framebuffer *fb = (struct gl_framebuffer *) data;
+   /* The fact that the framebuffer is in the hashtable means its refcount
+    * is one, but we're removing from the hashtable now.  So clear refcount.
+    */
+   /*assert(fb->RefCount == 1);*/
+   fb->RefCount = 0;
+   fb->Delete(fb);
+}
+
+/**
+ * Callback for deleting a renderbuffer object. Called by _mesa_HashDeleteAll()
+ */
+static void
+delete_renderbuffer_cb(GLuint id, void *data, void *userData)
+{
+   struct gl_renderbuffer *rb = (struct gl_renderbuffer *) data;
+   rb->RefCount = 0;  /* see comment for FBOs above */
+   rb->Delete(rb);
+}
+
+
+
+/**
+ * Deallocate a shared state object and all children structures.
  *
  * \param ctx GL context.
  * \param ss shared state pointer.
@@ -815,57 +683,14 @@ alloc_shared_state( GLcontext *ctx )
 static void
 free_shared_state( GLcontext *ctx, struct gl_shared_state *ss )
 {
-   /* Free display lists */
-   while (1) {
-      GLuint list = _mesa_HashFirstEntry(ss->DisplayList);
-      if (list) {
-         _mesa_destroy_list(ctx, list);
-      }
-      else {
-         break;
-      }
-   }
+   /*
+    * Free display lists
+    */
+   _mesa_HashDeleteAll(ss->DisplayList, delete_displaylist_cb, ctx);
    _mesa_DeleteHashTable(ss->DisplayList);
 
-   /* Free texture objects */
-   ASSERT(ctx->Driver.DeleteTexture);
-   /* the default textures */
-   (*ctx->Driver.DeleteTexture)(ctx, ss->Default1D);
-   (*ctx->Driver.DeleteTexture)(ctx, ss->Default2D);
-   (*ctx->Driver.DeleteTexture)(ctx, ss->Default3D);
-   (*ctx->Driver.DeleteTexture)(ctx, ss->DefaultCubeMap);
-   (*ctx->Driver.DeleteTexture)(ctx, ss->DefaultRect);
-   /* all other textures */
-   while (1) {
-      GLuint texName = _mesa_HashFirstEntry(ss->TexObjects);
-      if (texName) {
-         struct gl_texture_object *texObj = (struct gl_texture_object *)
-            _mesa_HashLookup(ss->TexObjects, texName);
-         ASSERT(texObj);
-         (*ctx->Driver.DeleteTexture)(ctx, texObj);
-         _mesa_HashRemove(ss->TexObjects, texName);
-      }
-      else {
-         break;
-      }
-   }
-   _mesa_DeleteHashTable(ss->TexObjects);
-
-#if FEATURE_NV_vertex_program
-   /* Free vertex programs */
-   while (1) {
-      GLuint prog = _mesa_HashFirstEntry(ss->Programs);
-      if (prog) {
-         struct program *p = (struct program *) _mesa_HashLookup(ss->Programs,
-                                                                 prog);
-         ASSERT(p);
-         ctx->Driver.DeleteProgram(ctx, p);
-         _mesa_HashRemove(ss->Programs, prog);
-      }
-      else {
-         break;
-      }
-   }
+#if defined(FEATURE_NV_vertex_program) || defined(FEATURE_NV_fragment_program)
+   _mesa_HashDeleteAll(ss->Programs, delete_program_cb, ctx);
    _mesa_DeleteHashTable(ss->Programs);
 #endif
 #if FEATURE_ARB_vertex_program
@@ -874,24 +699,53 @@ free_shared_state( GLcontext *ctx, struct gl_shared_state *ss )
 #if FEATURE_ARB_fragment_program
    _mesa_delete_program(ctx, ss->DefaultFragmentProgram);
 #endif
+
 #if FEATURE_ATI_fragment_shader
-   _mesa_delete_program(ctx, ss->DefaultFragmentShader);
+   _mesa_HashDeleteAll(ss->ATIShaders, delete_fragshader_cb, ctx);
+   _mesa_DeleteHashTable(ss->ATIShaders);
+   _mesa_delete_ati_fragment_shader(ctx, ss->DefaultFragmentShader);
 #endif
 
-#if FEATURE_ARB_vertex_buffer_object
+#if FEATURE_ARB_vertex_buffer_object || FEATURE_ARB_pixel_buffer_object
+   _mesa_HashDeleteAll(ss->BufferObjects, delete_bufferobj_cb, ctx);
    _mesa_DeleteHashTable(ss->BufferObjects);
 #endif
 
-   _mesa_DeleteHashTable (ss->GL2Objects);
+   _mesa_HashDeleteAll(ss->ArrayObjects, delete_arrayobj_cb, ctx);
+   _mesa_DeleteHashTable(ss->ArrayObjects);
+
+#if FEATURE_ARB_shader_objects
+   _mesa_HashDeleteAll(ss->ShaderObjects, delete_shader_cb, ctx);
+   _mesa_DeleteHashTable(ss->ShaderObjects);
+#endif
 
 #if FEATURE_EXT_framebuffer_object
+   _mesa_HashDeleteAll(ss->FrameBuffers, delete_framebuffer_cb, ctx);
    _mesa_DeleteHashTable(ss->FrameBuffers);
+   _mesa_HashDeleteAll(ss->RenderBuffers, delete_renderbuffer_cb, ctx);
    _mesa_DeleteHashTable(ss->RenderBuffers);
 #endif
 
+   /*
+    * Free texture objects (after FBOs since some textures might have
+    * been bound to FBOs).
+    */
+   ASSERT(ctx->Driver.DeleteTexture);
+   /* the default textures */
+   ctx->Driver.DeleteTexture(ctx, ss->Default1D);
+   ctx->Driver.DeleteTexture(ctx, ss->Default2D);
+   ctx->Driver.DeleteTexture(ctx, ss->Default3D);
+   ctx->Driver.DeleteTexture(ctx, ss->DefaultCubeMap);
+   ctx->Driver.DeleteTexture(ctx, ss->DefaultRect);
+   ctx->Driver.DeleteTexture(ctx, ss->Default1DArray);
+   ctx->Driver.DeleteTexture(ctx, ss->Default2DArray);
+   /* all other textures */
+   _mesa_HashDeleteAll(ss->TexObjects, delete_texture_cb, ctx);
+   _mesa_DeleteHashTable(ss->TexObjects);
+
    _glthread_DESTROY_MUTEX(ss->Mutex);
 
-   FREE(ss);
+   _mesa_free(ss);
 }
 
 
@@ -899,23 +753,39 @@ free_shared_state( GLcontext *ctx, struct gl_shared_state *ss )
  * Initialize fields of gl_current_attrib (aka ctx->Current.*)
  */
 static void
-_mesa_init_current( GLcontext *ctx )
+_mesa_init_current(GLcontext *ctx)
 {
    GLuint i;
 
-   /* Current group */
+   /* Init all to (0,0,0,1) */
    for (i = 0; i < VERT_ATTRIB_MAX; i++) {
       ASSIGN_4V( ctx->Current.Attrib[i], 0.0, 0.0, 0.0, 1.0 );
    }
-   /* special cases: */
+
+   /* redo special cases: */
    ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_WEIGHT], 1.0, 0.0, 0.0, 1.0 );
    ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_NORMAL], 0.0, 0.0, 1.0, 1.0 );
    ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR0], 1.0, 1.0, 1.0, 1.0 );
    ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR1], 0.0, 0.0, 0.0, 1.0 );
-   ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_FOG], 0.0, 0.0, 0.0, 0.0 );
+   ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR_INDEX], 1.0, 0.0, 0.0, 1.0 );
+   ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_EDGEFLAG], 1.0, 0.0, 0.0, 1.0 );
+}
 
-   ctx->Current.Index = 1;
-   ctx->Current.EdgeFlag = GL_TRUE;
+
+/**
+ * Init vertex/fragment program native limits from logical limits.
+ */
+static void
+init_natives(struct gl_program_constants *prog)
+{
+   prog->MaxNativeInstructions = prog->MaxInstructions;
+   prog->MaxNativeAluInstructions = prog->MaxAluInstructions;
+   prog->MaxNativeTexInstructions = prog->MaxTexInstructions;
+   prog->MaxNativeTexIndirections = prog->MaxTexIndirections;
+   prog->MaxNativeAttribs = prog->MaxAttribs;
+   prog->MaxNativeTemps = prog->MaxTemps;
+   prog->MaxNativeAddressRegs = prog->MaxAddressRegs;
+   prog->MaxNativeParameters = prog->MaxParameters;
 }
 
 
@@ -925,21 +795,26 @@ _mesa_init_current( GLcontext *ctx )
  * some of these values (such as number of texture units).
  */
 static void 
-_mesa_init_constants( GLcontext *ctx )
+_mesa_init_constants(GLcontext *ctx)
 {
    assert(ctx);
 
    assert(MAX_TEXTURE_LEVELS >= MAX_3D_TEXTURE_LEVELS);
    assert(MAX_TEXTURE_LEVELS >= MAX_CUBE_TEXTURE_LEVELS);
 
+   assert(MAX_TEXTURE_UNITS >= MAX_TEXTURE_COORD_UNITS);
+   assert(MAX_TEXTURE_UNITS >= MAX_TEXTURE_IMAGE_UNITS);
+
    /* Constants, may be overriden (usually only reduced) by device drivers */
    ctx->Const.MaxTextureLevels = MAX_TEXTURE_LEVELS;
    ctx->Const.Max3DTextureLevels = MAX_3D_TEXTURE_LEVELS;
    ctx->Const.MaxCubeTextureLevels = MAX_CUBE_TEXTURE_LEVELS;
    ctx->Const.MaxTextureRectSize = MAX_TEXTURE_RECT_SIZE;
-   ctx->Const.MaxTextureUnits = MAX_TEXTURE_UNITS;
+   ctx->Const.MaxArrayTextureLayers = MAX_ARRAY_TEXTURE_LAYERS;
    ctx->Const.MaxTextureCoordUnits = MAX_TEXTURE_COORD_UNITS;
    ctx->Const.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
+   ctx->Const.MaxTextureUnits = MIN2(ctx->Const.MaxTextureCoordUnits,
+                                     ctx->Const.MaxTextureImageUnits);
    ctx->Const.MaxTextureMaxAnisotropy = MAX_TEXTURE_MAX_ANISOTROPY;
    ctx->Const.MaxTextureLodBias = MAX_TEXTURE_LOD_BIAS;
    ctx->Const.MaxArrayLockSize = MAX_ARRAY_LOCK_SIZE;
@@ -964,37 +839,41 @@ _mesa_init_constants( GLcontext *ctx )
    ctx->Const.MaxViewportWidth = MAX_WIDTH;
    ctx->Const.MaxViewportHeight = MAX_HEIGHT;
 #if FEATURE_ARB_vertex_program
-   ctx->Const.MaxVertexProgramInstructions = MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS;
-   ctx->Const.MaxVertexProgramAttribs = MAX_NV_VERTEX_PROGRAM_INPUTS;
-   ctx->Const.MaxVertexProgramTemps = MAX_NV_VERTEX_PROGRAM_TEMPS;
-   ctx->Const.MaxVertexProgramLocalParams = MAX_NV_VERTEX_PROGRAM_PARAMS;
-   ctx->Const.MaxVertexProgramEnvParams = MAX_NV_VERTEX_PROGRAM_PARAMS;/*XXX*/
-   ctx->Const.MaxVertexProgramAddressRegs = MAX_VERTEX_PROGRAM_ADDRESS_REGS;
+   ctx->Const.VertexProgram.MaxInstructions = MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS;
+   ctx->Const.VertexProgram.MaxAluInstructions = 0;
+   ctx->Const.VertexProgram.MaxTexInstructions = 0;
+   ctx->Const.VertexProgram.MaxTexIndirections = 0;
+   ctx->Const.VertexProgram.MaxAttribs = MAX_NV_VERTEX_PROGRAM_INPUTS;
+   ctx->Const.VertexProgram.MaxTemps = MAX_PROGRAM_TEMPS;
+   ctx->Const.VertexProgram.MaxParameters = MAX_NV_VERTEX_PROGRAM_PARAMS;
+   ctx->Const.VertexProgram.MaxLocalParams = MAX_PROGRAM_LOCAL_PARAMS;
+   ctx->Const.VertexProgram.MaxEnvParams = MAX_PROGRAM_ENV_PARAMS;
+   ctx->Const.VertexProgram.MaxAddressRegs = MAX_VERTEX_PROGRAM_ADDRESS_REGS;
+   ctx->Const.VertexProgram.MaxUniformComponents = 4 * MAX_UNIFORMS;
+   init_natives(&ctx->Const.VertexProgram);
 #endif
+
 #if FEATURE_ARB_fragment_program
-   ctx->Const.MaxFragmentProgramInstructions = MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS;
-   ctx->Const.MaxFragmentProgramAttribs = MAX_NV_FRAGMENT_PROGRAM_INPUTS;
-   ctx->Const.MaxFragmentProgramTemps = MAX_NV_FRAGMENT_PROGRAM_TEMPS;
-   ctx->Const.MaxFragmentProgramLocalParams = MAX_NV_FRAGMENT_PROGRAM_PARAMS;
-   ctx->Const.MaxFragmentProgramEnvParams = MAX_NV_FRAGMENT_PROGRAM_PARAMS;/*XXX*/
-   ctx->Const.MaxFragmentProgramAddressRegs = MAX_FRAGMENT_PROGRAM_ADDRESS_REGS;
-   ctx->Const.MaxFragmentProgramAluInstructions = MAX_FRAGMENT_PROGRAM_ALU_INSTRUCTIONS;
-   ctx->Const.MaxFragmentProgramTexInstructions = MAX_FRAGMENT_PROGRAM_TEX_INSTRUCTIONS;
-   ctx->Const.MaxFragmentProgramTexIndirections = MAX_FRAGMENT_PROGRAM_TEX_INDIRECTIONS;
+   ctx->Const.FragmentProgram.MaxInstructions = MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS;
+   ctx->Const.FragmentProgram.MaxAluInstructions = MAX_FRAGMENT_PROGRAM_ALU_INSTRUCTIONS;
+   ctx->Const.FragmentProgram.MaxTexInstructions = MAX_FRAGMENT_PROGRAM_TEX_INSTRUCTIONS;
+   ctx->Const.FragmentProgram.MaxTexIndirections = MAX_FRAGMENT_PROGRAM_TEX_INDIRECTIONS;
+   ctx->Const.FragmentProgram.MaxAttribs = MAX_NV_FRAGMENT_PROGRAM_INPUTS;
+   ctx->Const.FragmentProgram.MaxTemps = MAX_PROGRAM_TEMPS;
+   ctx->Const.FragmentProgram.MaxParameters = MAX_NV_FRAGMENT_PROGRAM_PARAMS;
+   ctx->Const.FragmentProgram.MaxLocalParams = MAX_PROGRAM_LOCAL_PARAMS;
+   ctx->Const.FragmentProgram.MaxEnvParams = MAX_PROGRAM_ENV_PARAMS;
+   ctx->Const.FragmentProgram.MaxAddressRegs = MAX_FRAGMENT_PROGRAM_ADDRESS_REGS;
+   ctx->Const.FragmentProgram.MaxUniformComponents = 4 * MAX_UNIFORMS;
+   init_natives(&ctx->Const.FragmentProgram);
 #endif
-
    ctx->Const.MaxProgramMatrices = MAX_PROGRAM_MATRICES;
    ctx->Const.MaxProgramMatrixStackDepth = MAX_PROGRAM_MATRIX_STACK_DEPTH;
 
-   /* If we're running in the X server, do bounds checking to prevent
-    * segfaults and server crashes!
-    */
-#if defined(XFree86LOADER) && defined(IN_MODULE)
-   ctx->Const.CheckArrayBounds = GL_TRUE;
-#else
+   /* CheckArrayBounds is overriden by drivers/x11 for X server */
    ctx->Const.CheckArrayBounds = GL_FALSE;
-#endif
 
+   /* GL_ARB_draw_buffers */
    ctx->Const.MaxDrawBuffers = MAX_DRAW_BUFFERS;
 
    /* GL_OES_read_format */
@@ -1006,8 +885,50 @@ _mesa_init_constants( GLcontext *ctx )
    ctx->Const.MaxRenderbufferSize = MAX_WIDTH;
 #endif
 
+#if FEATURE_ARB_vertex_shader
+   ctx->Const.MaxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS;
+   ctx->Const.MaxVarying = MAX_VARYING;
+#endif
+
    /* sanity checks */
-   ASSERT(ctx->Const.MaxTextureUnits == MAX2(ctx->Const.MaxTextureImageUnits, ctx->Const.MaxTextureCoordUnits));
+   ASSERT(ctx->Const.MaxTextureUnits == MIN2(ctx->Const.MaxTextureImageUnits,
+                                             ctx->Const.MaxTextureCoordUnits));
+   ASSERT(ctx->Const.FragmentProgram.MaxLocalParams <= MAX_PROGRAM_LOCAL_PARAMS);
+   ASSERT(ctx->Const.VertexProgram.MaxLocalParams <= MAX_PROGRAM_LOCAL_PARAMS);
+
+   ASSERT(MAX_NV_FRAGMENT_PROGRAM_TEMPS <= MAX_PROGRAM_TEMPS);
+   ASSERT(MAX_NV_VERTEX_PROGRAM_TEMPS <= MAX_PROGRAM_TEMPS);
+   ASSERT(MAX_NV_VERTEX_PROGRAM_INPUTS <= VERT_ATTRIB_MAX);
+   ASSERT(MAX_NV_VERTEX_PROGRAM_OUTPUTS <= VERT_RESULT_MAX);
+}
+
+
+/**
+ * Do some sanity checks on the limits/constants for the given context.
+ * Only called the first time a context is bound.
+ */
+static void
+check_context_limits(GLcontext *ctx)
+{
+   /* Many context limits/constants are limited by the size of
+    * internal arrays.
+    */
+   assert(ctx->Const.MaxTextureImageUnits <= MAX_TEXTURE_IMAGE_UNITS);
+   assert(ctx->Const.MaxTextureCoordUnits <= MAX_TEXTURE_COORD_UNITS);
+   assert(ctx->Const.MaxTextureUnits <= MAX_TEXTURE_IMAGE_UNITS);
+   assert(ctx->Const.MaxTextureUnits <= MAX_TEXTURE_COORD_UNITS);
+
+   assert(ctx->Const.MaxViewportWidth <= MAX_WIDTH);
+   assert(ctx->Const.MaxViewportHeight <= MAX_WIDTH);
+
+   /* make sure largest texture image is <= MAX_WIDTH in size */
+   assert((1 << (ctx->Const.MaxTextureLevels -1 )) <= MAX_WIDTH);
+   assert((1 << (ctx->Const.MaxCubeTextureLevels -1 )) <= MAX_WIDTH);
+   assert((1 << (ctx->Const.Max3DTextureLevels -1 )) <= MAX_WIDTH);
+
+   assert(ctx->Const.MaxDrawBuffers <= MAX_DRAW_BUFFERS);
+
+   /* XXX probably add more tests */
 }
 
 
@@ -1020,7 +941,7 @@ _mesa_init_constants( GLcontext *ctx )
  * functions for the more complex data structures.
  */
 static GLboolean
-init_attrib_groups( GLcontext *ctx )
+init_attrib_groups(GLcontext *ctx)
 {
    assert(ctx);
 
@@ -1056,7 +977,7 @@ init_attrib_groups( GLcontext *ctx )
    _mesa_init_query( ctx );
    _mesa_init_rastpos( ctx );
    _mesa_init_scissor( ctx );
-   _mesa_init_shaderobjects (ctx);
+   _mesa_init_shader_state( ctx );
    _mesa_init_stencil( ctx );
    _mesa_init_transform( ctx );
    _mesa_init_varray( ctx );
@@ -1072,12 +993,6 @@ init_attrib_groups( GLcontext *ctx )
    ctx->NewState = _NEW_ALL;
    ctx->ErrorValue = (GLenum) GL_NO_ERROR;
    ctx->_Facing = 0;
-#if CHAN_TYPE == GL_FLOAT
-   ctx->ClampFragmentColors = GL_FALSE; /* XXX temporary */
-#else
-   ctx->ClampFragmentColors = GL_TRUE;
-#endif
-   ctx->ClampVertexColors = GL_TRUE;
 
    return GL_TRUE;
 }
@@ -1091,7 +1006,7 @@ init_attrib_groups( GLcontext *ctx )
 static int
 generic_nop(void)
 {
-   _mesa_problem(NULL, "User called no-op dispatch function (an unsupported extension function?)");
+   _mesa_warning(NULL, "User called no-op dispatch function (an unsupported extension function?)");
    return 0;
 }
 
@@ -1149,24 +1064,16 @@ alloc_dispatch_table(void)
  * \param driverContext pointer to driver-specific context data
  */
 GLboolean
-_mesa_initialize_context( GLcontext *ctx,
-                          const GLvisual *visual,
-                          GLcontext *share_list,
-                          const struct dd_function_table *driverFunctions,
-                          void *driverContext )
+_mesa_initialize_context(GLcontext *ctx,
+                         const GLvisual *visual,
+                         GLcontext *share_list,
+                         const struct dd_function_table *driverFunctions,
+                         void *driverContext)
 {
    ASSERT(driverContext);
    assert(driverFunctions->NewTextureObject);
    assert(driverFunctions->FreeTexImageData);
 
-   /* If the driver wants core Mesa to use special imports, it'll have to
-    * override these defaults.
-    */
-   _mesa_init_default_imports( &(ctx->imports), driverContext );
-
-   /* initialize the exports (Mesa functions called by the window system) */
-   _mesa_init_default_exports( &(ctx->exports) );
-
    /* misc one-time initializations */
    one_time_init(ctx);
 
@@ -1222,8 +1129,16 @@ _mesa_initialize_context( GLcontext *ctx,
    ctx->TnlModule.SwapCount = 0;
 #endif
 
-   ctx->_MaintainTexEnvProgram = (_mesa_getenv("MESA_TEX_PROG") != NULL);
-   ctx->_MaintainTnlProgram = (_mesa_getenv("MESA_TNL_PROG") != NULL);
+   ctx->FragmentProgram._MaintainTexEnvProgram
+      = (_mesa_getenv("MESA_TEX_PROG") != NULL);
+   ctx->FragmentProgram._UseTexEnvProgram = ctx->FragmentProgram._MaintainTexEnvProgram;
+
+   ctx->VertexProgram._MaintainTnlProgram
+      = (_mesa_getenv("MESA_TNL_PROG") != NULL);
+   if (ctx->VertexProgram._MaintainTnlProgram) {
+      /* this is required... */
+      ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE;
+   }
 
    ctx->FirstTimeCurrent = GL_TRUE;
 
@@ -1246,11 +1161,10 @@ _mesa_initialize_context( GLcontext *ctx,
  * \return pointer to a new __GLcontextRec or NULL if error.
  */
 GLcontext *
-_mesa_create_context( const GLvisual *visual,
-                      GLcontext *share_list,
-                      const struct dd_function_table *driverFunctions,
-                      void *driverContext )
-
+_mesa_create_context(const GLvisual *visual,
+                     GLcontext *share_list,
+                     const struct dd_function_table *driverFunctions,
+                     void *driverContext)
 {
    GLcontext *ctx;
 
@@ -1282,11 +1196,20 @@ _mesa_create_context( const GLvisual *visual,
 void
 _mesa_free_context_data( GLcontext *ctx )
 {
-   /* if we're destroying the current context, unbind it first */
-   if (ctx == _mesa_get_current_context()) {
-      _mesa_make_current(NULL, NULL, NULL);
+   if (!_mesa_get_current_context()){
+      /* No current context, but we may need one in order to delete
+       * texture objs, etc.  So temporarily bind the context now.
+       */
+      _mesa_make_current(ctx, NULL, NULL);
    }
 
+   /* unreference WinSysDraw/Read buffers */
+   _mesa_unreference_framebuffer(&ctx->WinSysDrawBuffer);
+   _mesa_unreference_framebuffer(&ctx->WinSysReadBuffer);
+   _mesa_unreference_framebuffer(&ctx->DrawBuffer);
+   _mesa_unreference_framebuffer(&ctx->ReadBuffer);
+
+   _mesa_free_attrib_data(ctx);
    _mesa_free_lighting_data( ctx );
    _mesa_free_eval_data( ctx );
    _mesa_free_texture_data( ctx );
@@ -1294,11 +1217,13 @@ _mesa_free_context_data( GLcontext *ctx )
    _mesa_free_viewport_data( ctx );
    _mesa_free_colortables_data( ctx );
    _mesa_free_program_data(ctx);
+   _mesa_free_shader_state(ctx);
    _mesa_free_query_data(ctx);
 
 #if FEATURE_ARB_vertex_buffer_object
    _mesa_delete_buffer_object(ctx, ctx->Array.NullBufferObj);
 #endif
+   _mesa_delete_array_object(ctx, ctx->Array.DefaultArrayObj);
 
    /* free dispatch tables */
    _mesa_free(ctx->Exec);
@@ -1315,7 +1240,12 @@ _mesa_free_context_data( GLcontext *ctx )
    }
 
    if (ctx->Extensions.String)
-      FREE((void *) ctx->Extensions.String);
+      _mesa_free((void *) ctx->Extensions.String);
+
+   /* unbind the context if it's currently bound */
+   if (ctx == _mesa_get_current_context()) {
+      _mesa_make_current(NULL, NULL, NULL);
+   }
 }
 
 
@@ -1331,7 +1261,7 @@ _mesa_destroy_context( GLcontext *ctx )
 {
    if (ctx) {
       _mesa_free_context_data(ctx);
-      FREE( (void *) ctx );
+      _mesa_free( (void *) ctx );
    }
 }
 
@@ -1386,7 +1316,7 @@ _mesa_copy_context( const GLcontext *src, GLcontext *dst, GLuint mask )
    if (mask & GL_LIGHTING_BIT) {
       GLuint i;
       /* begin with memcpy */
-      MEMCPY( &dst->Light, &src->Light, sizeof(struct gl_light) );
+      dst->Light = src->Light;
       /* fixup linked lists to prevent pointer insanity */
       make_empty_list( &(dst->Light.EnabledList) );
       for (i = 0; i < MAX_LIGHTS; i++) {
@@ -1461,6 +1391,11 @@ _mesa_copy_context( const GLcontext *src, GLcontext *dst, GLuint mask )
 /**
  * Check if the given context can render into the given framebuffer
  * by checking visual attributes.
+ *
+ * Most of these tests could go away because Mesa is now pretty flexible
+ * in terms of mixing rendering contexts with framebuffers.  As long
+ * as RGB vs. CI mode agree, we're probably good.
+ *
  * \return GL_TRUE if compatible, GL_FALSE otherwise.
  */
 static GLboolean 
@@ -1474,8 +1409,11 @@ check_compatible(const GLcontext *ctx, const GLframebuffer *buffer)
 
    if (ctxvis->rgbMode != bufvis->rgbMode)
       return GL_FALSE;
+#if 0
+   /* disabling this fixes the fgl_glxgears pbuffer demo */
    if (ctxvis->doubleBufferMode && !bufvis->doubleBufferMode)
       return GL_FALSE;
+#endif
    if (ctxvis->stereoMode && !bufvis->stereoMode)
       return GL_FALSE;
    if (ctxvis->haveAccumBuffer && !bufvis->haveAccumBuffer)
@@ -1490,8 +1428,11 @@ check_compatible(const GLcontext *ctx, const GLframebuffer *buffer)
       return GL_FALSE;
    if (ctxvis->blueMask && ctxvis->blueMask != bufvis->blueMask)
       return GL_FALSE;
+#if 0
+   /* disabled (see bug 11161) */
    if (ctxvis->depthBits && ctxvis->depthBits != bufvis->depthBits)
       return GL_FALSE;
+#endif
    if (ctxvis->stencilBits && ctxvis->stencilBits != bufvis->stencilBits)
       return GL_FALSE;
 
@@ -1500,53 +1441,75 @@ check_compatible(const GLcontext *ctx, const GLframebuffer *buffer)
 
 
 /**
- * Bind the given context to the given draw-buffer and read-buffer and
- * make it the current context for this thread.
+ * Do one-time initialization for the given framebuffer.  Specifically,
+ * ask the driver for the window's current size and update the framebuffer
+ * object to match.
+ * Really, the device driver should totally take care of this.
+ */
+static void
+initialize_framebuffer_size(GLcontext *ctx, GLframebuffer *fb)
+{
+   GLuint width, height;
+   if (ctx->Driver.GetBufferSize) {
+      ctx->Driver.GetBufferSize(fb, &width, &height);
+      if (ctx->Driver.ResizeBuffers)
+         ctx->Driver.ResizeBuffers(ctx, fb, width, height);
+      fb->Initialized = GL_TRUE;
+   }
+}
+
+
+/**
+ * Bind the given context to the given drawBuffer and readBuffer and
+ * make it the current context for the calling thread.
+ * We'll render into the drawBuffer and read pixels from the
+ * readBuffer (i.e. glRead/CopyPixels, glCopyTexImage, etc).
  *
- * \param newCtx new GL context. If NULL then there will be no current GL
- * context.
- * \param drawBuffer draw framebuffer.
- * \param readBuffer read framebuffer.
- * 
- * Check that the context's and framebuffer's visuals are compatible, returning
- * immediately otherwise. Sets the glapi current context via
- * _glapi_set_context(). If \p newCtx is not NULL, associates \p drawBuffer and
- * \p readBuffer with it and calls dd_function_table::ResizeBuffers if the buffers size has changed. 
- * Calls dd_function_table::MakeCurrent callback if defined.
+ * We check that the context's and framebuffer's visuals are compatible
+ * and return immediately if they're not.
  *
- * When a context is bound by the first time and the \c MESA_INFO environment
- * variable is set it calls print_info() as an aid for remote user
- * troubleshooting.
+ * \param newCtx  the new GL context. If NULL then there will be no current GL
+ *                context.
+ * \param drawBuffer  the drawing framebuffer
+ * \param readBuffer  the reading framebuffer
  */
 void
 _mesa_make_current( GLcontext *newCtx, GLframebuffer *drawBuffer,
                     GLframebuffer *readBuffer )
 {
+   GET_CURRENT_CONTEXT(oldCtx);
+
    if (MESA_VERBOSE & VERBOSE_API)
       _mesa_debug(newCtx, "_mesa_make_current()\n");
 
    /* Check that the context's and framebuffer's visuals are compatible.
     */
-   if (newCtx && drawBuffer && newCtx->DrawBuffer != drawBuffer) {
-      if (!check_compatible(newCtx, drawBuffer))
+   if (newCtx && drawBuffer && newCtx->WinSysDrawBuffer != drawBuffer) {
+      if (!check_compatible(newCtx, drawBuffer)) {
+         _mesa_warning(newCtx,
+              "MakeCurrent: incompatible visuals for context and drawbuffer");
          return;
+      }
    }
-   if (newCtx && readBuffer && newCtx->ReadBuffer != readBuffer) {
-      if (!check_compatible(newCtx, readBuffer))
+   if (newCtx && readBuffer && newCtx->WinSysReadBuffer != readBuffer) {
+      if (!check_compatible(newCtx, readBuffer)) {
+         _mesa_warning(newCtx,
+              "MakeCurrent: incompatible visuals for context and readbuffer");
          return;
+      }
    }
 
-#if !defined(IN_DRI_DRIVER)
-   /* We call this function periodically (just here for now) in
-    * order to detect when multithreading has begun.  In a DRI driver, this
-    * step is done by the driver loader (e.g., libGL).
-    */
-   _glapi_check_multithread();
-#endif /* !defined(IN_DRI_DRIVER) */
-
+   /* We used to call _glapi_check_multithread() here.  Now do it in drivers */
    _glapi_set_context((void *) newCtx);
    ASSERT(_mesa_get_current_context() == newCtx);
 
+   if (oldCtx) {
+      _mesa_unreference_framebuffer(&oldCtx->WinSysDrawBuffer);
+      _mesa_unreference_framebuffer(&oldCtx->WinSysReadBuffer);
+      _mesa_unreference_framebuffer(&oldCtx->DrawBuffer);
+      _mesa_unreference_framebuffer(&oldCtx->ReadBuffer);
+   }
+         
    if (!newCtx) {
       _glapi_set_dispatch(NULL);  /* none current */
    }
@@ -1558,56 +1521,79 @@ _mesa_make_current( GLcontext *newCtx, GLframebuffer *drawBuffer,
 
          ASSERT(drawBuffer->Name == 0);
          ASSERT(readBuffer->Name == 0);
-         newCtx->WinSysDrawBuffer = drawBuffer;
-         newCtx->WinSysReadBuffer = readBuffer;
-         /* don't replace user-buffer bindings with window system buffer */
+         _mesa_reference_framebuffer(&newCtx->WinSysDrawBuffer, drawBuffer);
+         _mesa_reference_framebuffer(&newCtx->WinSysReadBuffer, readBuffer);
+
+         /*
+          * Only set the context's Draw/ReadBuffer fields if they're NULL
+          * or not bound to a user-created FBO.
+          */
          if (!newCtx->DrawBuffer || newCtx->DrawBuffer->Name == 0) {
-            newCtx->DrawBuffer = drawBuffer;
-            newCtx->ReadBuffer = readBuffer;
+            _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) */
+            int i;
+            GLenum buffers[MAX_DRAW_BUFFERS];
+            for(i = 0; i < newCtx->Const.MaxDrawBuffers; i++) {
+               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
+         /* We want to get rid of these lines: */
+
 #if _HAVE_FULL_GL
          if (!drawBuffer->Initialized) {
-            /* get initial window size */
-            GLuint bufWidth, bufHeight;
-            /* ask device driver for size of the buffer */
-            (*newCtx->Driver.GetBufferSize)(drawBuffer, &bufWidth, &bufHeight);
-            /* set initial buffer size */
-            if (newCtx->Driver.ResizeBuffers)
-               newCtx->Driver.ResizeBuffers(newCtx, drawBuffer,
-                                            bufWidth, bufHeight);
-            drawBuffer->Initialized = GL_TRUE;
+            initialize_framebuffer_size(newCtx, drawBuffer);
          }
-
          if (readBuffer != drawBuffer && !readBuffer->Initialized) {
-            /* get initial window size */
-            GLuint bufWidth, bufHeight;
-            /* ask device driver for size of the buffer */
-            (*newCtx->Driver.GetBufferSize)(readBuffer, &bufWidth, &bufHeight);
-            /* set initial buffer size */
-            if (newCtx->Driver.ResizeBuffers)
-               newCtx->Driver.ResizeBuffers(newCtx, readBuffer,
-                                            bufWidth, bufHeight);
-            readBuffer->Initialized = GL_TRUE;
+            initialize_framebuffer_size(newCtx, readBuffer);
          }
+
+        _mesa_resizebuffers(newCtx);
 #endif
+
+#else
+         /* We want the drawBuffer and readBuffer to be initialized by
+          * the driver.
+          * This generally means the Width and Height match the actual
+          * window size and the renderbuffers (both hardware and software
+          * based) are allocated to match.  The later can generally be
+          * done with a call to _mesa_resize_framebuffer().
+          *
+          * It's theoretically possible for a buffer to have zero width
+          * or height, but for now, assert check that the driver did what's
+          * expected of it.
+          */
+         ASSERT(drawBuffer->Width > 0);
+         ASSERT(drawBuffer->Height > 0);
+#endif
+
          if (newCtx->FirstTimeCurrent) {
             /* set initial viewport and scissor size now */
-            _mesa_set_viewport(newCtx, 0, 0, drawBuffer->Width, drawBuffer->Height);
-            newCtx->Scissor.Width = drawBuffer->Width;
-            newCtx->Scissor.Height = drawBuffer->Height;
+            _mesa_set_viewport(newCtx, 0, 0,
+                               drawBuffer->Width, drawBuffer->Height);
+           _mesa_set_scissor(newCtx, 0, 0,
+                             drawBuffer->Width, drawBuffer->Height );
+            check_context_limits(newCtx);
          }
       }
 
-      /* Alert the driver - usually passed on to the sw t&l module,
-       * but also used to detect threaded cases in the radeon codegen
-       * hw t&l module.
-       */
-      if (newCtx->Driver.MakeCurrent)
-        newCtx->Driver.MakeCurrent( newCtx, drawBuffer, readBuffer );
-
       /* We can use this to help debug user's problems.  Tell them to set
        * the MESA_INFO env variable before running their app.  Then the
        * first time each context is made current we'll print some useful
@@ -1649,12 +1635,11 @@ _mesa_share_state(GLcontext *ctx, GLcontext *ctxToShare)
 
 
 /**
- * Get current context for the calling thread.
- * 
- * \return pointer to the current GL context.
+ * \return pointer to the current GL context for this thread.
  * 
  * Calls _glapi_get_context(). This isn't the fastest way to get the current
- * context.  If you need speed, see the #GET_CURRENT_CONTEXT macro in context.h.
+ * context.  If you need speed, see the #GET_CURRENT_CONTEXT macro in
+ * context.h.
  */
 GLcontext *
 _mesa_get_current_context( void )
@@ -1662,6 +1647,7 @@ _mesa_get_current_context( void )
    return (GLcontext *) _glapi_get_context();
 }
 
+
 /**
  * Get context's current API dispatch table.
  *
@@ -1701,7 +1687,7 @@ _mesa_get_dispatch(GLcontext *ctx)
  * This is called via _mesa_error().
  */
 void
-_mesa_record_error( GLcontext *ctx, GLenum error )
+_mesa_record_error(GLcontext *ctx, GLenum error)
 {
    if (!ctx)
       return;
@@ -1712,10 +1698,11 @@ _mesa_record_error( GLcontext *ctx, GLenum error )
 
    /* Call device driver's error handler, if any.  This is used on the Mac. */
    if (ctx->Driver.Error) {
-      (*ctx->Driver.Error)( ctx );
+      ctx->Driver.Error(ctx);
    }
 }
 
+
 /**
  * Execute glFinish().
  *
@@ -1723,15 +1710,16 @@ _mesa_record_error( GLcontext *ctx, GLenum error )
  * dd_function_table::Finish driver callback, if not NULL.
  */
 void GLAPIENTRY
-_mesa_Finish( void )
+_mesa_Finish(void)
 {
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
    if (ctx->Driver.Finish) {
-      (*ctx->Driver.Finish)( ctx );
+      ctx->Driver.Finish(ctx);
    }
 }
 
+
 /**
  * Execute glFlush().
  *
@@ -1739,12 +1727,12 @@ _mesa_Finish( void )
  * dd_function_table::Flush driver callback, if not NULL.
  */
 void GLAPIENTRY
-_mesa_Flush( void )
+_mesa_Flush(void)
 {
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
    if (ctx->Driver.Flush) {
-      (*ctx->Driver.Flush)( ctx );
+      ctx->Driver.Flush(ctx);
    }
 }