Bug 1275725 - Implement GLXSurface for encapsulating a GLXPixmap target. r?jgilbert draft
authorAndrew Comminos <andrew@comminos.com>
Wed, 25 May 2016 17:05:50 -0400
changeset 371066 7e8db8d631eca2d7daa4fa653c78568251dfee64
parent 371042 e1e5630d2498d51056df17cbaab492710484c3cd
child 371067 398cad412c0ce8f1229c83d19ad4c32e3c182146
push id19227
push userbmo:andrew@comminos.com
push dateWed, 25 May 2016 21:59:47 +0000
reviewersjgilbert
bugs1275725
milestone49.0a1
Bug 1275725 - Implement GLXSurface for encapsulating a GLXPixmap target. r?jgilbert MozReview-Commit-ID: 88j0J30ZRMc
dom/canvas/WebGLContext.cpp
gfx/gl/GLContextGLX.h
gfx/gl/GLContextProviderGLX.cpp
gfx/gl/GLScreenBuffer.cpp
gfx/gl/GLXLibrary.h
gfx/gl/SharedSurfaceGLX.cpp
gfx/gl/SharedSurfaceGLX.h
gfx/gl/SurfaceTypes.h
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -519,16 +519,17 @@ BaseCaps(const WebGLContextOptions& opti
 
     baseCaps.color = true;
     baseCaps.alpha = options.alpha;
     baseCaps.antialias = options.antialias;
     baseCaps.depth = options.depth;
     baseCaps.premultAlpha = options.premultipliedAlpha;
     baseCaps.preserve = options.preserveDrawingBuffer;
     baseCaps.stencil = options.stencil;
+    baseCaps.textureBinding = true;
 
     if (!baseCaps.alpha)
         baseCaps.premultAlpha = true;
 
     // we should really have this behind a
     // |gfxPlatform::GetPlatform()->GetScreenDepth() == 16| check, but
     // for now it's just behind a pref for testing/evaluation.
     baseCaps.bpp16 = gfxPrefs::WebGLPrefer16bpp();
--- a/gfx/gl/GLContextGLX.h
+++ b/gfx/gl/GLContextGLX.h
@@ -5,33 +5,126 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GLCONTEXTGLX_H_
 #define GLCONTEXTGLX_H_
 
 #include "GLContext.h"
 #include "GLXLibrary.h"
 #include "mozilla/X11Util.h"
+#include "mozilla/layers/ISurfaceAllocator.h"
 
 namespace mozilla {
 namespace gl {
 
+// A simple wrapper around an X11 pixmap with an associated GLXFBConfig.
+// Intended for use with the GL compositor, all GLXSurfaces expose flags
+// required for texture from pixmap.
+//
+// A primary goal of a GLXSurface is to treat the underlying X11 pixmap as an
+// opaque blob only accessible within GLX and the GL. This is because not all
+// buffers (particularly alpha) are always present in the X11 pixmap.
+class GLXSurface : public GenericAtomicRefCounted
+{
+public:
+    MOZ_DECLARE_REFCOUNTED_TYPENAME(GLXSurface)
+
+    static bool GetFBConfigWithID(Display* aDisplay, GLXFBConfigID aFBConfigID,
+                                  ScopedXFree<GLXFBConfig>* const out_config);
+
+    // Creates a new GLXSurface backed with a pixmap of the provided size and
+    // with the depth of the provided GLXFBConfig.
+    static already_AddRefed<GLXSurface> Create(Display* aDisplay,
+                                               GLXFBConfig& aConfig,
+                                               const gfx::IntSize& aSize);
+
+    // Creates a new GLXSurface by binds a new GLXPixmap to the provided pixmap.
+    //
+    // Note that the GLX specification does not permit multiple GLXPixmap
+    // bindings to the same X11 pixmap within the same address space.
+    static already_AddRefed<GLXSurface> Bind(Display* aDisplay,
+                                             Pixmap aPixmap,
+                                             GLXFBConfig& aConfig,
+                                             const gfx::IntSize& aSize,
+                                             bool aOwnsPixmap = false);
+
+    // Creates a new GLXSurface backed by a borrowed GLXPixmap.
+    static already_AddRefed<GLXSurface> Wrap(Display* aDisplay,
+                                             Pixmap aPixmap,
+                                             GLXPixmap aGLXPixmap,
+                                             GLXFBConfig& aConfig,
+                                             const gfx::IntSize& aSize,
+                                             bool aOwnsPixmap = false,
+                                             bool aOwnsGLXPixmap = false);
+
+    // Creates a compatible (with the same GLXFBConfig) GLXSurface.
+    already_AddRefed<GLXSurface> CreateCompatible(const gfx::IntSize& aSize);
+
+    // Queries this surface's GLXFBConfig for the given attribute value.
+    Maybe<int> GetFBConfigAttrib(int attrib);
+
+    GLXPixmap GetGLXPixmap() { return mGLXPixmap; }
+    GLXFBConfigID GetFBConfigID() { return mFBConfigID; }
+
+    bool ToSurfaceDescriptor(bool aInProcess,
+                             layers::SurfaceDescriptor* const out_descriptor)
+    {
+        Maybe<int> hasAlpha = GetFBConfigAttrib(LOCAL_GLX_ALPHA_SIZE);
+        if (!hasAlpha)
+            return false;
+
+        // On mesa, we need to recreate the GLXPixmap on the compositor side
+        // as each GLXPixmap's DRI drawable is stored in the X11 display
+        // (see https://bugs.freedesktop.org/show_bug.cgi?id=96219).
+        //
+        // The GLX spec, however, explicitly requires GLXPixmaps to be
+        // shareable OOP, so we permit this on other GLX implementations.
+        bool sharePixmap = aInProcess || !sGLXLibrary.IsMesa();
+        *out_descriptor = layers::SurfaceDescriptorGLX(sharePixmap ? mGLXPixmap : None,
+                                                       mPixmap,
+                                                       mFBConfigID,
+                                                       mSize,
+                                                       hasAlpha.value() > 0);
+        return true;
+    }
+
+    const gfx::IntSize GetSize() const { return mSize; }
+
+    void ReleasePixmap() { mOwnsPixmap = false; }
+    void ReleaseGLXPixmap() { mOwnsGLXPixmap = false; }
+
+private:
+    GLXSurface(Display* aDisplay, Pixmap aPixmap, GLXPixmap aGLXPixmap,
+               GLXFBConfigID aConfigID, const gfx::IntSize& aSize,
+               bool aOwnsPixmap, bool aOwnsGLXPixmap);
+    ~GLXSurface();
+
+    Display* mDisplay;
+    Pixmap mPixmap;
+    GLXPixmap mGLXPixmap;
+    GLXFBConfigID mFBConfigID;
+    gfx::IntSize mSize;
+
+    bool mOwnsPixmap;
+    bool mOwnsGLXPixmap;
+};
+
 class GLContextGLX : public GLContext
 {
 public:
     MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextGLX, override)
     static already_AddRefed<GLContextGLX>
     CreateGLContext(const SurfaceCaps& caps,
                     GLContextGLX* shareContext,
                     bool isOffscreen,
                     Display* display,
                     GLXDrawable drawable,
                     GLXFBConfig cfg,
                     bool deleteDrawable,
-                    gfxXlibSurface* pixmap = nullptr,
+                    GLXSurface* surface = nullptr,
                     ContextProfile profile = ContextProfile::OpenGLCompatibility);
 
     // Finds a GLXFBConfig compatible with the provided window.
     static bool
     FindFBConfigForWindow(Display* display, int screen, Window window,
                           ScopedXFree<GLXFBConfig>* const out_scopedConfigArr,
                           GLXFBConfig* const out_config, int* const out_visid);
 
@@ -53,47 +146,53 @@ public:
     virtual bool SetupLookupFunction() override;
 
     virtual bool IsDoubleBuffered() const override;
 
     virtual bool SupportsRobustness() const override;
 
     virtual bool SwapBuffers() override;
 
-    // Overrides the current GLXDrawable backing the context and makes the
-    // context current.
-    bool OverrideDrawable(GLXDrawable drawable);
+    // Redirects drawing to the specified surface.
+    // Only usable in offscreen contexts.
+    bool OverrideSurface(GLXSurface& aSurface);
 
-    // Undoes the effect of a drawable override.
-    bool RestoreDrawable();
+    // Unredirects the active GLXSurface.
+    bool RestoreSurface();
 
     virtual Maybe<gfx::IntSize> GetTargetSize() override;
 
+    // Creates a compatible pixmap that can be bound to this context using
+    // GLContextGLX::OverrideSurface.
+    already_AddRefed<GLXSurface> CreateCompatibleSurface(const gfx::IntSize& aSize);
+
 private:
     friend class GLContextProviderGLX;
 
     GLContextGLX(const SurfaceCaps& caps,
                  GLContext* shareContext,
                  bool isOffscreen,
                  Display *aDisplay,
                  GLXDrawable aDrawable,
+                 GLXFBConfigID aFBConfigID,
                  GLXContext aContext,
                  bool aDeleteDrawable,
                  bool aDoubleBuffered,
-                 gfxXlibSurface *aPixmap,
+                 GLXSurface *aSurface,
                  ContextProfile profile);
 
     GLXContext mContext;
     Display *mDisplay;
     GLXDrawable mDrawable;
+    GLXFBConfigID mFBConfigID;
     bool mDeleteDrawable;
     bool mDoubleBuffered;
 
     GLXLibrary* mGLX;
 
-    RefPtr<gfxXlibSurface> mPixmap;
+    RefPtr<GLXSurface> mSurface;
     bool mOwnsContext;
 };
 
 }
 }
 
 #endif // GLCONTEXTGLX_H_
