Bug 1205045 - remove GTK calls from compositor thread. r=jmuizelaar
authorLee Salzman <lsalzman@mozilla.com>
Tue, 15 Sep 2015 16:46:39 -0400
changeset 295819 3d9840db7d35ec36cbc5a5d87979aac9fe4d7568
parent 295818 eb338ca59783eaf9bb44e865ee7da3154582b62f
child 295820 c79d3947c307e5eddd13ae2bcb0c611dd201f94f
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjmuizelaar
bugs1205045
milestone43.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 1205045 - remove GTK calls from compositor thread. r=jmuizelaar
gfx/layers/basic/BasicCompositor.cpp
widget/gtk/nsWindow.cpp
widget/gtk/nsWindow.h
widget/nsIWidget.h
widget/nsShmImage.cpp
widget/nsShmImage.h
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -522,21 +522,21 @@ BasicCompositor::BeginFrame(const nsIntR
     *aRenderBoundsOut = Rect();
   }
 
   if (mInvalidRect.width <= 0 || mInvalidRect.height <= 0) {
     return;
   }
 
   if (mTarget) {
-    // If we have a copy target, then we don't have a widget-provided mDrawTarget (currently). Create a dummy
+    // If we have a copy target, then we don't have a widget-provided mDrawTarget (currently). Use a dummy
     // placeholder so that CreateRenderTarget() works.
-    mDrawTarget = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(1,1), SurfaceFormat::B8G8R8A8);
+    mDrawTarget = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
   } else {
-    mDrawTarget = mWidget->StartRemoteDrawing();
+    mDrawTarget = mWidget->StartRemoteDrawingInRegion(mInvalidRegion);
   }
   if (!mDrawTarget) {
     return;
   }
 
   // Setup an intermediate render target to buffer all compositing. We will
   // copy this into mDrawTarget (the widget), and/or mTarget in EndFrame()
   RefPtr<CompositingRenderTarget> target = CreateRenderTarget(mInvalidRect, INIT_MODE_CLEAR);
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -418,16 +418,21 @@ nsWindow::nsWindow()
     mRetryPointerGrab    = false;
     mWindowType          = eWindowType_child;
     mSizeState           = nsSizeMode_Normal;
     mLastSizeMode        = nsSizeMode_Normal;
     mSizeConstraints.mMaxSize = GetSafeWindowSize(mSizeConstraints.mMaxSize);
 
 #ifdef MOZ_X11
     mOldFocusWindow      = 0;
+
+    mXDisplay = nullptr;
+    mXWindow  = None;
+    mXVisual  = nullptr;
+    mXDepth   = 0;
 #endif /* MOZ_X11 */
     mPluginType          = PluginType_NONE;
 
     if (!gGlobalsInitialized) {
         gGlobalsInitialized = true;
 
         // It's OK if either of these fail, but it may not be one day.
         initialize_prefs();
@@ -716,20 +721,16 @@ nsWindow::Destroy(void)
     }
 
 #if (MOZ_WIDGET_GTK == 2) && defined(MOZ_X11)
     // make sure that we remove ourself as the plugin focus window
     if (gPluginFocusWindow == this) {
         gPluginFocusWindow->LoseNonXEmbedPluginFocus();
     }
 #endif /* MOZ_X11 && MOZ_WIDGET_GTK2 */
-  
-    // Destroy thebes surface now. Badness can happen if we destroy
-    // the surface after its X Window.
-    mThebesSurface = nullptr;
 
     GtkWidget *owningWidget = GetMozContainerWidget();
     if (mShell) {
         gtk_widget_destroy(mShell);
         mShell = nullptr;
         mContainer = nullptr;
         MOZ_ASSERT(!mGdkWindow,
                    "mGdkWindow should be NULL when mContainer is destroyed");
@@ -2166,17 +2167,17 @@ nsWindow::OnExposeEvent(cairo_t *cr)
 
     // If this widget uses OMTC...
     if (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
         listener->PaintWindow(this, region);
         listener->DidPaintWindow();
         return TRUE;
     }
 
-    RefPtr<DrawTarget> dt = StartRemoteDrawing();
+    RefPtr<DrawTarget> dt = GetDrawTarget(region);
     if(!dt) {
         return FALSE;
     }
     nsRefPtr<gfxContext> ctx = new gfxContext(dt);
 
 #ifdef MOZ_X11
     nsIntRect boundsRect; // for shaped only
 
@@ -2245,17 +2246,17 @@ nsWindow::OnExposeEvent(cairo_t *cr)
                 ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
                 ctx->SetPattern(pattern);
                 ctx->Paint();
             }
         }
     }
 #  ifdef MOZ_HAVE_SHMIMAGE
     if (mShmImage && MOZ_LIKELY(!mIsDestroyed)) {
-        mShmImage->Put(mGdkWindow, region);
+      mShmImage->Put(mXDisplay, mXWindow, region);
     }
 #  endif  // MOZ_HAVE_SHMIMAGE
 #endif // MOZ_X11
 
     listener->DidPaintWindow();
 
     // Synchronously flush any new dirty areas
 #if (MOZ_WIDGET_GTK == 2)
