b=1015218 Buffer image content layers on server-side xlib surfaces with OMTC basic r=karlt
authorFrederic Plourde <frederic.plourde@collabora.com>
Wed, 23 Jul 2014 11:02:25 +1200
changeset 195629 a500c62330d4
parent 195628 6e532c9826e7
child 195630 352fa9a8ea8e
push id27188
push usercbook@mozilla.com
push dateWed, 23 Jul 2014 13:53:43 +0000
treeherdermozilla-central@785acfd2ae48 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskarlt
bugs1015218
milestone34.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
b=1015218 Buffer image content layers on server-side xlib surfaces with OMTC basic r=karlt With image offscreen surfaces enabled for content layers on GTK3, our Basic compositor needs a way to deal with image layers buffering and compositing in a performant way. This patch subclasses BasicCompositor into a new X11BasicCompositor and makes use of a new TextureSource (X11DataTextureSourceBasic) in order to buffer TextureHost's data into gfxXlibSurface on compositor side so that we can use XRender when available to composite layer contents directly to the Window. When this buffering will occur, switch to ContentClientSingleBuffered.
gfx/layers/basic/X11BasicCompositor.cpp
gfx/layers/basic/X11BasicCompositor.h
gfx/layers/client/ContentClient.cpp
gfx/layers/ipc/CompositorParent.cpp
gfx/layers/moz.build
new file mode 100644
--- /dev/null
+++ b/gfx/layers/basic/X11BasicCompositor.cpp
@@ -0,0 +1,129 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+* 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 "X11BasicCompositor.h"
+#include "gfxPlatform.h"
+#include "gfx2DGlue.h"
+#include "gfxXlibSurface.h"
+#include "gfxImageSurface.h"
+#include "mozilla/X11Util.h"
+
+namespace mozilla {
+using namespace mozilla::gfx;
+
+namespace layers {
+
+bool
+X11DataTextureSourceBasic::Update(gfx::DataSourceSurface* aSurface,
+                                  nsIntRegion* aDestRegion,
+                                  gfx::IntPoint* aSrcOffset)
+{
+  // Reallocate our internal X11 surface if we don't have a DrawTarget yet,
+  // or if we changed surface size or format since last update.
+  if (!mBufferDrawTarget ||
+      (aSurface->GetSize() != mBufferDrawTarget->GetSize()) ||
+      (aSurface->GetFormat() != mBufferDrawTarget->GetFormat())) {
+
+    nsRefPtr<gfxASurface> surf;
+    gfxImageFormat imageFormat = SurfaceFormatToImageFormat(aSurface->GetFormat());
+    Display *display = DefaultXDisplay();
+    Screen *screen = DefaultScreenOfDisplay(display);
+    XRenderPictFormat *xrenderFormat =
+      gfxXlibSurface::FindRenderFormat(display, imageFormat);
+
+    if (xrenderFormat) {
+      surf = gfxXlibSurface::Create(screen, xrenderFormat,
+                                    ThebesIntSize(aSurface->GetSize()));
+    }
+
+    if (!surf) {
+      NS_WARNING("Couldn't create native surface, fallback to image surface");
+      surf = new gfxImageSurface(ThebesIntSize(aSurface->GetSize()), imageFormat);
+    }
+
+    mBufferDrawTarget = gfxPlatform::GetPlatform()->
+      CreateDrawTargetForSurface(surf, aSurface->GetSize());
+  }
+
+  // Image contents have changed, upload to our DrawTarget
+  // If aDestRegion is null, means we're updating the whole surface
+  // Note : Incremental update with a source offset is only used on Mac.
+  NS_ASSERTION(!aSrcOffset, "SrcOffset should not be used with linux OMTC basic");
+
+  if (aDestRegion) {
+    nsIntRegionRectIterator iter(*aDestRegion);
+    while (const nsIntRect* iterRect = iter.Next()) {
+      IntRect srcRect(iterRect->x, iterRect->y, iterRect->width, iterRect->height);
+      IntPoint dstPoint(iterRect->x, iterRect->y);
+
+      // We're uploading regions to our buffer, so let's just copy contents over
+      mBufferDrawTarget->CopySurface(aSurface, srcRect, dstPoint);
+    }
+  } else {
+    // We're uploading the whole buffer, so let's just copy the full surface
+    IntSize size = aSurface->GetSize();
+    mBufferDrawTarget->CopySurface(aSurface, IntRect(0, 0, size.width, size.height),
+                                   IntPoint(0, 0));
+  }
+
+  return true;
+}
+
+TextureSourceBasic*
+X11DataTextureSourceBasic::AsSourceBasic()
+{
+  return this;
+}
+
+IntSize
+X11DataTextureSourceBasic::GetSize() const
+{
+  if (!mBufferDrawTarget) {
+    NS_WARNING("Trying to query the size of an uninitialized TextureSource");
+    return IntSize(0, 0);
+  } else {
+    return mBufferDrawTarget->GetSize();
+  }
+}
+
+gfx::SurfaceFormat
+X11DataTextureSourceBasic::GetFormat() const
+{
+  if (!mBufferDrawTarget) {
+    NS_WARNING("Trying to query the format of an uninitialized TextureSource");
+    return gfx::SurfaceFormat::UNKNOWN;
+  } else {
+    return mBufferDrawTarget->GetFormat();
+  }
+}
+
+SourceSurface*
+X11DataTextureSourceBasic::GetSurface(DrawTarget* aTarget)
+{
+  RefPtr<gfx::SourceSurface> surface;
+  if (mBufferDrawTarget) {
+    surface = mBufferDrawTarget->Snapshot();
+    return surface.get();
+  } else {
+    return nullptr;
+  }
+}
+
+void
+X11DataTextureSourceBasic::DeallocateDeviceData()
+{
+  mBufferDrawTarget = nullptr;
+}
+
+TemporaryRef<DataTextureSource>
+X11BasicCompositor::CreateDataTextureSource(TextureFlags aFlags)
+{
+  RefPtr<DataTextureSource> result =
+    new X11DataTextureSourceBasic();
+  return result.forget();
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/basic/X11BasicCompositor.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+* 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 MOZILLA_GFX_X11BASICCOMPOSITOR_H
+#define MOZILLA_GFX_X11BASICCOMPOSITOR_H
+
+#include "mozilla/layers/BasicCompositor.h"
+#include "mozilla/layers/X11TextureSourceBasic.h"
+#include "mozilla/layers/TextureHostBasic.h"
+#include "gfxXlibSurface.h"
+#include "mozilla/gfx/2D.h"
+
+namespace mozilla {
+namespace layers {
+
+// TextureSource for Image-backed surfaces.
+class X11DataTextureSourceBasic : public DataTextureSource
+                                , public TextureSourceBasic
+{
+public:
+  X11DataTextureSourceBasic() {};
+
+  virtual bool Update(gfx::DataSourceSurface* aSurface,
+                      nsIntRegion* aDestRegion = nullptr,
+                      gfx::IntPoint* aSrcOffset = nullptr) MOZ_OVERRIDE;
+
+  virtual TextureSourceBasic* AsSourceBasic() MOZ_OVERRIDE;
+
+  virtual gfx::SourceSurface* GetSurface(gfx::DrawTarget* aTarget) MOZ_OVERRIDE;
+
+  virtual void DeallocateDeviceData() MOZ_OVERRIDE;
+
+  virtual gfx::IntSize GetSize() const MOZ_OVERRIDE;
+
+  virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE;
+
+private:
+  // We are going to buffer layer content on this xlib draw target
+  RefPtr<mozilla::gfx::DrawTarget> mBufferDrawTarget;
+};
+
+class X11BasicCompositor : public BasicCompositor
+{
+public:
+
+  X11BasicCompositor(nsIWidget *aWidget) : BasicCompositor(aWidget) {}
+
+  virtual TemporaryRef<DataTextureSource>
+  CreateDataTextureSource(TextureFlags aFlags = TextureFlags::NO_FLAGS) MOZ_OVERRIDE;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif /* MOZILLA_GFX_X11BASICCOMPOSITOR_H */
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -27,16 +27,19 @@
 #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING, etc
 #include "nsISupportsImpl.h"            // for gfxContext::Release, etc
 #include "nsIWidget.h"                  // for nsIWidget
 #include "prenv.h"                      // for PR_GetEnv
 #include "nsLayoutUtils.h"
 #ifdef XP_WIN
 #include "gfxWindowsPlatform.h"
 #endif
+#ifdef MOZ_WIDGET_GTK
+#include "gfxPlatformGtk.h"
+#endif
 #include "gfx2DGlue.h"
 
 namespace mozilla {
 
 using namespace gfx;
 
 namespace layers {
 
@@ -68,16 +71,23 @@ ContentClient::CreateContentClient(Compo
 
   bool useDoubleBuffering = false;
 
 #ifdef XP_WIN
   if (backend == LayersBackend::LAYERS_D3D11) {
     useDoubleBuffering = !!gfxWindowsPlatform::GetPlatform()->GetD2DDevice();
   } else
 #endif
+#ifdef MOZ_WIDGET_GTK
+  // We can't use double buffering when using image content with
+  // Xrender support on Linux, as ContentHostDoubleBuffered is not
+  // suited for direct uploads to the server.
+  if (!gfxPlatformGtk::GetPlatform()->UseImageOffscreenSurfaces() ||
+      !gfxPlatformGtk::GetPlatform()->UseXRender())
+#endif
   {
     useDoubleBuffering = (LayerManagerComposite::SupportsDirectTexturing() &&
                          backend != LayersBackend::LAYERS_D3D9) ||
                          backend == LayersBackend::LAYERS_BASIC;
   }
 
   if (useDoubleBuffering || PR_GetEnv("MOZ_FORCE_DOUBLE_BUFFERING")) {
     return new ContentClientDoubleBuffered(aForwarder);
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -14,16 +14,19 @@
 #include "base/message_loop.h"          // for MessageLoop
 #include "base/process.h"               // for ProcessHandle
 #include "base/process_util.h"          // for OpenProcessHandle
 #include "base/task.h"                  // for CancelableTask, etc
 #include "base/thread.h"                // for Thread
 #include "base/tracked.h"               // for FROM_HERE
 #include "gfxContext.h"                 // for gfxContext
 #include "gfxPlatform.h"                // for gfxPlatform
+#ifdef MOZ_WIDGET_GTK
+#include "gfxPlatformGtk.h"             // for gfxPlatform
+#endif
 #include "gfxPrefs.h"                   // for gfxPrefs
 #include "ipc/ShadowLayersManager.h"    // for ShadowLayersManager
 #include "mozilla/AutoRestore.h"        // for AutoRestore
 #include "mozilla/DebugOnly.h"          // for DebugOnly
 #include "mozilla/gfx/2D.h"          // for DrawTarget
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/ipc/Transport.h"      // for Transport
 #include "mozilla/layers/APZCTreeManager.h"  // for APZCTreeManager
@@ -31,16 +34,19 @@
 #include "mozilla/layers/BasicCompositor.h"  // for BasicCompositor
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/CompositorOGL.h"  // for CompositorOGL
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/layers/PLayerTransactionParent.h"
 #include "mozilla/mozalloc.h"           // for operator new, etc
+#ifdef MOZ_WIDGET_GTK
+#include "basic/X11BasicCompositor.h" // for X11BasicCompositor
+#endif
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ABORT_IF_FALSE, etc
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsIWidget.h"                  // for nsIWidget
 #include "nsRect.h"                     // for nsIntRect
 #include "nsTArray.h"                   // for nsTArray
 #include "nsThreadUtils.h"              // for NS_IsMainThread
 #include "nsXULAppAPI.h"                // for XRE_GetIOMessageLoop
@@ -893,17 +899,24 @@ CompositorParent::InitializeLayerManager
   for (size_t i = 0; i < aBackendHints.Length(); ++i) {
     RefPtr<Compositor> compositor;
     if (aBackendHints[i] == LayersBackend::LAYERS_OPENGL) {
       compositor = new CompositorOGL(mWidget,
                                      mEGLSurfaceSize.width,
                                      mEGLSurfaceSize.height,
                                      mUseExternalSurfaceSize);
     } else if (aBackendHints[i] == LayersBackend::LAYERS_BASIC) {
-      compositor = new BasicCompositor(mWidget);
+#ifdef MOZ_WIDGET_GTK
+      if (gfxPlatformGtk::GetPlatform()->UseXRender()) {
+        compositor = new X11BasicCompositor(mWidget);
+      } else
+#endif
+      {
+        compositor = new BasicCompositor(mWidget);
+      }
 #ifdef XP_WIN
     } else if (aBackendHints[i] == LayersBackend::LAYERS_D3D11) {
       compositor = new CompositorD3D11(mWidget);
     } else if (aBackendHints[i] == LayersBackend::LAYERS_D3D9) {
       compositor = new CompositorD3D9(this, mWidget);
 #endif
     }
 
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -177,16 +177,17 @@ if CONFIG['MOZ_X11']:
         'basic/TextureClientX11.h',
         'basic/X11TextureSourceBasic.h',
         'composite/X11TextureHost.h',
         'ipc/ShadowLayerUtilsX11.h',
         'opengl/X11TextureSourceOGL.h',
     ]
     SOURCES += [
         'basic/TextureClientX11.cpp',
+        'basic/X11BasicCompositor.cpp',
         'basic/X11TextureSourceBasic.cpp',
         'composite/X11TextureHost.cpp',
         'ipc/ShadowLayerUtilsX11.cpp',
         'opengl/X11TextureSourceOGL.cpp',
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     EXPORTS.mozilla.layers += [