Bug 1328752 - part 1, Add UiCompositorController r=dvander
authorRandall Barker <rbarker@mozilla.com>
Thu, 05 Jan 2017 11:04:38 -0800
changeset 375443 7ceb7d18b5e090f6283fbe7062bfd194f5863783
parent 375442 621e14f5c951442aaafa9703ecde8af8933fbc98
child 375444 8aa58e6577516d8bde4ff9d4555e59d6a511fc4f
push id6996
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 20:48:21 +0000
treeherdermozilla-beta@d89512dab048 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander
bugs1328752
milestone53.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 1328752 - part 1, Add UiCompositorController r=dvander
gfx/ipc/GPUParent.cpp
gfx/ipc/GPUParent.h
gfx/ipc/GPUProcessManager.cpp
gfx/ipc/GPUProcessManager.h
gfx/ipc/PGPU.ipdl
gfx/layers/ipc/CompositorBridgeParent.cpp
gfx/layers/ipc/CompositorBridgeParent.h
gfx/layers/ipc/CrossProcessCompositorBridgeParent.h
gfx/layers/ipc/PCompositorBridge.ipdl
gfx/layers/ipc/PUiCompositorController.ipdl
gfx/layers/ipc/UiCompositorControllerChild.cpp
gfx/layers/ipc/UiCompositorControllerChild.h
gfx/layers/ipc/UiCompositorControllerParent.cpp
gfx/layers/ipc/UiCompositorControllerParent.h
gfx/layers/moz.build
gfx/thebes/gfxPlatform.cpp
--- a/gfx/ipc/GPUParent.cpp
+++ b/gfx/ipc/GPUParent.cpp
@@ -21,16 +21,17 @@
 #include "mozilla/layers/APZThreadUtils.h"
 #include "mozilla/layers/APZCTreeManager.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/dom/VideoDecoderManagerParent.h"
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/ImageBridgeParent.h"
 #include "mozilla/dom/VideoDecoderManagerChild.h"
 #include "mozilla/layers/LayerTreeOwnerTracker.h"
+#include "mozilla/layers/UiCompositorControllerParent.h"
 #include "nsDebugImpl.h"
 #include "nsExceptionHandler.h"
 #include "nsThreadManager.h"
 #include "prenv.h"
 #include "ProcessUtils.h"
 #include "VRManager.h"
 #include "VRManagerParent.h"
 #include "VsyncBridgeParent.h"