--- a/gfx/gl/GLContextProviderGLX.cpp
+++ b/gfx/gl/GLContextProviderGLX.cpp
@@ -741,17 +741,17 @@ already_AddRefed<GLContextGLX>
 GLContextGLX::CreateGLContext(
                   const SurfaceCaps& caps,
                   GLContextGLX* shareContext,
                   bool isOffscreen,
                   Display* display,
                   GLXDrawable drawable,
                   GLXFBConfig cfg,
                   bool deleteDrawable,
-                  gfxXlibSurface* pixmap,
+                  GLXSurface* surface,
                   ContextProfile profile)
 {
     GLXLibrary& glx = sGLXLibrary;
 
     int db = 0;
     int err = glx.xGetFBConfigAttrib(display, cfg,
                                       LOCAL_GLX_DOUBLEBUFFER, &db);
     if (LOCAL_GLX_BAD_ATTRIBUTE != err) {
@@ -803,25 +803,28 @@ TRY_AGAIN_NO_SHARING:
             display,
             cfg,
             LOCAL_GLX_RGBA_TYPE,
             glxContext,
             True);
     }
 
     if (context) {
+        int cfgID;
+        glx.xGetFBConfigAttrib(display, cfg, LOCAL_GLX_FBCONFIG_ID, &cfgID);
         glContext = new GLContextGLX(caps,
                                       shareContext,
                                       isOffscreen,
                                       display,
                                       drawable,
+                                      (GLXFBConfigID) cfgID,
                                       context,
                                       deleteDrawable,
                                       db,
-                                      pixmap,
+                                      surface,
                                       profile);
         if (!glContext->Init())
             error = true;
     } else {
         error = true;
     }
 
     error |= xErrorHandler.SyncAndGetError(display);
