b=575469; implement CreateOffscreen and context sharing in GLContexts; r=bas
authorVladimir Vukicevic <vladimir@pobox.com>
Sun, 18 Jul 2010 22:01:14 -0700
changeset 47908 23b8e7fd1794114b204e21d068dae7e761834d59
parent 47907 a6078800db5a6eb8ded68f9f23fb34e098d221ee
child 47909 e235ebdbef50d1079b1a9934f438547dd0263b06
push idunknown
push userunknown
push dateunknown
reviewersbas
bugs575469
milestone2.0b2pre
b=575469; implement CreateOffscreen and context sharing in GLContexts; r=bas
content/canvas/src/WebGLContext.cpp
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.h
gfx/layers/opengl/LayerManagerOGLProgram.h
gfx/thebes/GLContext.cpp
gfx/thebes/GLContext.h
gfx/thebes/GLContextProvider.h
gfx/thebes/GLContextProviderCGL.mm
gfx/thebes/GLContextProviderEGL.cpp
gfx/thebes/GLContextProviderGLX.cpp
gfx/thebes/GLContextProviderImpl.h
gfx/thebes/GLContextProviderNull.cpp
gfx/thebes/GLContextProviderOSMesa.cpp
gfx/thebes/GLContextProviderWGL.cpp
gfx/thebes/GLXLibrary.h
gfx/thebes/WGLLibrary.h
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -165,31 +165,35 @@ WebGLContext::SetDimensions(PRInt32 widt
             return NS_OK;
         }
     }
 
     gl::ContextFormat format(gl::ContextFormat::BasicRGBA32);
     format.depth = 16;
     format.minDepth = 1;
 
-    gl = gl::GLContextProvider::CreatePBuffer(gfxIntSize(width, height), format);
+    gl = gl::GLContextProvider::CreatePBuffer(gfxIntSize(width, height),
+                                              gl::GLContextProvider::GetGlobalContext(),
+                                              format);
 
 #ifdef USE_GLES2
     // On native GLES2, no need to validate, the compiler will do it
     mShaderValidation = PR_FALSE;
 #else
     // Check the shader validator pref
     nsCOMPtr<nsIPrefBranch> prefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
     NS_ENSURE_TRUE(prefService != nsnull, NS_ERROR_FAILURE);
 
     prefService->GetBoolPref("webgl.shader_validator", &mShaderValidation);
 #endif
 
     if (!InitAndValidateGL()) {
-        gl = gl::GLContextProviderOSMesa::CreatePBuffer(gfxIntSize(width, height), format);
+        gl = gl::GLContextProviderOSMesa::CreatePBuffer(gfxIntSize(width, height),
+                                                        nsnull,
+                                                        format);
         if (!InitAndValidateGL()) {
             LogMessage("WebGL: Can't get a usable OpenGL context.");
             return NS_ERROR_FAILURE;
         }
         else {
             LogMessage("WebGL: Using software rendering via OSMesa");
         }
     }
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -71,33 +71,60 @@ LayerManagerOGL::LayerManagerOGL(nsIWidg
   , mBackBufferTexture(0)
   , mBackBufferSize(-1, -1)
   , mHasBGRA(0)
 {
 }
 
 LayerManagerOGL::~LayerManagerOGL()
 {
-  if (mGLContext)
-    mGLContext->MakeCurrent();
+  mRoot = nsnull;
+  CleanupResources();
+}
 
-  mRoot = NULL;
+void
+LayerManagerOGL::CleanupResources()
+{
+  if (!mGLContext)
+    return;
+
+  mGLContext->MakeCurrent();
 
   for (unsigned int i = 0; i < mPrograms.Length(); ++i)
     delete mPrograms[i];
+  mPrograms.Clear();
 
-  mPrograms.Clear();
+  mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
+
+  if (mBackBufferFBO) {
+    mGLContext->fDeleteFramebuffers(1, &mBackBufferFBO);
+    mBackBufferFBO = 0;
+  }
+
+  if (mBackBufferTexture) {
+    mGLContext->fDeleteTextures(1, &mBackBufferTexture);
+    mBackBufferTexture = 0;
+  }
+
+  if (mQuadVBO) {
+    mGLContext->fDeleteBuffers(1, &mQuadVBO);
+    mQuadVBO = 0;
+  }
+
+  mGLContext = nsnull;
 }
 
 PRBool
 LayerManagerOGL::Initialize(GLContext *aExistingContext)
 {
   if (aExistingContext) {
     mGLContext = aExistingContext;
   } else {
+    if (mGLContext)
+      CleanupResources();
     mGLContext = gl::GLContextProvider::CreateForWindow(mWidget);
 
     if (!mGLContext) {
       NS_WARNING("Failed to create LayerManagerOGL context");
       return PR_FALSE;
     }
   }
 
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -75,17 +75,19 @@ class LayerOGL;
  * the main thread.
  */
 class THEBES_API LayerManagerOGL : public LayerManager {
   typedef mozilla::gl::GLContext GLContext;
 
 public:
   LayerManagerOGL(nsIWidget *aWidget);
   virtual ~LayerManagerOGL();
-  
+
+  void CleanupResources();
+
   /**
    * Initializes the layer manager, this is when the layer manager will
    * actually access the device and attempt to create the swap chain used
    * to draw to the window. If this method fails the device cannot be used.
    * This function is not threadsafe.
    *
    * \param aExistingContext an existing GL context to use, instead of creating
    * our own for the widget.
--- a/gfx/layers/opengl/LayerManagerOGLProgram.h
+++ b/gfx/layers/opengl/LayerManagerOGLProgram.h
@@ -115,17 +115,20 @@ public:
     VertexAttrib = 0,
     TexCoordAttrib = 1
   };
 
   LayerManagerOGLProgram(GLContext *aGL)
     : mGL(aGL), mProgram(0)
   { }
 
-  virtual ~LayerManagerOGLProgram() { }
+  virtual ~LayerManagerOGLProgram() {
+    mGL->MakeCurrent();
+    mGL->fDeleteProgram(mProgram);
+  }
 
   void Activate() {
     NS_ASSERTION(mProgram != 0, "Attempting to activate a program that's not in use!");
     mGL->fUseProgram(mProgram);
     mGL->SetUserData(&sCurrentProgramKey, this);
   }
 
   void SetUniform(GLuint aUniform, float aFloatValue) {
@@ -194,21 +197,19 @@ public:
 
     if (!mUniformValues[aUniform].equalsFloatN(aFloatValues, 16)) {
       mGL->fUniformMatrix4fv(aUniform, 1, false, aFloatValues);
       mUniformValues[aUniform].setFloatN(aFloatValues, 16);
     }
   }
 
 protected:
-  GLContext *mGL;
+  nsRefPtr<GLContext> mGL;
 
   GLuint mProgram;
-  GLuint mFragmentShader;
-  GLuint mVertexShader;
 
   nsTArray<UniformValue> mUniformValues;
 
   GLint CreateShader(GLenum aShaderType,
                      const char *aShaderSource)
   {
     GLint success, len = 0;
 
@@ -249,25 +250,25 @@ protected:
     }
 
     return sh;
   }
 
   bool CreateProgram(const char *aVertexShaderString,
                      const char *aFragmentShaderString)
   {
-    mVertexShader = CreateShader(LOCAL_GL_VERTEX_SHADER, aVertexShaderString);
-    mFragmentShader = CreateShader(LOCAL_GL_FRAGMENT_SHADER, aFragmentShaderString);
+    GLuint vertexShader = CreateShader(LOCAL_GL_VERTEX_SHADER, aVertexShaderString);
+    GLuint fragmentShader = CreateShader(LOCAL_GL_FRAGMENT_SHADER, aFragmentShaderString);
 
-    if (!mVertexShader || !mFragmentShader)
+    if (!vertexShader || !fragmentShader)
       return false;
 
     mProgram = mGL->fCreateProgram();
-    mGL->fAttachShader(mProgram, mVertexShader);
-    mGL->fAttachShader(mProgram, mFragmentShader);
+    mGL->fAttachShader(mProgram, vertexShader);
+    mGL->fAttachShader(mProgram, fragmentShader);
 
     // bind common attribs to consistent indices
     mGL->fBindAttribLocation(mProgram, VertexAttrib, "aVertexCoord");
     mGL->fBindAttribLocation(mProgram, TexCoordAttrib, "aTexCoord");
 
     mGL->fLinkProgram(mProgram);
 
     GLint success, len;
@@ -291,20 +292,23 @@ protected:
       if (!success) {
         fprintf (stderr, "=== PROGRAM LINKING FAILED ===\n");
       } else {
         fprintf (stderr, "=== PROGRAM LINKING WARNINGS ===\n");
       }
       fprintf (stderr, "=== Log:\n%s\n", nsPromiseFlatCString(log).get());
       fprintf (stderr, "============\n");
 
+      // We can mark the shaders for deletion; they're attached to the program
+      // and will remain attached.
+      mGL->fDeleteShader(vertexShader);
+      mGL->fDeleteShader(fragmentShader);
+
       if (!success) {
         mGL->fDeleteProgram(mProgram);
-        mGL->fDeleteShader(mVertexShader);
-        mGL->fDeleteShader(mFragmentShader);
 
         mProgram = 0;
 
         return false;
       }
     }
 
     // Now query uniforms, so that we can initialize mUniformValues
--- a/gfx/thebes/GLContext.cpp
+++ b/gfx/thebes/GLContext.cpp
@@ -106,16 +106,17 @@ LibrarySymbolLoader::LookupSymbol(PRLibr
 
 PRBool
 LibrarySymbolLoader::LoadSymbols(PRLibrary *lib,
                                  SymLoadStruct *firstStruct,
                                  PlatformLookupFunction lookupFunction,
                                  const char *prefix)
 {
     char sbuf[MAX_SYMBOL_LENGTH * 2];
+    int failCount = 0;
 
     SymLoadStruct *ss = firstStruct;
     while (ss->symPointer) {
         *ss->symPointer = 0;
 
         for (int i = 0; i < MAX_SYMBOL_NAMES; i++) {
             if (ss->symNames[i] == nsnull)
                 break;
@@ -131,23 +132,23 @@ LibrarySymbolLoader::LoadSymbols(PRLibra
             if (p) {
                 *ss->symPointer = p;
                 break;
             }
         }
 
         if (*ss->symPointer == 0) {
             fprintf (stderr, "Can't find symbol '%s'\n", ss->symNames[0]);
-            return PR_FALSE;
+            failCount++;
         }
 
         ss++;
     }
 
-    return PR_TRUE;
+    return failCount == 0 ? PR_TRUE : PR_FALSE;
 }
 
 /*
  * XXX - we should really know the ARB/EXT variants of these
  * instead of only handling the symbol if it's exposed directly.
  */
 
 PRBool
@@ -174,23 +175,17 @@ GLContext::InitWithPrefix(const char *pr
         { (PRFuncPtr*) &fClearColor, { "ClearColor", NULL } },
 #ifdef USE_GLES2
         { (PRFuncPtr*) &fClearDepthf, { "ClearDepthf", NULL } },
 #else
         { (PRFuncPtr*) &fClearDepth, { "ClearDepth", NULL } },
 #endif
         { (PRFuncPtr*) &fClearStencil, { "ClearStencil", NULL } },
         { (PRFuncPtr*) &fColorMask, { "ColorMask", NULL } },
-        { (PRFuncPtr*) &fCreateProgram, { "CreateProgram", "CreateProgramARB", NULL } },
-        { (PRFuncPtr*) &fCreateShader, { "CreateShader", "CreateShaderARB", NULL } },
         { (PRFuncPtr*) &fCullFace, { "CullFace", NULL } },
-        { (PRFuncPtr*) &fDeleteBuffers, { "DeleteBuffers", "DeleteBuffersARB", NULL } },
-        { (PRFuncPtr*) &fDeleteTextures, { "DeleteTextures", "DeleteTexturesARB", NULL } },
-        { (PRFuncPtr*) &fDeleteProgram, { "DeleteProgram", "DeleteProgramARB", NULL } },
-        { (PRFuncPtr*) &fDeleteShader, { "DeleteShader", "DeleteShaderARB", NULL } },
         { (PRFuncPtr*) &fDetachShader, { "DetachShader", "DetachShaderARB", NULL } },
         { (PRFuncPtr*) &fDepthFunc, { "DepthFunc", NULL } },
         { (PRFuncPtr*) &fDepthMask, { "DepthMask", NULL } },
 #ifdef USE_GLES2
         { (PRFuncPtr*) &fDepthRangef, { "DepthRangef", NULL } },
 #else
         { (PRFuncPtr*) &fDepthRange, { "DepthRange", NULL } },
 #endif
@@ -212,18 +207,16 @@ GLContext::InitWithPrefix(const char *pr
         { (PRFuncPtr*) &fGetActiveAttrib, { "GetActiveAttrib", "GetActiveAttribARB", NULL } },
         { (PRFuncPtr*) &fGetActiveUniform, { "GetActiveUniform", "GetActiveUniformARB", NULL } },
         { (PRFuncPtr*) &fGetAttachedShaders, { "GetAttachedShaders", "GetAttachedShadersARB", NULL } },
         { (PRFuncPtr*) &fGetAttribLocation, { "GetAttribLocation", "GetAttribLocationARB", NULL } },
         { (PRFuncPtr*) &fGetIntegerv, { "GetIntegerv", NULL } },
         { (PRFuncPtr*) &fGetFloatv, { "GetFloatv", NULL } },
         { (PRFuncPtr*) &fGetBooleanv, { "GetBooleanv", NULL } },
         { (PRFuncPtr*) &fGetBufferParameteriv, { "GetBufferParameteriv", "GetBufferParameterivARB", NULL } },
-        { (PRFuncPtr*) &fGenBuffers, { "GenBuffers", "GenBuffersARB", NULL } },
-        { (PRFuncPtr*) &fGenTextures, { "GenTextures", NULL } },
         { (PRFuncPtr*) &fGetError, { "GetError", NULL } },
         { (PRFuncPtr*) &fGetProgramiv, { "GetProgramiv", "GetProgramivARB", NULL } },
         { (PRFuncPtr*) &fGetProgramInfoLog, { "GetProgramInfoLog", "GetProgramInfoLogARB", NULL } },
 #ifndef USE_GLES2
         { (PRFuncPtr*) &fTexCoordPointer, { "TexCoordPointer", NULL } },
 #endif
         { (PRFuncPtr*) &fTexParameteri, { "TexParameteri", NULL } },
         { (PRFuncPtr*) &fTexParameterf, { "TexParameterf", NULL } },
@@ -302,32 +295,38 @@ GLContext::InitWithPrefix(const char *pr
         { (PRFuncPtr*) &fGetShaderiv, { "GetShaderiv", NULL } },
         { (PRFuncPtr*) &fGetShaderInfoLog, { "GetShaderInfoLog", NULL } },
         { (PRFuncPtr*) &fGetShaderSource, { "GetShaderSource", NULL } },
         { (PRFuncPtr*) &fShaderSource, { "ShaderSource", NULL } },
         { (PRFuncPtr*) &fVertexAttribPointer, { "VertexAttribPointer", NULL } },
         { (PRFuncPtr*) &fBindFramebuffer, { "BindFramebuffer", "BindFramebufferEXT", NULL } },
         { (PRFuncPtr*) &fBindRenderbuffer, { "BindRenderbuffer", "BindRenderbufferEXT", NULL } },
         { (PRFuncPtr*) &fCheckFramebufferStatus, { "CheckFramebufferStatus", "CheckFramebufferStatusEXT", NULL } },
-        { (PRFuncPtr*) &fDeleteFramebuffers, { "DeleteFramebuffers", "DeleteFramebuffersEXT", NULL } },
-        { (PRFuncPtr*) &fDeleteRenderbuffers, { "DeleteRenderbuffers", "DeleteRenderbuffersEXT", NULL } },
         { (PRFuncPtr*) &fFramebufferRenderbuffer, { "FramebufferRenderbuffer", "FramebufferRenderbufferEXT", NULL } },
         { (PRFuncPtr*) &fFramebufferTexture2D, { "FramebufferTexture2D", "FramebufferTexture2DEXT", NULL } },
         { (PRFuncPtr*) &fGenerateMipmap, { "GenerateMipmap", "GenerateMipmapEXT", NULL } },
-        { (PRFuncPtr*) &fGenFramebuffers, { "GenFramebuffers", "GenFramebuffersEXT", NULL } },
-        { (PRFuncPtr*) &fGenRenderbuffers, { "GenRenderbuffers", "GenRenderbuffersEXT", NULL } },
         { (PRFuncPtr*) &fGetFramebufferAttachmentParameteriv, { "GetFramebufferAttachmentParameteriv", "GetFramebufferAttachmentParameterivEXT", NULL } },
         { (PRFuncPtr*) &fGetRenderbufferParameteriv, { "GetRenderbufferParameteriv", "GetRenderbufferParameterivEXT", NULL } },
         { (PRFuncPtr*) &fIsFramebuffer, { "IsFramebuffer", "IsFramebufferEXT", NULL } },
         { (PRFuncPtr*) &fIsRenderbuffer, { "IsRenderbuffer", "IsRenderbufferEXT", NULL } },
         { (PRFuncPtr*) &fRenderbufferStorage, { "RenderbufferStorage", "RenderbufferStorageEXT", NULL } },
-#if 0
-        { (PRFuncPtr*) &fMapBuffer, { "MapBuffer", NULL } },
-        { (PRFuncPtr*) &fUnmapBuffer, { "UnmapBuffer", NULL } },
-#endif
+
+        { (PRFuncPtr*) &priv_fGenBuffers, { "GenBuffers", "GenBuffersARB", NULL } },
+        { (PRFuncPtr*) &priv_fGenTextures, { "GenTextures", NULL } },
+        { (PRFuncPtr*) &priv_fCreateProgram, { "CreateProgram", "CreateProgramARB", NULL } },
+        { (PRFuncPtr*) &priv_fCreateShader, { "CreateShader", "CreateShaderARB", NULL } },
+        { (PRFuncPtr*) &priv_fGenFramebuffers, { "GenFramebuffers", "GenFramebuffersEXT", NULL } },
+        { (PRFuncPtr*) &priv_fGenRenderbuffers, { "GenRenderbuffers", "GenRenderbuffersEXT", NULL } },
+
+        { (PRFuncPtr*) &priv_fDeleteBuffers, { "DeleteBuffers", "DeleteBuffersARB", NULL } },
+        { (PRFuncPtr*) &priv_fDeleteTextures, { "DeleteTextures", "DeleteTexturesARB", NULL } },
+        { (PRFuncPtr*) &priv_fDeleteProgram, { "DeleteProgram", "DeleteProgramARB", NULL } },
+        { (PRFuncPtr*) &priv_fDeleteShader, { "DeleteShader", "DeleteShaderARB", NULL } },
+        { (PRFuncPtr*) &priv_fDeleteFramebuffers, { "DeleteFramebuffers", "DeleteFramebuffersEXT", NULL } },
+        { (PRFuncPtr*) &priv_fDeleteRenderbuffers, { "DeleteRenderbuffers", "DeleteRenderbuffersEXT", NULL } },
 
         { NULL, { NULL } },
 
     };
 
     mInitialized = LoadSymbols(&symbols[0], trygl, prefix);
     return mInitialized;
 }
@@ -467,10 +466,366 @@ BasicTextureImage::EndUpdate()
                                    LOCAL_GL_RGBA,
                                    LOCAL_GL_UNSIGNED_BYTE,
                                    uploadImage->Data());
     }
     mUpdateContext = NULL;
     return PR_TRUE;         // mTexture is bound
 }
 
+PRBool
+GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize)
+{
+    MakeCurrent();
+
+    bool alpha = mCreationFormat.alpha > 0;
+    int depth = mCreationFormat.depth;
+    int stencil = mCreationFormat.stencil;
+
+#ifdef USE_GLES2
+    const bool isMobile = true;
+#else
+    const bool isMobile = false;
+#endif
+
+    bool firstTime = (mOffscreenFBO == 0);
+
+    GLuint curBoundTexture = 0;
+    GLuint curBoundRenderbuffer = 0;
+    GLuint curBoundFramebuffer = 0;
+
+    GLint viewport[4];
+
+    // save a few things for later restoring
+    fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, (GLint*) &curBoundTexture);
+    fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*) &curBoundFramebuffer);
+    fGetIntegerv(LOCAL_GL_RENDERBUFFER_BINDING, (GLint*) &curBoundRenderbuffer);
+    fGetIntegerv(LOCAL_GL_VIEWPORT, viewport);
+
+    // If this is the first time we're going through this, we need
+    // to create the objects we'll use.  Otherwise, just bind them.
+    if (firstTime) {
+        fGenTextures(1, &mOffscreenTexture);
+        fBindTexture(LOCAL_GL_TEXTURE_2D, mOffscreenTexture);
+        fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
+        fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
+
+        fGenFramebuffers(1, &mOffscreenFBO);
+        fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mOffscreenFBO);
+
+        if (depth) {
+            fGenRenderbuffers(1, &mOffscreenDepthRB);
+        }
+
+        if (stencil) {
+            fGenRenderbuffers(1, &mOffscreenStencilRB);
+        }
+    } else {
+        fBindTexture(LOCAL_GL_TEXTURE_2D, mOffscreenTexture);
+        fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mOffscreenFBO);
+    }
+
+    // resize the FBO components
+    if (alpha) {
+        fTexImage2D(LOCAL_GL_TEXTURE_2D,
+                    0,
+                    LOCAL_GL_RGBA,
+                    aSize.width, aSize.height,
+                    0,
+                    LOCAL_GL_RGBA,
+                    LOCAL_GL_UNSIGNED_BYTE,
+                    NULL);
+    } else {
+        fTexImage2D(LOCAL_GL_TEXTURE_2D,
+                    0,
+                    LOCAL_GL_RGB,
+                    aSize.width, aSize.height,
+                    0,
+                    LOCAL_GL_RGB,
+                    isMobile ? LOCAL_GL_UNSIGNED_SHORT_5_6_5
+                             : LOCAL_GL_UNSIGNED_BYTE,
+                    NULL);
+    }
+
+
+    if (depth) {
+        fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mOffscreenDepthRB);
+        fRenderbufferStorage(LOCAL_GL_RENDERBUFFER,
+                             LOCAL_GL_DEPTH_COMPONENT16,
+                             aSize.width, aSize.height);
+    }
+
+    if (stencil) {
+        fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mOffscreenStencilRB);
+        fRenderbufferStorage(LOCAL_GL_RENDERBUFFER,
+                             LOCAL_GL_STENCIL_INDEX8,
+                             aSize.width, aSize.height);
+    }
+
+    // Now assemble the FBO, if we're creating one
+    // for the first time.
+    if (firstTime) {
+        fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
+                              LOCAL_GL_COLOR_ATTACHMENT0,
+                              LOCAL_GL_TEXTURE_2D,
+                              mOffscreenTexture,
+                              0);
+        if (depth) {
+            fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
+                                     LOCAL_GL_DEPTH_ATTACHMENT,
+                                     LOCAL_GL_RENDERBUFFER,
+                                     mOffscreenDepthRB);
+        }
+
+        if (stencil) {
+            fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
+                                     LOCAL_GL_STENCIL_ATTACHMENT,
+                                     LOCAL_GL_RENDERBUFFER,
+                                     mOffscreenStencilRB);
+        }
+    }
+
+    // We should be all resized.  Check for framebuffer completeness.
+    GLenum status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
+    if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
+        NS_WARNING("Error resizing offscreen framebuffer -- framebuffer not complete");
+        return PR_FALSE;
+    }
+
+    mOffscreenSize = aSize;
+    mOffscreenActualSize = aSize;
+
+    if (firstTime) {
+        UpdateActualFormat();
+    }
+
+    // We're good, and the framebuffer is already attached, so let's
+    // clear out our new framebuffer; otherwise we'll end up displaying
+    // random memory.  We saved all of these things earlier so that we
+    // can restore them.
+    fViewport(0, 0, aSize.width, aSize.height);
+
+    // Ok, now restore the GL state back to what it was before the resize took place.
+    fBindTexture(LOCAL_GL_TEXTURE_2D, curBoundTexture);
+    fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, curBoundRenderbuffer);
+    fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, curBoundFramebuffer);
+
+    // -don't- restore the viewport the first time through this, since
+    // the previous one isn't valid.
+    if (!firstTime)
+        fViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
+
+    ClearSafely();
+
+    return PR_TRUE;
+}
+
+void
+GLContext::DeleteOffscreenFBO()
+{
+    fDeleteFramebuffers(1, &mOffscreenFBO);
+    fDeleteTextures(1, &mOffscreenTexture);
+    fDeleteRenderbuffers(1, &mOffscreenDepthRB);
+    fDeleteRenderbuffers(1, &mOffscreenStencilRB);
+
+    mOffscreenFBO = 0;
+    mOffscreenTexture = 0;
+    mOffscreenDepthRB = 0;
+    mOffscreenStencilRB = 0;
+}
+
+void
+GLContext::ClearSafely()
+{
+    GLfloat clearColor[4];
+    GLfloat clearDepth;
+    GLint clearStencil;
+
+    fGetFloatv(LOCAL_GL_COLOR_CLEAR_VALUE, clearColor);
+    fGetFloatv(LOCAL_GL_DEPTH_CLEAR_VALUE, &clearDepth);
+    fGetIntegerv(LOCAL_GL_STENCIL_CLEAR_VALUE, &clearStencil);
+
+    fClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+    fClearStencil(0);
+#ifdef USE_GLES2
+    fClearDepthf(1.0f);
+#else
+    fClearDepth(1.0);
+#endif
+
+    fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT | LOCAL_GL_STENCIL_BUFFER_BIT);
+
+    fClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
+    fClearStencil(clearStencil);
+#ifdef USE_GLES2
+    fClearDepthf(clearDepth);
+#else
+    fClearDepth(clearDepth);
+#endif
+}
+
+void
+GLContext::UpdateActualFormat()
+{
+    // TODO
+}
+
+#ifdef DEBUG
+
+void
+GLContext::CreatedProgram(GLContext *aOrigin, GLuint aName)
+{
+    mTrackedPrograms.AppendElement(NamedResource(aOrigin, aName));
+}
+
+void
+GLContext::CreatedShader(GLContext *aOrigin, GLuint aName)
+{
+    mTrackedShaders.AppendElement(NamedResource(aOrigin, aName));
+}
+
+void
+GLContext::CreatedBuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
+{
+    for (GLsizei i = 0; i < aCount; ++i) {
+        mTrackedBuffers.AppendElement(NamedResource(aOrigin, aNames[i]));
+    }
+}
+
+void
+GLContext::CreatedTextures(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
+{
+    for (GLsizei i = 0; i < aCount; ++i) {
+        mTrackedTextures.AppendElement(NamedResource(aOrigin, aNames[i]));
+    }
+}
+
+void
+GLContext::CreatedFramebuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
+{
+    for (GLsizei i = 0; i < aCount; ++i) {
+        mTrackedFramebuffers.AppendElement(NamedResource(aOrigin, aNames[i]));
+    }
+}
+
+void
+GLContext::CreatedRenderbuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
+{
+    for (GLsizei i = 0; i < aCount; ++i) {
+        mTrackedRenderbuffers.AppendElement(NamedResource(aOrigin, aNames[i]));
+    }
+}
+
+static void
+RemoveNamesFromArray(GLContext *aOrigin, GLsizei aCount, GLuint *aNames, nsTArray<GLContext::NamedResource>& aArray)
+{
+    for (GLsizei j = 0; j < aCount; ++j) {
+        GLuint name = aNames[j];
+        PRBool found = PR_FALSE;
+        for (PRUint32 i = 0; i < aArray.Length(); ++i) {
+            if (aArray[i].name == name) {
+                aArray.RemoveElementAt(i);
+                found = PR_TRUE;
+                break;
+            }
+        }
+        if (!found)
+            printf_stderr("GL Context %p deleting resource %d, which doesn't exist!", aOrigin, name);
+    }
+}
+
+void
+GLContext::DeletedProgram(GLContext *aOrigin, GLuint aName)
+{
+    RemoveNamesFromArray(aOrigin, 1, &aName, mTrackedPrograms);
+}
+
+void
+GLContext::DeletedShader(GLContext *aOrigin, GLuint aName)
+{
+    RemoveNamesFromArray(aOrigin, 1, &aName, mTrackedShaders);
+}
+
+void
+GLContext::DeletedBuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
+{
+    RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedBuffers);
+}
+
+void
+GLContext::DeletedTextures(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
+{
+    RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedTextures);
+}
+
+void
+GLContext::DeletedFramebuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
+{
+    RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedFramebuffers);
+}
+
+void
+GLContext::DeletedRenderbuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames)
+{
+    RemoveNamesFromArray(aOrigin, aCount, aNames, mTrackedRenderbuffers);
+}
+
+static void
+MarkContextDestroyedInArray(GLContext *aContext, nsTArray<GLContext::NamedResource>& aArray)
+{
+    for (PRUint32 i = 0; i < aArray.Length(); ++i) {
+        if (aArray[i].origin == aContext)
+            aArray[i].originDeleted = PR_TRUE;
+    }
+}
+
+void
+GLContext::SharedContextDestroyed(GLContext *aChild)
+{
+    MarkContextDestroyedInArray(aChild, mTrackedPrograms);
+    MarkContextDestroyedInArray(aChild, mTrackedShaders);
+    MarkContextDestroyedInArray(aChild, mTrackedTextures);
+    MarkContextDestroyedInArray(aChild, mTrackedFramebuffers);
+    MarkContextDestroyedInArray(aChild, mTrackedRenderbuffers);
+    MarkContextDestroyedInArray(aChild, mTrackedBuffers);
+}
+
+static void
+ReportArrayContents(const nsTArray<GLContext::NamedResource>& aArray)
+{
+    nsTArray<GLContext::NamedResource> copy(aArray);
+    copy.Sort();
+
+    GLContext *lastContext = NULL;
+    for (PRUint32 i = 0; i < copy.Length(); ++i) {
+        if (lastContext != copy[i].origin) {
+            if (lastContext)
+                printf_stderr("\n");
+            printf_stderr("  [%p - %s] ", copy[i].origin, copy[i].originDeleted ? "deleted" : "live");
+            lastContext = copy[i].origin;
+        }
+        printf_stderr("%d ", copy[i].name);
+    }
+    printf_stderr("\n");
+}
+
+void
+GLContext::ReportOutstandingNames()
+{
+    printf_stderr("== GLContext %p ==\n", this);
+    printf_stderr("Outstanding Textures:\n");
+    ReportArrayContents(mTrackedTextures);
+    printf_stderr("Outstanding Buffers:\n");
+    ReportArrayContents(mTrackedBuffers);
+    printf_stderr("Outstanding Programs:\n");
+    ReportArrayContents(mTrackedPrograms);
+    printf_stderr("Outstanding Shaders:\n");
+    ReportArrayContents(mTrackedShaders);
+    printf_stderr("Outstanding Framebuffers:\n");
+    ReportArrayContents(mTrackedFramebuffers);
+    printf_stderr("Outstanding Renderbuffers:\n");
+    ReportArrayContents(mTrackedRenderbuffers);
+}
+
+#endif /* DEBUG */
+
 } /* namespace gl */
 } /* namespace mozilla */