@@ -215,16 +216,23 @@ GPUParent::RecvInitImageBridge(Endpoint<
 mozilla::ipc::IPCResult
 GPUParent::RecvInitVRManager(Endpoint<PVRManagerParent>&& aEndpoint)
 {
   VRManagerParent::CreateForGPUProcess(Move(aEndpoint));
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
+GPUParent::RecvInitUiCompositorController(Endpoint<PUiCompositorControllerParent>&& aEndpoint)
+{
+  UiCompositorControllerParent::Start(Move(aEndpoint));
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
 GPUParent::RecvUpdatePref(const GfxPrefSetting& setting)
 {
   gfxPrefs::Pref* pref = gfxPrefs::all()[setting.index()];
   pref->SetCachedValue(setting.value());
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
--- a/gfx/ipc/GPUParent.h
+++ b/gfx/ipc/GPUParent.h
@@ -31,16 +31,17 @@ public:
   void NotifyDeviceReset();
 
   mozilla::ipc::IPCResult RecvInit(nsTArray<GfxPrefSetting>&& prefs,
                                    nsTArray<GfxVarUpdate>&& vars,
                                    const DevicePrefs& devicePrefs) override;
   mozilla::ipc::IPCResult RecvInitVsyncBridge(Endpoint<PVsyncBridgeParent>&& aVsyncEndpoint) override;
   mozilla::ipc::IPCResult RecvInitImageBridge(Endpoint<PImageBridgeParent>&& aEndpoint) override;
   mozilla::ipc::IPCResult RecvInitVRManager(Endpoint<PVRManagerParent>&& aEndpoint) override;
+  mozilla::ipc::IPCResult RecvInitUiCompositorController(Endpoint<PUiCompositorControllerParent>&& aEndpoint) override;
   mozilla::ipc::IPCResult RecvUpdatePref(const GfxPrefSetting& pref) override;
   mozilla::ipc::IPCResult RecvUpdateVar(const GfxVarUpdate& pref) override;
   mozilla::ipc::IPCResult RecvNewWidgetCompositor(
       Endpoint<PCompositorBridgeParent>&& aEndpoint,
       const CSSToLayoutDeviceScale& aScale,
       const TimeDuration& aVsyncRate,
       const CompositorOptions& aOptions,
       const bool& aUseExternalSurface,
--- a/gfx/ipc/GPUProcessManager.cpp
+++ b/gfx/ipc/GPUProcessManager.cpp
@@ -28,16 +28,21 @@
 #include "VRManagerParent.h"
 #include "VsyncBridgeChild.h"
 #include "VsyncIOThreadHolder.h"
 #include "VsyncSource.h"
 #include "mozilla/dom/VideoDecoderManagerChild.h"
 #include "mozilla/dom/VideoDecoderManagerParent.h"
 #include "MediaPrefs.h"
 
+#if defined(MOZ_WIDGET_ANDROID)
+#include "mozilla/widget/AndroidUiThread.h"
+#include "mozilla/layers/UiCompositorControllerChild.h"
+#endif // defined(MOZ_WIDGET_ANDROID)
+
 namespace mozilla {
 namespace gfx {
 
 using namespace mozilla::layers;
 
 static StaticAutoPtr<GPUProcessManager> sSingleton;
 
 GPUProcessManager*
@@ -224,16 +229,54 @@ GPUProcessManager::EnsureVRManager()
     DisableGPUProcess("Failed to create PVRManager endpoints");
     return;
   }
 
   mGPUChild->SendInitVRManager(Move(parentPipe));
   VRManagerChild::InitWithGPUProcess(Move(childPipe));
 }
 
+#if defined(MOZ_WIDGET_ANDROID)
+void
+GPUProcessManager::EnsureUiCompositorController()
+{
+  if (UiCompositorControllerChild::IsInitialized()) {
+    return;
+  }
+
+  EnsureGPUReady();
+
+  RefPtr<nsThread> uiThread;
+
+  uiThread = GetAndroidUiThread();
+
+  MOZ_ASSERT(uiThread);
+
+  if (!mGPUChild) {
+    UiCompositorControllerChild::InitSameProcess(uiThread);
+    return;
+  }
+
+  ipc::Endpoint<PUiCompositorControllerParent> parentPipe;
+  ipc::Endpoint<PUiCompositorControllerChild> childPipe;
+  nsresult rv = PUiCompositorController::CreateEndpoints(
+    mGPUChild->OtherPid(),
+    base::GetCurrentProcId(),
+    &parentPipe,
+    &childPipe);
+  if (NS_FAILED(rv)) {
+    DisableGPUProcess("Failed to create PUiCompositorController endpoints");
+    return;
+  }
+
+  mGPUChild->SendInitUiCompositorController(Move(parentPipe));
+  UiCompositorControllerChild::InitWithGPUProcess(uiThread, mProcessToken, Move(childPipe));
+}
+#endif // defined(MOZ_WIDGET_ANDROID)
+
 void
 GPUProcessManager::OnProcessLaunchComplete(GPUProcessHost* aHost)
 {
   MOZ_ASSERT(mProcess && mProcess == aHost);
 
   if (!mProcess->IsConnected()) {
     DisableGPUProcess("Failed to connect GPU process");
     return;
@@ -477,31 +520,37 @@ GPUProcessManager::DestroyProcess()
   mProcess->Shutdown();
   mProcessToken = 0;
   mProcess = nullptr;
   mGPUChild = nullptr;
   if (mVsyncBridge) {
     mVsyncBridge->Close();
     mVsyncBridge = nullptr;
   }
+#if defined(MOZ_WIDGET_ANDROID)
+  UiCompositorControllerChild::Shutdown();
+#endif // defined(MOZ_WIDGET_ANDROID)
 }
 
 RefPtr<CompositorSession>
 GPUProcessManager::CreateTopLevelCompositor(nsBaseWidget* aWidget,
                                             LayerManager* aLayerManager,
                                             CSSToLayoutDeviceScale aScale,
                                             const CompositorOptions& aOptions,
                                             bool aUseExternalSurfaceSize,
                                             const gfx::IntSize& aSurfaceSize)
 {
   uint64_t layerTreeId = AllocateLayerTreeId();
 
   EnsureGPUReady();
   EnsureImageBridgeChild();
   EnsureVRManager();
+#if defined(MOZ_WIDGET_ANDROID)
+  EnsureUiCompositorController();
+#endif // defined(MOZ_WIDGET_ANDROID)
 
   if (mGPUChild) {
     RefPtr<CompositorSession> session = CreateRemoteSession(
       aWidget,
       aLayerManager,
       layerTreeId,
       aScale,
       aOptions,
--- a/gfx/ipc/GPUProcessManager.h
+++ b/gfx/ipc/GPUProcessManager.h
@@ -188,16 +188,17 @@ private:
 
   void HandleProcessLost();
 
   void EnsureVsyncIOThread();
   void ShutdownVsyncIOThread();
 
   void EnsureImageBridgeChild();
   void EnsureVRManager();
+  void EnsureUiCompositorController();
 
   RefPtr<CompositorSession> CreateRemoteSession(
     nsBaseWidget* aWidget,
     LayerManager* aLayerManager,
     const uint64_t& aRootLayerTreeId,
     CSSToLayoutDeviceScale aScale,
     const CompositorOptions& aOptions,
     bool aUseExternalSurfaceSize,
--- a/gfx/ipc/PGPU.ipdl
+++ b/gfx/ipc/PGPU.ipdl
@@ -3,16 +3,17 @@
  * 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 GraphicsMessages;
 include protocol PCompositorBridge;
 include protocol PImageBridge;
 include protocol PVRManager;
 include protocol PVsyncBridge;
+include protocol PUiCompositorController;
 include protocol PVideoDecoderManager;
 
 using base::ProcessId from "base/process.h";
 using mozilla::TimeDuration from "mozilla/TimeStamp.h";
 using mozilla::CSSToLayoutDeviceScale from "Units.h";
 using mozilla::gfx::IntSize from "mozilla/gfx/2D.h";
 using mozilla::layers::CompositorOptions from "mozilla/layers/CompositorOptions.h";
 using mozilla::Telemetry::Accumulation from "mozilla/TelemetryComms.h";
@@ -47,16 +48,17 @@ parent:
   // Sent by the UI process to initiate core settings.
   async Init(GfxPrefSetting[] prefs,
              GfxVarUpdate[] vars,
              DevicePrefs devicePrefs);
 
   async InitVsyncBridge(Endpoint<PVsyncBridgeParent> endpoint);
   async InitImageBridge(Endpoint<PImageBridgeParent> endpoint);
   async InitVRManager(Endpoint<PVRManagerParent> endpoint);
+  async InitUiCompositorController(Endpoint<PUiCompositorControllerParent> endpoint);
 
   // Called to update a gfx preference or variable.
   async UpdatePref(GfxPrefSetting pref);
   async UpdateVar(GfxVarUpdate var);
 
   // Create a new top-level compositor.
   async NewWidgetCompositor(Endpoint<PCompositorBridgeParent> endpoint,
                             CSSToLayoutDeviceScale scale,
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -416,20 +416,21 @@ CompositorBridgeParent::~CompositorBridg
   // We expect all textures to be destroyed by now.
   MOZ_DIAGNOSTIC_ASSERT(textures.Length() == 0);
   for (unsigned int i = 0; i < textures.Length(); ++i) {
     RefPtr<TextureHost> tex = TextureHost::AsTextureHost(textures[i]);
     tex->DeallocateDeviceData();
   }
 }
 
-void
-CompositorBridgeParent::ForceIsFirstPaint()
+mozilla::ipc::IPCResult
+CompositorBridgeParent::RecvForceIsFirstPaint()
 {
   mCompositionManager->ForceIsFirstPaint();
+  return IPC_OK();
 }
 
 void
 CompositorBridgeParent::StopAndClearResources()
 {
   if (mForceCompositionTask) {
     mForceCompositionTask->Cancel();
     mForceCompositionTask = nullptr;
@@ -1112,16 +1113,23 @@ CompositorBridgeParent::RecvGetComposito
 }
 
 RefPtr<APZCTreeManager>
 CompositorBridgeParent::GetAPZCTreeManager()
 {
   return mApzcTreeManager;
 }
 
+CompositorBridgeParent*
+CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(const uint64_t& aLayersId)
+{
+  MonitorAutoLock lock(*sIndirectLayerTreesLock);
+  return sIndirectLayerTrees[aLayersId].mParent;
+}
+
 bool
 CompositorBridgeParent::CanComposite()
 {
   return mLayerManager &&
          mLayerManager->GetRoot() &&
          !mPaused;
 }
 
--- a/gfx/layers/ipc/CompositorBridgeParent.h
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -260,17 +260,17 @@ public:
 
   /**
    * This forces the is-first-paint flag to true. This is intended to
    * be called by the widget code when it loses its viewport information
    * (or for whatever reason wants to refresh the viewport information).
    * The information refresh happens because the compositor will call
    * SetFirstPaintViewport on the next frame of composition.
    */
-  void ForceIsFirstPaint();
+  mozilla::ipc::IPCResult RecvForceIsFirstPaint() override;
 
   static void SetShadowProperties(Layer* aLayer);
 
   void NotifyChildCreated(uint64_t aChild);
 
   void AsyncRender();
 
   // Can be called from any thread
@@ -436,16 +436,17 @@ public:
                                                    CompositorOptions* aOptions) override;
 
   RefPtr<APZCTreeManager> GetAPZCTreeManager();
 
   CompositorOptions GetOptions() const {
     return mOptions;
   }
 
+  static CompositorBridgeParent* GetCompositorBridgeParentFromLayersId(const uint64_t& aLayersId);
 private:
 
   void Initialize();
 
   /**
    * Called during destruction in order to release resources as early as possible.
    */
   void StopAndClearResources();
@@ -475,22 +476,26 @@ protected:
                                  TextureFactoryIdentifier* aTextureFactoryIdentifier,
                                  bool* aSuccess) override;
   virtual bool DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers) override;
   virtual void ScheduleTask(already_AddRefed<CancelableRunnable>, int);
 
   void SetEGLSurfaceSize(int width, int height);
 
   void InitializeLayerManager(const nsTArray<LayersBackend>& aBackendHints);
+
+public:
   void PauseComposition();
   void ResumeComposition();
   void ResumeCompositionAndResize(int width, int height);
+  void Invalidate();
+
+protected:
   void ForceComposition();
   void CancelCurrentCompositeTask();
-  void Invalidate();
 
   // CompositorVsyncSchedulerOwner
   bool IsPendingComposite() override;
   void FinishPendingComposite() override;
   void CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr) override;
 
   RefPtr<Compositor> NewCompositor(const nsTArray<LayersBackend>& aBackendHints);
   void ResetCompositorTask(const nsTArray<LayersBackend>& aBackendHints,
--- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h
+++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h
@@ -49,16 +49,17 @@ public:
                          const uint64_t& aSeqNo,
                          bool* aResult,
                          TextureFactoryIdentifier* aOutIdentifier) override
   { return IPC_FAIL_NO_REASON(this); }
   virtual mozilla::ipc::IPCResult RecvRequestOverfill() override { return IPC_OK(); }
   virtual mozilla::ipc::IPCResult RecvWillClose() override { return IPC_OK(); }
   virtual mozilla::ipc::IPCResult RecvPause() override { return IPC_OK(); }
   virtual mozilla::ipc::IPCResult RecvResume() override { return IPC_OK(); }
+  virtual mozilla::ipc::IPCResult RecvForceIsFirstPaint() override { return IPC_OK(); }
   virtual mozilla::ipc::IPCResult RecvNotifyChildCreated(const uint64_t& child) override;
   virtual mozilla::ipc::IPCResult RecvNotifyChildRecreated(const uint64_t& child) override { return IPC_FAIL_NO_REASON(this); }
   virtual mozilla::ipc::IPCResult RecvAdoptChild(const uint64_t& child) override { return IPC_FAIL_NO_REASON(this); }
   virtual mozilla::ipc::IPCResult RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
                                 const gfx::IntRect& aRect) override
   { return IPC_OK(); }
   virtual mozilla::ipc::IPCResult RecvFlushRendering() override { return IPC_OK(); }
   virtual mozilla::ipc::IPCResult RecvForcePresent() override { return IPC_OK(); }
--- a/gfx/layers/ipc/PCompositorBridge.ipdl
+++ b/gfx/layers/ipc/PCompositorBridge.ipdl
@@ -172,16 +172,17 @@ parent:
 
   // The child is about to be destroyed, so perform any necessary cleanup.
   sync WillClose();
 
   // Pause/resume the compositor. These are intended to be used on mobile, when
   // the compositor needs to pause/resume in lockstep with the application.
   sync Pause();
   sync Resume();
+  async ForceIsFirstPaint();
 
   // See bug 1316632 comment #33 for why this has to be sync. Otherwise,
   // there are ordering issues with SendPLayerTransactionConstructor.
   sync NotifyChildCreated(uint64_t id);
 
   async AdoptChild(uint64_t id);
 
   // Same as NotifyChildCreated, but used when child processes need to
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/PUiCompositorController.ipdl
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* 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/. */
+
+namespace mozilla {
+namespace layers {
+
+/**
+ * The PUiCompositorController protocol is used to pause and resume the
+ * compositor from the UI thread. Primarily used on Android to coordinate registering and
+ * releasing the surface with the compositor.
+ */
+sync protocol PUiCompositorController
+{
+
+parent:
+  // Pause/resume the compositor. These are intended to be used on mobile, when
+  // the compositor needs to pause/resume in lockstep with the application.
+  sync Pause(uint64_t layersId);
+  sync Resume(uint64_t layersId);
+  sync ResumeAndResize(uint64_t layersId, int32_t height, int32_t width);
+  async InvalidateAndRender(uint64_t layersId);
+};
+
+} // layers
+} // mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/UiCompositorControllerChild.cpp
@@ -0,0 +1,184 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=99: */
+/* 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 "UiCompositorControllerChild.h"
+#include "UiCompositorControllerParent.h"
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/layers/CompositorThread.h"
+#include "mozilla/StaticPtr.h"
+#include "nsThreadUtils.h"
+
+namespace mozilla {
+namespace layers {
+
+static bool sInitialized = false;
+static StaticRefPtr<UiCompositorControllerChild> sChild;
+static StaticRefPtr<UiCompositorControllerParent> sParent;
+
+UiCompositorControllerChild::UiCompositorControllerChild(RefPtr<nsThread> aThread, const uint64_t& aProcessToken)
+ : mUiThread(aThread),
+   mProcessToken(aProcessToken)
+{
+}
+
+UiCompositorControllerChild::~UiCompositorControllerChild()
+{
+}
+
+/* static */ UiCompositorControllerChild*
+UiCompositorControllerChild::Get()
+{
+  return sChild;
+}
+
+/* static */ bool
+UiCompositorControllerChild::IsInitialized()
+{
+  return sInitialized;
+}
+
+/* static */ void
+UiCompositorControllerChild::Shutdown()
+{
+  RefPtr<UiCompositorControllerChild> child = sChild;
+  if (child) {
+    child->Close();
+    sInitialized = false;
+  }
+}
+
+/* static */ void
+UiCompositorControllerChild::InitSameProcess(RefPtr<nsThread> aThread)
+{
+  MOZ_ASSERT(!sChild);
+  MOZ_ASSERT(!sParent);
+  MOZ_ASSERT(aThread);
+  MOZ_ASSERT(!sInitialized);
+
+  sInitialized = true;
+  RefPtr<UiCompositorControllerChild> child = new UiCompositorControllerChild(aThread, 0);
+  sParent = new UiCompositorControllerParent();
+  aThread->Dispatch(NewRunnableMethod(child, &UiCompositorControllerChild::OpenForSameProcess), nsIThread::DISPATCH_NORMAL);
+}
+
+/* static */ void
+UiCompositorControllerChild::InitWithGPUProcess(RefPtr<nsThread> aThread,
+                                                const uint64_t& aProcessToken,
+                                                Endpoint<PUiCompositorControllerChild>&& aEndpoint)
+{
+  MOZ_ASSERT(!sChild);
+  MOZ_ASSERT(!sParent);
+  MOZ_ASSERT(aThread);
+  MOZ_ASSERT(!sInitialized);
+
+  sInitialized = true;
+  RefPtr<UiCompositorControllerChild> child = new UiCompositorControllerChild(aThread, aProcessToken);
+
+  RefPtr<nsIRunnable> task = NewRunnableMethod<Endpoint<PUiCompositorControllerChild>&&>(
+    child, &UiCompositorControllerChild::OpenForGPUProcess, Move(aEndpoint));
+
+  aThread->Dispatch(task.forget(), nsIThread::DISPATCH_NORMAL);
+}
+
+void
+UiCompositorControllerChild::OpenForSameProcess()
+{
+  MOZ_ASSERT(sParent);
+  MOZ_ASSERT(!sChild);
+  MOZ_ASSERT(IsOnUiThread());
+
+  if (!Open(sParent->GetIPCChannel(),
+           mozilla::layers::CompositorThreadHolder::Loop(),
+           mozilla::ipc::ChildSide)) {
+    sParent = nullptr;
+    return;
+  }
+
+  AddRef();
+  sChild = this;
+}
+
+void
+UiCompositorControllerChild::OpenForGPUProcess(Endpoint<PUiCompositorControllerChild>&& aEndpoint)
+{
+  MOZ_ASSERT(!sChild);
+  MOZ_ASSERT(IsOnUiThread());
+
+  if (!aEndpoint.Bind(this)) {
+    // The GPU Process Manager might be gone if we receive ActorDestroy very
+    // late in shutdown.
+    if (GPUProcessManager* gpm = GPUProcessManager::Get()) {
+      gpm->NotifyRemoteActorDestroyed(mProcessToken);
+    }
+    return;
+  }
+
+  AddRef();
+  sChild = this;
+}
+
+void
+UiCompositorControllerChild::Close()
+{
+  if (!IsOnUiThread()) {
+    mUiThread->Dispatch(NewRunnableMethod(this, &UiCompositorControllerChild::Close), nsIThread::DISPATCH_NORMAL);
+    return;
+  }
+
+  // We clear mProcessToken when the channel is closed.
+  if (!mProcessToken) {
+    return;
+  }
+
+  // Clear the process token so we don't notify the GPUProcessManager. It already
+  // knows we're closed since it manually called Close, and in fact the GPM could
+  // have already been destroyed during shutdown.
+  mProcessToken = 0;
+  if (this == sChild) {
+    sChild = nullptr;
+  }
+
+  // Close the underlying IPC channel.
+  PUiCompositorControllerChild::Close();
+}
+
+void
+UiCompositorControllerChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+  if (mProcessToken) {
+    GPUProcessManager::Get()->NotifyRemoteActorDestroyed(mProcessToken);
+    mProcessToken = 0;
+    sParent = nullptr;
+  }
+}
+
+void
+UiCompositorControllerChild::DeallocPUiCompositorControllerChild()
+{
+  Release();
+  sInitialized = false;
+}
+
+void
+UiCompositorControllerChild::ProcessingError(Result aCode, const char* aReason)
+{
+  MOZ_RELEASE_ASSERT(aCode == MsgDropped, "Processing error in UiCompositorControllerChild");
+}
+
+void
+UiCompositorControllerChild::HandleFatalError(const char* aName, const char* aMsg) const
+{
+  dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aName, aMsg, OtherPid());
+}
+
+bool
+UiCompositorControllerChild::IsOnUiThread() const
+{
+  return NS_GetCurrentThread() == mUiThread;
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/UiCompositorControllerChild.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=99: */
+/* 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 include_gfx_ipc_UiCompositorControllerChild_h
+#define include_gfx_ipc_UiCompositorControllerChild_h
+
+#include "mozilla/layers/PUiCompositorControllerChild.h"
+#include "mozilla/RefPtr.h"
+#include <nsThread.h>
+
+namespace mozilla {
+namespace layers {
+
+class UiCompositorControllerChild final : public PUiCompositorControllerChild
+{
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(UiCompositorControllerChild)
+
+  static bool IsInitialized();
+  static void Shutdown();
+  static UiCompositorControllerChild* Get();
+  static void InitSameProcess(RefPtr<nsThread> aThread);
+  static void InitWithGPUProcess(RefPtr<nsThread> aThread,
+                                 const uint64_t& aProcessToken,
+                                 Endpoint<PUiCompositorControllerChild>&& aEndpoint);
+
+  void Close();
+
+  void ActorDestroy(ActorDestroyReason aWhy) override;
+  void DeallocPUiCompositorControllerChild() override;
+  void ProcessingError(Result aCode, const char* aReason) override;
+
+  virtual void HandleFatalError(const char* aName, const char* aMsg) const override;
+
+private:
+  UiCompositorControllerChild(RefPtr<nsThread> aThread, const uint64_t& aProcessToken);
+  ~UiCompositorControllerChild();
+  void OpenForSameProcess();
+  void OpenForGPUProcess(Endpoint<PUiCompositorControllerChild>&& aEndpoint);
+  bool IsOnUiThread() const;
+
+  RefPtr<nsThread> mUiThread;
+  uint64_t mProcessToken;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // include_gfx_ipc_UiCompositorControllerChild_h
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/UiCompositorControllerParent.cpp
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=99: */
+/* 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 "UiCompositorControllerParent.h"
+#include "mozilla/layers/CompositorBridgeParent.h"
+#include "mozilla/layers/CompositorThread.h"
+
+namespace mozilla {
+namespace layers {
+
+RefPtr<UiCompositorControllerParent>
+UiCompositorControllerParent::Start(Endpoint<PUiCompositorControllerParent>&& aEndpoint)
+{
+  RefPtr<UiCompositorControllerParent> parent = new UiCompositorControllerParent();
+
+  RefPtr<Runnable> task = NewRunnableMethod<Endpoint<PUiCompositorControllerParent>&&>(
+    parent, &UiCompositorControllerParent::Open, Move(aEndpoint));
+  CompositorThreadHolder::Loop()->PostTask(task.forget());
+
+  return parent;
+}
+
+UiCompositorControllerParent::UiCompositorControllerParent()
+{
+  MOZ_COUNT_CTOR(UiCompositorControllerParent);
+}
+
+UiCompositorControllerParent::~UiCompositorControllerParent()
+{
+  MOZ_COUNT_DTOR(UiCompositorControllerParent);
+}
+
+void
+UiCompositorControllerParent::Open(Endpoint<PUiCompositorControllerParent>&& aEndpoint)
+{
+  if (!aEndpoint.Bind(this)) {
+    // We can't recover from this.
+    MOZ_CRASH("Failed to bind UiCompositorControllerParent to endpoint");
+  }
+  AddRef();
+}
+
+mozilla::ipc::IPCResult
+UiCompositorControllerParent::RecvPause(const uint64_t& aLayersId)
+{
+  CompositorBridgeParent* parent = CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(aLayersId);
+  if (parent) {
+    parent->PauseComposition();
+  }
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+UiCompositorControllerParent::RecvResume(const uint64_t& aLayersId)
+{
+  CompositorBridgeParent* parent = CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(aLayersId);
+  if (parent) {
+    parent->ResumeComposition();
+  }
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+UiCompositorControllerParent::RecvResumeAndResize(const uint64_t& aLayersId,
+                                                  const int32_t& aHeight,
+                                                  const int32_t& aWidth)
+{
+  CompositorBridgeParent* parent = CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(aLayersId);
+  if (parent) {
+    parent->ResumeCompositionAndResize(aHeight, aWidth);
+  }
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+UiCompositorControllerParent::RecvInvalidateAndRender(const uint64_t& aLayersId)
+{
+  CompositorBridgeParent* parent = CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(aLayersId);
+  if (parent) {
+    parent->Invalidate();
+    parent->ScheduleComposition();
+  }
+  return IPC_OK();
+}
+
+void
+UiCompositorControllerParent::Shutdown()
+{
+  MessageLoop* ccloop = CompositorThreadHolder::Loop();
+  if (MessageLoop::current() != ccloop) {
+    ccloop->PostTask(NewRunnableMethod(this, &UiCompositorControllerParent::ShutdownImpl));
+    return;
+  }
+
+  ShutdownImpl();
+}
+
+void
+UiCompositorControllerParent::ShutdownImpl()
+{
+  Close();
+}
+
+void
+UiCompositorControllerParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+}
+
+void
+UiCompositorControllerParent::DeallocPUiCompositorControllerParent()
+{
+  Release();
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/UiCompositorControllerParent.h
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=99: */
+/* 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 include_gfx_ipc_UiCompositorControllerParent_h
+#define include_gfx_ipc_UiCompositorControllerParent_h
+
+#include "mozilla/RefPtr.h"
+#include "mozilla/layers/PUiCompositorControllerParent.h"
+
+namespace mozilla {
+namespace layers {
+
+class UiCompositorControllerParent final : public PUiCompositorControllerParent
+{
+public:
+  UiCompositorControllerParent();
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(UiCompositorControllerParent)
+
+  static RefPtr<UiCompositorControllerParent> Start(Endpoint<PUiCompositorControllerParent>&& aEndpoint);
+
+  mozilla::ipc::IPCResult RecvPause(const uint64_t& aLayersId) override;
+  mozilla::ipc::IPCResult RecvResume(const uint64_t& aLayersId) override;
+  mozilla::ipc::IPCResult RecvResumeAndResize(const uint64_t& aLayersId,
+                                              const int32_t& aHeight,
+                                              const int32_t& aWidth) override;
+  mozilla::ipc::IPCResult RecvInvalidateAndRender(const uint64_t& aLayersId) override;
+
+  void ActorDestroy(ActorDestroyReason aWhy) override;
+  void DeallocPUiCompositorControllerParent() override;
+
+  void Shutdown();
+
+private:
+  ~UiCompositorControllerParent();
+
+  void Open(Endpoint<PUiCompositorControllerParent>&& aEndpoint);
+  void ShutdownImpl();
+
+private:
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // include_gfx_ipc_UiCompositorControllerParent_h
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -178,16 +178,18 @@ EXPORTS.mozilla.layers += [
     'ipc/LayerTransactionParent.h',
     'ipc/LayerTreeOwnerTracker.h',
     'ipc/RemoteContentController.h',
     'ipc/ShadowLayers.h',
     'ipc/SharedPlanarYCbCrImage.h',
     'ipc/SharedRGBImage.h',
     'ipc/SynchronousTask.h',
     'ipc/TextureForwarder.h',
+    'ipc/UiCompositorControllerChild.h',
+    'ipc/UiCompositorControllerParent.h',
     'ipc/VideoBridgeChild.h',
     'ipc/VideoBridgeParent.h',
     'LayerMetricsWrapper.h',
     'LayersTypes.h',
     'opengl/CompositingRenderTargetOGL.h',
     'opengl/CompositorOGL.h',
     'opengl/MacIOSurfaceTextureClientOGL.h',
     'opengl/MacIOSurfaceTextureHostOGL.h',
@@ -342,16 +344,18 @@ UNIFIED_SOURCES += [
     'ipc/LayerAnimationUtils.cpp',
     'ipc/LayerTransactionChild.cpp',
     'ipc/LayerTransactionParent.cpp',
     'ipc/LayerTreeOwnerTracker.cpp',
     'ipc/RemoteContentController.cpp',
     'ipc/ShadowLayers.cpp',
     'ipc/SharedPlanarYCbCrImage.cpp',
     'ipc/SharedRGBImage.cpp',
+    'ipc/UiCompositorControllerChild.cpp',
+    'ipc/UiCompositorControllerParent.cpp',
     'ipc/VideoBridgeChild.cpp',
     'ipc/VideoBridgeParent.cpp',
     'LayerScope.cpp',
     'LayersLogging.cpp',
     'LayerSorter.cpp',
     'LayersTypes.cpp',
     'opengl/CompositingRenderTargetOGL.cpp',
     'opengl/CompositorOGL.cpp',
@@ -389,25 +393,26 @@ if CONFIG['_MSC_VER'] and CONFIG['CPU_AR
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     SOURCES += [
         'basic/MacIOSurfaceTextureHostBasic.cpp',
         'opengl/MacIOSurfaceTextureClientOGL.cpp',
         'opengl/MacIOSurfaceTextureHostOGL.cpp',
     ]
 
-IPDL_SOURCES = [
+IPDL_SOURCES += [
     'ipc/LayersMessages.ipdlh',
     'ipc/LayersSurfaces.ipdlh',
     'ipc/PAPZ.ipdl',
     'ipc/PAPZCTreeManager.ipdl',
     'ipc/PCompositorBridge.ipdl',
     'ipc/PImageBridge.ipdl',
     'ipc/PLayerTransaction.ipdl',
     'ipc/PTexture.ipdl',
+    'ipc/PUiCompositorController.ipdl',
     'ipc/PVideoBridge.ipdl',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 LOCAL_INCLUDES += [
     '/docshell/base',  # for nsDocShell.h
     '/layout/base',    # for TouchManager.h
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -89,16 +89,17 @@
 #include "mozilla/gfx/Logging.h"
 
 #if defined(MOZ_WIDGET_GTK)
 #include "gfxPlatformGtk.h" // xxx - for UseFcFontList
 #endif
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "TexturePoolOGL.h"
+#include "mozilla/layers/UiCompositorControllerChild.h"
 #endif
 
 #ifdef USE_SKIA
 # ifdef __GNUC__
 #  pragma GCC diagnostic push
 #  pragma GCC diagnostic ignored "-Wshadow"
 # endif
 # include "skia/include/core/SkGraphics.h"
@@ -957,17 +958,19 @@ gfxPlatform::ShutdownLayersIPC()
         if (gfxPrefs::ChildProcessShutdown()) {
           layers::CompositorBridgeChild::ShutDown();
           layers::ImageBridgeChild::ShutDown();
         }
     } else if (XRE_IsParentProcess()) {
         gfx::VRManagerChild::ShutDown();
         layers::CompositorBridgeChild::ShutDown();
         layers::ImageBridgeChild::ShutDown();
-
+#if defined(MOZ_WIDGET_ANDROID)
+        layers::UiCompositorControllerChild::Shutdown();
+#endif // defined(MOZ_WIDGET_ANDROID)
         // This has to happen after shutting down the child protocols.
         layers::CompositorThreadHolder::Shutdown();
     } else {
       // TODO: There are other kind of processes and we should make sure gfx
       // stuff is either not created there or shut down properly.
     }
 }