@@ -945,49 +948,61 @@ GLContextGLX::GetTargetSize()
     XGetGeometry(mDisplay, mDrawable, &root, &x, &y, &width, &height,
                  &border, &depth);
     Maybe<gfx::IntSize> size;
     size.emplace(width, height);
     return size;
 }
 
 bool
-GLContextGLX::OverrideDrawable(GLXDrawable drawable)
+GLContextGLX::OverrideSurface(GLXSurface& aSurface)
 {
+    MOZ_ASSERT(mIsOffscreen, "Only offscreen contexts may render to a GLXPixmap.");
+    MOZ_RELEASE_ASSERT(aSurface.GetFBConfigID() == mFBConfigID, "Incompatible FBConfig!");
+
     if (Screen())
         Screen()->AssureBlitted();
-    Bool result = mGLX->xMakeCurrent(mDisplay, drawable, mContext);
+    Bool result = mGLX->xMakeCurrent(mDisplay, aSurface.GetGLXPixmap(), mContext);
     return result;
 }
 
 bool
-GLContextGLX::RestoreDrawable()
+GLContextGLX::RestoreSurface()
 {
     return mGLX->xMakeCurrent(mDisplay, mDrawable, mContext);
 }
 
+already_AddRefed<GLXSurface>
+GLContextGLX::CreateCompatibleSurface(const gfx::IntSize& aSize)
+{
+    MOZ_ASSERT(IsOffscreen(), "Only offscreen contexts may bind to a GLXPixmap.");
+    return mSurface->CreateCompatible(aSize);
+}
+
 GLContextGLX::GLContextGLX(
                   const SurfaceCaps& caps,
                   GLContext* shareContext,
                   bool isOffscreen,
                   Display *aDisplay,
                   GLXDrawable aDrawable,
+                  GLXFBConfigID aFBConfigID,
                   GLXContext aContext,
                   bool aDeleteDrawable,
                   bool aDoubleBuffered,
-                  gfxXlibSurface *aPixmap,
+                  GLXSurface *aSurface,
                   ContextProfile profile)
     : GLContext(caps, shareContext, isOffscreen),//aDeleteDrawable ? true : false, aShareContext, ),
       mContext(aContext),
       mDisplay(aDisplay),
       mDrawable(aDrawable),
+      mFBConfigID(aFBConfigID),
       mDeleteDrawable(aDeleteDrawable),
       mDoubleBuffered(aDoubleBuffered),
       mGLX(&sGLXLibrary),