@@ -3823,19 +3824,22 @@ nsWindow::Create(nsIWidget        *aPare
     }
 
     // resize so that everything is set to the right dimensions
     if (!mIsTopLevel)
         Resize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, false);
 
 #ifdef MOZ_X11
     if (mGdkWindow) {
-      // force creation of native window via internal call to gdk_window_ensure_native
-      // in case it was not created already
-      gdk_x11_window_get_xid(mGdkWindow);
+      mXDisplay = GDK_WINDOW_XDISPLAY(mGdkWindow);
+      mXWindow = gdk_x11_window_get_xid(mGdkWindow);
+
+      GdkVisual* gdkVisual = gdk_window_get_visual(mGdkWindow);
+      mXVisual = gdk_x11_visual_get_xvisual(gdkVisual);
+      mXDepth = gdk_visual_get_depth(gdkVisual);
     }
 #endif
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::SetWindowClass(const nsAString &xulWinType)
@@ -6304,119 +6308,69 @@ nsWindow::GetSurfaceForGdkDrawable(GdkDr
                                     gfxIntSize(aSize.width, aSize.height));
     }
 
     return result.forget();
 }
 #endif
 
 already_AddRefed<DrawTarget>
-nsWindow::StartRemoteDrawing()
-{
-  gfxASurface *surf = GetThebesSurface();
-  if (!surf) {
+nsWindow::GetDrawTarget(const nsIntRegion& aRegion)
+{
+  if (!mGdkWindow) {
     return nullptr;
   }
 
-  nsIntSize size = surf->GetSize();
+  nsIntRect bounds = aRegion.GetBounds();
+  IntSize size(bounds.XMost(), bounds.YMost());
   if (size.width <= 0 || size.height <= 0) {
     return nullptr;
   }
 
-  gfxPlatform *platform = gfxPlatform::GetPlatform();
-  if (platform->SupportsAzureContentForType(BackendType::CAIRO) ||
-      surf->GetType() == gfxSurfaceType::Xlib) {
-    return platform->CreateDrawTargetForSurface(surf, size);
-  } else if (platform->SupportsAzureContentForType(BackendType::SKIA) &&
-             surf->GetType() == gfxSurfaceType::Image) {
-    gfxImageSurface* imgSurf = static_cast<gfxImageSurface*>(surf);
-    SurfaceFormat format = ImageFormatToSurfaceFormat(imgSurf->Format());
-    return platform->CreateDrawTargetForData(
-                     imgSurf->Data(), size, imgSurf->Stride(), format);
-  } else {
-    return nullptr;
+  RefPtr<DrawTarget> dt;
+
+#ifdef MOZ_X11
+#  ifdef MOZ_HAVE_SHMIMAGE
+  if (nsShmImage::UseShm()) {
+    dt = nsShmImage::EnsureShmImage(size,
+                                    mXDisplay, mXVisual, mXDepth,
+                                    mShmImage);
   }
+#  endif  // MOZ_HAVE_SHMIMAGE
+  if (!dt) {
+    RefPtr<gfxXlibSurface> surf = new gfxXlibSurface(mXDisplay, mXWindow, mXVisual, size);
+    if (!surf->CairoStatus()) {
+      dt = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surf.get(), surf->GetSize());
+    }
+  }
+#endif // MOZ_X11
+
+  return dt.forget();
+}
+
+already_AddRefed<DrawTarget>
+nsWindow::StartRemoteDrawingInRegion(nsIntRegion& aInvalidRegion)
+{
+  return GetDrawTarget(aInvalidRegion);
 }
 
 void
 nsWindow::EndRemoteDrawingInRegion(DrawTarget* aDrawTarget, nsIntRegion& aInvalidRegion)
 {
 #ifdef MOZ_X11
 #  ifdef MOZ_HAVE_SHMIMAGE
   if (!mGdkWindow || !mShmImage) {
     return;
   }
 
-  if (mThebesSurface) {
-    aInvalidRegion.AndWith(nsIntRect(nsIntPoint(0, 0), mThebesSurface->GetSize()));
-  }
-
-  mShmImage->Put(mGdkWindow, aInvalidRegion);
-
+  mShmImage->Put(mXDisplay, mXWindow, aInvalidRegion);
 #  endif // MOZ_HAVE_SHMIMAGE
 #endif // MOZ_X11
 }
 
-// return the gfxASurface for rendering to this widget
-gfxASurface*
-nsWindow::GetThebesSurface()
-{
-    if (!mGdkWindow)
-        return nullptr;
-
-#ifdef MOZ_X11
-    gint width, height;
-
-#if (MOZ_WIDGET_GTK == 2)
-    gdk_drawable_get_size(GDK_DRAWABLE(mGdkWindow), &width, &height);
-#else
-    width = GdkCoordToDevicePixels(gdk_window_get_width(mGdkWindow));
-    height = GdkCoordToDevicePixels(gdk_window_get_height(mGdkWindow));
-#endif
-
-    // Owen Taylor says this is the right thing to do!
-    width = std::min(32767, width);
-    height = std::min(32767, height);
-    gfxIntSize size(width, height);
-
-    GdkVisual *gdkVisual = gdk_window_get_visual(mGdkWindow);
-    Visual* visual = gdk_x11_visual_get_xvisual(gdkVisual);
-
-#  ifdef MOZ_HAVE_SHMIMAGE
-    bool usingShm = false;
-    if (nsShmImage::UseShm()) {
-        // EnsureShmImage() is a dangerous interface, but we guarantee
-        // that the thebes surface and the shmimage have the same
-        // lifetime
-        mThebesSurface =
-            nsShmImage::EnsureShmImage(size,
-                                       visual, gdk_visual_get_depth(gdkVisual),
-                                       mShmImage);
-        usingShm = mThebesSurface != nullptr;
-    }
-    if (!usingShm)
-#  endif  // MOZ_HAVE_SHMIMAGE
-    {
-        mThebesSurface = new gfxXlibSurface
-            (GDK_WINDOW_XDISPLAY(mGdkWindow),
-             gdk_x11_window_get_xid(mGdkWindow),
-             visual,
-             size);
-    }
-#endif // MOZ_X11
-
-    // if the surface creation is reporting an error, then
-    // we don't have a surface to give back
-    if (mThebesSurface && mThebesSurface->CairoStatus() != 0) {
-        mThebesSurface = nullptr;
-    }
-
-    return mThebesSurface;
-}
-
 // Code shared begin BeginMoveDrag and BeginResizeDrag
 bool
 nsWindow::GetDragInfo(WidgetMouseEvent* aMouseEvent,
                       GdkWindow** aWindow, gint* aButton,
                       gint* aRootX, gint* aRootY)
 {
     if (aMouseEvent->button != WidgetMouseEvent::eLeftButton) {
         // we can only begin a move drag with the left mouse button
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -202,17 +202,17 @@ public:
                                                gint             aX,
                                                gint             aY,
                                                GtkSelectionData*aSelectionData,
                                                guint            aInfo,
                                                guint            aTime,
                                                gpointer         aData);
 
     virtual already_AddRefed<mozilla::gfx::DrawTarget>
-                       StartRemoteDrawing() override;
+                       StartRemoteDrawingInRegion(nsIntRegion& aInvalidRegion) override;
     virtual void       EndRemoteDrawingInRegion(mozilla::gfx::DrawTarget* aDrawTarget,
                                                 nsIntRegion& aInvalidRegion) override;
 
 private:
     void               UpdateAlpha(gfxPattern* aPattern, nsIntRect aBoundsRect);
 
     void               NativeMove();
     void               NativeResize();
@@ -295,17 +295,17 @@ public:
     void               ApplyTransparencyBitmap();
     void               ClearTransparencyBitmap();
 
    virtual void        SetTransparencyMode(nsTransparencyMode aMode) override;
    virtual nsTransparencyMode GetTransparencyMode() override;
    virtual nsresult    ConfigureChildren(const nsTArray<Configuration>& aConfigurations) override;
    nsresult            UpdateTranslucentWindowAlphaInternal(const nsIntRect& aRect,
                                                             uint8_t* aAlphas, int32_t aStride);
-    virtual gfxASurface *GetThebesSurface();
+    virtual already_AddRefed<mozilla::gfx::DrawTarget> GetDrawTarget(const nsIntRegion& aRegion);
 
 #if (MOZ_WIDGET_GTK == 2)
     static already_AddRefed<gfxASurface> GetSurfaceForGdkDrawable(GdkDrawable* aDrawable,
                                                                   const nsIntSize& aSize);
 #endif
     NS_IMETHOD         ReparentNativeWidget(nsIWidget* aNewParent) override;
 
     virtual nsresult SynthesizeNativeMouseEvent(mozilla::LayoutDeviceIntPoint aPoint,
@@ -390,21 +390,27 @@ private:
     int32_t             mTransparencyBitmapWidth;
     int32_t             mTransparencyBitmapHeight;
 
 #if GTK_CHECK_VERSION(3,4,0)
     // This field omits duplicate scroll events caused by GNOME bug 726878.
     guint32             mLastScrollEventTime;
 #endif
 
+#ifdef MOZ_X11
+    Display*            mXDisplay;
+    Drawable            mXWindow;
+    Visual*             mXVisual;
+    int                 mXDepth;
+#endif
+
 #ifdef MOZ_HAVE_SHMIMAGE
-    // If we're using xshm rendering, mThebesSurface wraps mShmImage
+    // If we're using xshm rendering
     nsRefPtr<nsShmImage>  mShmImage;
 #endif
-    nsRefPtr<gfxASurface> mThebesSurface;
 
 #ifdef ACCESSIBILITY
     nsRefPtr<mozilla::a11y::Accessible> mRootAccessible;
 
     /**
      * Request to create the accessible for this window if it is top level.
      */
     void                CreateRootAccessible();
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -1223,16 +1223,19 @@ class nsIWidget : public nsISupports {
 
     /**
      * Return a DrawTarget for the window which can be composited into.
      *
      * Called by BasicCompositor on the compositor thread for OMTC drawing
      * before each composition.
      */
     virtual already_AddRefed<mozilla::gfx::DrawTarget> StartRemoteDrawing() = 0;
+    virtual already_AddRefed<mozilla::gfx::DrawTarget> StartRemoteDrawingInRegion(nsIntRegion& aInvalidRegion) {
+      return StartRemoteDrawing();
+    }
 
     /**
      * Ensure that what was painted into the DrawTarget returned from
      * StartRemoteDrawing reaches the screen.
      *
      * Called by BasicCompositor on the compositor thread for OMTC drawing
      * after each composition.
      */
--- a/widget/nsShmImage.cpp
+++ b/widget/nsShmImage.cpp
@@ -10,42 +10,53 @@
 #elif defined(MOZ_WIDGET_QT)
 #include <QWindow>
 #endif
 
 #include "nsShmImage.h"
 #ifdef MOZ_WIDGET_GTK
 #include "gfxPlatformGtk.h"
 #endif
-#include "gfxImageSurface.h"
 
 #ifdef MOZ_HAVE_SHMIMAGE
 
 using namespace mozilla::ipc;
+using namespace mozilla::gfx;
 
 // If XShm isn't available to our client, we'll try XShm once, fail,
 // set this to false and then never try again.
 static bool gShmAvailable = true;
 bool nsShmImage::UseShm()
 {
 #ifdef MOZ_WIDGET_GTK
     return (gShmAvailable && !gfxPlatformGtk::GetPlatform()->UseXRender());
 #else
     return gShmAvailable;
 #endif
 }
 
+#ifdef MOZ_WIDGET_GTK
+static int gShmError = 0;
+
+static int
+TrapShmError(Display* aDisplay, XErrorEvent* aEvent)
+{
+    // store the error code and ignore the error
+    gShmError = aEvent->error_code;
+    return 0;
+}
+#endif
+
 already_AddRefed<nsShmImage>
 nsShmImage::Create(const gfxIntSize& aSize,
-                   Visual* aVisual, unsigned int aDepth)
+                   Display* aDisplay, Visual* aVisual, unsigned int aDepth)
 {
-    Display* dpy = DISPLAY();
-
     nsRefPtr<nsShmImage> shm = new nsShmImage();
-    shm->mImage = XShmCreateImage(dpy, aVisual, aDepth,
+    shm->mDisplay = aDisplay;
+    shm->mImage = XShmCreateImage(aDisplay, aVisual, aDepth,
                                   ZPixmap, nullptr,
                                   &(shm->mInfo),
                                   aSize.width, aSize.height);
     if (!shm->mImage) {
         return nullptr;
     }
 
     size_t size = SharedMemory::PageAlignedSize(
@@ -55,137 +66,103 @@ nsShmImage::Create(const gfxIntSize& aSi
         return nullptr;
     }
 
     shm->mInfo.shmid = shm->mSegment->GetHandle();
     shm->mInfo.shmaddr =
         shm->mImage->data = static_cast<char*>(shm->mSegment->memory());
     shm->mInfo.readOnly = False;
 
-    int xerror = 0;
 #if defined(MOZ_WIDGET_GTK)
-    gdk_error_trap_push();
-    Status attachOk = XShmAttach(dpy, &shm->mInfo);
-    XSync(dpy, False);
-    xerror = gdk_error_trap_pop();
+    gShmError = 0;
+    XErrorHandler previousHandler = XSetErrorHandler(TrapShmError);
+    Status attachOk = XShmAttach(aDisplay, &shm->mInfo);
+    XSync(aDisplay, False);
+    XSetErrorHandler(previousHandler);
+    if (gShmError) {
+      attachOk = 0;
+    }
 #elif defined(MOZ_WIDGET_QT)
-    Status attachOk = XShmAttach(dpy, &shm->mInfo);
+    Status attachOk = XShmAttach(aDisplay, &shm->mInfo);
 #endif
 
-    if (!attachOk || xerror) {
+    if (!attachOk) {
         // Assume XShm isn't available, and don't attempt to use it
         // again.
         gShmAvailable = false;
         return nullptr;
     }
 
     shm->mXAttached = true;
     shm->mSize = aSize;
     switch (shm->mImage->depth) {
     case 32:
         if ((shm->mImage->red_mask == 0xff0000) &&
             (shm->mImage->green_mask == 0xff00) &&
             (shm->mImage->blue_mask == 0xff)) {
-            shm->mFormat = gfxImageFormat::ARGB32;
+            shm->mFormat = SurfaceFormat::B8G8R8A8;
             break;
         }
         goto unsupported;
     case 24:
         // Only xRGB is supported.
         if ((shm->mImage->red_mask == 0xff0000) &&
             (shm->mImage->green_mask == 0xff00) &&
             (shm->mImage->blue_mask == 0xff)) {
-            shm->mFormat = gfxImageFormat::RGB24;
+            shm->mFormat = SurfaceFormat::B8G8R8X8;
             break;
         }
         goto unsupported;
     case 16:
-        shm->mFormat = gfxImageFormat::RGB16_565; break;
+        shm->mFormat = SurfaceFormat::R5G6B5;
+        break;
     unsupported:
     default:
         NS_WARNING("Unsupported XShm Image format!");
         gShmAvailable = false;
         return nullptr;
     }
     return shm.forget();
 }
 
-already_AddRefed<gfxASurface>
-nsShmImage::AsSurface()
+already_AddRefed<DrawTarget>
+nsShmImage::CreateDrawTarget()
 {
-    return nsRefPtr<gfxASurface>(
-        new gfxImageSurface(static_cast<unsigned char*>(mSegment->memory()),
-                            mSize,
-                            mImage->bytes_per_line,
-                            mFormat)
-        ).forget();
+  return gfxPlatform::GetPlatform()->CreateDrawTargetForData(
+    static_cast<unsigned char*>(mSegment->memory()),
+    mSize,
+    mImage->bytes_per_line,
+    mFormat);
 }
 
-#if (MOZ_WIDGET_GTK == 2)
+#ifdef MOZ_WIDGET_GTK
 void
-nsShmImage::Put(GdkWindow* aWindow, const nsIntRegion& aRegion)
+nsShmImage::Put(Display* aDisplay, Drawable aWindow, const nsIntRegion& aRegion)
 {
-    GdkDrawable* gd;
-    gint dx, dy;
-    gdk_window_get_internal_paint_info(aWindow, &gd, &dx, &dy);
-
-    Display* dpy = gdk_x11_get_default_xdisplay();
-    Drawable d = GDK_DRAWABLE_XID(gd);
-
-    GC gc = XCreateGC(dpy, d, 0, nullptr);
+    GC gc = XCreateGC(aDisplay, aWindow, 0, nullptr);
     nsIntRegion bounded;
     bounded.And(aRegion, nsIntRect(0, 0, mImage->width, mImage->height));
     nsIntRegionRectIterator iter(bounded);
     for (const nsIntRect *r = iter.Next(); r; r = iter.Next()) {
-        XShmPutImage(dpy, d, gc, mImage,
+        XShmPutImage(aDisplay, aWindow, gc, mImage,
                      r->x, r->y,
-                     r->x - dx, r->y - dy,
+                     r->x, r->y,
                      r->width, r->height,
                      False);
     }
-    XFreeGC(dpy, gc);
+
+    XFreeGC(aDisplay, gc);
 
     // FIXME/bug 597336: we need to ensure that the shm image isn't
     // scribbled over before all its pending XShmPutImage()s complete.
     // However, XSync() is an unnecessarily heavyweight
     // synchronization mechanism; other options are possible.  If this
     // XSync is shown to hurt responsiveness, we need to explore the
     // other options.
-    XSync(dpy, False);
-}
-
-#elif (MOZ_WIDGET_GTK == 3)
-void
-nsShmImage::Put(GdkWindow* aWindow, const nsIntRegion& aRegion)
-{
-    Display* dpy = gdk_x11_get_default_xdisplay();
-    Drawable d = GDK_WINDOW_XID(aWindow);
-    int dx = 0, dy = 0;
-
-    GC gc = XCreateGC(dpy, d, 0, nullptr);
-    nsIntRegion bounded;
-    bounded.And(aRegion, nsIntRect(0, 0, mImage->width, mImage->height));
-    nsIntRegionRectIterator iter(bounded);
-    for (const nsIntRect *r = iter.Next(); r; r = iter.Next()) {
-        XShmPutImage(dpy, d, gc, mImage,
-                     r->x, r->y,
-                     r->x - dx, r->y - dy,
-                     r->width, r->height,
-                     False);
-    }
-
-    XFreeGC(dpy, gc);
-
-    // FIXME/bug 597336: we need to ensure that the shm image isn't
-    // scribbled over before all its pending XShmPutImage()s complete.
-    // However, XSync() is an unnecessarily heavyweight
-    // synchronization mechanism; other options are possible.  If this
-    // XSync is shown to hurt responsiveness, we need to explore the
-    // other options.
-    XSync(dpy, False);
+    XSync(aDisplay, False);
 }
 
 #elif defined(MOZ_WIDGET_QT)
 void
 nsShmImage::Put(QWindow* aWindow, QRect& aRect)
 {
     Display* dpy = gfxQtPlatform::GetXDisplay(aWindow);
     Drawable d = aWindow->winId();
@@ -197,24 +174,25 @@ nsShmImage::Put(QWindow* aWindow, QRect&
                  inter.x(), inter.y(),
                  inter.x(), inter.y(),
                  inter.width(), inter.height(),
                  False);
     XFreeGC(dpy, gc);
 }
 #endif
 
-already_AddRefed<gfxASurface>
-nsShmImage::EnsureShmImage(const gfxIntSize& aSize, Visual* aVisual, unsigned int aDepth,
-               nsRefPtr<nsShmImage>& aImage)
+already_AddRefed<DrawTarget>
+nsShmImage::EnsureShmImage(const gfxIntSize& aSize,
+                           Display* aDisplay, Visual* aVisual, unsigned int aDepth,
+                           nsRefPtr<nsShmImage>& aImage)
 {
     if (!aImage || aImage->Size() != aSize) {
         // Because we XSync() after XShmAttach() to trap errors, we
         // know that the X server has the old image's memory mapped
         // into its address space, so it's OK to destroy the old image
         // here even if there are outstanding Puts.  The Detach is
         // ordered after the Puts.
-        aImage = nsShmImage::Create(aSize, aVisual, aDepth);
+        aImage = nsShmImage::Create(aSize, aDisplay, aVisual, aDepth);
     }
-    return !aImage ? nullptr : aImage->AsSurface();
+    return !aImage ? nullptr : aImage->CreateDrawTarget();
 }
 
 #endif  // defined(MOZ_X11) && defined(MOZ_HAVE_SHAREDMEMORYSYSV)
--- a/widget/nsShmImage.h
+++ b/widget/nsShmImage.h
@@ -10,82 +10,80 @@
 #include "mozilla/ipc/SharedMemorySysV.h"
 
 #if defined(MOZ_X11) && defined(MOZ_HAVE_SHAREDMEMORYSYSV)
 #  define MOZ_HAVE_SHMIMAGE
 #endif
 
 #ifdef MOZ_HAVE_SHMIMAGE
 
+#include "mozilla/gfx/2D.h"
 #include "nsIWidget.h"
-#include "gfxTypes.h"
 #include "nsAutoPtr.h"
 
 #include "mozilla/X11Util.h"
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 #include <X11/extensions/XShm.h>
 
-#if defined(MOZ_WIDGET_GTK)
-#define DISPLAY gdk_x11_get_default_xdisplay
-#elif defined(MOZ_WIDGET_QT)
-#define DISPLAY mozilla::DefaultXDisplay
-#endif
-
+#ifdef MOZ_WIDGET_QT
 class QRect;
 class QWindow;
-class gfxASurface;
+#endif
 
 class nsShmImage {
     // bug 1168843, compositor thread may create shared memory instances that are destroyed by main thread on shutdown, so this must use thread-safe RC to avoid hitting assertion
     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsShmImage)
 
     typedef mozilla::ipc::SharedMemorySysV SharedMemorySysV;
 
 public:
-    typedef gfxImageFormat Format;
-
     static bool UseShm();
     static already_AddRefed<nsShmImage>
-        Create(const gfxIntSize& aSize, Visual* aVisual, unsigned int aDepth);
-    static already_AddRefed<gfxASurface>
-        EnsureShmImage(const gfxIntSize& aSize, Visual* aVisual, unsigned int aDepth,
+        Create(const gfxIntSize& aSize,
+               Display* aDisplay, Visual* aVisual, unsigned int aDepth);
+    static already_AddRefed<mozilla::gfx::DrawTarget>
+        EnsureShmImage(const gfxIntSize& aSize,
+                       Display* aDisplay, Visual* aVisual, unsigned int aDepth,
                        nsRefPtr<nsShmImage>& aImage);
 
 private:
     ~nsShmImage() {
         if (mImage) {
-            mozilla::FinishX(DISPLAY());
+            mozilla::FinishX(mDisplay);
             if (mXAttached) {
-                XShmDetach(DISPLAY(), &mInfo);
+                XShmDetach(mDisplay, &mInfo);
             }
             XDestroyImage(mImage);
         }
     }
 
 public:
-    already_AddRefed<gfxASurface> AsSurface();
+    already_AddRefed<mozilla::gfx::DrawTarget> CreateDrawTarget();
 
 #ifdef MOZ_WIDGET_GTK
-    void Put(GdkWindow* aWindow, const nsIntRegion& aRegion);
+    void Put(Display* aDisplay, Drawable aWindow, const nsIntRegion& aRegion);
 #elif defined(MOZ_WIDGET_QT)
     void Put(QWindow* aWindow, QRect& aRect);
 #endif
 
     gfxIntSize Size() const { return mSize; }
 
 private:
     nsShmImage()
         : mImage(nullptr)
+        , mDisplay(nullptr)
+        , mFormat(mozilla::gfx::SurfaceFormat::UNKNOWN)
         , mXAttached(false)
     { mInfo.shmid = SharedMemorySysV::NULLHandle(); }
 
     nsRefPtr<SharedMemorySysV>   mSegment;
     XImage*                      mImage;
+    Display*                     mDisplay;
     XShmSegmentInfo              mInfo;
     gfxIntSize                   mSize;
-    Format                       mFormat;
+    mozilla::gfx::SurfaceFormat  mFormat;
     bool                         mXAttached;
 };
 
 #endif // MOZ_HAVE_SHMIMAGE
 
 #endif