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 277000 5753576396107c2080e75a8fc8d47cf8b5a2a565
parent 276999 420fa39a00953598780365a65c9c0f4261e34276
child 277002 189161dc16163e36f6e917d360a2c37764f4543c
push idunknown
push userunknown
push dateunknown
reviewersjgilbert, nical
bugs1187440
milestone42.0a1
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() {