-      mPixmap(aPixmap),
+      mSurface(aSurface),
       mOwnsContext(true)
 {
     MOZ_ASSERT(mGLX);
     // See 899855
     SetProfileVersion(profile, 200);
 }
 
 
@@ -1028,20 +1043,21 @@ GLContextProviderGLX::CreateWrappingExis
 
     if (aContext && aSurface) {
         SurfaceCaps caps = SurfaceCaps::Any();
         RefPtr<GLContextGLX> glContext =
             new GLContextGLX(caps,
                              nullptr, // SharedContext
                              false, // Offscreen
                              (Display*)DefaultXDisplay(), // Display
-                             (GLXDrawable)aSurface, (GLXContext)aContext,
+                             (GLXDrawable)aSurface, None,
+                             (GLXContext)aContext,
                              false, // aDeleteDrawable,
                              true,
-                             (gfxXlibSurface*)nullptr,
+                             (GLXSurface*)nullptr,
                              ContextProfile::OpenGLCompatibility);
 
         glContext->mOwnsContext = false;
         gGlobalContext = glContext;
 
         return glContext.forget();
     }
 
@@ -1099,30 +1115,44 @@ ChooseConfig(GLXLibrary* glx, Display* d
              ScopedXFree<GLXFBConfig>* const out_scopedConfigArr,
              GLXFBConfig* const out_config, int* const out_visid)
 {
     ScopedXFree<GLXFBConfig>& scopedConfigArr = *out_scopedConfigArr;
 
     if (minCaps.antialias)
         return false;
 
-    int attribs[] = {
+    AutoTArray<int, 17> attribs;
+    int baseAttribs[] = {
         LOCAL_GLX_DRAWABLE_TYPE, LOCAL_GLX_PIXMAP_BIT,
         LOCAL_GLX_X_RENDERABLE, True,
         LOCAL_GLX_RED_SIZE, 8,
         LOCAL_GLX_GREEN_SIZE, 8,
         LOCAL_GLX_BLUE_SIZE, 8,
         LOCAL_GLX_ALPHA_SIZE, minCaps.alpha ? 8 : 0,
         LOCAL_GLX_DEPTH_SIZE, minCaps.depth ? 16 : 0,
         LOCAL_GLX_STENCIL_SIZE, minCaps.stencil ? 8 : 0,
-        0
+        None
     };
+    attribs.AppendElements(baseAttribs, MOZ_ARRAY_LENGTH(baseAttribs));
+
+    if (glx->UseTextureFromPixmap() && minCaps.textureBinding) {
+        int tfpAttribs[] = {
+            (minCaps.alpha ? LOCAL_GLX_BIND_TO_TEXTURE_RGBA_EXT
+                           : LOCAL_GLX_BIND_TO_TEXTURE_RGB_EXT), True,
+            LOCAL_GLX_RENDER_TYPE, LOCAL_GLX_RGBA_BIT,
+            LOCAL_GLX_BIND_TO_TEXTURE_TARGETS_EXT, LOCAL_GLX_TEXTURE_2D_BIT_EXT,
+        };
+        attribs.AppendElements(tfpAttribs, MOZ_ARRAY_LENGTH(tfpAttribs));
+    }
+
+    attribs.AppendElement(None);
 
     int numConfigs = 0;
-    scopedConfigArr = glx->xChooseFBConfig(display, screen, attribs, &numConfigs);
+    scopedConfigArr = glx->xChooseFBConfig(display, screen, attribs.Elements(), &numConfigs);
     if (!scopedConfigArr || !numConfigs)
         return false;
 
     // Issues with glxChooseFBConfig selection and sorting:
     // * ALPHA_SIZE is sorted as 'largest total RGBA bits first'. If we don't request
     //   alpha bits, we'll probably get RGBA anyways, since 32 is more than 24.
     // * DEPTH_SIZE is sorted largest first, including for `0` inputs.
     // * STENCIL_SIZE is smallest first, but it might return `8` even though we ask for
@@ -1240,53 +1270,28 @@ CreateOffscreenPixmapContext(const IntSi
         return nullptr;
     }
 
     Visual* visual;
     int depth;
     FindVisualAndDepth(display, visid, &visual, &depth);
 
     ScopedXErrorHandler xErrorHandler;
-    bool error = false;
-    // Must be declared before goto:
-    Drawable drawable;
-    GLXPixmap pixmap;
 
     gfx::IntSize dummySize(16, 16);
-    RefPtr<gfxXlibSurface> surface = gfxXlibSurface::Create(DefaultScreenOfDisplay(display),
-                                                            visual,
-                                                            dummySize);
-    if (surface->CairoStatus() != 0) {
-        error = true;
-        goto DONE_CREATING_PIXMAP;
-    }
-
-    // Handle slightly different signature between glXCreatePixmap and
-    // its pre-GLX-1.3 extension equivalent (though given the ABI, we
-    // might not need to).
-    drawable = surface->XDrawable();
-    if (glx->GLXVersionCheck(1, 3)) {
-        pixmap = glx->xCreatePixmap(display, config, drawable, nullptr);
-    } else {
-        pixmap = glx->xCreateGLXPixmapWithConfig(display, config, drawable);
-    }
-
-    if (pixmap == 0) {
-        error = true;
-    }
-
-DONE_CREATING_PIXMAP:
+    RefPtr<GLXSurface> surface = GLXSurface::Create(display, config, dummySize);
 
     bool serverError = xErrorHandler.SyncAndGetError(display);
-    if (error || serverError)
+    if (!surface || serverError)
         return nullptr;
 
     GLContextGLX* shareContext = GetGlobalContextGLX();
-    return GLContextGLX::CreateGLContext(minCaps, shareContext, true, display, pixmap,
-                                         config, true, surface, profile);
+    return GLContextGLX::CreateGLContext(minCaps, shareContext, true, display,
+                                         surface->GetGLXPixmap(), config, false,
+                                         surface, profile);
 }
 
 /*static*/ already_AddRefed<GLContext>
 GLContextProviderGLX::CreateHeadless(CreateContextFlags)
 {
     IntSize dummySize = IntSize(16, 16);
     SurfaceCaps dummyCaps = SurfaceCaps::Any();
     return CreateOffscreenPixmapContext(dummySize, dummyCaps);
@@ -1340,11 +1345,136 @@ GLContextProviderGLX::GetGlobalContext()
 }
 
 /*static*/ void
 GLContextProviderGLX::Shutdown()
 {
     gGlobalContext = nullptr;
 }
 
+/*static*/ bool
+GLXSurface::GetFBConfigWithID(Display* aDisplay, GLXFBConfigID aFBConfigID,
+                              ScopedXFree<GLXFBConfig>* const out_config)
+{
+    int xscreen = DefaultScreen(aDisplay);
+    int attribs[] = {
+        LOCAL_GLX_FBCONFIG_ID, (int) aFBConfigID,
+        None
+    };
+    int numConfigs = 0;
+    *out_config = sGLXLibrary.xChooseFBConfig(aDisplay, xscreen, attribs, &numConfigs);
+    MOZ_ASSERT(numConfigs <= 1);
+    return numConfigs;
+}
+
+/*static*/ already_AddRefed<GLXSurface>
+GLXSurface::Create(Display* aDisplay, GLXFBConfig& aConfig,
+                   const gfx::IntSize& aSize)
+{
+    int visid = 0;
+    if (sGLXLibrary.xGetFBConfigAttrib(aDisplay, aConfig, LOCAL_GLX_VISUAL_ID,
+                                       &visid) != Success)
+        return nullptr;
+
+    // Use the associated X11 visual's depth for the created pixmap.
+    int depth = 0;
+    Visual *visual;
+    FindVisualAndDepth(aDisplay, visid, &visual, &depth);
+
+    Pixmap pixmap = XCreatePixmap(aDisplay, DefaultRootWindow(aDisplay),
+                                  aSize.width, aSize.height, depth);
+    if (!pixmap)
+        return nullptr;
+
+    return GLXSurface::Bind(aDisplay, pixmap, aConfig, aSize, true);
+}
+
+/*static*/ already_AddRefed<GLXSurface>
+GLXSurface::Bind(Display* aDisplay, Pixmap aPixmap, GLXFBConfig& aConfig,
+                 const gfx::IntSize& aSize, bool aOwnsPixmap)
+{
+    int alphaSize = 0;
+    if (sGLXLibrary.xGetFBConfigAttrib(aDisplay, aConfig, LOCAL_GLX_ALPHA_SIZE,
+                                       &alphaSize) != Success)
+        return nullptr;
+
+    int tfpAttribs[] = {
+        LOCAL_GLX_TEXTURE_TARGET_EXT, LOCAL_GLX_TEXTURE_2D_EXT,
+        LOCAL_GLX_TEXTURE_FORMAT_EXT,
+        (alphaSize ? LOCAL_GLX_TEXTURE_FORMAT_RGBA_EXT
+                   : LOCAL_GLX_TEXTURE_FORMAT_RGB_EXT),
+        None
+    };
+
+    GLXPixmap glxPixmap = sGLXLibrary.xCreatePixmap(aDisplay, aConfig, aPixmap,
+        sGLXLibrary.UseTextureFromPixmap() ? tfpAttribs : nullptr);
+    if (!glxPixmap)
+        return nullptr;
+
+    return GLXSurface::Wrap(aDisplay, aPixmap, glxPixmap, aConfig, aSize,
+                            aOwnsPixmap, true);
+}
+
+/*static*/ already_AddRefed<GLXSurface>
+GLXSurface::Wrap(Display* aDisplay, Pixmap aPixmap, GLXPixmap aGLXPixmap,
+                 GLXFBConfig& aConfig, const gfx::IntSize& aSize,
+                 bool aOwnsPixmap, bool aOwnsGLXPixmap)
+{
+    int configId = 0;
+    if (sGLXLibrary.xGetFBConfigAttrib(aDisplay, aConfig, LOCAL_GLX_FBCONFIG_ID,
+          &configId) != Success)
+        return nullptr;
+
+    RefPtr<GLXSurface> surface = new GLXSurface(aDisplay, aPixmap, aGLXPixmap,
+                                                (GLXFBConfigID) configId, aSize,
+                                                aOwnsPixmap, aOwnsGLXPixmap);
+    return surface.forget();
+}
+
+GLXSurface::GLXSurface(Display* aDisplay, Pixmap aPixmap, GLXPixmap aGLXPixmap,
+                       GLXFBConfigID aConfigID, const gfx::IntSize& aSize,
+                       bool aOwnsPixmap, bool aOwnsGLXPixmap)
+    : mDisplay(aDisplay)
+    , mPixmap(aPixmap)
+    , mGLXPixmap(aGLXPixmap)
+    , mFBConfigID(aConfigID)
+    , mSize(aSize)
+    , mOwnsPixmap(aOwnsPixmap)
+    , mOwnsGLXPixmap(aOwnsGLXPixmap)
+{
+}
+
+GLXSurface::~GLXSurface()
+{
+  if (mOwnsGLXPixmap)
+      sGLXLibrary.xDestroyPixmap(mDisplay, mGLXPixmap);
+
+  if (mOwnsPixmap)
+      XFreePixmap(mDisplay, mPixmap);
+
+}
+
+already_AddRefed<GLXSurface>
+GLXSurface::CreateCompatible(const gfx::IntSize& aSize)
+{
+    ScopedXFree<GLXFBConfig> cfg;
+    if (!GetFBConfigWithID(mDisplay, mFBConfigID, &cfg))
+        return nullptr;
+    return GLXSurface::Create(mDisplay, *cfg, aSize);
+}
+
+Maybe<int>
+GLXSurface::GetFBConfigAttrib(int aAttrib)
+{
+    ScopedXFree<GLXFBConfig> cfg;
+    if (!GetFBConfigWithID(mDisplay, mFBConfigID, &cfg))
+        return Nothing();
+
+    int value = 0;
+    if (sGLXLibrary.xGetFBConfigAttrib(mDisplay, *cfg, aAttrib, &value) != Success)
+        return Nothing();
+
+    return Some(value);
+}
+
 } /* namespace gl */
 } /* namespace mozilla */
 
