Bug 1187440 - Implement GLX shared surfaces on the OpenGL compositor. r=jgilbert,nical
authorAndrew Comminos <acomminos@mozilla.com>
Thu, 30 Jul 2015 12:40:56 -0400
changeset 287180 5753576396107c2080e75a8fc8d47cf8b5a2a565
parent 287179 420fa39a00953598780365a65c9c0f4261e34276
child 287181 189161dc16163e36f6e917d360a2c37764f4543c
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert, nical
bugs1187440
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1187440 - Implement GLX shared surfaces on the OpenGL compositor. r=jgilbert,nical
dom/canvas/WebGLContext.cpp
gfx/gl/GLContextGLX.h
gfx/gl/GLContextProviderGLX.cpp
gfx/gl/GLScreenBuffer.cpp
gfx/gl/SharedSurfaceGLX.cpp
gfx/gl/SharedSurfaceGLX.h
gfx/gl/SurfaceTypes.h
gfx/gl/moz.build
gfx/layers/client/ClientCanvasLayer.cpp
gfx/layers/ipc/ShadowLayerUtilsX11.cpp
gfx/layers/ipc/ShadowLayerUtilsX11.h
gfx/layers/opengl/TextureHostOGL.cpp
gfx/thebes/gfxXlibSurface.cpp
gfx/thebes/gfxXlibSurface.h
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -680,19 +680,20 @@ CreateOffscreen(GLContext* gl, const Web
     baseCaps.depth = options.depth;
     baseCaps.premultAlpha = options.premultipliedAlpha;
     baseCaps.preserve = options.preserveDrawingBuffer;
     baseCaps.stencil = options.stencil;
 
     if (!baseCaps.alpha)
         baseCaps.premultAlpha = true;
 
-    if (gl->IsANGLE()) {
+    if (gl->IsANGLE() || gl->GetContextType() == GLContextType::GLX) {
         // We can't use no-alpha formats on ANGLE yet because of:
         // https://code.google.com/p/angleproject/issues/detail?id=764
+        // GLX only supports GL_RGBA pixmaps as well.
         baseCaps.alpha = 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 = Preferences::GetBool("webgl.prefer-16bpp", false);
 
@@ -944,22 +945,22 @@ WebGLContext::SetDimensions(int32_t sign
     if (gl->DebugMode())
         printf_stderr("--- WebGL context created: %p\n", gl.get());
 #endif
 
     mResetLayer = true;
     mOptionsFrozen = true;
 
     // Update our internal stuff:
-    if (gl->WorkAroundDriverBugs() && gl->IsANGLE()) {
+    if (gl->WorkAroundDriverBugs()) {
         if (!mOptions.alpha && gl->Caps().alpha)
             mNeedsFakeNoAlpha = true;
 
         // ANGLE doesn't quite handle this properly.
-        if (gl->Caps().depth && !gl->Caps().stencil)
+        if (gl->Caps().depth && !gl->Caps().stencil && gl->IsANGLE())
             mNeedsFakeNoStencil = true;
     }
 
     // Update mOptions.
     mOptions.depth = gl->Caps().depth;
     mOptions.stencil = gl->Caps().stencil;
     mOptions.antialias = gl->Caps().antialias;
 
--- a/gfx/gl/GLContextGLX.h
+++ b/gfx/gl/GLContextGLX.h
@@ -45,16 +45,23 @@ 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);
+
+    // Undoes the effect of a drawable override.
+    bool RestoreDrawable();
+
     virtual Maybe<gfx::IntSize> GetTargetSize() override;
 
 private:
     friend class GLContextProviderGLX;
 
     GLContextGLX(const SurfaceCaps& caps,
                  GLContext* shareContext,
                  bool isOffscreen,
--- a/gfx/gl/GLContextProviderGLX.cpp
+++ b/gfx/gl/GLContextProviderGLX.cpp
@@ -25,16 +25,17 @@
 #include "nsIWidget.h"
 #include "GLXLibrary.h"
 #include "gfxXlibSurface.h"
 #include "gfxContext.h"
 #include "gfxPlatform.h"
 #include "GLContextGLX.h"
 #include "gfxUtils.h"
 #include "gfx2DGlue.h"
+#include "GLScreenBuffer.h"
 
 #include "gfxCrashReporterUtils.h"
 
 #ifdef MOZ_WIDGET_GTK
 #include "gfxPlatformGtk.h"
 #endif
 
 namespace mozilla {
@@ -921,16 +922,31 @@ GLContextGLX::GetTargetSize()
     unsigned int border, depth;
     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)
+{
+    if (Screen())
+        Screen()->AssureBlitted();
+    Bool result = mGLX->xMakeCurrent(mDisplay, drawable, mContext);
+    return result;
+}
+
+bool
+GLContextGLX::RestoreDrawable()
+{
+    return mGLX->xMakeCurrent(mDisplay, mDrawable, mContext);
+}
+
 GLContextGLX::GLContextGLX(
                   const SurfaceCaps& caps,
                   GLContext* shareContext,
                   bool isOffscreen,
                   Display *aDisplay,
                   GLXDrawable aDrawable,
                   GLXContext aContext,
                   bool aDeleteDrawable,
--- a/gfx/gl/GLScreenBuffer.cpp
+++ b/gfx/gl/GLScreenBuffer.cpp
@@ -785,17 +785,18 @@ ReadBuffer::SetReadBuffer(GLenum userMod
 {
     if (!mGL->IsSupported(GLFeature::read_buffer))
         return;
 
     GLenum internalMode;
 
     switch (userMode) {
     case LOCAL_GL_BACK:
-        internalMode = (mFB == 0) ? LOCAL_GL_BACK
+    case LOCAL_GL_FRONT:
+        internalMode = (mFB == 0) ? userMode
                                   : LOCAL_GL_COLOR_ATTACHMENT0;
         break;
 
     case LOCAL_GL_NONE:
         internalMode = LOCAL_GL_NONE;
         break;
 
     default:
new file mode 100644
--- /dev/null
+++ b/gfx/gl/SharedSurfaceGLX.cpp
@@ -0,0 +1,110 @@
+/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "SharedSurfaceGLX.h"
+#include "gfxXlibSurface.h"
+#include "GLXLibrary.h"
+#include "GLContextProvider.h"
+#include "GLContextGLX.h"
+#include "GLScreenBuffer.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)
+{
+    UniquePtr<SharedSurface_GLXDrawable> ret;
+    Display* display = DefaultXDisplay();
+    Screen* screen = XDefaultScreenOfDisplay(display);
+    Visual* visual = gfxXlibSurface::FindVisual(screen, gfxImageFormat::ARGB32);
+
+    RefPtr<gfxXlibSurface> surf = gfxXlibSurface::Create(screen, visual, size);
+    if (!deallocateClient)
+        surf->ReleasePixmap();
+
+    ret.reset(new SharedSurface_GLXDrawable(prodGL, size, inSameProcess, surf));
+    return Move(ret);
+}
+
+
+SharedSurface_GLXDrawable::SharedSurface_GLXDrawable(GLContext* gl,
+                                                     const gfx::IntSize& size,
+                                                     bool inSameProcess,
+                                                     const RefPtr<gfxXlibSurface>& xlibSurface)
+    : SharedSurface(SharedSurfaceType::GLXDrawable,
+                    AttachmentType::Screen,
+                    gl,
+                    size,
+                    true,
+                    true)
+    , mXlibSurface(xlibSurface)
+    , mInSameProcess(inSameProcess)
+{}
+
+void
+SharedSurface_GLXDrawable::Fence()
+{
+    mGL->MakeCurrent();
+    mGL->fFlush();
+}
+
+void
+SharedSurface_GLXDrawable::LockProdImpl()
+{
+    mGL->Screen()->SetReadBuffer(LOCAL_GL_FRONT);
+    GLContextGLX::Cast(mGL)->OverrideDrawable(mXlibSurface->GetGLXPixmap());
+}
+
+void
+SharedSurface_GLXDrawable::UnlockProdImpl()
+{
+    GLContextGLX::Cast(mGL)->RestoreDrawable();
+}
+
+bool
+SharedSurface_GLXDrawable::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor)
+{
+  if (!mXlibSurface)
+      return false;
+
+   *out_descriptor = layers::SurfaceDescriptorX11(mXlibSurface, mInSameProcess);
+   return true;
+}
+
+/* static */
+UniquePtr<SurfaceFactory_GLXDrawable>
+SurfaceFactory_GLXDrawable::Create(GLContext* prodGL,
+                                   const SurfaceCaps& caps,
+                                   const RefPtr<layers::ISurfaceAllocator>& allocator,
+                                   const layers::TextureFlags& flags)
+{
+    MOZ_ASSERT(caps.alpha, "GLX surfaces require an alpha channel!");
+
+    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)
+{
+    bool deallocateClient = !!(mFlags & layers::TextureFlags::DEALLOCATE_CLIENT);
+    return SharedSurface_GLXDrawable::Create(mGL, mCaps, size, deallocateClient,
+                                             mAllocator->IsSameProcess());
+}
+
+} // namespace gl
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/gl/SharedSurfaceGLX.h
@@ -0,0 +1,67 @@
+/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * 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 SharedSurface_GLXDrawable
+    : public SharedSurface
+{
+public:
+    static UniquePtr<SharedSurface_GLXDrawable> Create(GLContext* prodGL,
+                                                       const SurfaceCaps& caps,
+                                                       const gfx::IntSize& size,
+                                                       bool deallocateClient,
+                                                       bool inSameProcess);
+
+    virtual void Fence() override;
+    virtual bool WaitSync() override { return true; }
+    virtual bool PollSync() override { return true; }
+
+    virtual void LockProdImpl() override;
+    virtual void UnlockProdImpl() override;
+
+    virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
+private:
+    SharedSurface_GLXDrawable(GLContext* gl,
+                              const gfx::IntSize& size,
+                              bool inSameProcess,
+                              const RefPtr<gfxXlibSurface>& xlibSurface);
+
+    RefPtr<gfxXlibSurface> mXlibSurface;
+    bool mInSameProcess;
+};
+
+class SurfaceFactory_GLXDrawable
+    : public SurfaceFactory
+{
+public:
+    static UniquePtr<SurfaceFactory_GLXDrawable> Create(GLContext* prodGL,
+                                                        const SurfaceCaps& caps,
+                                                        const RefPtr<layers::ISurfaceAllocator>& allocator,
+                                                        const layers::TextureFlags& flags);
+
+    virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) override;
+
+private:
+    SurfaceFactory_GLXDrawable(GLContext* prodGL, const SurfaceCaps& caps,
+                               const RefPtr<layers::ISurfaceAllocator>& allocator,
+                               const layers::TextureFlags& flags)
+        : SurfaceFactory(SharedSurfaceType::GLXDrawable, prodGL, caps, allocator, flags)
+    { }
+};
+
+} // namespace gl
+} // namespace mozilla
+
+#endif // SHARED_SURFACE_GLX_H_
--- a/gfx/gl/SurfaceTypes.h
+++ b/gfx/gl/SurfaceTypes.h
@@ -71,16 +71,17 @@ enum class SharedSurfaceType : uint8_t {
 
     Basic,
     EGLImageShare,
     EGLSurfaceANGLE,
     DXGLInterop,
     DXGLInterop2,
     Gralloc,
     IOSurface,
+    GLXDrawable,
 
     Max
 };
 
 enum class AttachmentType : uint8_t {
     Screen = 0,
 
     GLTexture,
--- a/gfx/gl/moz.build
+++ b/gfx/gl/moz.build
@@ -103,16 +103,20 @@ if gl_provider == 'CGL':
     SOURCES += [
         'SharedSurfaceIO.cpp',
     ]
 elif gl_provider == 'GLX':
     # GLContextProviderGLX.cpp needs to be kept out of UNIFIED_SOURCES
     # as it includes X11 headers which cause conflicts.
     SOURCES += [
         'GLContextProviderGLX.cpp',
+        'SharedSurfaceGLX.cpp'
+    ]
+    EXPORTS += [
+        'SharedSurfaceGLX.h'
     ]
 else:
     UNIFIED_SOURCES += [
         'GLContextProvider%s.cpp' % gl_provider,
     ]
 
 UNIFIED_SOURCES += [
     'AndroidNativeWindow.cpp',
--- a/gfx/layers/client/ClientCanvasLayer.cpp
+++ b/gfx/layers/client/ClientCanvasLayer.cpp
@@ -27,16 +27,21 @@
 #ifdef MOZ_WIDGET_GONK
 #include "SharedSurfaceGralloc.h"
 #endif
 
 #ifdef XP_MACOSX
 #include "SharedSurfaceIO.h"
 #endif
 
+#ifdef GL_PROVIDER_GLX
+#include "GLXLibrary.h"
+#include "SharedSurfaceGLX.h"
+#endif
+
 using namespace mozilla::gfx;
 using namespace mozilla::gl;
 
 namespace mozilla {
 namespace layers {
 
 ClientCanvasLayer::~ClientCanvasLayer()
 {
@@ -81,16 +86,19 @@ ClientCanvasLayer::Initialize(const Data
 
   if (!gfxPrefs::WebGLForceLayersReadback()) {
     switch (forwarder->GetCompositorBackendType()) {
       case mozilla::layers::LayersBackend::LAYERS_OPENGL: {
 #if defined(XP_MACOSX)
         factory = SurfaceFactory_IOSurface::Create(mGLContext, caps, forwarder, mFlags);
 #elif defined(MOZ_WIDGET_GONK)
         factory = MakeUnique<SurfaceFactory_Gralloc>(mGLContext, caps, forwarder, mFlags);
+#elif defined(GL_PROVIDER_GLX)
+        if (sGLXLibrary.UseTextureFromPixmap())
+          factory = SurfaceFactory_GLXDrawable::Create(mGLContext, caps, forwarder, mFlags);
 #else
         if (mGLContext->GetContextType() == GLContextType::EGL) {
           if (XRE_IsParentProcess()) {
             factory = SurfaceFactory_EGLImage::Create(mGLContext, caps, forwarder,
                                                       mFlags);
           }
         }
 #endif
--- a/gfx/layers/ipc/ShadowLayerUtilsX11.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsX11.cpp
@@ -57,33 +57,40 @@ UsingXCompositing()
 static XRenderPictFormat*
 GetXRenderPictFormatFromId(Display* aDisplay, PictFormat aFormatId)
 {
   XRenderPictFormat tmplate;
   tmplate.id = aFormatId;
   return XRenderFindFormat(aDisplay, PictFormatID, &tmplate, 0);
 }
 
-SurfaceDescriptorX11::SurfaceDescriptorX11(gfxXlibSurface* aSurf)
+SurfaceDescriptorX11::SurfaceDescriptorX11(gfxXlibSurface* aSurf,
+                                           bool aForwardGLX)
   : mId(aSurf->XDrawable())
   , mSize(aSurf->GetSize())
+  , mGLXPixmap(None)
 {
   const XRenderPictFormat *pictFormat = aSurf->XRenderFormat();
   if (pictFormat) {
     mFormat = pictFormat->id;
   } else {
     mFormat = cairo_xlib_surface_get_visual(aSurf->CairoSurface())->visualid;
   }
+
+  if (aForwardGLX) {
+    mGLXPixmap = aSurf->GetGLXPixmap();
+  }
 }
 
 SurfaceDescriptorX11::SurfaceDescriptorX11(Drawable aDrawable, XID aFormatID,
                                            const gfx::IntSize& aSize)
   : mId(aDrawable)
   , mFormat(aFormatID)
   , mSize(aSize)
+  , mGLXPixmap(None)
 { }
 
 already_AddRefed<gfxXlibSurface>
 SurfaceDescriptorX11::OpenForeign() const
 {
   Display* display = DefaultXDisplay();
   Screen* screen = DefaultScreenOfDisplay(display);
 
@@ -95,16 +102,22 @@ SurfaceDescriptorX11::OpenForeign() cons
     Visual* visual;
     int depth;
     FindVisualAndDepth(display, mFormat, &visual, &depth);
     if (!visual)
       return nullptr;
 
     surf = new gfxXlibSurface(display, mId, visual, mSize);
   }
+
+#ifdef GL_PROVIDER_GLX
+  if (mGLXPixmap)
+    surf->BindGLXPixmap(mGLXPixmap);
+#endif
+
   return surf->CairoStatus() ? nullptr : surf.forget();
 }
 
 /*static*/ void
 ShadowLayerForwarder::PlatformSyncBeforeUpdate()
 {
   if (UsingXCompositing()) {
     // If we're using X surfaces, then we need to finish all pending
--- a/gfx/layers/ipc/ShadowLayerUtilsX11.h
+++ b/gfx/layers/ipc/ShadowLayerUtilsX11.h
@@ -26,17 +26,17 @@ class Message;
 
 namespace mozilla {
 namespace layers {
 
 struct SurfaceDescriptorX11 {
   SurfaceDescriptorX11()
   { }
 
-  explicit SurfaceDescriptorX11(gfxXlibSurface* aSurf);
+  explicit SurfaceDescriptorX11(gfxXlibSurface* aSurf, bool aForwardGLX = false);
 
   SurfaceDescriptorX11(Drawable aDrawable, XID aFormatID,
                        const gfx::IntSize& aSize);
 
   // Default copy ctor and operator= are OK
 
   bool operator==(const SurfaceDescriptorX11& aOther) const {
     // Define == as two descriptors having the same XID for now,
@@ -47,35 +47,39 @@ struct SurfaceDescriptorX11 {
     return mId == aOther.mId;
   }
 
   already_AddRefed<gfxXlibSurface> OpenForeign() const;
 
   Drawable mId;
   XID mFormat; // either a PictFormat or VisualID
   gfx::IntSize mSize;
+  Drawable mGLXPixmap; // used to prevent multiple bindings to the same GLXPixmap in-process
 };
 
 } // namespace layers
 } // namespace mozilla
 
 namespace IPC {
 
 template <>
 struct ParamTraits<mozilla::layers::SurfaceDescriptorX11> {
   typedef mozilla::layers::SurfaceDescriptorX11 paramType;
 
   static void Write(Message* aMsg, const paramType& aParam) {
     WriteParam(aMsg, aParam.mId);
     WriteParam(aMsg, aParam.mSize);
     WriteParam(aMsg, aParam.mFormat);
+    WriteParam(aMsg, aParam.mGLXPixmap);
   }
 
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult) {
     return (ReadParam(aMsg, aIter, &aResult->mId) &&
             ReadParam(aMsg, aIter, &aResult->mSize) &&
-            ReadParam(aMsg, aIter, &aResult->mFormat));
+            ReadParam(aMsg, aIter, &aResult->mFormat) &&
+            ReadParam(aMsg, aIter, &aResult->mGLXPixmap)
+            );
   }
 };
 
 } // namespace IPC
 
 #endif  // mozilla_layers_ShadowLayerUtilsX11_h
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -28,16 +28,19 @@
 # include "GrallocImages.h"  // for GrallocImage
 # include "EGLImageHelpers.h"
 #endif
 
 #ifdef XP_MACOSX
 #include "mozilla/layers/MacIOSurfaceTextureHostOGL.h"
 #endif
 
+#ifdef GL_PROVIDER_GLX
+#include "mozilla/layers/X11TextureHost.h"
+#endif
 
 using namespace mozilla::gl;
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 class Compositor;
@@ -88,16 +91,24 @@ CreateTextureHostOGL(const SurfaceDescri
 #ifdef MOZ_WIDGET_GONK
     case SurfaceDescriptor::TNewSurfaceDescriptorGralloc: {
       const NewSurfaceDescriptorGralloc& desc =
         aDesc.get_NewSurfaceDescriptorGralloc();
       result = new GrallocTextureHostOGL(aFlags, desc);
       break;
     }
 #endif
+
+#ifdef GL_PROVIDER_GLX
+    case SurfaceDescriptor::TSurfaceDescriptorX11: {
+      const auto& desc = aDesc.get_SurfaceDescriptorX11();
+      result = new X11TextureHost(aFlags, desc);
+      break;
+#endif
+    }
     default: return nullptr;
   }
   return result.forget();
 }
 
 static gl::TextureImage::Flags
 FlagsToGLFlags(TextureFlags aFlags)
 {
--- a/gfx/thebes/gfxXlibSurface.cpp
+++ b/gfx/thebes/gfxXlibSurface.cpp
@@ -75,23 +75,23 @@ gfxXlibSurface::gfxXlibSurface(cairo_sur
     mDrawable = cairo_xlib_surface_get_drawable(csurf);
     mDisplay = cairo_xlib_surface_get_display(csurf);
 
     Init(csurf, true);
 }
 
 gfxXlibSurface::~gfxXlibSurface()
 {
-#if defined(GL_PROVIDER_GLX)
-    if (mGLXPixmap) {
-        gl::sGLXLibrary.DestroyPixmap(mDisplay, mGLXPixmap);
-    }
-#endif
     // gfxASurface's destructor calls RecordMemoryFreed().
     if (mPixmapTaken) {
+#if defined(GL_PROVIDER_GLX)
+        if (mGLXPixmap) {
+            gl::sGLXLibrary.DestroyPixmap(mDisplay, mGLXPixmap);
+        }
+#endif
         XFreePixmap (mDisplay, mDrawable);
     }
 }
 
 static Drawable
 CreatePixmap(Screen *screen, const gfx::IntSize& size, unsigned int depth,
              Drawable relatedDrawable)
 {
@@ -266,17 +266,17 @@ gfxXlibSurface::CreateSimilarSurface(gfx
 
     return gfxASurface::CreateSimilarSurface(aContent, aSize);
 }
 
 void
 gfxXlibSurface::Finish()
 {
 #if defined(GL_PROVIDER_GLX)
-    if (mGLXPixmap) {
+    if (mPixmapTaken && mGLXPixmap) {
         gl::sGLXLibrary.DestroyPixmap(mDisplay, mGLXPixmap);
         mGLXPixmap = None;
     }
 #endif
     gfxASurface::Finish();
 }
 
 const gfx::IntSize
@@ -600,9 +600,17 @@ gfxXlibSurface::GetGLXPixmap()
         cairo_surface_has_show_text_glyphs(CairoSurface());
         NS_ASSERTION(CairoStatus() != CAIRO_STATUS_SURFACE_FINISHED,
             "GetGLXPixmap called after surface finished");
 #endif
         mGLXPixmap = gl::sGLXLibrary.CreatePixmap(this);
     }
     return mGLXPixmap;
 }
+
+void
+gfxXlibSurface::BindGLXPixmap(GLXPixmap aPixmap)
+{
+    MOZ_ASSERT(!mGLXPixmap, "A GLXPixmap is already bound!");
+    mGLXPixmap = aPixmap;
+}
+
 #endif
--- a/gfx/thebes/gfxXlibSurface.h
+++ b/gfx/thebes/gfxXlibSurface.h
@@ -82,16 +82,19 @@ public:
     // on those created by a Create() factory method.
     Drawable ReleasePixmap();
 
     // Find a visual and colormap pair suitable for rendering to this surface.
     bool GetColormapAndVisual(Colormap* colormap, Visual **visual);
 
 #if defined(GL_PROVIDER_GLX)
     GLXPixmap GetGLXPixmap();
+    // Binds a GLXPixmap backed by this context's surface.
+    // Primarily for use in sharing surfaces.
+    void BindGLXPixmap(GLXPixmap aPixmap);
 #endif
 
     // Return true if cairo will take its slow path when this surface is used
     // in a pattern with EXTEND_PAD.  As a workaround for XRender's RepeatPad
     // not being implemented correctly on old X servers, cairo avoids XRender
     // and instead reads back to perform EXTEND_PAD with pixman.  Cairo does
     // this for servers older than xorg-server 1.7.
     bool IsPadSlow() {