--- a/gfx/thebes/GLContext.h
+++ b/gfx/thebes/GLContext.h
@@ -52,16 +52,17 @@
 #include "gfxContext.h"
 #include "gfxRect.h"
 #include "nsISupportsImpl.h"
 #include "prlink.h"
 
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 #include "nsRegion.h"
+#include "nsAutoPtr.h"
 
 #ifndef GLAPIENTRY
 #ifdef XP_WIN
 #define GLAPIENTRY __stdcall
 #else
 #define GLAPIENTRY
 #endif
 #define GLAPI
@@ -244,29 +245,120 @@ protected:
     GetImageForUpload(gfxASurface* aUpdateSurface) = 0;
 
     PRBool mTextureInited;
     GLContext* mGLContext;
     nsRefPtr<gfxContext> mUpdateContext;
     nsIntRect mUpdateRect;
 };
 
+struct THEBES_API ContextFormat {
+    static const ContextFormat BasicRGBA32Format;
+
+    enum StandardContextFormat {
+        Empty,
+        BasicRGBA32,
+        StrictBasicRGBA32,
+        BasicRGB24,
+        StrictBasicRGB24,
+        BasicRGB16_565,
+        StrictBasicRGB16_565
+    };
+
+    ContextFormat() {
+        memset(this, 0, sizeof(ContextFormat));
+    }
+
+    ContextFormat(const StandardContextFormat cf) {
+        memset(this, 0, sizeof(ContextFormat));
+
+        switch (cf) {
+        case BasicRGBA32:
+            red = green = blue = alpha = 8;
+            minRed = minGreen = minBlue = minAlpha = 1;
+            break;
+
+        case StrictBasicRGBA32:
+            red = green = blue = alpha = 8;
+            minRed = minGreen = minBlue = minAlpha = 8;
+            break;
+
+        case BasicRGB24:
+            red = green = blue = 8;
+            minRed = minGreen = minBlue = 1;
+            break;
+
+        case StrictBasicRGB24:
+            red = green = blue = 8;
+            minRed = minGreen = minBlue = 8;
+            break;
+
+        case StrictBasicRGB16_565:
+            red = minRed = 5;
+            green = minGreen = 6;
+            blue = minBlue = 5;
+            break;
+
+        default:
+            break;
+        }
+    }
+
+    int depth, minDepth;
+    int stencil, minStencil;
+    int red, minRed;
+    int green, minGreen;
+    int blue, minBlue;
+    int alpha, minAlpha;
+
+    int colorBits() const { return red + green + blue; }
+};
+
 class GLContext
     : public LibrarySymbolLoader
 {
     THEBES_INLINE_DECL_THREADSAFE_REFCOUNTING(GLContext)
 public:
-    GLContext()
-      : mInitialized(PR_FALSE)
+    GLContext(const ContextFormat& aFormat,
+              PRBool aIsOffscreen = PR_FALSE,
+              GLContext *aSharedContext = nsnull)
+      : mInitialized(PR_FALSE),
+        mCreationFormat(aFormat),
+        mIsOffscreen(aIsOffscreen),
+        mSharedContext(aSharedContext),
+        mOffscreenTexture(0),
+        mOffscreenFBO(0),
+        mOffscreenDepthRB(0),
+        mOffscreenStencilRB(0)
     {
         mUserData.Init();
     }
 
-    virtual ~GLContext() { }
+    virtual ~GLContext() {
+#ifdef DEBUG
+        if (mSharedContext) {
+            GLContext *tip = mSharedContext;
+            while (tip->mSharedContext)
+                tip = tip->mSharedContext;
+            tip->SharedContextDestroyed(this);
+            tip->ReportOutstandingNames();
+        }
+#endif
+    }
 
+    enum GLContextType {
+        ContextTypeUnknown,
+        ContextTypeWGL,
+        ContextTypeCGL,
+        ContextTypeGLX,
+        ContextTypeEGL,
+        ContextTypeOSMesa
+    };
+
+    virtual GLContextType GetContextType() { return ContextTypeUnknown; }
     virtual PRBool MakeCurrent() = 0;
     virtual PRBool SetupLookupFunction() = 0;
 
     virtual void WindowDestroyed() {}
 
     void *GetUserData(void *aKey) {
         void *result = nsnull;
         mUserData.Get(aKey, &result);
@@ -274,33 +366,32 @@ public:
     }
 
     void SetUserData(void *aKey, void *aValue) {
         mUserData.Put(aKey, aValue);
     }
 
     enum NativeDataType {
       NativeGLContext,
-      NativeCGLContext,
-      NativePBuffer,
       NativeImageSurface,
+      NativeThebesSurface,
       NativeDataTypeMax
     };
 
     virtual void *GetNativeData(NativeDataType aType) { return NULL; }
+    GLContext *GetSharedContext() { return mSharedContext; }
 
-    /* If this is a PBuffer context, resize the pbufer to the given dimensions,
-     * keping the same format and attributes.  If the resize succeeds, return
-     * PR_TRUE.  Otherwise, or if this is not a pbuffer, return PR_FALSE.
-     *
-     * On a successful resize, the previous contents of the pbuffer are cleared,
-     * and the new contents are undefined.
+    const ContextFormat& CreationFormat() { return mCreationFormat; }
+    const ContextFormat& ActualFormat() { return mActualFormat; }
+
+    /**
+     * If this context is double-buffered, returns TRUE.
      */
-    virtual PRBool Resize(const gfxIntSize& aNewSize) { return PR_FALSE; }
-
+    virtual PRBool IsDoubleBuffered() { return PR_FALSE; }
+ 
     /**
      * If this context wraps a double-buffered target, swap the back
      * and front buffers.  It should be assumed that after a swap, the
      * contents of the new back buffer are undefined.
      */
     virtual PRBool SwapBuffers() { return PR_FALSE; }
 
     /**
@@ -321,16 +412,109 @@ public:
     }
 
     virtual void DestroyTexture(GLuint tex)
     {
         MakeCurrent();
         fDeleteTextures(1, &tex); 
     }
 
+    /*
+     * Offscreen support API
+     */
+
+    /*
+     * Bind aOffscreen's color buffer as a texture to the TEXTURE_2D
+     * target.  Returns TRUE on success, otherwise FALSE.  If
+     * aOffscreen is not an offscreen context, returns FALSE.  If
+     * BindOffscreenNeedsTexture() returns TRUE, then you should have
+     * a 2D texture name bound whose image will be replaced by the
+     * contents of the offscreen context.  If it returns FALSE,
+     * the current 2D texture binding will be replaced.
+     *
+     * After a successul call to BindTex2DOffscreen, UnbindTex2DOffscreen
+     * *must* be called once rendering is complete.
+     *
+     * The same texture unit must be active for Bind/Unbind of a given
+     * context.
+     */
+    virtual PRBool BindOffscreenNeedsTexture(GLContext *aOffscreen) {
+        return aOffscreen->mOffscreenTexture == 0;
+    }
+
+    virtual PRBool BindTex2DOffscreen(GLContext *aOffscreen) {
+        if (aOffscreen->GetContextType() != GetContextType()) {
+          return PR_FALSE;
+        }
+
+        if (!aOffscreen->mOffscreenFBO) {
+            return PR_FALSE;
+        }
+
+        if (!aOffscreen->mSharedContext ||
+            aOffscreen->mSharedContext != mSharedContext)
+        {
+            return PR_FALSE;
+        }
+
+        fBindTexture(LOCAL_GL_TEXTURE_2D, aOffscreen->mOffscreenTexture);
+
+        return PR_TRUE;
+    }
+
+    virtual void UnbindTex2DOffscreen(GLContext *aOffscreen) { }
+
+    PRBool IsOffscreen() {
+        return mIsOffscreen;
+    }
+
+    /*
+     * All the methods below are only valid if IsOffscreen() returns
+     * true.
+     */
+
+    /*
+     * Resize the current offscreen buffer.  Returns true on success.
+     * If it returns false, the context should be treated as unusable
+     * and should be recreated.  After the resize, the viewport is not
+     * changed; glViewport should be called as appropriate.
+     */
+    virtual PRBool ResizeOffscreen(const gfxIntSize& aNewSize) {
+        if (mOffscreenFBO)
+            return ResizeOffscreenFBO(aNewSize);
+        return PR_FALSE;
+    }
+
+    /*
+     * Return size of this offscreen context.
+     */
+    gfxIntSize OffscreenSize() {
+        return mOffscreenSize;
+    }
+
+    /*
+     * In some cases, we have to allocate a bigger offscreen buffer
+     * than what's requested.  This is the bigger size.
+     */
+    gfxIntSize OffscreenActualSize() {
+        return mOffscreenActualSize;
+    }
+
+    /*
+     * If this context is FBO-backed, return the FBO or the color
+     * buffer texture.  If the context is not FBO-backed, 0 is
+     * returned (which is also a valid FBO binding).
+     */
+    GLuint GetOffscreenFBO() {
+        return mOffscreenFBO;
+    }
+    GLuint GetOffscreenTexture() {
+        return mOffscreenTexture;
+    }
+
     /**
      * Return a valid, allocated TextureImage of |aSize| with
      * |aContentType|.  The TextureImage's texture is configured to
      * use |aWrapMode| (usually GL_CLAMP_TO_EDGE or GL_REPEAT) and by
      * default, GL_LINEAR filtering.  Specify
      * |aUseNearestFilter=PR_TRUE| for GL_NEAREST filtering.  Return
      * NULL if creating the TextureImage fails.
      *
@@ -341,18 +525,41 @@ public:
      */
     virtual already_AddRefed<TextureImage>
     CreateTextureImage(const nsIntSize& aSize,
                        TextureImage::ContentType aContentType,
                        GLint aWrapMode,
                        PRBool aUseNearestFilter=PR_FALSE);
 
 protected:
+    PRPackedBool mInitialized;
+    ContextFormat mCreationFormat;
+    PRPackedBool mIsOffscreen;
+    nsRefPtr<GLContext> mSharedContext;
 
-    PRBool mInitialized;
+    void UpdateActualFormat();
+    ContextFormat mActualFormat;
+
+    gfxIntSize mOffscreenSize;
+    gfxIntSize mOffscreenActualSize;
+    GLuint mOffscreenTexture;
+
+    // helper to create/resize an offscreen FBO,
+    // for offscreen implementations that use FBOs.
+    PRBool ResizeOffscreenFBO(const gfxIntSize& aSize);
+    void DeleteOffscreenFBO();
+    GLuint mOffscreenFBO;
+    GLuint mOffscreenDepthRB;
+    GLuint mOffscreenStencilRB;
+
+    // Clear to transparent black, with 0 depth and stencil,
+    // while preserving current ClearColor etc. values.
+    // Useful for resizing offscreen buffers.
+    void ClearSafely();
+
     nsDataHashtable<nsVoidPtrHashKey, void*> mUserData;
 
     PRBool InitWithPrefix(const char *prefix, PRBool trygl);
 
     PRBool IsExtensionSupported(const char *extension);
 
     virtual already_AddRefed<TextureImage>
     CreateBasicTextureImage(GLuint aTexture,
@@ -403,30 +610,18 @@ public:
 #else
     typedef void (GLAPIENTRY * PFNGLCLEARDEPTHPROC) (GLclampd);
     PFNGLCLEARDEPTHPROC fClearDepth;
 #endif
     typedef void (GLAPIENTRY * PFNGLCLEARSTENCILPROC) (GLint);
     PFNGLCLEARSTENCILPROC fClearStencil;
     typedef void (GLAPIENTRY * PFNGLCOLORMASKPROC) (realGLboolean red, realGLboolean green, realGLboolean blue, realGLboolean alpha);
     PFNGLCOLORMASKPROC fColorMask;
-    typedef GLuint (GLAPIENTRY * PFNGLCREATEPROGRAMPROC) (void);
-    PFNGLCREATEPROGRAMPROC fCreateProgram;
-    typedef GLuint (GLAPIENTRY * PFNGLCREATESHADERPROC) (GLenum type);
-    PFNGLCREATESHADERPROC fCreateShader;
     typedef void (GLAPIENTRY * PFNGLCULLFACEPROC) (GLenum mode);
     PFNGLCULLFACEPROC fCullFace;
-    typedef void (GLAPIENTRY * PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint* buffers);
-    PFNGLDELETEBUFFERSPROC fDeleteBuffers;
-    typedef void (GLAPIENTRY * PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint* textures);
-    PFNGLDELETETEXTURESPROC fDeleteTextures;
-    typedef void (GLAPIENTRY * PFNGLDELETEPROGRAMPROC) (GLuint program);
-    PFNGLDELETEPROGRAMPROC fDeleteProgram;
-    typedef void (GLAPIENTRY * PFNGLDELETESHADERPROC) (GLuint shader);
-    PFNGLDELETESHADERPROC fDeleteShader;
     typedef void (GLAPIENTRY * PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader);
     PFNGLDETACHSHADERPROC fDetachShader;
     typedef void (GLAPIENTRY * PFNGLDEPTHFUNCPROC) (GLenum);
     PFNGLDEPTHFUNCPROC fDepthFunc;
     typedef void (GLAPIENTRY * PFNGLDEPTHMASKPROC) (realGLboolean);
     PFNGLDEPTHMASKPROC fDepthMask;
 #ifdef USE_GLES2
     typedef void (GLAPIENTRY * PFNGLDEPTHRANGEFPROC) (GLclampf, GLclampf);
@@ -468,20 +663,16 @@ public:
     typedef void (GLAPIENTRY * PFNGLGETINTEGERVPROC) (GLenum pname, GLint *params);
     PFNGLGETINTEGERVPROC fGetIntegerv;
     typedef void (GLAPIENTRY * PFNGLGETFLOATVPROC) (GLenum pname, GLfloat *params);
     PFNGLGETFLOATVPROC fGetFloatv;
     typedef void (GLAPIENTRY * PFNGLGETBOOLEANBPROC) (GLenum pname, realGLboolean *params);
     PFNGLGETBOOLEANBPROC fGetBooleanv;
     typedef void (GLAPIENTRY * PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint* params);
     PFNGLGETBUFFERPARAMETERIVPROC fGetBufferParameteriv;
-    typedef void (GLAPIENTRY * PFNGLGENBUFFERSPROC) (GLsizei n, GLuint* buffers);
-    PFNGLGENBUFFERSPROC fGenBuffers;
-    typedef void (GLAPIENTRY * PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures);
-    PFNGLGENTEXTURESPROC fGenTextures;
     typedef void (GLAPIENTRY * PFNGLGENERATEMIPMAPPROC) (GLenum target);
     PFNGLGENERATEMIPMAPPROC fGenerateMipmap;
     typedef GLenum (GLAPIENTRY * PFNGLGETERRORPROC) (void);
     PFNGLGETERRORPROC fGetError;
     typedef void (GLAPIENTRY * PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint* param);
     PFNGLGETPROGRAMIVPROC fGetProgramiv;
     typedef void (GLAPIENTRY * PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
     PFNGLGETPROGRAMINFOLOGPROC fGetProgramInfoLog;
@@ -518,22 +709,16 @@ public:
     typedef realGLboolean (GLAPIENTRY * PFNGLISSHADERPROC) (GLuint shader);
     PFNGLISSHADERPROC fIsShader;
     typedef realGLboolean (GLAPIENTRY * PFNGLISTEXTUREPROC) (GLuint texture);
     PFNGLISTEXTUREPROC fIsTexture;
     typedef void (GLAPIENTRY * PFNGLLINEWIDTHPROC) (GLfloat width);
     PFNGLLINEWIDTHPROC fLineWidth;
     typedef void (GLAPIENTRY * PFNGLLINKPROGRAMPROC) (GLuint program);
     PFNGLLINKPROGRAMPROC fLinkProgram;
-#if 0
-    typedef void * (GLAPIENTRY * PFNGLMAPBUFFERPROC) (GLenum target, GLenum access);
-    PFNGLMAPBUFFERPROC fMapBuffer;
-    typedef realGLboolean (GLAPIENTRY * PFNGLUNAMPBUFFERPROC) (GLenum target);
-    PFNGLUNAMPBUFFERPROC fUnmapBuffer;
-#endif
     typedef void (GLAPIENTRY * PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param);
     PFNGLPIXELSTOREIPROC fPixelStorei;
     typedef void (GLAPIENTRY * PFNGLPOLYGONOFFSETPROC) (GLfloat factor, GLfloat bias);
     PFNGLPOLYGONOFFSETPROC fPolygonOffset;
     typedef void (GLAPIENTRY * PFNGLREADBUFFERPROC) (GLenum);
     PFNGLREADBUFFERPROC fReadBuffer;
     typedef void (GLAPIENTRY * PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
     PFNGLREADPIXELSPROC fReadPixels;
@@ -645,39 +830,289 @@ public:
     PFNGLSHADERSOURCEPROC fShaderSource;
 
     typedef void (GLAPIENTRY * PFNGLBINDFRAMEBUFFER) (GLenum target, GLuint framebuffer);
     PFNGLBINDFRAMEBUFFER fBindFramebuffer;
     typedef void (GLAPIENTRY * PFNGLBINDRENDERBUFFER) (GLenum target, GLuint renderbuffer);
     PFNGLBINDRENDERBUFFER fBindRenderbuffer;
     typedef GLenum (GLAPIENTRY * PFNGLCHECKFRAMEBUFFERSTATUS) (GLenum target);
     PFNGLCHECKFRAMEBUFFERSTATUS fCheckFramebufferStatus;
-    typedef void (GLAPIENTRY * PFNGLDELETEFRAMEBUFFERS) (GLsizei n, const GLuint* ids);
-    PFNGLDELETEFRAMEBUFFERS fDeleteFramebuffers;
-    typedef void (GLAPIENTRY * PFNGLDELETERENDERBUFFERS) (GLsizei n, const GLuint* ids);
-    PFNGLDELETERENDERBUFFERS fDeleteRenderbuffers;
     typedef void (GLAPIENTRY * PFNGLFRAMEBUFFERRENDERBUFFER) (GLenum target, GLenum attachmentPoint, GLenum renderbufferTarget, GLuint renderbuffer);
     PFNGLFRAMEBUFFERRENDERBUFFER fFramebufferRenderbuffer;
     typedef void (GLAPIENTRY * PFNGLFRAMEBUFFERTEXTURE2D) (GLenum target, GLenum attachmentPoint, GLenum textureTarget, GLuint texture, GLint level);
     PFNGLFRAMEBUFFERTEXTURE2D fFramebufferTexture2D;
     typedef void (GLAPIENTRY * PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIV) (GLenum target, GLenum attachment, GLenum pname, GLint* value);
     PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIV fGetFramebufferAttachmentParameteriv;
     typedef void (GLAPIENTRY * PFNGLGETRENDERBUFFERPARAMETERIV) (GLenum target, GLenum pname, GLint* value);
     PFNGLGETRENDERBUFFERPARAMETERIV fGetRenderbufferParameteriv;
-    typedef void (GLAPIENTRY * PFNGLGENFRAMEBUFFERS) (GLsizei n, GLuint* ids);
-    PFNGLGENFRAMEBUFFERS fGenFramebuffers;
-    typedef void (GLAPIENTRY * PFNGLGENRENDERBUFFERS) (GLsizei n, GLuint* ids);
-    PFNGLGENRENDERBUFFERS fGenRenderbuffers;
     typedef realGLboolean (GLAPIENTRY * PFNGLISFRAMEBUFFER) (GLuint framebuffer);
     PFNGLISFRAMEBUFFER fIsFramebuffer;
     typedef realGLboolean (GLAPIENTRY * PFNGLISRENDERBUFFER) (GLuint renderbuffer);
     PFNGLISRENDERBUFFER fIsRenderbuffer;
     typedef void (GLAPIENTRY * PFNGLRENDERBUFFERSTORAGE) (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height);
     PFNGLRENDERBUFFERSTORAGE fRenderbufferStorage;
 
+protected:
+    /* These are special -- they create or delete GL resources that can live
+     * in a shared namespace.  In DEBUG, we wrap these calls so that we can
+     * check when we have something that failed to do cleanup at the time the
+     * final context is destroyed.
+     */
+
+    typedef GLuint (GLAPIENTRY * PFNGLCREATEPROGRAMPROC) (void);
+    PFNGLCREATEPROGRAMPROC priv_fCreateProgram;
+    typedef GLuint (GLAPIENTRY * PFNGLCREATESHADERPROC) (GLenum type);
+    PFNGLCREATESHADERPROC priv_fCreateShader;
+    typedef void (GLAPIENTRY * PFNGLGENBUFFERSPROC) (GLsizei n, GLuint* buffers);
+    PFNGLGENBUFFERSPROC priv_fGenBuffers;
+    typedef void (GLAPIENTRY * PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures);
+    PFNGLGENTEXTURESPROC priv_fGenTextures;
+    typedef void (GLAPIENTRY * PFNGLGENFRAMEBUFFERS) (GLsizei n, GLuint* ids);
+    PFNGLGENFRAMEBUFFERS priv_fGenFramebuffers;
+    typedef void (GLAPIENTRY * PFNGLGENRENDERBUFFERS) (GLsizei n, GLuint* ids);
+    PFNGLGENRENDERBUFFERS priv_fGenRenderbuffers;
+
+    typedef void (GLAPIENTRY * PFNGLDELETEPROGRAMPROC) (GLuint program);
+    PFNGLDELETEPROGRAMPROC priv_fDeleteProgram;
+    typedef void (GLAPIENTRY * PFNGLDELETESHADERPROC) (GLuint shader);
+    PFNGLDELETESHADERPROC priv_fDeleteShader;
+    typedef void (GLAPIENTRY * PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint* buffers);
+    PFNGLDELETEBUFFERSPROC priv_fDeleteBuffers;
+    typedef void (GLAPIENTRY * PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint* textures);
+    PFNGLDELETETEXTURESPROC priv_fDeleteTextures;
+    typedef void (GLAPIENTRY * PFNGLDELETEFRAMEBUFFERS) (GLsizei n, const GLuint* ids);
+    PFNGLDELETEFRAMEBUFFERS priv_fDeleteFramebuffers;
+    typedef void (GLAPIENTRY * PFNGLDELETERENDERBUFFERS) (GLsizei n, const GLuint* ids);
+    PFNGLDELETERENDERBUFFERS priv_fDeleteRenderbuffers;
+
+public:
+#ifndef DEBUG
+    GLuint GLAPIENTRY fCreateProgram() {
+        return priv_fCreateProgram();
+    }
+
+    GLuint GLAPIENTRY fCreateShader(GLenum t) {
+        return priv_fCreateShader(t);
+    }
+
+    void GLAPIENTRY fGenBuffers(GLsizei n, GLuint* names) {
+        priv_fGenBuffers(n, names);
+    }
+
+    void GLAPIENTRY fGenTextures(GLsizei n, GLuint* names) {
+        priv_fGenTextures(n, names);
+    }
+
+    void GLAPIENTRY fGenFramebuffers(GLsizei n, GLuint* names) {
+        priv_fGenFramebuffers(n, names);
+    }
+
+    void GLAPIENTRY fGenRenderbuffers(GLsizei n, GLuint* names) {
+        priv_fGenRenderbuffers(n, names);
+    }
+
+    void GLAPIENTRY fDeleteProgram(GLuint program) {
+        priv_fDeleteProgram(program);
+    }
+
+    void GLAPIENTRY fDeleteShader(GLuint shader) {
+        priv_fDeleteShader(shader);
+    }
+
+    void GLAPIENTRY fDeleteBuffers(GLsizei n, GLuint *names) {
+        priv_fDeleteBuffers(n, names);
+    }
+
+    void GLAPIENTRY fDeleteTextures(GLsizei n, GLuint *names) {
+        priv_fDeleteTextures(n, names);
+    }
+
+    void GLAPIENTRY fDeleteFramebuffers(GLsizei n, GLuint *names) {
+        priv_fDeleteFramebuffers(n, names);
+    }
+
+    void GLAPIENTRY fDeleteRenderbuffers(GLsizei n, GLuint *names) {
+        priv_fDeleteRenderbuffers(n, names);
+    }
+#else
+    GLuint GLAPIENTRY fCreateProgram() {
+        GLuint ret = priv_fCreateProgram();
+        if (mSharedContext) {
+            GLContext *tip = mSharedContext;
+            while (tip->mSharedContext)
+                tip = tip->mSharedContext;
+            tip->CreatedProgram(this, ret);
+        }
+        return ret;
+    }
+
+    GLuint GLAPIENTRY fCreateShader(GLenum t) {
+        GLuint ret = priv_fCreateShader(t);
+        if (mSharedContext) {
+            GLContext *tip = mSharedContext;
+            while (tip->mSharedContext)
+                tip = tip->mSharedContext;
+            tip->CreatedShader(this, ret);
+        }
+        return ret;
+    }
+
+    void GLAPIENTRY fGenBuffers(GLsizei n, GLuint* names) {
+        priv_fGenBuffers(n, names);
+        if (mSharedContext) {
+            GLContext *tip = mSharedContext;
+            while (tip->mSharedContext)
+                tip = tip->mSharedContext;
+            tip->CreatedBuffers(this, n, names);
+        }
+    }
+
+    void GLAPIENTRY fGenTextures(GLsizei n, GLuint* names) {
+        priv_fGenTextures(n, names);
+        if (mSharedContext) {
+            GLContext *tip = mSharedContext;
+            while (tip->mSharedContext)
+                tip = tip->mSharedContext;
+            tip->CreatedTextures(this, n, names);
+        }
+    }
+
+    void GLAPIENTRY fGenFramebuffers(GLsizei n, GLuint* names) {
+        priv_fGenFramebuffers(n, names);
+        if (mSharedContext) {
+            GLContext *tip = mSharedContext;
+            while (tip->mSharedContext)
+                tip = tip->mSharedContext;
+            tip->CreatedFramebuffers(this, n, names);
+        }
+    }
+
+    void GLAPIENTRY fGenRenderbuffers(GLsizei n, GLuint* names) {
+        priv_fGenRenderbuffers(n, names);
+        if (mSharedContext) {
+            GLContext *tip = mSharedContext;
+            while (tip->mSharedContext)
+                tip = tip->mSharedContext;
+            tip->CreatedRenderbuffers(this, n, names);
+        }
+    }
+
+    void GLAPIENTRY fDeleteProgram(GLuint program) {
+        priv_fDeleteProgram(program);
+        if (mSharedContext) {
+            GLContext *tip = mSharedContext;
+            while (tip->mSharedContext)
+                tip = tip->mSharedContext;
+            tip->DeletedProgram(this, program);
+        }
+    }
+
+    void GLAPIENTRY fDeleteShader(GLuint shader) {
+        priv_fDeleteShader(shader);
+        if (mSharedContext) {
+            GLContext *tip = mSharedContext;
+            while (tip->mSharedContext)
+                tip = tip->mSharedContext;
+            tip->DeletedShader(this, shader);
+        }
+    }
+
+    void GLAPIENTRY fDeleteBuffers(GLsizei n, GLuint *names) {
+        priv_fDeleteBuffers(n, names);
+        if (mSharedContext) {
+            GLContext *tip = mSharedContext;
+            while (tip->mSharedContext)
+                tip = tip->mSharedContext;
+            tip->DeletedBuffers(this, n, names);
+        }
+    }
+
+    void GLAPIENTRY fDeleteTextures(GLsizei n, GLuint *names) {
+        priv_fDeleteTextures(n, names);
+        if (mSharedContext) {
+            GLContext *tip = mSharedContext;
+            while (tip->mSharedContext)
+                tip = tip->mSharedContext;
+            tip->DeletedTextures(this, n, names);
+        }
+    }
+
+    void GLAPIENTRY fDeleteFramebuffers(GLsizei n, GLuint *names) {
+        priv_fDeleteFramebuffers(n, names);
+        if (mSharedContext) {
+            GLContext *tip = mSharedContext;
+            while (tip->mSharedContext)
+                tip = tip->mSharedContext;
+            tip->DeletedFramebuffers(this, n, names);
+        }
+
+    }
+
+    void GLAPIENTRY fDeleteRenderbuffers(GLsizei n, GLuint *names) {
+        priv_fDeleteRenderbuffers(n, names);
+        if (mSharedContext) {
+            GLContext *tip = mSharedContext;
+            while (tip->mSharedContext)
+                tip = tip->mSharedContext;
+            tip->DeletedRenderbuffers(this, n, names);
+        }
+    }
+
+    void CreatedProgram(GLContext *aOrigin, GLuint aName);
+    void CreatedShader(GLContext *aOrigin, GLuint aName);
+    void CreatedBuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
+    void CreatedTextures(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
+    void CreatedFramebuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
+    void CreatedRenderbuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
+    void DeletedProgram(GLContext *aOrigin, GLuint aName);
+    void DeletedShader(GLContext *aOrigin, GLuint aName);
+    void DeletedBuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
+    void DeletedTextures(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
+    void DeletedFramebuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
+    void DeletedRenderbuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
+
+    void SharedContextDestroyed(GLContext *aChild);
+    void ReportOutstandingNames();
+
+    struct NamedResource {
+        NamedResource()
+            : origin(nsnull), name(0), originDeleted(PR_FALSE)
+        { }
+
+        NamedResource(GLContext *aOrigin, GLuint aName)
+            : origin(aOrigin), name(aName), originDeleted(PR_FALSE)
+        { }
+
+        GLContext *origin;
+        GLuint name;
+        PRBool originDeleted;
+
+        // for sorting
+        bool operator<(const NamedResource& aOther) const {
+            if (intptr_t(origin) < intptr_t(aOther.origin))
+                return true;
+            if (name < aOther.name)
+                return true;
+            return false;
+        }
+        bool operator==(const NamedResource& aOther) const {
+            return origin == aOther.origin &&
+                name == aOther.name &&
+                originDeleted == aOther.originDeleted;
+        }
+    };
+
+    nsTArray<NamedResource> mTrackedPrograms;
+    nsTArray<NamedResource> mTrackedShaders;
+    nsTArray<NamedResource> mTrackedTextures;
+    nsTArray<NamedResource> mTrackedFramebuffers;
+    nsTArray<NamedResource> mTrackedRenderbuffers;
+    nsTArray<NamedResource> mTrackedBuffers;
+#endif
+    
 };
 
 inline void
 GLDebugPrintError(GLContext* aCx, const char* const aFile, int aLine)
 {
   GLenum err = aCx->fGetError();
   if (err) {
     fprintf(stderr, "GL ERROR: 0x%04x at %s:%d\n", err, aFile, aLine);
--- a/gfx/thebes/GLContextProvider.h
+++ b/gfx/thebes/GLContextProvider.h
@@ -43,66 +43,16 @@
 #include "nsAutoPtr.h"
 
 class nsIWidget;
 class gfxASurface;
 
 namespace mozilla {
 namespace gl {
 
-struct THEBES_API ContextFormat {
-    static const ContextFormat BasicRGBA32Format;
-
-    enum StandardContextFormat {
-        Empty,
-        BasicRGBA32,
-        StrictBasicRGBA32,
-        BasicRGBX32,
-        StrictBasicRGBX32
-    };
-
-    ContextFormat(const StandardContextFormat cf) {
-        memset(this, 0, sizeof(ContextFormat));
-
-        switch (cf) {
-        case BasicRGBA32:
-            red = green = blue = alpha = 8;
-            minRed = minGreen = minBlue = minAlpha = 1;
-            break;
-
-        case StrictBasicRGBA32:
-            red = green = blue = alpha = 8;
-            minRed = minGreen = minBlue = minAlpha = 8;
-            break;
-
-        case BasicRGBX32:
-            red = green = blue = 8;
-            minRed = minGreen = minBlue = 1;
-            break;
-
-        case StrictBasicRGBX32:
-            red = green = blue = alpha = 8;
-            minRed = minGreen = minBlue = 8;
-            break;
-
-        default:
-            break;
-        }
-    }
-
-    int depth, minDepth;
-    int stencil, minStencil;
-    int red, minRed;
-    int green, minGreen;
-    int blue, minBlue;
-    int alpha, minAlpha;
-
-    int colorBits() const { return red + green + blue; }
-};
-
 #define IN_GL_CONTEXT_PROVIDER_H
 
 // Null and OSMesa are always there
 #define GL_CONTEXT_PROVIDER_NAME GLContextProviderNull
 #include "GLContextProviderImpl.h"
 #undef GL_CONTEXT_PROVIDER_NAME
 
 #define GL_CONTEXT_PROVIDER_NAME GLContextProviderOSMesa
--- a/gfx/thebes/GLContextProviderCGL.mm
+++ b/gfx/thebes/GLContextProviderCGL.mm
@@ -45,17 +45,21 @@
 #include "gfxPlatform.h"
 
 namespace mozilla {
 namespace gl {
 
 class CGLLibrary
 {
 public:
-    CGLLibrary() : mInitialized(PR_FALSE), mOGLLibrary(nsnull) {}
+    CGLLibrary()
+      : mInitialized(PR_FALSE),
+        mOGLLibrary(nsnull),
+        mPixelFormat(nsnull)
+    { }
 
     PRBool EnsureInitialized()
     {
         if (mInitialized) {
             return PR_TRUE;
         }
         if (!mOGLLibrary) {
             mOGLLibrary = PR_LoadLibrary("/System/Library/Frameworks/OpenGL.framework/OpenGL");
@@ -64,96 +68,208 @@ public:
                 return PR_FALSE;
             }
         }
         
         mInitialized = PR_TRUE;
         return PR_TRUE;
     }
 
+    NSOpenGLPixelFormat *PixelFormat()
+    {
+        if (mPixelFormat == nsnull) {
+            NSOpenGLPixelFormatAttribute attribs[] = {
+                NSOpenGLPFAAccelerated,
+                (NSOpenGLPixelFormatAttribute)nil 
+            };
+
+            mPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
+        }
+
+        return mPixelFormat;
+    }
 private:
     PRBool mInitialized;
     PRLibrary *mOGLLibrary;
+    NSOpenGLPixelFormat *mPixelFormat;
 }; 
 
 CGLLibrary sCGLLibrary;
 
 class GLContextCGL : public GLContext
 {
+    friend class GLContextProviderCGL;
+
 public:
-    GLContextCGL(NSOpenGLContext *aContext)
-        : mContext(aContext), mCGLContext(nsnull), mPBuffer(nsnull)
+    GLContextCGL(const ContextFormat& aFormat,
+                 GLContext *aShareContext,
+                 NSOpenGLContext *aContext,
+                 PRBool aIsOffscreen = PR_FALSE)
+        : GLContext(aFormat, aIsOffscreen, aShareContext),
+          mContext(aContext),
+          mPBuffer(nsnull),
+          mTempTextureName(0)
     { }
 
-    GLContextCGL(CGLContextObj aContext, CGLPBufferObj aPBuffer)
-        : mContext(nsnull), mCGLContext(aContext), mPBuffer(aPBuffer)
+    GLContextCGL(const ContextFormat& aFormat,
+                 GLContext *aShareContext,
+                 NSOpenGLContext *aContext,
+                 NSOpenGLPixelBuffer *aPixelBuffer)
+        : GLContext(aFormat, PR_TRUE, aShareContext),
+          mContext(aContext),
+          mPBuffer(aPixelBuffer),
+          mTempTextureName(0)
     { }
 
     ~GLContextCGL()
     {
+        if (mOffscreenFBO) {
+            MakeCurrent();
+            DeleteOffscreenFBO();
+        }
+
         if (mContext)
             [mContext release];
 
-        if (mCGLContext)
-            CGLDestroyContext(mCGLContext);
+        if (mPBuffer)
+            [mPBuffer release];
+    }
 
-        if (mPBuffer)
-            CGLDestroyPBuffer(mPBuffer);
+    GLContextType GetContextType() {
+        return ContextTypeCGL;
     }
 
     PRBool Init()
     {
         MakeCurrent();
         return InitWithPrefix("gl", PR_TRUE);
     }
 
     void *GetNativeData(NativeDataType aType)
     { 
         switch (aType) {
         case NativeGLContext:
             return mContext;
 
-        case NativeCGLContext:
-            return mCGLContext ? mCGLContext : [mContext CGLContextObj];
-
-        case NativePBuffer:
-            return mPBuffer;
-
         default:
             return nsnull;
         }
     }
 
     PRBool MakeCurrent()
     {
         if (mContext) {
             [mContext makeCurrentContext];
-        } else if (mCGLContext) {
-            CGLSetCurrentContext(mCGLContext);
         }
         return PR_TRUE;
     }
 
     PRBool SetupLookupFunction()
     {
         return PR_FALSE;
     }
 
+    PRBool BindTex2DOffscreen(GLContext *aOffscreen);
+    void UnbindTex2DOffscreen(GLContext *aOffscreen);
+    PRBool ResizeOffscreen(const gfxIntSize& aNewSize);
+
     virtual already_AddRefed<TextureImage>
     CreateBasicTextureImage(GLuint aTexture,
                             const nsIntSize& aSize,
                             TextureImage::ContentType aContentType,
                             GLContext* aContext);
 
-private:
     NSOpenGLContext *mContext;
-    CGLContextObj mCGLContext;
-    CGLPBufferObj mPBuffer;
+    NSOpenGLPixelBuffer *mPBuffer;
+    GLuint mTempTextureName;
 };
 
+PRBool
+GLContextCGL::BindTex2DOffscreen(GLContext *aOffscreen)
+{
+    if (aOffscreen->GetContextType() != ContextTypeCGL) {
+        NS_WARNING("non-CGL context");
+        return PR_FALSE;
+    }
+
+    if (!aOffscreen->IsOffscreen()) {
+        NS_WARNING("non-offscreen context");
+        return PR_FALSE;
+    }
+
+    GLContextCGL *offs = static_cast<GLContextCGL*>(aOffscreen);
+
+    if (offs->mPBuffer) {
+        fGenTextures(1, &mTempTextureName);
+        fBindTexture(LOCAL_GL_TEXTURE_2D, mTempTextureName);
+
+        [mContext
+         setTextureImageToPixelBuffer:offs->mPBuffer
+         colorBuffer:LOCAL_GL_FRONT];
+    } else if (offs->mOffscreenTexture) {
+        if (offs->GetSharedContext() != GLContextProviderCGL::GetGlobalContext())
+        {
+            NS_WARNING("offscreen FBO context can only be bound with context sharing!");
+            return PR_FALSE;
+        }
+
+        fBindTexture(LOCAL_GL_TEXTURE_2D, offs->mOffscreenTexture);
+    } else {
+        NS_WARNING("don't know how to bind this!");
+        return PR_FALSE;
+    }
+
+    return PR_TRUE;
+}
+
+void
+GLContextCGL::UnbindTex2DOffscreen(GLContext *aOffscreen)
+{
+    NS_ASSERTION(aOffscreen->GetContextType() == ContextTypeCGL, "wrong type");
+
+    GLContextCGL *offs = static_cast<GLContextCGL*>(aOffscreen);
+    if (offs->mPBuffer) {
+        NS_ASSERTION(mTempTextureName, "We didn't have an offscreen texture name?");
+        fDeleteTextures(1, &mTempTextureName);
+        mTempTextureName = 0;
+    }
+}
+
+PRBool
+GLContextCGL::ResizeOffscreen(const gfxIntSize& aNewSize)
+{
+    if (mPBuffer) {
+        NSOpenGLPixelBuffer *pb = [[NSOpenGLPixelBuffer alloc]
+                                   initWithTextureTarget:LOCAL_GL_TEXTURE_2D
+                                   textureInternalFormat:(mCreationFormat.alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB)
+                                   textureMaxMipMapLevel:0
+                                   pixelsWide:aNewSize.width
+                                   pixelsHigh:aNewSize.height];
+        if (!pb) {
+            return PR_FALSE;
+        }
+
+        [mPBuffer release];
+        mPBuffer = pb;
+
+        mOffscreenSize = aNewSize;
+        mOffscreenActualSize = aNewSize;
+
+        [mContext setPixelBuffer:pb cubeMapFace:0 mipMapLevel:0
+         currentVirtualScreen:[mContext currentVirtualScreen]];
+
+        MakeCurrent();
+        ClearSafely();
+
+        return PR_TRUE;
+    }
+
+    return ResizeOffscreenFBO(aNewSize);
+}
+
 class TextureImageCGL : public BasicTextureImage
 {
     friend already_AddRefed<TextureImage>
     GLContextCGL::CreateBasicTextureImage(GLuint,
                                           const nsIntSize&,
                                           TextureImage::ContentType,
                                           GLContext*);
 
@@ -199,124 +315,210 @@ GLContextCGL::CreateBasicTextureImage(GL
                                       TextureImage::ContentType aContentType,
                                       GLContext* aContext)
 {
     nsRefPtr<TextureImageCGL> teximage(
         new TextureImageCGL(aTexture, aSize, aContentType, aContext));
     return teximage.forget();
 }
 
+static GLContextCGL *
+GetGlobalContextCGL()
+{
+    return static_cast<GLContextCGL*>(GLContextProviderCGL::GetGlobalContext());
+}
+
 already_AddRefed<GLContext>
 GLContextProviderCGL::CreateForWindow(nsIWidget *aWidget)
 {
     if (!sCGLLibrary.EnsureInitialized()) {
         return nsnull;
     }
-    NSOpenGLPixelFormatAttribute attributes [] = {
-        NSOpenGLPFAAccelerated,
-        (NSOpenGLPixelFormatAttribute)nil 
-    };
-    
-    NSOpenGLPixelFormat *pixelFormat = [[(NSOpenGLPixelFormat *)[NSOpenGLPixelFormat alloc] 
-                                         initWithAttributes:attributes] 
-                                        autorelease]; 
+
+    GLContextCGL *shareContext = GetGlobalContextCGL();
+
     NSOpenGLContext *context = [[NSOpenGLContext alloc] 
-                                initWithFormat:pixelFormat 
-                                shareContext:NULL];
-
-    if (context == nil) {
+                                initWithFormat:sCGLLibrary.PixelFormat()
+                                shareContext:(shareContext ? shareContext->mContext : NULL)];
+    if (!context) {
         return nsnull;
     }
 
-    nsRefPtr<GLContextCGL> glContext = new GLContextCGL(context);
+    NSView *childView = (NSView *)aWidget->GetNativeData(NS_NATIVE_WIDGET);
+    [context setView:childView];
+
+    nsRefPtr<GLContextCGL> glContext = new GLContextCGL(ContextFormat(ContextFormat::BasicRGB24),
+                                                        shareContext,
+                                                        context);
     if (!glContext->Init()) {
         return nsnull;
-    }
-    
-    NSView *childView = (NSView *)aWidget->GetNativeData(NS_NATIVE_WIDGET);
-    if ([context view] != childView) {
-        [context setView:childView];
-    }
+    }    
 
-    return glContext.forget().get();
+    return glContext.forget();
 }
 
-already_AddRefed<GLContext>
-GLContextProviderCGL::CreatePBuffer(const gfxIntSize &aSize,
-                                    const ContextFormat &aFormat)
+static already_AddRefed<GLContextCGL>
+CreateOffscreenPBufferContext(const gfxIntSize& aSize,
+                              const ContextFormat& aFormat,
+                              PRBool aShare = PR_FALSE)
 {
     if (!sCGLLibrary.EnsureInitialized()) {
         return nsnull;
     }
 
-    nsTArray<CGLPixelFormatAttribute> attribs;
+    GLContextCGL *shareContext = aShare ? GetGlobalContextCGL() : nsnull;
+    if (aShare && !shareContext) {
+        return nsnull;
+    }
+
+    nsTArray<NSOpenGLPixelFormatAttribute> attribs;
+
+#define A_(_x)  attribs.AppendElement(NSOpenGLPixelFormatAttribute(_x))
+    A_(NSOpenGLPFAAccelerated);
+    A_(NSOpenGLPFAPixelBuffer);
+    A_(NSOpenGLPFAMinimumPolicy);
 
-#define A1_(_x) do {                                                    \
-        attribs.AppendElement((CGLPixelFormatAttribute) _x);            \
-    } while(0)
-#define A2_(_x,_y) do {                                                 \
-        attribs.AppendElement((CGLPixelFormatAttribute) _x);            \
-        attribs.AppendElement((CGLPixelFormatAttribute) _y);            \
-    } while(0)
+    A_(NSOpenGLPFAColorSize);
+    A_(aFormat.colorBits());
+
+    A_(NSOpenGLPFAAlphaSize);
+    A_(aFormat.alpha);
 
-    A1_(kCGLPFAAccelerated);
-    A1_(kCGLPFAMinimumPolicy);
-    A1_(kCGLPFAPBuffer);
+    A_(NSOpenGLPFADepthSize);
+    A_(aFormat.depth);
+
+    A_(NSOpenGLPFAStencilSize);
+    A_(aFormat.stencil);
 
-    A2_(kCGLPFAColorSize, aFormat.colorBits());
-    A2_(kCGLPFAAlphaSize, aFormat.alpha);
-    A2_(kCGLPFADepthSize, aFormat.depth);
+    A_(0);
+#undef A_
+
+    printf_stderr("colorbits: %d alpha: %d depth: %d stencil: %d\n", aFormat.colorBits(), aFormat.alpha, aFormat.depth, aFormat.stencil);
 
-    A1_(0);
-
-    CGLError err;
+    NSOpenGLPixelFormat *pbFormat = [[NSOpenGLPixelFormat alloc]
+                                     initWithAttributes:attribs.Elements()];
+    if (!pbFormat) {
+        return nsnull;
+    }
 
-    GLint nFormats;
-    CGLPixelFormatObj pixelFormat;
-    CGLContextObj context;
-    CGLPBufferObj pbuffer;
-    GLint screen;
+    NSOpenGLPixelBuffer *pb = [[NSOpenGLPixelBuffer alloc]
+                               initWithTextureTarget:LOCAL_GL_TEXTURE_2D
+                               textureInternalFormat:(aFormat.alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB)
+                               textureMaxMipMapLevel:0
+                               pixelsWide:aSize.width
+                               pixelsHigh:aSize.height];
+    if (!pb) {
+        [pbFormat release];
+        return nsnull;
+    }
 
-    err = CGLChoosePixelFormat(attribs.Elements(), &pixelFormat, &nFormats);
-    if (err) {
+    NSOpenGLContext *context = [[NSOpenGLContext alloc]
+                                initWithFormat:pbFormat
+                                shareContext:shareContext ? shareContext->mContext : NULL];
+    if (!context) {
+        [pbFormat release];
+        [pb release];
         return nsnull;
     }
 
-    err = CGLCreateContext(pixelFormat, NULL, &context);
-    if (err) {
+    [context
+     setPixelBuffer:pb
+     cubeMapFace:0
+     mipMapLevel:0
+     currentVirtualScreen:[context currentVirtualScreen]];
+
+    {
+        GLint l;
+        [pbFormat getValues:&l forAttribute:NSOpenGLPFADepthSize forVirtualScreen:[context currentVirtualScreen]];
+        printf_stderr("*** depth: %d (req: %d)\n", l, aFormat.depth);
+    }
+
+    [pbFormat release];
+
+    nsRefPtr<GLContextCGL> glContext = new GLContextCGL(aFormat, shareContext, context, pb);
+    return glContext.forget();
+}
+
+static already_AddRefed<GLContextCGL>
+CreateOffscreenFBOContext(const gfxIntSize& aSize,
+                          const ContextFormat& aFormat,
+                          PRBool aShare = PR_TRUE)
+{
+    if (!sCGLLibrary.EnsureInitialized()) {
         return nsnull;
     }
 
-    err = CGLCreatePBuffer(aSize.width, aSize.height, LOCAL_GL_TEXTURE_2D,
-                           LOCAL_GL_RGBA,
-                           0, &pbuffer);
-    if (err) {
+    GLContextCGL *shareContext = aShare ? GetGlobalContextCGL() : nsnull;
+    if (aShare && !shareContext) {
+        // if there is no share context, then we can't use FBOs.
         return nsnull;
     }
 
-    err = CGLGetVirtualScreen(context, &screen);
-    if (err) {
+    NSOpenGLContext *context = [[NSOpenGLContext alloc]
+                                initWithFormat:sCGLLibrary.PixelFormat()
+                                shareContext:shareContext ? shareContext->mContext : NULL];
+    if (!context) {
         return nsnull;
     }
 
-    err = CGLSetPBuffer(context, pbuffer, 0, 0, screen);
-    if (err) {
-        return nsnull;
+    nsRefPtr<GLContextCGL> glContext = new GLContextCGL(aFormat, shareContext, context, PR_TRUE);
+    return glContext.forget();
+}
+
+already_AddRefed<GLContext>
+GLContextProviderCGL::CreateOffscreen(const gfxIntSize& aSize,
+                                      const ContextFormat& aFormat)
+{
+    nsRefPtr<GLContextCGL> glContext;
+
+    glContext = CreateOffscreenPBufferContext(aSize, aFormat);
+    if (glContext &&
+        glContext->Init())
+    {
+        glContext->mOffscreenSize = aSize;
+        glContext->mOffscreenActualSize = aSize;
+
+        return glContext.forget();
     }
 
-    CGLDestroyPixelFormat(pixelFormat);
-
-    nsRefPtr<GLContextCGL> glContext = new GLContextCGL(context, pbuffer);
-    if (!glContext->Init()) {
-        return nsnull;
+    // try a FBO as second choice
+    glContext = CreateOffscreenFBOContext(aSize, aFormat);
+    if (glContext &&
+        glContext->Init() &&
+        glContext->ResizeOffscreenFBO(aSize))
+    {
+        return glContext.forget();
     }
 
-    return glContext.forget().get();
+    // everything failed
+    return nsnull;
 }
 
 already_AddRefed<GLContext>
 GLContextProviderCGL::CreateForNativePixmapSurface(gfxASurface *aSurface)
 {
     return nsnull;
 }
 
+static nsRefPtr<GLContext> gGlobalContext;
+
+GLContext *
+GLContextProviderCGL::GetGlobalContext()
+{
+    if (!sCGLLibrary.EnsureInitialized()) {
+        return nsnull;
+    }
+
+    if (!gGlobalContext) {
+        // There are bugs in some older drivers with pbuffers less
+        // than 16x16 in size; also 16x16 is POT so that we can do
+        // a FBO with it on older video cards.  A FBO context for
+        // sharing is preferred since it has no associated target.
+        gGlobalContext = CreateOffscreenFBOContext(gfxIntSize(16, 16),
+                                                   ContextFormat(ContextFormat::BasicRGB24),
+                                                   PR_FALSE);
+    }
+
+    return gGlobalContext;
+}
+
 } /* namespace gl */
 } /* namespace mozilla */
--- a/gfx/thebes/GLContextProviderEGL.cpp
+++ b/gfx/thebes/GLContextProviderEGL.cpp
@@ -50,29 +50,27 @@
 #include <QtOpenGL/QGLWidget>
 #define GLdouble_defined 1
 // we're using default display for now
 #define GET_NATIVE_WINDOW(aWidget) (EGLNativeWindowType)static_cast<QWidget*>(aWidget->GetNativeData(NS_NATIVE_SHELLWIDGET))->handle()
 #endif
 
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
+#include "mozilla/X11Util.h"
 #include "gfxXlibSurface.h"
 typedef Display *EGLNativeDisplayType;
 typedef Pixmap   EGLNativePixmapType;
 typedef Window   EGLNativeWindowType;
 
 #define EGL_LIB "/usr/lib/libEGL.so"
 #define GLES2_LIB "/usr/lib/libGLESv2.so"
 
 #elif defined(ANDROID)
 
-#include <android/log.h>
-#define ALOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gecko" , ## args)
-
 /* from widget */
 #include "AndroidBridge.h"
 
 typedef void *EGLNativeDisplayType;
 typedef void *EGLNativePixmapType;
 typedef void *EGLNativeWindowType;
 
 #define EGL_LIB "/system/lib/libEGL.so"
@@ -106,20 +104,53 @@ typedef void *EGLCastToRelevantPtr;
 typedef void *EGLImageKHR;
 typedef void *GLeglImageOES;
 
 #define EGL_DEFAULT_DISPLAY  ((EGLNativeDisplayType)0)
 #define EGL_NO_CONTEXT       ((EGLContext)0)
 #define EGL_NO_DISPLAY       ((EGLDisplay)0)
 #define EGL_NO_SURFACE       ((EGLSurface)0)
 
+#define EGL_DISPLAY()        sEGLLibrary.Display()
+
+static int
+next_power_of_two(int v)
+{
+    v--;
+    v |= v >> 1;
+    v |= v >> 2;
+    v |= v >> 4;
+    v |= v >> 8;
+    v |= v >> 16;
+    v++;
+
+    return v;
+}
+
+static bool
+is_power_of_two(int v)
+{
+    NS_ASSERTION(v >= 0, "bad value");
+
+    if (v == 0)
+        return true;
+
+    return (v & (v-1)) == 0;
+}
+
 static class EGLLibrary
 {
 public:
-    EGLLibrary() : mInitialized(PR_FALSE) {}
+    EGLLibrary() 
+        : mInitialized(PR_FALSE)
+    {
+        mHave_EGL_KHR_image_base = PR_FALSE;
+        mHave_EGL_KHR_image_pixmap = PR_FALSE;
+        mHave_EGL_KHR_gl_texture_2D_image = PR_FALSE;
+    }
 
     typedef EGLDisplay (*pfnGetDisplay)(void *display_id);
     pfnGetDisplay fGetDisplay;
     typedef EGLContext (*pfnGetCurrentContext)(void);
     pfnGetCurrentContext fGetCurrentContext;
     typedef EGLBoolean (*pfnMakeCurrent)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
     pfnMakeCurrent fMakeCurrent;
     typedef EGLBoolean (*pfnDestroyContext)(EGLDisplay dpy, EGLContext ctx);
@@ -212,65 +243,190 @@ public:
             { NULL, { NULL } }
         };
 
         if (!LibrarySymbolLoader::LoadSymbols(mEGLLibrary, &earlySymbols[0])) {
             NS_WARNING("Couldn't find required entry points in EGL library (early init)");
             return PR_FALSE;
         }
 
+        mEGLDisplay = fGetDisplay(EGL_DEFAULT_DISPLAY);
+        if (!fInitialize(mEGLDisplay, NULL, NULL))
+            return PR_FALSE;
+        
+        const char *extensions = (const char*) fQueryString(mEGLDisplay, LOCAL_EGL_EXTENSIONS);
+
+        // note the extra space -- this ugliness tries to match
+        // EGL_KHR_image in the middle of the string, or right at the
+        // end.  It's a prefix for other extensions, so we have to do
+        // this...
+        PRBool hasKHRImage;
+        if (strstr(extensions, "EGL_KHR_image ") ||
+            (strlen(extensions) >= strlen("EGL_KHR_image") &&
+             strcmp(extensions+(strlen(extensions)-strlen("EGL_KHR_image")), "EGL_KHR_image")))
+        {
+            hasKHRImage = PR_TRUE;
+        }
+
+        if (strstr(extensions, "EGL_KHR_image_base")) {
+            mHave_EGL_KHR_image_base = PR_TRUE;
+        }
+            
+        if (strstr(extensions, "EGL_KHR_image_pixmap")) {
+            mHave_EGL_KHR_image_pixmap = PR_TRUE;
+            
+        }
+
+        if (strstr(extensions, "EGL_KHR_gl_texture_2D_image")) {
+            mHave_EGL_KHR_gl_texture_2D_image = PR_TRUE;
+        }
+
+        if (hasKHRImage) {
+            mHave_EGL_KHR_image_base = PR_TRUE;
+            mHave_EGL_KHR_image_pixmap = PR_TRUE;
+        }
+
         LibrarySymbolLoader::SymLoadStruct khrSymbols[] = {
             { (PRFuncPtr*) &fCreateImageKHR, { "eglCreateImageKHR", NULL } },
             { (PRFuncPtr*) &fDestroyImageKHR, { "eglDestroyImageKHR", NULL } },
             { (PRFuncPtr*) &fImageTargetTexture2DOES, { "glEGLImageTargetTexture2DOES", NULL } },
             { NULL, { NULL } }
         };
 
-        if (!LibrarySymbolLoader::LoadSymbols(mEGLLibrary, &khrSymbols[0],
-               (LibrarySymbolLoader::PlatformLookupFunction)fGetProcAddress))
-        {
-            // just means that EGL_image_* isn't supported
-            fCreateImageKHR = nsnull;
+        LibrarySymbolLoader::LoadSymbols(mEGLLibrary, &khrSymbols[0],
+                                         (LibrarySymbolLoader::PlatformLookupFunction)fGetProcAddress);
+
+        if (!fCreateImageKHR) {
+            mHave_EGL_KHR_image_base = PR_FALSE;
+            mHave_EGL_KHR_image_pixmap = PR_FALSE;
+            mHave_EGL_KHR_gl_texture_2D_image = PR_FALSE;
+        }
+
+        if (!fImageTargetTexture2DOES) {
+            mHave_EGL_KHR_gl_texture_2D_image = PR_FALSE;
         }
 
         mInitialized = PR_TRUE;
         return PR_TRUE;
     }
 
+    EGLDisplay Display() {
+        return mEGLDisplay;
+    }
+
+    PRBool HasKHRImageBase() {
+        return mHave_EGL_KHR_image_base;
+    }
+
+    PRBool HasKHRImagePixmap() {
+        return mHave_EGL_KHR_image_base;
+    }
+
+    PRBool HasKHRImageTexture2D() {
+        return mHave_EGL_KHR_gl_texture_2D_image;
+    }
+
+    void
+    DumpEGLConfig(EGLConfig cfg)
+    {
+        int attrval;
+        int err;
+
+#define ATTR(_x) do {                                                   \
+            fGetConfigAttrib(mEGLDisplay, cfg, LOCAL_EGL_##_x, &attrval);  \
+            if ((err = fGetError()) != 0x3000) {                        \
+                printf_stderr("  %s: ERROR (0x%04x)", #_x, err);        \
+            } else {                                                    \
+                printf_stderr("  %s: %d (0x%04x)", #_x, attrval, attrval); \
+            }                                                           \
+        } while(0)
+
+        printf_stderr("EGL Config: %d [0x%08x]", (int)cfg, (PRUint32)cfg);
+
+        ATTR(BUFFER_SIZE);
+        ATTR(ALPHA_SIZE);
+        ATTR(BLUE_SIZE);
+        ATTR(GREEN_SIZE);
+        ATTR(RED_SIZE);
+        ATTR(DEPTH_SIZE);
+        ATTR(STENCIL_SIZE);
+        ATTR(CONFIG_CAVEAT);
+        ATTR(CONFIG_ID);
+        ATTR(LEVEL);
+        ATTR(MAX_PBUFFER_HEIGHT);
+        ATTR(MAX_PBUFFER_PIXELS);
+        ATTR(MAX_PBUFFER_WIDTH);
+        ATTR(NATIVE_RENDERABLE);
+        ATTR(NATIVE_VISUAL_ID);
+        ATTR(NATIVE_VISUAL_TYPE);
+        ATTR(PRESERVED_RESOURCES);
+        ATTR(SAMPLES);
+        ATTR(SAMPLE_BUFFERS);
+        ATTR(SURFACE_TYPE);
+        ATTR(TRANSPARENT_TYPE);
+        ATTR(TRANSPARENT_RED_VALUE);
+        ATTR(TRANSPARENT_GREEN_VALUE);
+        ATTR(TRANSPARENT_BLUE_VALUE);
+        ATTR(BIND_TO_TEXTURE_RGB);
+        ATTR(BIND_TO_TEXTURE_RGBA);
+        ATTR(MIN_SWAP_INTERVAL);
+        ATTR(MAX_SWAP_INTERVAL);
+        ATTR(LUMINANCE_SIZE);
+        ATTR(ALPHA_MASK_SIZE);
+        ATTR(COLOR_BUFFER_TYPE);
+        ATTR(RENDERABLE_TYPE);
+        ATTR(CONFORMANT);
+
+#undef ATTR
+    }
+
 private:
     PRBool mInitialized;
     PRLibrary *mEGLLibrary;
+    EGLDisplay mEGLDisplay;
+
+    PRPackedBool mHave_EGL_KHR_image_base;
+    PRPackedBool mHave_EGL_KHR_image_pixmap;
+    PRPackedBool mHave_EGL_KHR_gl_texture_2D_image;
 } sEGLLibrary;
 
 class GLContextEGL : public GLContext
 {
     friend class TextureImageEGL;
 
 public:
-    GLContextEGL(EGLDisplay aDisplay, EGLConfig aConfig,
-                 EGLSurface aSurface, EGLContext aContext,
-                 void *aGLWidget = nsnull,
-                 gfxASurface *aASurface = nsnull)
-        : mDisplay(aDisplay), mConfig(aConfig) 
+    GLContextEGL(const ContextFormat& aFormat,
+                 GLContext *aShareContext,
+                 EGLConfig aConfig,
+                 EGLSurface aSurface,
+                 EGLContext aContext,
+                 PRBool aIsOffscreen = PR_FALSE)
+        : GLContext(aFormat, aIsOffscreen, aShareContext)
+        , mConfig(aConfig) 
         , mSurface(aSurface), mContext(aContext)
-        , mGLWidget(aGLWidget)
-        , mASurface(aASurface)
+        , mGLWidget(nsnull)
+        , mThebesSurface(nsnull)
         , mBound(PR_FALSE)
+        , mIsPBuffer(PR_FALSE)
     {}
 
     ~GLContextEGL()
     {
         // If mGLWidget is non-null, then we've been given it by the GL context provider,
         // and it's managed by the widget implementation. In this case, We can't destroy
         // our contexts.
         if (mGLWidget)
             return;
 
-        sEGLLibrary.fDestroyContext(mDisplay, mContext);
-        sEGLLibrary.fDestroySurface(mDisplay, mSurface);
+        sEGLLibrary.fDestroyContext(EGL_DISPLAY(), mContext);
+        sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface);
+    }
+
+    GLContextType GetContextType() {
+        return ContextTypeEGL;
     }
 
     PRBool Init()
     {
         if (!OpenLibrary(GLES2_LIB)) {
             NS_WARNING("Couldn't load EGL LIB.");
             return PR_FALSE;
         }
@@ -282,106 +438,263 @@ public:
     PRBool BindTexImage()
     {
         if (!mSurface)
             return PR_FALSE;
 
         if (mBound && !ReleaseTexImage())
             return PR_FALSE;
 
-        EGLBoolean success = sEGLLibrary.fBindTexImage(mDisplay,
+        EGLBoolean success = sEGLLibrary.fBindTexImage(EGL_DISPLAY(),
             (EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER);
         if (success == LOCAL_EGL_FALSE)
             return PR_FALSE;
 
         mBound = PR_TRUE;
         return PR_TRUE;
     }
 
     PRBool ReleaseTexImage()
     {
         if (!mBound)
             return PR_TRUE;
 
-        if (!mDisplay || !mSurface)
+        if (!mSurface)
             return PR_FALSE;
 
         EGLBoolean success;
-        success = sEGLLibrary.fReleaseTexImage(mDisplay, (EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER);
+        success = sEGLLibrary.fReleaseTexImage(EGL_DISPLAY(),
+                                               (EGLSurface)mSurface,
+                                               LOCAL_EGL_BACK_BUFFER);
         if (success == LOCAL_EGL_FALSE)
             return PR_FALSE;
 
         mBound = PR_FALSE;
         return PR_TRUE;
     }
 
-    PRBool MakeCurrent()
-    {
+    PRBool MakeCurrent(PRBool aForce) {
         PRBool succeeded = PR_TRUE;
 
         // Assume that EGL has the same problem as WGL does,
         // where MakeCurrent with an already-current context is
         // still expensive.
-        if (sEGLLibrary.fGetCurrentContext() != mContext) {
+        if (aForce || sEGLLibrary.fGetCurrentContext() != mContext) {
             if (mGLWidget) {
 #ifdef MOZ_WIDGET_QT
                 static_cast<QGLWidget*>(mGLWidget)->makeCurrent();
 #else
                 succeeded = PR_FALSE;
 #endif
             } else {
-                succeeded = sEGLLibrary.fMakeCurrent(mDisplay, mSurface, mSurface, mContext);
+                succeeded = sEGLLibrary.fMakeCurrent(EGL_DISPLAY(),
+                                                     mSurface, mSurface,
+                                                     mContext);
             }
             NS_ASSERTION(succeeded, "Failed to make GL context current!");
         }
 
         return succeeded;
     }
 
+    PRBool MakeCurrent()
+    {
+        return MakeCurrent(PR_FALSE);
+    }
+
     PRBool SetupLookupFunction()
     {
         mLookupFunc = (PlatformLookupFunction)sEGLLibrary.fGetProcAddress;
         return PR_TRUE;
     }
 
     void *GetNativeData(NativeDataType aType)
     {
         switch (aType) {
         case NativeGLContext:
             return mContext;
 
-        case NativePBuffer:
-            return mSurface;
-
         default:
             return nsnull;
         }
     }
 
     PRBool SwapBuffers()
     {
-        return sEGLLibrary.fSwapBuffers(mDisplay, mSurface);
+        return sEGLLibrary.fSwapBuffers(EGL_DISPLAY(), mSurface);
     }
 
     virtual already_AddRefed<TextureImage>
     CreateTextureImage(const nsIntSize& aSize,
                        TextureImage::ContentType aContentType,
                        GLint aWrapMode,
                        PRBool aUseNearestFilter=PR_FALSE);
 
-private:
-    EGLDisplay mDisplay;
+    // hold a reference to the given surface
+    // for the lifetime of this context.
+    void HoldSurface(gfxASurface *aSurf) {
+        mThebesSurface = aSurf;
+    }
+
+    void SetQtGLWidget(void *widget) {
+        mGLWidget = widget;
+    }
+
+    void SetIsPBuffer() {
+        mIsPBuffer = PR_TRUE;
+    }
+
+    EGLContext Context() {
+        return mContext;
+    }
+
+    PRBool BindTex2DOffscreen(GLContext *aOffscreen);
+    void UnbindTex2DOffscreen(GLContext *aOffscreen);
+    PRBool ResizeOffscreen(const gfxIntSize& aNewSize);
+    void BindOffscreenFramebuffer();
+
+    static already_AddRefed<GLContextEGL>
+    CreateEGLPixmapOffscreenContext(const gfxIntSize& aSize,
+                                    const ContextFormat& aFormat);
+
+    static already_AddRefed<GLContextEGL>
+    CreateEGLPBufferOffscreenContext(const gfxIntSize& aSize,
+                                     const ContextFormat& aFormat);
+
+    void SetOffscreenSize(const gfxIntSize &aRequestedSize,
+                          const gfxIntSize &aActualSize)
+    {
+        mOffscreenSize = aRequestedSize;
+        mOffscreenActualSize = aActualSize;
+    }
+
+protected:
+    friend class GLContextProviderEGL;
+
     EGLConfig  mConfig;
     EGLSurface mSurface;
     EGLContext mContext;
-    void      *mGLWidget;
-    nsRefPtr <gfxASurface> mASurface;
-    PRBool     mBound;
+    void *mGLWidget;
+    nsRefPtr<gfxASurface> mThebesSurface;
+    PRBool mBound;
+
+    PRPackedBool mIsPBuffer;
 };
 
+PRBool
+GLContextEGL::BindTex2DOffscreen(GLContext *aOffscreen)
+{
+    if (aOffscreen->GetContextType() != ContextTypeEGL) {
+        NS_WARNING("non-EGL context");
+        return PR_FALSE;
+    }
+
+    GLContextEGL *offs = static_cast<GLContextEGL*>(aOffscreen);
+
+    if (offs->mIsPBuffer) {
+        PRBool ok = sEGLLibrary.fBindTexImage(EGL_DISPLAY(),
+                                              offs->mSurface,
+                                              LOCAL_EGL_BACK_BUFFER);
+        return ok;
+    }
+
+    if (offs->mOffscreenTexture) {
+        if (offs->GetSharedContext() != GLContextProviderEGL::GetGlobalContext())
+        {
+            NS_WARNING("offscreen FBO context can only be bound with context sharing!");
+            return PR_FALSE;
+        }
+
+        fBindTexture(LOCAL_GL_TEXTURE_2D, offs->mOffscreenTexture);
+        return PR_TRUE;
+    }
+
+    NS_WARNING("don't know how to bind this!");
+
+    return PR_FALSE;
+}
+
+void
+GLContextEGL::UnbindTex2DOffscreen(GLContext *aOffscreen)
+{
+    NS_ASSERTION(aOffscreen->GetContextType() == ContextTypeEGL, "wrong type");
+
+    GLContextEGL *offs = static_cast<GLContextEGL*>(aOffscreen);
+
+    if (offs->mIsPBuffer) {
+        sEGLLibrary.fReleaseTexImage(EGL_DISPLAY(),
+                                     offs->mSurface,
+                                     LOCAL_EGL_BACK_BUFFER);
+    }
+}
+
+PRBool
+GLContextEGL::ResizeOffscreen(const gfxIntSize& aNewSize)
+{
+    if (mIsPBuffer) {
+        EGLint pbattrs[] = {
+            LOCAL_EGL_WIDTH, 0,
+            LOCAL_EGL_HEIGHT, 0,
+            LOCAL_EGL_TEXTURE_TARGET, LOCAL_EGL_TEXTURE_2D,
+
+            LOCAL_EGL_TEXTURE_FORMAT,
+            mCreationFormat.minAlpha ?
+              LOCAL_EGL_TEXTURE_RGBA :
+              LOCAL_EGL_TEXTURE_RGB,
+
+            LOCAL_EGL_NONE
+        };
+
+        EGLSurface surface = nsnull;
+        gfxIntSize pbsize(aNewSize);
+
+TRY_AGAIN_POWER_OF_TWO:
+        pbattrs[1] = pbsize.width;
+        pbattrs[3] = pbsize.height;
+
+        surface = sEGLLibrary.fCreatePbufferSurface(EGL_DISPLAY(), mConfig, pbattrs);
+        if (!surface) {
+            if (!is_power_of_two(pbsize.width) ||
+                !is_power_of_two(pbsize.height))
+            {
+                if (!is_power_of_two(pbsize.width))
+                    pbsize.width = next_power_of_two(pbsize.width);
+                if (!is_power_of_two(pbsize.height))
+                    pbsize.height = next_power_of_two(pbsize.height);
+
+                NS_WARNING("Failed to resize pbuffer, trying power of two dims");
+                goto TRY_AGAIN_POWER_OF_TWO;
+            }
+
+            NS_WARNING("Failed to resize pbuffer");
+            return nsnull;
+        }
+
+        SetOffscreenSize(aNewSize, pbsize);
+
+        sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface);
+
+        mSurface = surface;
+
+        MakeCurrent(PR_TRUE);
+        ClearSafely();
+
+        return PR_TRUE;
+    }
+
+    return ResizeOffscreenFBO(aNewSize);
+}
+
+
+static GLContextEGL *
+GetGlobalContextEGL()
+{
+    return static_cast<GLContextEGL*>(GLContextProviderEGL::GetGlobalContext());
+}
+
 class TextureImageEGL : public TextureImage
 {
 public:
     TextureImageEGL(GLuint aTexture,
                     const nsIntSize& aSize,
                     ContentType aContentType,
                     GLContext* aContext,
                     GLContextEGL* aImpl)
@@ -397,17 +710,17 @@ public:
         mGLContext->fDeleteTextures(1, &mTexture);
         mImpl = NULL;
     }
 
     virtual gfxContext* BeginUpdate(nsIntRegion& aRegion)
     {
         NS_ASSERTION(!mUpdateContext, "BeginUpdate() without EndUpdate()?");
 
-        mUpdateContext = new gfxContext(mImpl->mASurface);
+        mUpdateContext = new gfxContext(mImpl->mThebesSurface);
         // TextureImageEGL can handle updates to disparate regions
         // aRegion = aRegion;
         return mUpdateContext;
     }
 
     virtual PRBool EndUpdate()
     {
         NS_ASSERTION(mUpdateContext, "EndUpdate() without BeginUpdate()?");
@@ -440,17 +753,17 @@ GLContextEGL::CreateTextureImage(const n
       gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32;
 
   nsRefPtr<gfxASurface> pixmap =
     gfxPlatform::GetPlatform()->
       CreateOffscreenSurface(gfxIntSize(aSize.width, aSize.height),
                              imageFormat);
 
   nsRefPtr<GLContext> impl =
-      sGLContextProvider.CreateForNativePixmapSurface(pixmap);
+      GLContextProviderEGL::CreateForNativePixmapSurface(pixmap);
   if (!impl)
       // FIXME: should fall back on BasicTextureImage here
       return NULL;
 
   MakeCurrent();
 
   GLuint texture;
   fGenTextures(1, &texture);
@@ -475,39 +788,45 @@ GLContextEGL::CreateTextureImage(const n
 already_AddRefed<GLContext>
 GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget)
 {
     if (!sEGLLibrary.EnsureInitialized()) {
         return nsnull;
     }
 
 #ifdef MOZ_WIDGET_QT
+
     QWidget *viewport = static_cast<QWidget*>(aWidget->GetNativeData(NS_NATIVE_SHELLWIDGET));
     if (!viewport)
         return nsnull;
 
     if (viewport->paintEngine()->type() == QPaintEngine::OpenGL2) {
         // Qt widget viewport already have GL context created by Qt
         // Create dummy GLContextEGL class
         nsRefPtr<GLContextEGL> glContext =
-            new GLContextEGL(NULL, NULL, NULL,
-                             sEGLLibrary.fGetCurrentContext(),
-                             viewport);
+            new GLContextEGL(ContextFormat(ContextFormat::BasicRGBA32),
+                             NULL,
+                             NULL, NULL,
+                             sEGLLibrary.fGetCurrentContext());
         if (!glContext->Init())
             return nsnull;
-        return glContext.forget().get();
-    } else {
-        // All Qt nsIWidget's have the same X-Window surface
-        // And EGL not allowing to create multiple GL context for the same window
-        // we should be able to create GL context for QGV viewport once, and reuse it for all child widgets
-        NS_WARNING("Need special GLContext implementation for QT widgets structure");
-        // Switch to software rendering here
-        return nsnull;
+        glContext->SetQtGLWidget(viewport);
+
+        return glContext.forget();
     }
-#endif
+
+    // All Qt nsIWidget's have the same X-Window surface
+    // And EGL not allowing to create multiple GL context for the same window
+    // we should be able to create GL context for QGV viewport once, and reuse it for all child widgets
+    NS_ERROR("Need special GLContext implementation for QT widgets structure");
+
+    // Switch to software rendering here
+    return nsnull;
+
+#else
 
     EGLDisplay display;
     EGLConfig  config;
     EGLSurface surface;
     EGLContext context;
 
     display = sEGLLibrary.fGetDisplay(aWidget->GetNativeData(NS_NATIVE_DISPLAY));
     if (!display) {
@@ -527,23 +846,46 @@ GLContextProviderEGL::CreateForWindow(ns
         LOCAL_EGL_GREEN_SIZE,      6,
         LOCAL_EGL_BLUE_SIZE,       5,
         LOCAL_EGL_ALPHA_SIZE,      0,
 #endif
 
         LOCAL_EGL_NONE
     };
 
-    EGLint ncfg = 0;
-    if (!sEGLLibrary.fChooseConfig(display, attribs, &config, 1, &ncfg) ||
+    EGLConfig configs[64];
+    EGLint ncfg = 64;
+    if (!sEGLLibrary.fChooseConfig(display, attribs, configs, ncfg, &ncfg) ||
         ncfg < 1)
     {
         return nsnull;
     }
 
+    config = 0;
+
+    for (int i = 0; i < ncfg; ++i) {
+        EGLint r, g, b;
+
+        sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), configs[i], LOCAL_EGL_RED_SIZE, &r);
+        sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), configs[i], LOCAL_EGL_GREEN_SIZE, &g);
+        sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), configs[i], LOCAL_EGL_BLUE_SIZE, &b);
+
+        if (r == 5 && g == 6 && b == 5) {
+            config = configs[i];
+#ifdef DEBUG
+            sEGLLibrary.DumpEGLConfig(config);
+#endif
+            break;
+        }
+    }
+
+    if (!config) {
+        return nsnull;
+    }
+
 #ifdef ANDROID
     // On Android, we have to ask Java to make the eglCreateWindowSurface
     // call for us.  See GLHelpers.java for a description of why.
     //
     // We also only have one true "window", so we just use it directly and ignore
     // what was passed in.
     surface = mozilla::AndroidBridge::Bridge()->
         CallEglCreateWindowSurface(display, config,
@@ -561,136 +903,304 @@ GLContextProviderEGL::CreateForWindow(ns
         return nsnull;
     }
 
     EGLint cxattribs[] = {
         LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2,
         LOCAL_EGL_NONE
     };
 
-    context = sEGLLibrary.fCreateContext(display, config, 0, cxattribs);
+    GLContextEGL *shareContext = GetGlobalContextEGL();
+
+TRY_AGAIN_NO_SHARING:
+    context = sEGLLibrary.fCreateContext(display,
+                                         config,
+                                         shareContext ? shareContext->mContext : EGL_NO_CONTEXT,
+                                         cxattribs);
     if (!context) {
+        if (shareContext) {
+            NS_WARNING("CreateForWindow -- couldn't share, trying again");
+            shareContext = nsnull;
+            goto TRY_AGAIN_NO_SHARING;
+        }
+
+        NS_WARNING("CreateForWindow -- no context, giving up");
         sEGLLibrary.fDestroySurface(display, surface);
         return nsnull;
     }
 
-    nsRefPtr<GLContextEGL> glContext = new GLContextEGL(display, config, surface, context);
+    nsRefPtr<GLContextEGL> glContext = new GLContextEGL(ContextFormat(ContextFormat::BasicRGB24),
+                                                        shareContext,
+                                                        config, surface, context);
 
     if (!glContext->Init())
         return nsnull;
 
-    return glContext.forget().get();
+    return glContext.forget();
+#endif
 }
 
-already_AddRefed<GLContext>
-GLContextProviderEGL::CreatePBuffer(const gfxIntSize &aSize, const ContextFormat &aFormat)
+already_AddRefed<GLContextEGL>
+GLContextEGL::CreateEGLPBufferOffscreenContext(const gfxIntSize& aSize,
+                                               const ContextFormat& aFormat)
 {
-    if (!sEGLLibrary.EnsureInitialized()) {
-        return nsnull;
-    }
-
-    EGLDisplay display;
     EGLConfig config;
     EGLSurface surface;
     EGLContext context;
 
-    display = sEGLLibrary.fGetDisplay(EGL_DEFAULT_DISPLAY);
-    if (!sEGLLibrary.fInitialize(display, NULL, NULL))
-        return nsnull;
-
-    nsTArray<int> attribs;
-
-#define A1_(_x)  do { attribs.AppendElement(_x); } while(0)
-#define A2_(_x,_y)  do {                                                \
-        attribs.AppendElement(_x);                                      \
-        attribs.AppendElement(_y);                                      \
-    } while(0)
+    EGLint attribs[] = {
+        LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
+        LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PBUFFER_BIT,
 
-    A2_(LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT);
-    A2_(LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PBUFFER_BIT);
-    /* fix this for mobile */
-    A2_(LOCAL_EGL_BUFFER_SIZE, 15 /*aFormat.colorBits()*/);
-    A2_(LOCAL_EGL_RED_SIZE, 4 /*aFormat.red*/);
-    A2_(LOCAL_EGL_GREEN_SIZE, 4 /*aFormat.green*/);
-    A2_(LOCAL_EGL_BLUE_SIZE, 4 /*aFormat.blue*/);
-    A2_(LOCAL_EGL_ALPHA_SIZE, aFormat.alpha ? 4 : 0);
-    A2_(LOCAL_EGL_DEPTH_SIZE, aFormat.depth ? 16 : 0);
-    A2_(LOCAL_EGL_STENCIL_SIZE, aFormat.stencil);
-    A1_(LOCAL_EGL_NONE);
-
-    EGLConfig configs[32];
-    int numConfigs = 32;
+        LOCAL_EGL_RED_SIZE, aFormat.red,
+        LOCAL_EGL_GREEN_SIZE, aFormat.green,
+        LOCAL_EGL_BLUE_SIZE, aFormat.blue,
+        LOCAL_EGL_ALPHA_SIZE, aFormat.alpha,
+        LOCAL_EGL_DEPTH_SIZE, aFormat.minDepth,
+        LOCAL_EGL_STENCIL_SIZE, aFormat.minStencil,
 
-    if (!sEGLLibrary.fChooseConfig(display, attribs.Elements(),
-                                   configs, numConfigs,
-                                   &numConfigs))
-        return nsnull;
+        aFormat.minAlpha ?
+          LOCAL_EGL_BIND_TO_TEXTURE_RGBA :
+          LOCAL_EGL_BIND_TO_TEXTURE_RGB,
+        LOCAL_EGL_TRUE,
 
-    if (numConfigs == 0)
-        return nsnull;
-
-    // shrug
-    config = configs[0];
-
-    EGLint pbattrs[] = {
-        LOCAL_EGL_WIDTH, aSize.width,
-        LOCAL_EGL_HEIGHT, aSize.height,
         LOCAL_EGL_NONE
     };
 
-    surface = sEGLLibrary.fCreatePbufferSurface(display, config, pbattrs);
-    if (!surface)
+    EGLConfig configs[64];
+    int numConfigs = 64;
+
+    if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(),
+                                   attribs,
+                                   configs, numConfigs,
+                                   &numConfigs)
+        || numConfigs == 0)
+    {
+        NS_WARNING("No configs");
+        // no configs? no pbuffers!
         return nsnull;
+    }
+
+    // XXX do some smarter matching here
+    config = configs[0];
+#ifdef DEBUG
+    sEGLLibrary.DumpEGLConfig(config);
+#endif
+
+    gfxIntSize pbsize(aSize);
+
+    EGLint pbattrs[] = {
+        LOCAL_EGL_WIDTH, 0,
+        LOCAL_EGL_HEIGHT, 0,
+
+        LOCAL_EGL_TEXTURE_TARGET, LOCAL_EGL_TEXTURE_2D,
+
+        LOCAL_EGL_TEXTURE_FORMAT,
+        aFormat.minAlpha ?
+          LOCAL_EGL_TEXTURE_RGBA :
+          LOCAL_EGL_TEXTURE_RGB,
+
+        LOCAL_EGL_NONE
+    };
+
+TRY_AGAIN_POWER_OF_TWO:
+    pbattrs[1] = pbsize.width;
+    pbattrs[3] = pbsize.height;
+
+    surface = sEGLLibrary.fCreatePbufferSurface(EGL_DISPLAY(), config, pbattrs);
+    if (!surface) {
+        if (!is_power_of_two(pbsize.width) ||
+            !is_power_of_two(pbsize.height))
+        {
+            if (!is_power_of_two(pbsize.width))
+                pbsize.width = next_power_of_two(pbsize.width);
+            if (!is_power_of_two(pbsize.height))
+                pbsize.height = next_power_of_two(pbsize.height);
+
+            NS_WARNING("Failed to create pbuffer, trying power of two dims");
+            goto TRY_AGAIN_POWER_OF_TWO;
+        }
+
+        NS_WARNING("Failed to create pbuffer");
+        return nsnull;
+    }
 
     sEGLLibrary.fBindAPI(LOCAL_EGL_OPENGL_ES_API);
 
     EGLint cxattrs[] = {
         LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2,
         LOCAL_EGL_NONE
     };
 
-    context = sEGLLibrary.fCreateContext(display, config, EGL_NO_CONTEXT, cxattrs);
+    context = sEGLLibrary.fCreateContext(EGL_DISPLAY(),
+                                         config,
+                                         EGL_NO_CONTEXT,
+                                         cxattrs);
     if (!context) {
-        sEGLLibrary.fDestroySurface(display, surface);
+        NS_WARNING("Failed to create context");
+        sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface);
+        return nsnull;
+    }
+
+    nsRefPtr<GLContextEGL> glContext = new GLContextEGL(aFormat, nsnull,
+                                                        config, surface, context,
+                                                        PR_TRUE);
+
+    if (!glContext->Init()) {
+        return nsnull;
+    }
+
+    glContext->SetOffscreenSize(aSize, pbsize);
+
+    glContext->SetIsPBuffer();
+
+    return glContext.forget();
+}
+
+already_AddRefed<GLContextEGL>
+GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& aSize,
+                                              const ContextFormat& aFormat)
+{
+    // XXX -- write me.
+    // This needs to find a FBConfig/Visual that matches aFormat, and allocate
+    // a gfxXlibSurface of the appropriat format, and then create a context
+    // for it.
+    //
+    // The code below is almost correct, except it doesn't do the format-FBConfig
+    // matching, instead just creating a random gfxXlibSurface.  The code below just
+    // uses context sharing and a FBO target, when instead it should avoid context
+    // sharing if some form of texture-from-pixmap functionality is available.
+
+    gfxASurface *thebesSurface = nsnull;
+    EGLNativePixmapType pixmap = 0;
+
+#ifdef MOZ_X11
+    nsRefPtr<gfxXlibSurface> xsurface =
+        gfxXlibSurface::Create(DefaultScreenOfDisplay(DefaultXDisplay()),
+                               gfxXlibSurface::FindRenderFormat(DefaultXDisplay(),
+                                                                gfxASurface::ImageFormatRGB24),
+                               gfxIntSize(16, 16));
+    if (xsurface->CairoStatus() != 0)
+        return nsnull;
+
+    thebesSurface = xsurface;
+    pixmap = xsurface->XDrawable();
+#endif
+
+    if (!pixmap) {
         return nsnull;
     }
 
-    nsRefPtr<GLContextEGL> glContext = new GLContextEGL(display, config, surface, context);
+    EGLSurface surface;
+
+    EGLConfig configs[32];
+    int numConfigs = 32;
+    EGLConfig config = 0;
+
+    EGLint pixmap_config[] = {
+        LOCAL_EGL_SURFACE_TYPE,         LOCAL_EGL_PIXMAP_BIT,
+        LOCAL_EGL_RENDERABLE_TYPE,      LOCAL_EGL_OPENGL_ES2_BIT,
+        LOCAL_EGL_DEPTH_SIZE,           0,
+        LOCAL_EGL_STENCIL_SIZE,         0,
+        LOCAL_EGL_NONE
+    };
 
-    if (!glContext->Init())
+    if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(), pixmap_config,
+                                   configs, numConfigs, &numConfigs))
+        return nsnull;
+
+    if (numConfigs == 0)
+        return nsnull;
+
+    for (int i = 0; i < numConfigs; ++i) {
+        surface = sEGLLibrary.fCreatePixmapSurface(EGL_DISPLAY(),
+                                                   configs[i],
+                                                   pixmap,
+                                                   NULL);
+        if (surface != EGL_NO_SURFACE) {
+            config = configs[i];
+            break;
+        }
+    }
+
+    if (!config)
         return nsnull;
 
-    return glContext.forget().get();
+    EGLint cxattribs[] = {
+        LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2,
+        LOCAL_EGL_NONE
+    };
+
+    GLContextEGL *shareContext = GetGlobalContextEGL();
+    if (!shareContext) {
+        // we depend on context sharing currently
+        sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface);
+        return nsnull;
+    }
+
+    EGLContext context = sEGLLibrary.fCreateContext(EGL_DISPLAY(),
+                                                    config,
+                                                    shareContext->Context(),
+                                                    cxattribs);
+    if (!context) {
+        sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface);
+        return nsnull;
+    }
+
+    nsRefPtr<GLContextEGL> glContext = new GLContextEGL(aFormat, shareContext,
+                                                        config, surface, context,
+                                                        PR_TRUE);
+
+    if (!glContext->Init() ||
+        !glContext->ResizeOffscreenFBO(aSize))
+        return nsnull;
+
+    glContext->HoldSurface(thebesSurface);
+
+    return glContext.forget();
+}
+
+// Under EGL, if we're under X11, then we have to create a Pixmap
+// because Maemo's EGL implementation doesn't support pbuffers at all
+// for some reason.  On Android, pbuffers are supported fine, though
+// often without the ability to texture from them directly.
+already_AddRefed<GLContext>
+GLContextProviderEGL::CreateOffscreen(const gfxIntSize& aSize,
+                                      const ContextFormat& aFormat)
+{
+    if (!sEGLLibrary.EnsureInitialized()) {
+        return nsnull;
+    }
+
+#if defined(ANDROID)
+    return GLContextEGL::CreateEGLPBufferOffscreenContext(aSize, aFormat);
+#elif defined(MOZ_X11)
+    return GLContextEGL::CreateEGLPixmapOffscreenContext(aSize, aFormat);
+#else
+    return nsnull;
+#endif
 }
 
 already_AddRefed<GLContext>
 GLContextProviderEGL::CreateForNativePixmapSurface(gfxASurface *aSurface)
 {
-    EGLDisplay display = nsnull;
     EGLSurface surface = nsnull;
     EGLContext context = nsnull;
 
     if (!sEGLLibrary.EnsureInitialized())
         return nsnull;
 
 #ifdef MOZ_X11
     if (aSurface->GetType() != gfxASurface::SurfaceTypeXlib) {
         // Not implemented
         return nsnull;
     }
 
     gfxXlibSurface *xsurface = static_cast<gfxXlibSurface*>(aSurface);
 
-    display = sEGLLibrary.fGetDisplay((EGLNativeDisplayType)xsurface->XDisplay());
-    if (!display)
-        return nsnull;
-
-    if (!sEGLLibrary.fInitialize(display, NULL, NULL))
-        return nsnull;
-
     EGLConfig configs[32];
     int numConfigs = 32;
 
     EGLint pixmap_config[] = {
         LOCAL_EGL_SURFACE_TYPE,         LOCAL_EGL_PIXMAP_BIT,
         LOCAL_EGL_RENDERABLE_TYPE,      LOCAL_EGL_OPENGL_ES2_BIT,
         LOCAL_EGL_DEPTH_SIZE,           0,
         LOCAL_EGL_BIND_TO_TEXTURE_RGB,  LOCAL_EGL_TRUE,
@@ -704,57 +1214,79 @@ GLContextProviderEGL::CreateForNativePix
     };
 
     EGLint pixmap_config_rgba[] = {
         LOCAL_EGL_TEXTURE_TARGET,       LOCAL_EGL_TEXTURE_2D,
         LOCAL_EGL_TEXTURE_FORMAT,       LOCAL_EGL_TEXTURE_RGBA,
         LOCAL_EGL_NONE
     };
 
-    if (!sEGLLibrary.fChooseConfig(display, pixmap_config,
+    if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(), pixmap_config,
                                    configs, numConfigs, &numConfigs))
         return nsnull;
 
     if (numConfigs == 0)
         return nsnull;
 
     PRBool opaque =
         aSurface->GetContentType() == gfxASurface::CONTENT_COLOR;
     int i = 0;
     for (i = 0; i < numConfigs; ++i) {
         if (opaque)
-            surface = sEGLLibrary.fCreatePixmapSurface(display, configs[i],
+            surface = sEGLLibrary.fCreatePixmapSurface(EGL_DISPLAY(), configs[i],
                                                        xsurface->XDrawable(),
                                                        pixmap_config_rgb);
         else
-            surface = sEGLLibrary.fCreatePixmapSurface(display, configs[i],
+            surface = sEGLLibrary.fCreatePixmapSurface(EGL_DISPLAY(), configs[i],
                                                        xsurface->XDrawable(),
                                                        pixmap_config_rgba);
 
         if (surface != EGL_NO_SURFACE)
             break;
     }
 
 
     EGLint cxattribs[] = {
         LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2,
         LOCAL_EGL_NONE
     };
 
-    context = sEGLLibrary.fCreateContext(display, configs[i], 0, cxattribs);
+    context = sEGLLibrary.fCreateContext(EGL_DISPLAY(),
+                                         configs[i],
+                                         EGL_NO_SURFACE,
+                                         cxattribs);
     if (!context) {
-        sEGLLibrary.fDestroySurface(display, surface);
+        sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface);
         return nsnull;
     }
 
     nsRefPtr<GLContextEGL> glContext =
-        new GLContextEGL(display, configs[i], surface, context, NULL, aSurface);
+        new GLContextEGL(ContextFormat(ContextFormat::BasicRGBA32),
+                         nsnull, configs[i], surface, context, PR_FALSE);
+    glContext->HoldSurface(xsurface);
 
     return glContext.forget().get();
 #else
+    (void)surface;
+    (void)context;
+
     // Not implemented
     return nsnull;
 #endif
 }
 
+static nsRefPtr<GLContext> gGlobalContext;
+
+GLContext *
+GLContextProviderEGL::GetGlobalContext()
+{
+    static bool triedToCreateContext = false;
+    if (!triedToCreateContext && !gGlobalContext) {
+        triedToCreateContext = true;
+        gGlobalContext = CreateOffscreen(gfxIntSize(16, 16));
+    }
+
+    return gGlobalContext;
+}
+
 } /* namespace gl */
 } /* namespace mozilla */
 
--- a/gfx/thebes/GLContextProviderGLX.cpp
+++ b/gfx/thebes/GLContextProviderGLX.cpp
@@ -48,24 +48,28 @@
 #include <X11/Xutil.h>
 
 #include "mozilla/X11Util.h"
 
 #include "GLContextProvider.h"
 #include "nsDebug.h"
 #include "nsIWidget.h"
 #include "GLXLibrary.h"
-#include "gfxASurface.h"
+#include "gfxXlibSurface.h"
 #include "gfxContext.h"
 #include "gfxImageSurface.h"
 #include "gfxPlatform.h"
 
 namespace mozilla {
 namespace gl {
 
+static PRBool gIsATI = PR_FALSE;
+static PRBool gIsChromium = PR_FALSE;
+static int gGLXVersion = 0;
+
 PRBool
 GLXLibrary::EnsureInitialized()
 {
     if (mInitialized) {
         return PR_TRUE;
     }
 
     if (!mOGLLibrary) {
@@ -85,24 +89,62 @@ GLXLibrary::EnsureInitialized()
         { (PRFuncPtr*) &xGetFBConfigs, { "glXGetFBConfigs", NULL } },
         { (PRFuncPtr*) &xCreatePbuffer, { "glXCreatePbuffer", NULL } },
         { (PRFuncPtr*) &xCreateNewContext, { "glXCreateNewContext", NULL } },
         { (PRFuncPtr*) &xDestroyPbuffer, { "glXDestroyPbuffer", NULL } },
         { (PRFuncPtr*) &xGetVisualFromFBConfig, { "glXGetVisualFromFBConfig", NULL } },
         { (PRFuncPtr*) &xGetFBConfigAttrib, { "glXGetFBConfigAttrib", NULL } },
         { (PRFuncPtr*) &xSwapBuffers, { "glXSwapBuffers", NULL } },
         { (PRFuncPtr*) &xQueryServerString, { "glXQueryServerString", NULL } },
+        { (PRFuncPtr*) &xCreatePixmap, { "glXCreatePixmap", NULL } },
+        { (PRFuncPtr*) &xDestroyPixmap, { "glXDestroyPixmap", NULL } },
+        { (PRFuncPtr*) &xGetClientString, { "glXGetClientString", NULL } },
+        { (PRFuncPtr*) &xCreateContext, { "glXCreateContext", NULL } },
         { NULL, { NULL } }
     };
 
     if (!LibrarySymbolLoader::LoadSymbols(mOGLLibrary, &symbols[0])) {
         NS_WARNING("Couldn't find required entry point in OpenGL shared library");
         return PR_FALSE;
     }
 
+    const char *vendor = xQueryServerString(DefaultXDisplay(),
+                                            DefaultScreen(DefaultXDisplay()),
+                                            GLX_VENDOR);
+    const char *serverVersionStr = xQueryServerString(DefaultXDisplay(),
+                                                      DefaultScreen(DefaultXDisplay()),
+                                                      GLX_VERSION);
+    const char *clientVersionStr = xGetClientString(DefaultXDisplay(),
+                                                    GLX_VERSION);
+
+
+    int serverVersion = 0, clientVersion = 0;
+    if (serverVersionStr &&
+        strlen(serverVersionStr) > 3 &&
+        serverVersionStr[1] == '.')
+    {
+        serverVersion = (serverVersionStr[0] - '0') << 8 | (serverVersionStr[2] - '0');
+    }
+
+    if (clientVersion &&
+        strlen(clientVersionStr) > 3 &&
+        clientVersionStr[1] == '.')
+    {
+        clientVersion = (clientVersionStr[0] - '0') << 8 | (clientVersionStr[2] - '0');
+    }
+
+    gGLXVersion = PR_MIN(clientVersion, serverVersion);
+
+    if (gGLXVersion < 0x0103)
+        return PR_FALSE;
+
+    gIsATI = vendor && strstr(vendor, "ATI");
+    gIsChromium = (vendor && strstr(vendor, "Chromium")) ||
+        (serverVersion && strstr(serverVersionStr, "Chromium"));
+
     mInitialized = PR_TRUE;
     return PR_TRUE;
 }
 
 GLXLibrary sGLXLibrary;
 
 static bool ctxErrorOccurred = false;
 static int
@@ -111,111 +153,142 @@ ctxErrorHandler(Display *dpy, XErrorEven
     ctxErrorOccurred = true;
     return 0;
 }
 
 class GLContextGLX : public GLContext
 {
 public:
     static already_AddRefed<GLContextGLX>
-    CreateGLContext(Display *display, GLXDrawable drawable, GLXFBConfig cfg, PRBool pbuffer)
+    CreateGLContext(const ContextFormat& format,
+                    Display *display,
+                    GLXDrawable drawable,
+                    GLXFBConfig cfg,
+                    XVisualInfo *vinfo,
+                    GLContextGLX *shareContext,
+                    PRBool deleteDrawable,
+                    gfxXlibSurface *pixmap = nsnull)
     {
         int db = 0, err;
         err = sGLXLibrary.xGetFBConfigAttrib(display, cfg,
                                              GLX_DOUBLEBUFFER, &db);
         if (GLX_BAD_ATTRIBUTE != err) {
 #ifdef DEBUG
             printf("[GLX] FBConfig is %sdouble-buffered\n", db ? "" : "not ");
 #endif
         }
 
         ctxErrorOccurred = false;
-        int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&ctxErrorHandler);
+        int (*oldHandler)(Display *, XErrorEvent *);
+        GLXContext context;
+
+TRY_AGAIN_NO_SHARING:
+        oldHandler = XSetErrorHandler(&ctxErrorHandler);
 
-        GLXContext context = sGLXLibrary.xCreateNewContext(display,
-                                                           cfg,
-                                                           GLX_RGBA_TYPE,
-                                                           NULL,
-                                                           True);
+        if (gGLXVersion >= 0x0103) {
+            context = sGLXLibrary.xCreateNewContext(display,
+                                                    cfg,
+                                                    GLX_RGBA_TYPE,
+                                                    shareContext ? shareContext->mContext : NULL,
+                                                    True);
+        } else {
+            context = sGLXLibrary.xCreateContext(display,
+                                                 vinfo,
+                                                 shareContext ? shareContext->mContext : NULL,
+                                                 True);
+        }
 
         XSync(display, False);
         XSetErrorHandler(oldHandler);
 
         if (!context || ctxErrorOccurred) {
+            if (shareContext) {
+                shareContext = nsnull;
+                goto TRY_AGAIN_NO_SHARING;
+            }
             NS_WARNING("Failed to create GLXContext!");
             return nsnull;
         }
 
-        nsRefPtr<GLContextGLX> glContext(new GLContextGLX(display, 
+        nsRefPtr<GLContextGLX> glContext(new GLContextGLX(format,
+                                                          shareContext,
+                                                          display, 
                                                           drawable, 
                                                           context,
-                                                          pbuffer,
-                                                          db));
+                                                          deleteDrawable,
+                                                          db,
+                                                          pixmap));
         if (!glContext->Init()) {
             return nsnull;
         }
 
         return glContext.forget();
     }
 
     ~GLContextGLX()
     {
-        if (mPBuffer) {
-            sGLXLibrary.xDestroyPbuffer(mDisplay, mWindow);
+        sGLXLibrary.xDeleteContext(mDisplay, mContext);
+
+        if (mDeleteDrawable) {
+            sGLXLibrary.xDestroyPixmap(mDisplay, mDrawable);
         }
+    }
 
-        sGLXLibrary.xDeleteContext(mDisplay, mContext);
+    GLContextType GetContextType() {
+        return ContextTypeGLX;
     }
 
     PRBool Init()
     {
         MakeCurrent();
         SetupLookupFunction();
         if (!InitWithPrefix("gl", PR_TRUE)) {
             return PR_FALSE;
         }
 
         return IsExtensionSupported("GL_EXT_framebuffer_object");
     }
 
     PRBool MakeCurrent()
     {
-        Bool succeeded = sGLXLibrary.xMakeCurrent(mDisplay, mWindow, mContext);
+        Bool succeeded = sGLXLibrary.xMakeCurrent(mDisplay, mDrawable, mContext);
         NS_ASSERTION(succeeded, "Failed to make GL context current!");
         return succeeded;
     }
 
     PRBool SetupLookupFunction()
     {
         mLookupFunc = (PlatformLookupFunction)sGLXLibrary.xGetProcAddress;
         return PR_TRUE;
     }
 
     void *GetNativeData(NativeDataType aType)
     {
         switch(aType) {
         case NativeGLContext:
             return mContext;
  
-        case NativePBuffer:
-            if (mPBuffer) {
-                return (void *)mWindow;
-            }
-            // fall through
+        case NativeThebesSurface:
+            return mPixmap;
 
         default:
             return nsnull;
         }
     }
 
-    virtual PRBool SwapBuffers()
+    PRBool IsDoubleBuffered()
     {
-        if (mPBuffer || !mDoubleBuffered)
+        return mDoubleBuffered;
+    }
+
+    PRBool SwapBuffers()
+    {
+        if (!mDoubleBuffered)
             return PR_FALSE;
-        sGLXLibrary.xSwapBuffers(mDisplay, mWindow);
+        sGLXLibrary.xSwapBuffers(mDisplay, mDrawable);
         return PR_TRUE;
     }
 
     void WindowDestroyed()
     {
         for (unsigned int i=0; i<textures.Length(); i++) {
             GLContext::DestroyTexture(textures.ElementAt(i));
         }
@@ -244,29 +317,43 @@ public:
 
     virtual already_AddRefed<TextureImage>
     CreateBasicTextureImage(GLuint aTexture,
                             const nsIntSize& aSize,
                             TextureImage::ContentType aContentType,
                             GLContext* aContext);
 
 private:
-    GLContextGLX(Display *aDisplay, GLXDrawable aWindow, GLXContext aContext, PRBool aPBuffer = PR_FALSE, PRBool aDoubleBuffered=PR_FALSE)
-        : mContext(aContext), 
-          mDisplay(aDisplay), 
-          mWindow(aWindow), 
-          mPBuffer(aPBuffer),
-          mDoubleBuffered(aDoubleBuffered) {}
+    friend class GLContextProviderGLX;
+
+    GLContextGLX(const ContextFormat& aFormat,
+                 GLContext *aShareContext,
+                 Display *aDisplay,
+                 GLXDrawable aDrawable,
+                 GLXContext aContext,
+                 PRBool aDeleteDrawable,
+                 PRBool aDoubleBuffered,
+                 gfxXlibSurface *aPixmap)
+        : GLContext(aFormat, aDeleteDrawable ? PR_TRUE : PR_FALSE, aShareContext),
+          mContext(aContext),
+          mDisplay(aDisplay),
+          mDrawable(aDrawable),
+          mDeleteDrawable(aDeleteDrawable),
+          mDoubleBuffered(aDoubleBuffered),
+          mPixmap(aPixmap)
+    { }
 
     GLXContext mContext;
     Display *mDisplay;
-    GLXDrawable mWindow;
-    PRBool mPBuffer;
-    PRBool mDoubleBuffered;
+    GLXDrawable mDrawable;
+    PRPackedBool mDeleteDrawable;
+    PRPackedBool mDoubleBuffered;
+
     nsTArray<GLuint> textures;
+    nsRefPtr<gfxXlibSurface> mPixmap;
 };
 
 // FIXME/bug 575505: this is a (very slow!) placeholder
 // implementation.  Much better would be to create a Pixmap, wrap that
 // in a GLXPixmap, and then glXBindTexImage() to our texture.
 class TextureImageGLX : public BasicTextureImage
 {
     friend already_AddRefed<TextureImage>
@@ -316,17 +403,24 @@ GLContextGLX::CreateBasicTextureImage(GL
                                       TextureImage::ContentType aContentType,
                                       GLContext* aContext)
 {
     nsRefPtr<TextureImageGLX> teximage(
         new TextureImageGLX(aTexture, aSize, aContentType, aContext));
     return teximage.forget();
 }
 
-static PRBool AreCompatibleVisuals(XVisualInfo *one, XVisualInfo *two)
+static GLContextGLX *
+GetGlobalContextGLX()
+{
+    return static_cast<GLContextGLX*>(GLContextProviderGLX::GetGlobalContext());
+}
+
+static PRBool
+AreCompatibleVisuals(XVisualInfo *one, XVisualInfo *two)
 {
     if (one->c_class != two->c_class) {
         return PR_FALSE;
     }
 
     if (one->depth != two->depth) {
         return PR_FALSE;
     }	
@@ -357,21 +451,19 @@ GLContextProviderGLX::CreateForWindow(ns
     // be available for the existing visual, or if it is, the GL
     // performance might be suboptimal.  But using the existing visual
     // is a relatively safe intermediate step.
 
     Display *display = (Display*)aWidget->GetNativeData(NS_NATIVE_DISPLAY); 
     int xscreen = DefaultScreen(display);
     Window window = GET_NATIVE_WINDOW(aWidget);
 
-    const char *vendor = sGLXLibrary.xQueryServerString(display, xscreen, GLX_VENDOR);
-    PRBool isATI = vendor && strstr(vendor, "ATI");
     int numConfigs;
     ScopedXFree<GLXFBConfig> cfgs;
-    if (isATI) {
+    if (gIsATI) {
         const int attribs[] = {
             GLX_DOUBLEBUFFER, False,
             0
         };
         cfgs = sGLXLibrary.xChooseFBConfig(display,
                                            xscreen,
                                            attribs,
                                            &numConfigs);
@@ -397,122 +489,261 @@ GLContextProviderGLX::CreateForWindow(ns
         return nsnull;
     }
     const VisualID widgetVisualID = XVisualIDFromVisual(widgetAttrs.visual);
 #ifdef DEBUG
     printf("[GLX] widget has VisualID 0x%lx\n", widgetVisualID);
 #endif
 
     ScopedXFree<XVisualInfo> vi;
-    if (isATI) {
+    if (gIsATI) {
         XVisualInfo vinfo_template;
         int nvisuals;
         vinfo_template.visual   = widgetAttrs.visual;
         vinfo_template.visualid = XVisualIDFromVisual(vinfo_template.visual);
         vinfo_template.depth    = widgetAttrs.depth;
         vinfo_template.screen   = xscreen;
         vi = XGetVisualInfo(display, VisualIDMask|VisualDepthMask|VisualScreenMask,
                             &vinfo_template, &nvisuals);
         NS_ASSERTION(vi && nvisuals == 1, "Could not locate unique matching XVisualInfo for Visual");
     }
 
     int matchIndex = -1;
+    ScopedXFree<XVisualInfo> vinfo;
+
     for (int i = 0; i < numConfigs; i++) {
-        ScopedXFree<XVisualInfo> info(sGLXLibrary.xGetVisualFromFBConfig(display, cfgs[i]));
-        if (!info) {
+        vinfo = sGLXLibrary.xGetVisualFromFBConfig(display, cfgs[i]);
+        if (!vinfo) {
             continue;
         }
-        if (isATI) {
-            if (AreCompatibleVisuals(vi, info)) {
+        if (gIsATI) {
+            if (AreCompatibleVisuals(vi, vinfo)) {
                 matchIndex = i;
                 break;
             }
         } else {
-            if (widgetVisualID == info->visualid) {
+            if (widgetVisualID == vinfo->visualid) {
                 matchIndex = i;
                 break;
             }
         }
     }
 
     if (matchIndex == -1) {
         NS_WARNING("[GLX] Couldn't find a FBConfig matching widget visual");
         return nsnull;
     }
 
-    nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(display,
+    GLContextGLX *shareContext = GetGlobalContextGLX();
+
+    nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(ContextFormat(ContextFormat::BasicRGB24),
+                                                                     display,
                                                                      window,
                                                                      cfgs[matchIndex],
+                                                                     vinfo,
+                                                                     shareContext,
                                                                      PR_FALSE);
     return glContext.forget();
 }
 
-already_AddRefed<GLContext>
-GLContextProviderGLX::CreatePBuffer(const gfxIntSize &aSize, const ContextFormat& aFormat)
+static already_AddRefed<GLContextGLX>
+CreateOffscreenPixmapContext(const gfxIntSize& aSize,
+                             const ContextFormat& aFormat,
+                             PRBool aShare)
 {
     if (!sGLXLibrary.EnsureInitialized()) {
         return nsnull;
     }
 
-    nsTArray<int> attribs;
+    Display *display = DefaultXDisplay();
+    int xscreen = DefaultScreen(display);
+
+    int attribs[] = {
+        GLX_DOUBLEBUFFER, False,
+        GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
+        GLX_X_RENDERABLE, True,
+        GLX_RED_SIZE, 1,
+        GLX_GREEN_SIZE, 1,
+        GLX_BLUE_SIZE, 1,
+        GLX_ALPHA_SIZE, 0,
+        GLX_DEPTH_SIZE, 0,
+        0
+    };
+    int numConfigs = 0;
+
+    ScopedXFree<GLXFBConfig> cfgs;
+    cfgs = sGLXLibrary.xChooseFBConfig(display,
+                                       xscreen,
+                                       attribs,
+                                       &numConfigs);
+    if (!cfgs) {
+        return nsnull;
+    }
+
+    NS_ASSERTION(numConfigs > 0,
+                 "glXChooseFBConfig() failed to match our requested format and violated its spec (!)");
+
+    ScopedXFree<XVisualInfo> vinfo;
+    int chosenIndex;
+
+    for (int i = 0; i < numConfigs; ++i) {
+        int dtype, visid;
+
+        if (sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i], GLX_DRAWABLE_TYPE, &dtype) != Success
+            || !(dtype & GLX_PIXMAP_BIT))
+        {
+            continue;
+        }
+        if (sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i], GLX_VISUAL_ID, &visid) != Success
+            || visid == 0)
+        {
+            continue;
+        }
+
+        vinfo = sGLXLibrary.xGetVisualFromFBConfig(display, cfgs[i]);
+
+        if (vinfo) {
+            chosenIndex = i;
+            break;
+        }
+    }
+
+    if (!vinfo) {
+        NS_WARNING("glXChooseFBConfig() didn't give us any configs with visuals!");
+        return nsnull;
+    }
+
+    nsRefPtr<gfxXlibSurface> xsurface = gfxXlibSurface::Create(DefaultScreenOfDisplay(display),
+                                                               vinfo->visual,
+                                                               gfxIntSize(16, 16));
+    if (xsurface->CairoStatus() != 0) {
+        return nsnull;
+    }
+
+   
+    GLXPixmap glxpixmap = sGLXLibrary.xCreatePixmap(display,
+                                                    cfgs[chosenIndex],
+                                                    xsurface->XDrawable(),
+                                                    NULL);
+    if (glxpixmap == 0) {
+        return nsnull;
+    }
+
+    GLContextGLX *shareContext = aShare ? GetGlobalContextGLX() : nsnull;
+
+    nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(aFormat,
+                                                                     display,
+                                                                     glxpixmap,
+                                                                     cfgs[chosenIndex],
+                                                                     vinfo,
+                                                                     shareContext,
+                                                                     PR_TRUE,
+                                                                     xsurface);
+
+    return glContext.forget();
+}
+
+already_AddRefed<GLContext>
+GLContextProviderGLX::CreateOffscreen(const gfxIntSize& aSize,
+                                      const ContextFormat& aFormat)
+{
+
+    nsRefPtr<GLContextGLX> glContext =
+        CreateOffscreenPixmapContext(aSize, aFormat, PR_TRUE);
+
+    if (!glContext) {
+        return nsnull;
+    }
+
+    if (!glContext->GetSharedContext()) {
+        // no point in returning anything if sharing failed, we can't
+        // render from this
+        return nsnull;
+    }
+
+    if (!glContext->ResizeOffscreenFBO(aSize)) {
+        // we weren't able to create the initial
+        // offscreen FBO, so this is dead
+        return nsnull;
+    }
+
+    return glContext.forget();
+}
+
+already_AddRefed<GLContext>
+GLContextProviderGLX::CreateForNativePixmapSurface(gfxASurface *aSurface)
+{
+    if (!sGLXLibrary.EnsureInitialized()) {
+        return nsnull;
+    }
+
+    if (aSurface->GetType() != gfxASurface::SurfaceTypeXlib) {
+        NS_WARNING("GLContextProviderGLX::CreateForNativePixmapSurface called with non-Xlib surface");
+        return nsnull;
+    }
+
+    nsAutoTArray<int, 20> attribs;
 
 #define A1_(_x)  do { attribs.AppendElement(_x); } while(0)
 #define A2_(_x,_y)  do {                                                \
         attribs.AppendElement(_x);                                      \
         attribs.AppendElement(_y);                                      \
     } while(0)
 
+    A2_(GLX_DOUBLEBUFFER, False);
+    A2_(GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT);
+    A1_(0);
+
     int numFormats;
     Display *display = DefaultXDisplay();
     int xscreen = DefaultScreen(display);
 
-    A2_(GLX_DOUBLEBUFFER, False);
-    A2_(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
-
-    A2_(GLX_RED_SIZE, aFormat.red);
-    A2_(GLX_GREEN_SIZE, aFormat.green);
-    A2_(GLX_BLUE_SIZE, aFormat.blue);
-    A2_(GLX_ALPHA_SIZE, aFormat.alpha);
-    A2_(GLX_DEPTH_SIZE, aFormat.depth);
-    A1_(0);
-
     ScopedXFree<GLXFBConfig> cfg(sGLXLibrary.xChooseFBConfig(display,
                                                              xscreen,
                                                              attribs.Elements(),
                                                              &numFormats));
     if (!cfg) {
         return nsnull;
     }
     NS_ASSERTION(numFormats > 0,
                  "glXChooseFBConfig() failed to match our requested format and violated its spec (!)");
-   
-    nsTArray<int> pbattribs;
-    pbattribs.AppendElement(GLX_PBUFFER_WIDTH);
-    pbattribs.AppendElement(aSize.width);
-    pbattribs.AppendElement(GLX_PBUFFER_HEIGHT);
-    pbattribs.AppendElement(aSize.height);
-    pbattribs.AppendElement(GLX_PRESERVED_CONTENTS);
-    pbattribs.AppendElement(True);
-    pbattribs.AppendElement(0);
+
+    gfxXlibSurface *xs = static_cast<gfxXlibSurface*>(aSurface);
+
+    GLXPixmap glxpixmap = sGLXLibrary.xCreatePixmap(display,
+                                                    cfg[0],
+                                                    xs->XDrawable(),
+                                                    NULL);
 
-    GLXPbuffer pbuffer = sGLXLibrary.xCreatePbuffer(display,
-                                                    cfg[0],
-                                                    pbattribs.Elements());
-
-    if (pbuffer == 0) {
+    nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(ContextFormat(ContextFormat::BasicRGB24),
+                                                                     display,
+                                                                     glxpixmap,
+                                                                     cfg[0],
+                                                                     NULL,
+                                                                     NULL,
+                                                                     PR_FALSE,
+                                                                     xs);
+    
+    if (!glContext->Init()) {
         return nsnull;
     }
 
-    nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(display,
-                                                                     pbuffer,
-                                                                     cfg[0],
-                                                                     PR_TRUE);
     return glContext.forget();
 }
 
-already_AddRefed<GLContext>
-GLContextProviderGLX::CreateForNativePixmapSurface(gfxASurface *aSurface)
+static nsRefPtr<GLContext> gGlobalContext;
+
+GLContext *
+GLContextProviderGLX::GetGlobalContext()
 {
-    return nsnull;
+    static bool triedToCreateContext = false;
+    if (!triedToCreateContext && !gGlobalContext) {
+        triedToCreateContext = true;
+        gGlobalContext = CreateOffscreenPixmapContext(gfxIntSize(1, 1),
+                                                      ContextFormat(ContextFormat::BasicRGB24),
+                                                      PR_FALSE);
+    }
+
+    return gGlobalContext;
 }
 
 } /* namespace gl */
 } /* namespace mozilla */
--- a/gfx/thebes/GLContextProviderImpl.h
+++ b/gfx/thebes/GLContextProviderImpl.h
@@ -42,38 +42,70 @@
 #error GL_CONTEXT_PROVIDER_NAME not defined
 #endif
 
 class THEBES_API GL_CONTEXT_PROVIDER_NAME
 {
 public:
     /**
      * Create a context that renders to the surface of the widget that is
-     * passed in.
+     * passed in.  The context is always created with an RGB pixel format,
+     * with no alpha, depth or stencil.  If any of those features are needed,
+     * either use a framebuffer, or use CreateOffscreen.
+     *
+     * This context will attempt to share resources with all other window
+     * contexts.  As such, it's critical that resources allocated that are not
+     * needed by other contexts be deleted before the context is destroyed.
      *
-     * @param Widget whose surface to create a context for
-     * @return Context to use for this window
+     * The GetSharedContext() method will return non-null if sharing
+     * was successful.
+     *
+     * Note: a context created for a widget /must not/ hold a strong
+     * reference to the widget; otherwise a cycle can be created through
+     * a GL layer manager.
+     *
+     * @param aWidget Widget whose surface to create a context for
+     *
+     * @return Context to use for the window
      */
     static already_AddRefed<GLContext>
     CreateForWindow(nsIWidget *aWidget);
 
     /**
-     * Creates a PBuffer.
+     * Create a context for offscreen rendering.  The target of this
+     * context should be treated as opaque -- it might be a FBO, or a
+     * pbuffer, or some other construct.  Users of this GLContext
+     * should not bind framebuffer 0 directly, and instead should bind
+     * the framebuffer returned by GetOffscreenFBO().
      *
-     * @param aSize Size of the pbuffer to create
-     * @param aFormat A ContextFormat describing the desired context attributes.  Defaults to a basic RGBA32 context.
+     * The offscreen context returned by this method will always have
+     * the ability to be rendered into a context created by a window.
+     * It might or might not share resources with the global context;
+     * query GetSharedContext() for a non-null result to check.  If
+     * resource sharing can be avoided on the target platform, it will
+     * be, in order to isolate the offscreen context.
      *
-     * @return Context to use for this Pbuffer
+     * @param aSize The initial size of this offscreen context.
+     * @param aFormat The ContextFormat for this offscreen context.
+     *
+     * @return Context to use for offscreen rendering
      */
     static already_AddRefed<GLContext>
-    CreatePBuffer(const gfxIntSize &aSize,
-                  const ContextFormat& aFormat = ContextFormat::BasicRGBA32Format);
+    CreateOffscreen(const gfxIntSize& aSize,
+                    const ContextFormat& aFormat = ContextFormat::BasicRGBA32Format);
 
     /**
      * Try to create a GL context from native surface for arbitrary gfxASurface
      * If surface not compatible this will return NULL
      *
      * @param aSurface surface to create a context for
+     *
      * @return Context to use for this surface
      */
     static already_AddRefed<GLContext>
     CreateForNativePixmapSurface(gfxASurface *aSurface);
+
+    /**
+     * Get a pointer to the global context, creating it if it doesn't exist.
+     */
+    static GLContext *
+    GetGlobalContext();
 };
--- a/gfx/thebes/GLContextProviderNull.cpp
+++ b/gfx/thebes/GLContextProviderNull.cpp
@@ -40,21 +40,28 @@ namespace gl {
 
 already_AddRefed<GLContext>
 GLContextProviderNull::CreateForWindow(nsIWidget*)
 {
     return nsnull;
 }
 
 already_AddRefed<GLContext>
-GLContextProviderNull::CreateForNativePixmapSurface(gfxASurface *aSurface)
+GLContextProviderNull::CreateOffscreen(const gfxIntSize&,
+                                       const ContextFormat&)
 {
-    return 0;
+    return nsnull;
 }
 
 already_AddRefed<GLContext>
-GLContextProviderNull::CreatePBuffer(const gfxIntSize &, const ContextFormat &)
+GLContextProviderNull::CreateForNativePixmapSurface(gfxASurface *)
+{
+    return nsnull;
+}
+
+GLContext *
+GLContextProviderNull::GetGlobalContext()
 {
     return nsnull;
 }
 
 } /* namespace gl */
 } /* namespace mozilla */
--- a/gfx/thebes/GLContextProviderOSMesa.cpp
+++ b/gfx/thebes/GLContextProviderOSMesa.cpp
@@ -148,61 +148,71 @@ OSMesaLibrary::EnsureInitialized()
 
     mInitialized = PR_TRUE;
     return PR_TRUE;
 }
 
 class GLContextOSMesa : public GLContext
 {
 public:
-    GLContextOSMesa()
-        : mThebesSurface(nsnull),
+    GLContextOSMesa(const ContextFormat& aFormat)
+        : GLContext(aFormat, PR_TRUE, nsnull),
+          mThebesSurface(nsnull),
           mContext(nsnull)
     {
     }
 
     ~GLContextOSMesa()
     {
         if (mContext)
             sOSMesaLibrary.fDestroyContext(mContext);
     }
 
-    PRBool Init(const gfxIntSize &aSize, const ContextFormat& aFormat)
+    GLContextType GetContextType() {
+        return ContextTypeOSMesa;
+    }
+
+    PRBool Init(const gfxIntSize &aSize)
     {
         int osmesa_format = -1;
         int gfxasurface_imageformat = -1;
         PRBool format_accepted = PR_FALSE;
 
-        if (aFormat.red == 8 && aFormat.green == 8 && aFormat.blue == 8) {
-            if (aFormat.alpha == 8) {
-                osmesa_format = OSMESA_BGRA;
-                gfxasurface_imageformat = gfxASurface::ImageFormatARGB32;
-                format_accepted = PR_TRUE;
-            }
-            else if (aFormat.alpha == 0) {
+        if (mCreationFormat.red > 0 &&
+            mCreationFormat.green > 0 &&
+            mCreationFormat.blue > 0 &&
+            mCreationFormat.red <= 8 &&
+            mCreationFormat.green <= 8 &&
+            mCreationFormat.blue <= 8)
+        {
+            if (mCreationFormat.alpha == 0) {
                 // we can't use OSMESA_BGR because it is packed 24 bits per pixel.
                 // So we use OSMESA_BGRA and have to use ImageFormatRGB24
                 // to make sure that the dummy alpha channel is ignored.
                 osmesa_format = OSMESA_BGRA;
                 gfxasurface_imageformat = gfxASurface::ImageFormatRGB24;
                 format_accepted = PR_TRUE;
+            } else if (mCreationFormat.alpha <= 8) {
+                osmesa_format = OSMESA_BGRA;
+                gfxasurface_imageformat = gfxASurface::ImageFormatARGB32;
+                format_accepted = PR_TRUE;
             }
         }
         if (!format_accepted) {
             NS_WARNING("Pixel format not supported with OSMesa.");
             return PR_FALSE;
         }
 
         mThebesSurface = new gfxImageSurface(aSize, gfxASurface::gfxImageFormat(gfxasurface_imageformat));
         if (mThebesSurface->CairoStatus() != 0) {
             NS_WARNING("image surface failed");
             return PR_FALSE;
         }
 
-        mContext = sOSMesaLibrary.fCreateContextExt(osmesa_format, aFormat.depth, aFormat.stencil, 0, NULL);
+        mContext = sOSMesaLibrary.fCreateContextExt(osmesa_format, mCreationFormat.depth, mCreationFormat.stencil, 0, NULL);
         if (!mContext) {
             NS_WARNING("OSMesaCreateContextExt failed!");
             return PR_FALSE;
         }
 
         if (!MakeCurrent()) return PR_FALSE;
         if (!SetupLookupFunction()) return PR_FALSE;
 
@@ -210,20 +220,20 @@ public:
         sOSMesaLibrary.fPixelStore(OSMESA_Y_UP, 0);
 
         return InitWithPrefix("gl", PR_TRUE);
     }
 
     PRBool MakeCurrent()
     {
         PRBool succeeded
-          = sOSMesaLibrary.fMakeCurrent (mContext, mThebesSurface->Data(),
-                                         LOCAL_GL_UNSIGNED_BYTE,
-                                         mThebesSurface->Width(),
-                                         mThebesSurface->Height());
+          = sOSMesaLibrary.fMakeCurrent(mContext, mThebesSurface->Data(),
+                                        LOCAL_GL_UNSIGNED_BYTE,
+                                        mThebesSurface->Width(),
+                                        mThebesSurface->Height());
         NS_ASSERTION(succeeded, "Failed to make OSMesa context current!");
 
         return succeeded;
     }
 
     PRBool SetupLookupFunction()
     {
         mLookupFunc = (PlatformLookupFunction)sOSMesaLibrary.fGetProcAddress;
@@ -247,31 +257,33 @@ private:
 
 already_AddRefed<GLContext>
 GLContextProviderOSMesa::CreateForWindow(nsIWidget *aWidget)
 {
     return nsnull;
 }
 
 already_AddRefed<GLContext>
-GLContextProviderOSMesa::CreateForNativePixmapSurface(gfxASurface *aSurface)
-{
-    return 0;
-}
-
-already_AddRefed<GLContext>
-GLContextProviderOSMesa::CreatePBuffer(const gfxIntSize &aSize, const ContextFormat& aFormat)
+GLContextProviderOSMesa::CreateOffscreen(const gfxIntSize& aSize,
+                                         const ContextFormat& aFormat)
 {
     if (!sOSMesaLibrary.EnsureInitialized()) {
         return nsnull;
     }
 
-    nsRefPtr<GLContextOSMesa> glContext = new GLContextOSMesa;
+    nsRefPtr<GLContextOSMesa> glContext = new GLContextOSMesa(aFormat);
 
-    if (!glContext->Init(aSize, aFormat)) {
+    if (!glContext->Init(aSize))
+    {
         return nsnull;
     }
 
-    return glContext.forget().get();
+    return glContext.forget();
+}
+
+GLContext *
+GLContextProviderOSMesa::GetGlobalContext()
+{
+    return nsnull;
 }
 
 } /* namespace gl */
 } /* namespace mozilla */
--- a/gfx/thebes/GLContextProviderWGL.cpp
+++ b/gfx/thebes/GLContextProviderWGL.cpp
@@ -44,19 +44,72 @@
 #include "gfxPlatform.h"
 #include "gfxWindowsSurface.h"
 
 namespace mozilla {
 namespace gl {
 
 WGLLibrary sWGLLibrary;
 
-static HWND gDummyWindow = 0;
-static HDC gDummyWindowDC = 0;
-static HANDLE gDummyWindowGLContext = 0;
+static HWND gSharedWindow = 0;
+static HDC gSharedWindowDC = 0;
+static HGLRC gSharedWindowGLContext = 0;
+static int gSharedWindowPixelFormat = 0;
+
+static HWND
+CreateDummyWindow(HDC *aWindowDC = nsnull)
+{
+    WNDCLASSW wc;
+    if (!GetClassInfoW(GetModuleHandle(NULL), L"GLContextWGLClass", &wc)) {
+        ZeroMemory(&wc, sizeof(WNDCLASSW));
+        wc.style = CS_OWNDC;
+        wc.hInstance = GetModuleHandle(NULL);
+        wc.lpfnWndProc = DefWindowProc;
+        wc.lpszClassName = L"GLContextWGLClass";
+        if (!RegisterClassW(&wc)) {
+            NS_WARNING("Failed to register GLContextWGLClass?!");
+            // er. failed to register our class?
+            return NULL;
+        }
+    }
+
+    HWND win = CreateWindowW(L"GLContextWGLClass", L"GLContextWGL", 0,
+                             0, 0, 16, 16,
+                             NULL, NULL, GetModuleHandle(NULL), NULL);
+    NS_ENSURE_TRUE(win, NULL);
+
+    HDC dc = GetDC(win);
+    NS_ENSURE_TRUE(dc, NULL);
+
+    if (gSharedWindowPixelFormat == 0) {
+        PIXELFORMATDESCRIPTOR pfd;
+        ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
+        pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
+        pfd.nVersion = 1;
+        pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
+        pfd.iPixelType = PFD_TYPE_RGBA;
+        pfd.cColorBits = 24;
+        pfd.cDepthBits = 0;
+        pfd.iLayerType = PFD_MAIN_PLANE;
+
+        gSharedWindowPixelFormat = ChoosePixelFormat(dc, &pfd);
+    }
+
+    if (!SetPixelFormat(dc, gSharedWindowPixelFormat, NULL)) {
+        NS_WARNING("SetPixelFormat failed!");
+        DestroyWindow(win);
+        return NULL;
+    }
+
+    if (aWindowDC) {
+        *aWindowDC = dc;
+    }
+
+    return win;
+}
 
 PRBool
 WGLLibrary::EnsureInitialized()
 {
     if (mInitialized)
         return PR_TRUE;
 
     if (!mOGLLibrary) {
@@ -69,79 +122,38 @@ WGLLibrary::EnsureInitialized()
 
     LibrarySymbolLoader::SymLoadStruct earlySymbols[] = {
         { (PRFuncPtr*) &fCreateContext, { "wglCreateContext", NULL } },
         { (PRFuncPtr*) &fMakeCurrent, { "wglMakeCurrent", NULL } },
         { (PRFuncPtr*) &fGetProcAddress, { "wglGetProcAddress", NULL } },
         { (PRFuncPtr*) &fDeleteContext, { "wglDeleteContext", NULL } },
         { (PRFuncPtr*) &fGetCurrentContext, { "wglGetCurrentContext", NULL } },
         { (PRFuncPtr*) &fGetCurrentDC, { "wglGetCurrentDC", NULL } },
+        { (PRFuncPtr*) &fShareLists, { "wglShareLists", NULL } },
         { NULL, { NULL } }
     };
 
     if (!LibrarySymbolLoader::LoadSymbols(mOGLLibrary, &earlySymbols[0])) {
         NS_WARNING("Couldn't find required entry points in OpenGL DLL (early init)");
         return PR_FALSE;
     }
 
-    // This is ridiculous -- we have to actually create a context to get the OpenGL
-    // ICD to load.
-
-    WNDCLASSW wc;
-    if (!GetClassInfoW(GetModuleHandle(NULL), L"DummyGLWindowClass", &wc)) {
-        ZeroMemory(&wc, sizeof(WNDCLASSW));
-        wc.hInstance = GetModuleHandle(NULL);
-        wc.lpfnWndProc = DefWindowProc;
-        wc.lpszClassName = L"DummyGLWindowClass";
-        if (!RegisterClassW(&wc)) {
-            NS_WARNING("Failed to register DummyGLWindowClass?!");
-            // er. failed to register our class?
-            return PR_FALSE;
-        }
-    }
-
-    gDummyWindow = CreateWindowW(L"DummyGLWindowClass", L"DummyGLWindow", 0,
-                                 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 
-                                 CW_USEDEFAULT, NULL, NULL, GetModuleHandle(NULL), NULL);
-    if (!gDummyWindow) {
-        NS_WARNING("CreateWindow DummyGLWindow failed");
-        return PR_FALSE;
-    }
-
-    gDummyWindowDC = GetDC(gDummyWindow);
-    if (!gDummyWindowDC) {
-        NS_WARNING("GetDC gDummyWindow failed");
-        return PR_FALSE;
-    }
-
-    // find default pixel format
-    PIXELFORMATDESCRIPTOR pfd;
-    ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
-    pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
-    pfd.nVersion = 1;
-    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
-    int pixelformat = ChoosePixelFormat(gDummyWindowDC, &pfd);
-
-    // set the pixel format for the dc
-    if (!SetPixelFormat(gDummyWindowDC, pixelformat, &pfd)) {
-        NS_WARNING("SetPixelFormat failed");
-        return PR_FALSE;
-    }
+    // This is ridiculous -- we have to actually create a context to
+    // get the OpenGL ICD to load.
+    gSharedWindow = CreateDummyWindow(&gSharedWindowDC);
+    NS_ENSURE_TRUE(gSharedWindow, PR_FALSE);
 
     // create rendering context
-    gDummyWindowGLContext = fCreateContext(gDummyWindowDC);
-    if (!gDummyWindowGLContext) {
-        NS_WARNING("wglCreateContext failed");
-        return PR_FALSE;
-    }
+    gSharedWindowGLContext = fCreateContext(gSharedWindowDC);
+    NS_ENSURE_TRUE(gSharedWindowGLContext, PR_FALSE);
 
     HGLRC curCtx = fGetCurrentContext();
     HDC curDC = fGetCurrentDC();
 
-    if (!fMakeCurrent((HDC)gDummyWindowDC, (HGLRC)gDummyWindowGLContext)) {
+    if (!fMakeCurrent((HDC)gSharedWindowDC, (HGLRC)gSharedWindowGLContext)) {
         NS_WARNING("wglMakeCurrent failed");
         return PR_FALSE;
     }
 
     // Now we can grab all the other symbols that we couldn't without having
     // a context current.
 
     LibrarySymbolLoader::SymLoadStruct pbufferSymbols[] = {
@@ -172,43 +184,85 @@ WGLLibrary::EnsureInitialized()
         // this isn't an error, just means that we don't have the pixel format extension
         fChoosePixelFormat = nsnull;
     }
 
     // reset back to the previous context, just in case
     fMakeCurrent(curDC, curCtx);
 
     mInitialized = PR_TRUE;
+
+    // Call this to create the global GLContext instance,
+    // and to check for errors.  Note that this must happen /after/
+    // setting mInitialized to TRUE, or an infinite loop results.
+    if (GLContextProviderWGL::GetGlobalContext() == nsnull) {
+        mInitialized = PR_FALSE;
+        return PR_FALSE;
+    }
+
     return PR_TRUE;
 }
 
 class GLContextWGL : public GLContext
 {
 public:
-    GLContextWGL(HDC aDC, HGLRC aContext)
-        : mContext(aContext), mDC(aDC), mPBuffer(nsnull), mPixelFormat(-1)
-    { }
+    GLContextWGL(const ContextFormat& aFormat,
+                 GLContext *aSharedContext,
+                 HDC aDC,
+                 HGLRC aContext,
+                 HWND aWindow = nsnull,
+                 PRBool aIsOffscreen = PR_FALSE)
+        : GLContext(aFormat, aIsOffscreen, aSharedContext),
+          mDC(aDC),
+          mContext(aContext),
+          mWnd(aWindow),
+          mPBuffer(NULL),
+          mPixelFormat(0)
+    {
+    }
 
-    GLContextWGL(HANDLE aPBuffer, int aPixelFormat) {
-        mPBuffer = aPBuffer;
-        mPixelFormat = aPixelFormat;
-        mDC = sWGLLibrary.fGetPbufferDC(mPBuffer);
-        mContext = sWGLLibrary.fCreateContext(mDC);
+    GLContextWGL(const ContextFormat& aFormat,
+                 GLContext *aSharedContext,
+                 HANDLE aPbuffer,
+                 HDC aDC,
+                 HGLRC aContext,
+                 int aPixelFormat)
+        : GLContext(aFormat, PR_TRUE, aSharedContext),
+          mDC(aDC),
+          mContext(aContext),
+          mWnd(NULL),
+          mPBuffer(aPbuffer),
+          mPixelFormat(aPixelFormat)
+    {
     }
 
     ~GLContextWGL()
     {
+        if (mOffscreenFBO) {
+            MakeCurrent();
+            DeleteOffscreenFBO();
+        }
+
         sWGLLibrary.fDeleteContext(mContext);
 
         if (mPBuffer)
             sWGLLibrary.fDestroyPbuffer(mPBuffer);
+        if (mWnd)
+            DestroyWindow(mWnd);
+    }
+
+    GLContextType GetContextType() {
+        return ContextTypeWGL;
     }
 
     PRBool Init()
     {
+        if (!mDC || !mContext)
+            return PR_FALSE;
+
         MakeCurrent();
         SetupLookupFunction();
         return InitWithPrefix("gl", PR_TRUE);
     }
 
     PRBool MakeCurrent()
     {
         BOOL succeeded = PR_TRUE;
@@ -232,77 +286,141 @@ public:
     }
 
     void *GetNativeData(NativeDataType aType)
     {
         switch (aType) {
         case NativeGLContext:
             return mContext;
 
-        case NativePBuffer:
-            return mPBuffer;
-
         default:
             return nsnull;
         }
     }
 
-    PRBool Resize(const gfxIntSize& aNewSize) {
-        if (!mPBuffer)
-            return PR_FALSE;
+    PRBool BindTex2DOffscreen(GLContext *aOffscreen);
+    void UnbindTex2DOffscreen(GLContext *aOffscreen);
+    PRBool ResizeOffscreen(const gfxIntSize& aNewSize);
+
+    HGLRC Context() { return mContext; }
+
+    virtual already_AddRefed<TextureImage>
+    CreateBasicTextureImage(GLuint aTexture,
+                            const nsIntSize& aSize,
+                            TextureImage::ContentType aContentType,
+                            GLContext* aContext);
+
+protected:
+    friend class GLContextProviderWGL;
+
+    HDC mDC;
+    HGLRC mContext;
+    HWND mWnd;
+    HANDLE mPBuffer;
+    int mPixelFormat;
+};
+
+PRBool
+GLContextWGL::BindTex2DOffscreen(GLContext *aOffscreen)
+{
+    if (aOffscreen->GetContextType() != ContextTypeWGL) {
+        NS_WARNING("non-WGL context");
+        return PR_FALSE;
+    }
+
+    if (!aOffscreen->IsOffscreen()) {
+        NS_WARNING("non-offscreen context");
+        return PR_FALSE;
+    }
+
+    GLContextWGL *offs = static_cast<GLContextWGL*>(aOffscreen);
 
-        nsTArray<int> pbattribs;
-        pbattribs.AppendElement(LOCAL_WGL_TEXTURE_FORMAT_ARB);
-        // XXX fixme after bug 571092 lands and we have the format available
-        if (true /*aFormat.alpha > 0*/) {
-            pbattribs.AppendElement(LOCAL_WGL_TEXTURE_RGBA_ARB);
-        } else {
-            pbattribs.AppendElement(LOCAL_WGL_TEXTURE_RGB_ARB);
+    if (offs->mPBuffer) {
+        BOOL ok = sWGLLibrary.fBindTexImage(offs->mPBuffer,
+                                            LOCAL_WGL_FRONT_LEFT_ARB);
+        if (!ok) {
+            NS_WARNING("CanvasLayerOGL::Updated wglBindTexImageARB failed");
+            return PR_FALSE;
+        }
+    } else if (offs->mOffscreenTexture) {
+        if (offs->GetSharedContext() != GLContextProviderWGL::GetGlobalContext())
+        {
+            NS_WARNING("offscreen FBO context can only be bound with context sharing!");
+            return PR_FALSE;
         }
-        pbattribs.AppendElement(LOCAL_WGL_TEXTURE_TARGET_ARB);
-        pbattribs.AppendElement(LOCAL_WGL_TEXTURE_2D_ARB);
+
+        fBindTexture(LOCAL_GL_TEXTURE_2D, offs->mOffscreenTexture);
+    } else {
+        NS_WARNING("don't know how to bind this!");
+        return PR_FALSE;
+    }
+
+    return PR_TRUE;
+}
+
+void
+GLContextWGL::UnbindTex2DOffscreen(GLContext *aOffscreen)
+{
+    NS_ASSERTION(aOffscreen->GetContextType() == ContextTypeWGL, "wrong type");
 
-        pbattribs.AppendElement(0);
+    GLContextWGL *offs = static_cast<GLContextWGL*>(aOffscreen);
+    if (offs->mPBuffer) {
+        // XXX so, according to the extension, ReleaseTexImage is not required to
+        // preserve color buffer contents.  This sucks, but everywhere that I've
+        // tried it the color buffer is preserved.  So let's cross our fingers..
+        sWGLLibrary.fReleaseTexImage(offs->mPBuffer, LOCAL_WGL_FRONT_LEFT_ARB);
+    }
+}
 
-        HANDLE newbuf = sWGLLibrary.fCreatePbuffer(gDummyWindowDC, mPixelFormat,
+PRBool
+GLContextWGL::ResizeOffscreen(const gfxIntSize& aNewSize)
+{
+    if (mPBuffer) {
+        int pbattrs[] = {
+            LOCAL_WGL_TEXTURE_FORMAT_ARB,
+              mCreationFormat.alpha > 0 ? LOCAL_WGL_TEXTURE_RGBA_ARB
+                                        : LOCAL_WGL_TEXTURE_RGB_ARB,
+            LOCAL_WGL_TEXTURE_TARGET_ARB, LOCAL_WGL_TEXTURE_2D_ARB,
+            0
+        };
+
+        HANDLE newbuf = sWGLLibrary.fCreatePbuffer(gSharedWindowDC, mPixelFormat,
                                                    aNewSize.width, aNewSize.height,
-                                                   pbattribs.Elements());
+                                                   pbattrs);
         if (!newbuf)
             return PR_FALSE;
 
         bool isCurrent = false;
         if (sWGLLibrary.fGetCurrentContext() == mContext) {
             sWGLLibrary.fMakeCurrent(NULL, NULL);
             isCurrent = true;
         }
 
-        // hey, it worked!
         sWGLLibrary.fDestroyPbuffer(mPBuffer);
 
         mPBuffer = newbuf;
         mDC = sWGLLibrary.fGetPbufferDC(mPBuffer);
 
-        if (isCurrent)
-            MakeCurrent();
+        mOffscreenSize = aNewSize;
+        mOffscreenActualSize = aNewSize;
+
+        MakeCurrent();
+        ClearSafely();
 
         return PR_TRUE;
     }
 
-    virtual already_AddRefed<TextureImage>
-    CreateBasicTextureImage(GLuint aTexture,
-                            const nsIntSize& aSize,
-                            TextureImage::ContentType aContentType,
-                            GLContext* aContext);
+    return ResizeOffscreenFBO(aNewSize);
+}
 
-private:
-    HGLRC mContext;
-    HDC mDC;
-    HANDLE mPBuffer;
-    int mPixelFormat;
-};
+static GLContextWGL *
+GetGlobalContextWGL()
+{
+    return static_cast<GLContextWGL*>(GLContextProviderWGL::GetGlobalContext());
+}
 
 class TextureImageWGL : public BasicTextureImage
 {
     friend already_AddRefed<TextureImage>
     GLContextWGL::CreateBasicTextureImage(GLuint,
                                           const nsIntSize&,
                                           TextureImage::ContentType,
                                           GLContext*);
@@ -346,131 +464,234 @@ GLContextWGL::CreateBasicTextureImage(GL
 }
 
 already_AddRefed<GLContext>
 GLContextProviderWGL::CreateForWindow(nsIWidget *aWidget)
 {
     if (!sWGLLibrary.EnsureInitialized()) {
         return nsnull;
     }
+
     /**
        * We need to make sure we call SetPixelFormat -after- calling 
        * EnsureInitialized, otherwise it can load/unload the dll and 
        * wglCreateContext will fail.
        */
 
     HDC dc = (HDC)aWidget->GetNativeData(NS_NATIVE_GRAPHIC);
 
-    PIXELFORMATDESCRIPTOR pfd;
-    ZeroMemory(&pfd, sizeof(pfd));
-
-    pfd.nSize = sizeof(pfd);
-    pfd.nVersion = 1;
-    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
-    pfd.iPixelType = PFD_TYPE_RGBA;
-    pfd.cColorBits = 32;
-    pfd.cDepthBits = 0;
-    pfd.iLayerType = PFD_MAIN_PLANE;
-    int iFormat = ChoosePixelFormat(dc, &pfd);
-
-    SetPixelFormat(dc, iFormat, &pfd);
+    SetPixelFormat(dc, gSharedWindowPixelFormat, NULL);
     HGLRC context = sWGLLibrary.fCreateContext(dc);
     if (!context) {
         return nsnull;
     }
 
-    nsRefPtr<GLContextWGL> glContext = new GLContextWGL(dc, context);
-    glContext->Init();
+    GLContextWGL *shareContext = GetGlobalContextWGL();
+    if (shareContext &&
+        !sWGLLibrary.fShareLists(shareContext->Context(), context))
+    {
+        shareContext = nsnull;
+    }
 
-    return glContext.forget().get();
-}
-
-already_AddRefed<GLContext>
-GLContextProviderWGL::CreatePBuffer(const gfxIntSize& aSize, const ContextFormat& aFormat)
-{
-    if (!sWGLLibrary.EnsureInitialized()) {
+    nsRefPtr<GLContextWGL> glContext = new GLContextWGL(ContextFormat(ContextFormat::BasicRGB24),
+                                                        shareContext, dc, context);
+    if (!glContext->Init()) {
         return nsnull;
     }
 
-    nsTArray<int> attribs;
+    return glContext.forget();
+}
+
+static already_AddRefed<GLContextWGL>
+CreatePBufferOffscreenContext(const gfxIntSize& aSize,
+                              const ContextFormat& aFormat)
+{
+#define A1(_a,_x)  do { _a.AppendElement(_x); } while(0)
+#define A2(_a,_x,_y)  do { _a.AppendElement(_x); _a.AppendElement(_y); } while(0)
+
+    nsTArray<int> attrs;
 
-#define A1_(_x)  do { attribs.AppendElement(_x); } while(0)
-#define A2_(_x,_y)  do {                                                \
-        attribs.AppendElement(_x);                                      \
-        attribs.AppendElement(_y);                                      \
-    } while(0)
+    A2(attrs, LOCAL_WGL_SUPPORT_OPENGL_ARB, LOCAL_GL_TRUE);
+    A2(attrs, LOCAL_WGL_DRAW_TO_PBUFFER_ARB, LOCAL_GL_TRUE);
+    A2(attrs, LOCAL_WGL_DOUBLE_BUFFER_ARB, LOCAL_GL_FALSE);
+
+    A2(attrs, LOCAL_WGL_ACCELERATION_ARB, LOCAL_WGL_FULL_ACCELERATION_ARB);
 
-    A2_(LOCAL_WGL_SUPPORT_OPENGL_ARB, LOCAL_GL_TRUE);
-    A2_(LOCAL_WGL_DRAW_TO_PBUFFER_ARB, LOCAL_GL_TRUE);
-    A2_(LOCAL_WGL_DOUBLE_BUFFER_ARB, LOCAL_GL_FALSE);
+    A2(attrs, LOCAL_WGL_COLOR_BITS_ARB, aFormat.colorBits());
+    A2(attrs, LOCAL_WGL_RED_BITS_ARB, aFormat.red);
+    A2(attrs, LOCAL_WGL_GREEN_BITS_ARB, aFormat.green);
+    A2(attrs, LOCAL_WGL_BLUE_BITS_ARB, aFormat.blue);
+    A2(attrs, LOCAL_WGL_ALPHA_BITS_ARB, aFormat.alpha);
 
-    A2_(LOCAL_WGL_ACCELERATION_ARB, LOCAL_WGL_FULL_ACCELERATION_ARB);
+    A2(attrs, LOCAL_WGL_DEPTH_BITS_ARB, aFormat.depth);
 
-    A2_(LOCAL_WGL_COLOR_BITS_ARB, aFormat.colorBits());
-    A2_(LOCAL_WGL_RED_BITS_ARB, aFormat.red);
-    A2_(LOCAL_WGL_GREEN_BITS_ARB, aFormat.green);
-    A2_(LOCAL_WGL_BLUE_BITS_ARB, aFormat.blue);
-    A2_(LOCAL_WGL_ALPHA_BITS_ARB, aFormat.alpha);
+    if (aFormat.alpha > 0) {
+        A2(attrs, LOCAL_WGL_BIND_TO_TEXTURE_RGBA_ARB, LOCAL_GL_TRUE);
+    } else {
+        A2(attrs, LOCAL_WGL_BIND_TO_TEXTURE_RGB_ARB, LOCAL_GL_TRUE);
+    }
 
-    A2_(LOCAL_WGL_DEPTH_BITS_ARB, aFormat.depth);
+    A2(attrs, LOCAL_WGL_DOUBLE_BUFFER_ARB, LOCAL_GL_FALSE);
+    A2(attrs, LOCAL_WGL_STEREO_ARB, LOCAL_GL_FALSE);
+
+    A1(attrs, 0);
 
-    if (aFormat.alpha > 0)
-        A2_(LOCAL_WGL_BIND_TO_TEXTURE_RGBA_ARB, LOCAL_GL_TRUE);
-    else
-        A2_(LOCAL_WGL_BIND_TO_TEXTURE_RGB_ARB, LOCAL_GL_TRUE);
-
-    A2_(LOCAL_WGL_DOUBLE_BUFFER_ARB, LOCAL_GL_FALSE);
-    A2_(LOCAL_WGL_STEREO_ARB, LOCAL_GL_FALSE);
+    nsTArray<int> pbattrs;
+    A2(pbattrs, LOCAL_WGL_TEXTURE_TARGET_ARB, LOCAL_WGL_TEXTURE_2D_ARB);
 
-    A1_(0);
+    if (aFormat.alpha > 0) {
+        A2(pbattrs, LOCAL_WGL_TEXTURE_FORMAT_ARB, LOCAL_WGL_TEXTURE_RGBA_ARB);
+    } else {
+        A2(pbattrs, LOCAL_WGL_TEXTURE_FORMAT_ARB, LOCAL_WGL_TEXTURE_RGB_ARB);
+    }
+    A1(pbattrs, 0);
 
-#define MAX_NUM_FORMATS 256
-    UINT numFormats = MAX_NUM_FORMATS;
-    int formats[MAX_NUM_FORMATS];
+    UINT numFormats = 256;
+    int formats[256];
 
-    if (!sWGLLibrary.fChoosePixelFormat(gDummyWindowDC,
-                                        attribs.Elements(), NULL,
+    if (!sWGLLibrary.fChoosePixelFormat(gSharedWindowDC,
+                                        attrs.Elements(), NULL,
                                         numFormats, formats, &numFormats)
         || numFormats == 0)
     {
         return nsnull;
     }
 
     // XXX add back the priority choosing code here
     int chosenFormat = formats[0];
 
-    nsTArray<int> pbattribs;
-    pbattribs.AppendElement(LOCAL_WGL_TEXTURE_FORMAT_ARB);
-    if (aFormat.alpha > 0) {
-        pbattribs.AppendElement(LOCAL_WGL_TEXTURE_RGBA_ARB);
-    } else {
-        pbattribs.AppendElement(LOCAL_WGL_TEXTURE_RGB_ARB);
-    }
-    pbattribs.AppendElement(LOCAL_WGL_TEXTURE_TARGET_ARB);
-    pbattribs.AppendElement(LOCAL_WGL_TEXTURE_2D_ARB);
-
-    // hmm, do we need mipmaps?
-    //pbattribs.AppendElement(LOCAL_WGL_MIPMAP_TEXTURE_ARB);
-    //pbattribs.AppendElement(LOCAL_GL_TRUE);
-
-    pbattribs.AppendElement(0);
-
-    HANDLE pbuffer = sWGLLibrary.fCreatePbuffer(gDummyWindowDC, chosenFormat,
+    HANDLE pbuffer = sWGLLibrary.fCreatePbuffer(gSharedWindowDC, chosenFormat,
                                                 aSize.width, aSize.height,
-                                                pbattribs.Elements());
+                                                pbattrs.Elements());
     if (!pbuffer) {
         return nsnull;
     }
 
-    nsRefPtr<GLContextWGL> glContext = new GLContextWGL(pbuffer, chosenFormat);
-    glContext->Init();
+    HDC pbdc = sWGLLibrary.fGetPbufferDC(pbuffer);
+    NS_ASSERTION(pbdc, "expected a dc");
+
+    HGLRC context = sWGLLibrary.fCreateContext(pbdc);
+    if (!context) {
+        sWGLLibrary.fDestroyPbuffer(pbuffer);
+        return PR_FALSE;
+    }
+
+    nsRefPtr<GLContextWGL> glContext = new GLContextWGL(aFormat,
+                                                        nsnull,
+                                                        pbuffer,
+                                                        pbdc,
+                                                        context,
+                                                        chosenFormat);
+
+    return glContext.forget();
+}
+
+static already_AddRefed<GLContextWGL>
+CreateWindowOffscreenContext(const gfxIntSize& aSize,
+                             const ContextFormat& aFormat)
+{
+    // CreateWindowOffscreenContext must return a global-shared context
+    GLContextWGL *shareContext = GetGlobalContextWGL();
+    if (!shareContext) {
+        return nsnull;
+    }
+    
+    HDC dc;
+    HWND win = CreateDummyWindow(&dc);
+    if (!win) {
+        return nsnull;
+    }
+    
+    HGLRC context = sWGLLibrary.fCreateContext(dc);
+    if (!context) {
+        return nsnull;
+    }
+
+    if (!sWGLLibrary.fShareLists(shareContext->Context(), context)) {
+        NS_WARNING("wglShareLists failed!");
 
-    return glContext.forget().get();
+        sWGLLibrary.fDeleteContext(context);
+        DestroyWindow(win);
+        return nsnull;
+    }
+
+    nsRefPtr<GLContextWGL> glContext = new GLContextWGL(aFormat, shareContext,
+                                                        dc, context, win, PR_TRUE);
+
+    return glContext.forget();
+}
+
+already_AddRefed<GLContext>
+GLContextProviderWGL::CreateOffscreen(const gfxIntSize& aSize,
+                                      const ContextFormat& aFormat)
+{
+    if (!sWGLLibrary.EnsureInitialized()) {
+        return nsnull;
+    }
+
+    nsRefPtr<GLContextWGL> glContext;
+
+    // Always try to create a pbuffer context first, because we
+    // want the context isolation.
+    if (sWGLLibrary.fCreatePbuffer &&
+        sWGLLibrary.fChoosePixelFormat)
+    {
+        glContext = CreatePBufferOffscreenContext(aSize, aFormat);
+    }
+
+    // If it failed, then create a window context and use a FBO.
+    if (!glContext) {
+        glContext = CreateWindowOffscreenContext(aSize, aFormat);
+    }
+
+    if (!glContext ||
+        !glContext->Init())
+    {
+        return nsnull;
+    }
+
+    glContext->mOffscreenSize = aSize;
+    glContext->mOffscreenActualSize = aSize;
+
+    if (!glContext->mPBuffer &&
+        !glContext->ResizeOffscreenFBO(aSize))
+    {
+        return nsnull;
+    }
+
+    return glContext.forget();
 }
 
 already_AddRefed<GLContext>
 GLContextProviderWGL::CreateForNativePixmapSurface(gfxASurface *aSurface)
 {
     return nsnull;
 }
 
+static nsRefPtr<GLContextWGL> gGlobalContext;
+
+GLContext *
+GLContextProviderWGL::GetGlobalContext()
+{
+    if (!sWGLLibrary.EnsureInitialized()) {
+        return nsnull;
+    }
+
+    static bool triedToCreateContext = false;
+
+    if (!triedToCreateContext && !gGlobalContext) {
+        triedToCreateContext = true;
+
+        // conveniently, we already have what we need...
+        gGlobalContext = new GLContextWGL(ContextFormat(ContextFormat::BasicRGB24), nsnull,
+                                          gSharedWindowDC, gSharedWindowGLContext);
+        if (!gGlobalContext->Init()) {
+            NS_WARNING("Global context GLContext initialization failed?");
+            gGlobalContext = nsnull;
+            return PR_FALSE;
+        }
+    }
+
+    return static_cast<GLContext*>(gGlobalContext);
+}
+
 } /* namespace gl */
 } /* namespace mozilla */
--- a/gfx/thebes/GLXLibrary.h
+++ b/gfx/thebes/GLXLibrary.h
@@ -95,16 +95,33 @@ public:
     typedef void (GLAPIENTRY * PFNGLXSWAPBUFFERS) (Display *,
                                                    GLXDrawable);
     PFNGLXSWAPBUFFERS xSwapBuffers;
     typedef const char * (GLAPIENTRY * PFNGLXQUERYSERVERSTRING) (Display *,
                                                                  int,
                                                                  int);
     PFNGLXQUERYSERVERSTRING xQueryServerString;
 
+    typedef GLXPixmap (GLAPIENTRY * PFNGLXCREATEPIXMAP) (Display *,
+                                                         GLXFBConfig,
+                                                         Pixmap,
+                                                         const int *);
+    PFNGLXCREATEPIXMAP xCreatePixmap;
+    typedef void (GLAPIENTRY * PFNGLXDESTROYPIXMAP) (Display *,
+                                                     GLXPixmap);
+    PFNGLXDESTROYPIXMAP xDestroyPixmap;
+    typedef const char * (GLAPIENTRY * PFNGLXGETCLIENTSTRING) (Display *,
+                                                               int);
+    PFNGLXGETCLIENTSTRING xGetClientString;
+    typedef GLXContext (GLAPIENTRY * PFNGLXCREATECONTEXT) (Display *,
+                                                           XVisualInfo *,
+                                                           GLXContext,
+                                                           Bool);
+    PFNGLXCREATECONTEXT xCreateContext;
+
     PRBool EnsureInitialized();
 
 private:
     PRBool mInitialized;
     PRLibrary *mOGLLibrary;
 };
 
 // a global GLXLibrary instance
--- a/gfx/thebes/WGLLibrary.h
+++ b/gfx/thebes/WGLLibrary.h
@@ -51,16 +51,18 @@ public:
     typedef BOOL (GLAPIENTRY * PFNWGLMAKECURRENTPROC) (HDC, HGLRC);
     PFNWGLMAKECURRENTPROC fMakeCurrent;
     typedef PROC (GLAPIENTRY * PFNWGLGETPROCADDRESSPROC) (LPCSTR);
     PFNWGLGETPROCADDRESSPROC fGetProcAddress;
     typedef HGLRC (GLAPIENTRY * PFNWGLGETCURRENTCONTEXT) (void);
     PFNWGLGETCURRENTCONTEXT fGetCurrentContext;
     typedef HDC (GLAPIENTRY * PFNWGLGETCURRENTDC) (void);
     PFNWGLGETCURRENTDC fGetCurrentDC;
+    typedef BOOL (GLAPIENTRY * PFNWGLSHARELISTS) (HGLRC oldContext, HGLRC newContext);
+    PFNWGLSHARELISTS fShareLists;
 
     typedef HANDLE (WINAPI * PFNWGLCREATEPBUFFERPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int* piAttribList);
     PFNWGLCREATEPBUFFERPROC fCreatePbuffer;
     typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFERPROC) (HANDLE hPbuffer);
     PFNWGLDESTROYPBUFFERPROC fDestroyPbuffer;
     typedef HDC (WINAPI * PFNWGLGETPBUFFERDCPROC) (HANDLE hPbuffer);
     PFNWGLGETPBUFFERDCPROC fGetPbufferDC;