--- a/gfx/gl/GLScreenBuffer.cpp
+++ b/gfx/gl/GLScreenBuffer.cpp
@@ -109,22 +109,16 @@ GLScreenBuffer::CreateFactory(GLContext*
                   factory = SurfaceFactory_D3D11Interop::Create(gl, caps, forwarder, flags);
                 }
 #endif
               break;
             }
             default:
               break;
         }
-
-#ifdef GL_PROVIDER_GLX
-        if (!factory && sGLXLibrary.UseTextureFromPixmap()) {
-            factory = SurfaceFactory_GLXDrawable::Create(gl, caps, forwarder, flags);
-        }
-#endif
     }
 
     return factory;
 }
 
 GLScreenBuffer::GLScreenBuffer(GLContext* gl,
                                const SurfaceCaps& caps,
                                UniquePtr<SurfaceFactory> factory)
--- a/gfx/gl/GLXLibrary.h
+++ b/gfx/gl/GLXLibrary.h
@@ -128,16 +128,17 @@ public:
     void ReleaseTexImage(Display* aDisplay, GLXPixmap aPixmap);
     void UpdateTexImage(Display* aDisplay, GLXPixmap aPixmap);
 
     bool UseTextureFromPixmap() { return mUseTextureFromPixmap; }
     bool HasRobustness() { return mHasRobustness; }
     bool HasCreateContextAttribs() { return mHasCreateContextAttribs; }
     bool SupportsTextureFromPixmap(gfxASurface* aSurface);
     bool IsATI() { return mIsATI; }
+    bool IsMesa() { return mClientIsMesa; }
     bool GLXVersionCheck(int aMajor, int aMinor);
 
 private:
     
     typedef void (GLAPIENTRY * PFNGLXDESTROYCONTEXTPROC) (Display*,
                                                           GLXContext);
     PFNGLXDESTROYCONTEXTPROC xDestroyContextInternal;
     typedef Bool (GLAPIENTRY * PFNGLXMAKECURRENTPROC) (Display*,
--- a/gfx/gl/SharedSurfaceGLX.cpp
+++ b/gfx/gl/SharedSurfaceGLX.cpp
@@ -6,130 +6,104 @@
 #include "SharedSurfaceGLX.h"
 #include "gfxXlibSurface.h"
 #include "GLXLibrary.h"
 #include "GLContextProvider.h"
 #include "GLContextGLX.h"
 #include "GLScreenBuffer.h"
 #include "mozilla/gfx/SourceSurfaceCairo.h"
 #include "mozilla/layers/LayersSurfaces.h"
-#include "mozilla/layers/ShadowLayerUtilsX11.h"
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/X11Util.h"
 
 namespace mozilla {
 namespace gl {
 
 /* static */
 UniquePtr<SharedSurface_GLXDrawable>
 SharedSurface_GLXDrawable::Create(GLContext* prodGL,
                                   const SurfaceCaps& caps,
                                   const gfx::IntSize& size,
                                   bool deallocateClient,
                                   bool inSameProcess)
 {
+    GLContextGLX* glxContext = GLContextGLX::Cast(prodGL);
     UniquePtr<SharedSurface_GLXDrawable> ret;
-    Display* display = DefaultXDisplay();
-    Screen* screen = XDefaultScreenOfDisplay(display);
-    Visual* visual = gfxXlibSurface::FindVisual(screen, gfx::SurfaceFormat::A8R8G8B8_UINT32);
+    RefPtr<GLXSurface> surf = glxContext->CreateCompatibleSurface(size);
+    if (!surf)
+        return nullptr;
 
-    RefPtr<gfxXlibSurface> surf = gfxXlibSurface::Create(screen, visual, size);
-    if (!deallocateClient)
+    if (!deallocateClient) {
         surf->ReleasePixmap();
+        surf->ReleaseGLXPixmap();
+    }
 
-    ret.reset(new SharedSurface_GLXDrawable(prodGL, size, inSameProcess, surf));
+    ret.reset(new SharedSurface_GLXDrawable(prodGL, size, inSameProcess, caps.alpha, surf));
     return Move(ret);
 }
 
 
 SharedSurface_GLXDrawable::SharedSurface_GLXDrawable(GLContext* gl,
                                                      const gfx::IntSize& size,
                                                      bool inSameProcess,
-                                                     const RefPtr<gfxXlibSurface>& xlibSurface)
+                                                     bool hasAlpha,
+                                                     const RefPtr<GLXSurface>& glxSurface)
     : SharedSurface(SharedSurfaceType::GLXDrawable,
                     AttachmentType::Screen,
                     gl,
                     size,
-                    true,
+                    hasAlpha,
                     true)
-    , mXlibSurface(xlibSurface)
+    , mGLXSurface(glxSurface)
     , mInSameProcess(inSameProcess)
 {}
 
 void
 SharedSurface_GLXDrawable::ProducerReleaseImpl()
 {
     mGL->MakeCurrent();
     mGL->fFlush();
 }
 
 void
 SharedSurface_GLXDrawable::LockProdImpl()
 {
     mGL->Screen()->SetReadBuffer(LOCAL_GL_FRONT);
-    GLContextGLX::Cast(mGL)->OverrideDrawable(mXlibSurface->GetGLXPixmap());
+    if (!GLContextGLX::Cast(mGL)->OverrideSurface(*mGLXSurface))
+        gfxWarning() << "Failed to redirect to GLXSurface.";
 }
 
 void
 SharedSurface_GLXDrawable::UnlockProdImpl()
 {
-    GLContextGLX::Cast(mGL)->RestoreDrawable();
+    if (!GLContextGLX::Cast(mGL)->RestoreSurface())
+        gfxWarning() << "Failed to unredirect to GLXSurface.";
 }
 
 bool
 SharedSurface_GLXDrawable::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor)
 {
-    if (!mXlibSurface)
+    if (!mGLXSurface)
         return false;
 
-    *out_descriptor = layers::SurfaceDescriptorX11(mXlibSurface, mInSameProcess);
-    return true;
-}
-
-bool
-SharedSurface_GLXDrawable::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface)
-{
-    MOZ_ASSERT(out_surface);
-    RefPtr<gfx::DataSourceSurface> dataSurf =
-        new gfx::DataSourceSurfaceCairo(mXlibSurface->CairoSurface());
-
-    gfx::DataSourceSurface::ScopedMap mapSrc(dataSurf, gfx::DataSourceSurface::READ);
-    if (!mapSrc.IsMapped()) {
-        return false;
-    }
-
-    gfx::DataSourceSurface::ScopedMap mapDest(out_surface, gfx::DataSourceSurface::WRITE);
-    if (!mapDest.IsMapped()) {
-        return false;
-    }
-
-    if (mapDest.GetStride() == mapSrc.GetStride()) {
-        memcpy(mapDest.GetData(),
-               mapSrc.GetData(),
-               out_surface->GetSize().height * mapDest.GetStride());
-    } else {
-        for (int32_t i = 0; i < dataSurf->GetSize().height; i++) {
-            memcpy(mapDest.GetData() + i * mapDest.GetStride(),
-                   mapSrc.GetData() + i * mapSrc.GetStride(),
-                   std::min(mapSrc.GetStride(), mapDest.GetStride()));
-        }
-    }
-
-    return true;
+    return mGLXSurface->ToSurfaceDescriptor(mInSameProcess, out_descriptor);
 }
 
 /* static */
 UniquePtr<SurfaceFactory_GLXDrawable>
 SurfaceFactory_GLXDrawable::Create(GLContext* prodGL,
                                    const SurfaceCaps& caps,
                                    const RefPtr<layers::ClientIPCAllocator>& allocator,
                                    const layers::TextureFlags& flags)
 {
-    MOZ_ASSERT(caps.alpha, "GLX surfaces require an alpha channel!");
-
+    MOZ_ASSERT(caps.alpha == prodGL->Caps().alpha &&
+               caps.depth == prodGL->Caps().depth &&
+               caps.stencil == prodGL->Caps().stencil,
+               "GLX requires the same buffer depths as the context.");
+    MOZ_ASSERT(prodGL->Caps().textureBinding, "Context must be initialized to support TFP.");
     typedef SurfaceFactory_GLXDrawable ptrT;
     UniquePtr<ptrT> ret(new ptrT(prodGL, caps, allocator,
                                  flags & ~layers::TextureFlags::ORIGIN_BOTTOM_LEFT));
     return Move(ret);
 }
 
 UniquePtr<SharedSurface>
 SurfaceFactory_GLXDrawable::CreateShared(const gfx::IntSize& size)
--- a/gfx/gl/SharedSurfaceGLX.h
+++ b/gfx/gl/SharedSurfaceGLX.h
@@ -4,21 +4,21 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef SHARED_SURFACE_GLX_H_
 #define SHARED_SURFACE_GLX_H_
 
 #include "SharedSurface.h"
 #include "mozilla/RefPtr.h"
 
-class gfxXlibSurface;
-
 namespace mozilla {
 namespace gl {
 
+class GLXSurface;
+
 class SharedSurface_GLXDrawable
     : public SharedSurface
 {
 public:
     static UniquePtr<SharedSurface_GLXDrawable> Create(GLContext* prodGL,
                                                        const SurfaceCaps& caps,
                                                        const gfx::IntSize& size,
                                                        bool deallocateClient,
@@ -26,25 +26,24 @@ public:
 
     virtual void ProducerAcquireImpl() override {}
     virtual void ProducerReleaseImpl() override;
 
     virtual void LockProdImpl() override;
     virtual void UnlockProdImpl() override;
 
     virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
-
-    virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) override;
 private:
     SharedSurface_GLXDrawable(GLContext* gl,
                               const gfx::IntSize& size,
                               bool inSameProcess,
-                              const RefPtr<gfxXlibSurface>& xlibSurface);
+                              bool hasAlpha,
+                              const RefPtr<GLXSurface>& glxSurface);
 
-    RefPtr<gfxXlibSurface> mXlibSurface;
+    RefPtr<GLXSurface> mGLXSurface;
     bool mInSameProcess;
 };
 
 class SurfaceFactory_GLXDrawable
     : public SurfaceFactory
 {
 public:
     static UniquePtr<SurfaceFactory_GLXDrawable> Create(GLContext* prodGL,
--- a/gfx/gl/SurfaceTypes.h
+++ b/gfx/gl/SurfaceTypes.h
@@ -21,16 +21,17 @@ struct SurfaceCaps final
 {
     bool any;
     bool color, alpha;
     bool bpp16;
     bool depth, stencil;
     bool antialias;
     bool premultAlpha;
     bool preserve;
+    bool textureBinding;
 
     // The surface allocator that we want to create this
     // for.  May be null.
     RefPtr<layers::ISurfaceAllocator> surfaceAllocator;
 
     SurfaceCaps();
     SurfaceCaps(const SurfaceCaps& other);
     ~SurfaceCaps();