Implement ImageBridge support for the GPU process. (bug 1287366 part 3, r=mattwoodrow,billm)
authorDavid Anderson <danderson@mozilla.com>
Wed, 20 Jul 2016 00:19:27 -0700
changeset 330875 a0f0837ba27de9a5d109c74ae860229ae425abfa
parent 330874 f4a1a01e9eda05d889457a25e315b43ad7fc0e66
child 330876 90f9475f974640c8ccbadfaef6ab442752d869f5
push id9858
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 14:37:10 +0000
treeherdermozilla-aurora@203106ef6cb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow, billm
bugs1287366
milestone50.0a1
Implement ImageBridge support for the GPU process. (bug 1287366 part 3, r=mattwoodrow,billm)
gfx/ipc/GPUParent.cpp
gfx/ipc/GPUParent.h
gfx/ipc/GPUProcessManager.cpp
gfx/ipc/PGPU.ipdl
gfx/layers/ipc/ImageBridgeChild.cpp
gfx/layers/ipc/ImageBridgeChild.h
gfx/layers/ipc/ImageBridgeParent.cpp
gfx/layers/ipc/ImageBridgeParent.h
--- a/gfx/ipc/GPUParent.cpp
+++ b/gfx/ipc/GPUParent.cpp
@@ -8,16 +8,17 @@
 #include "gfxPlatform.h"
 #include "gfxPrefs.h"
 #include "GPUProcessHost.h"
 #include "VsyncBridgeParent.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/ipc/ProcessChild.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/CompositorThread.h"
+#include "mozilla/layers/ImageBridgeParent.h"
 
 namespace mozilla {
 namespace gfx {
 
 using namespace ipc;
 using namespace layers;
 
 GPUParent::GPUParent()
@@ -57,16 +58,23 @@ GPUParent::RecvInit(nsTArray<GfxPrefSett
 bool
 GPUParent::RecvInitVsyncBridge(Endpoint<PVsyncBridgeParent>&& aVsyncEndpoint)
 {
   VsyncBridgeParent::Start(Move(aVsyncEndpoint));
   return true;
 }
 
 bool
+GPUParent::RecvInitImageBridge(Endpoint<PImageBridgeParent>&& aEndpoint)
+{
+  ImageBridgeParent::CreateForGPUProcess(Move(aEndpoint));
+  return true;
+}
+
+bool
 GPUParent::RecvUpdatePref(const GfxPrefSetting& setting)
 {
   gfxPrefs::Pref* pref = gfxPrefs::all()[setting.index()];
   pref->SetCachedValue(setting.value());
   return true;
 }
 
 static void
@@ -93,16 +101,22 @@ GPUParent::RecvNewWidgetCompositor(Endpo
 }
 
 bool
 GPUParent::RecvNewContentCompositorBridge(Endpoint<PCompositorBridgeParent>&& aEndpoint)
 {
   return CompositorBridgeParent::CreateForContent(Move(aEndpoint));
 }
 
+bool
+GPUParent::RecvNewContentImageBridge(Endpoint<PImageBridgeParent>&& aEndpoint)
+{
+  return ImageBridgeParent::CreateForContent(Move(aEndpoint));
+}
+
 void
 GPUParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   if (AbnormalShutdown == aWhy) {
     NS_WARNING("Shutting down GPU process early due to a crash!");
     ProcessChild::QuickExit();
   }
 
--- a/gfx/ipc/GPUParent.h
+++ b/gfx/ipc/GPUParent.h
@@ -21,23 +21,25 @@ public:
   ~GPUParent();
 
   bool Init(base::ProcessId aParentPid,
             MessageLoop* aIOLoop,
             IPC::Channel* aChannel);
 
   bool RecvInit(nsTArray<GfxPrefSetting>&& prefs) override;
   bool RecvInitVsyncBridge(Endpoint<PVsyncBridgeParent>&& aVsyncEndpoint) override;
+  bool RecvInitImageBridge(Endpoint<PImageBridgeParent>&& aEndpoint) override;
   bool RecvUpdatePref(const GfxPrefSetting& pref) override;
   bool RecvNewWidgetCompositor(
     Endpoint<PCompositorBridgeParent>&& aEndpoint,
     const CSSToLayoutDeviceScale& aScale,
     const bool& aUseExternalSurface,
     const IntSize& aSurfaceSize) override;
   bool RecvNewContentCompositorBridge(Endpoint<PCompositorBridgeParent>&& aEndpoint) override;
+  bool RecvNewContentImageBridge(Endpoint<PImageBridgeParent>&& aEndpoint) override;
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
 private:
   RefPtr<VsyncBridgeParent> mVsyncBridge;
 };
 
 } // namespace gfx
--- a/gfx/ipc/GPUProcessManager.cpp
+++ b/gfx/ipc/GPUProcessManager.cpp
@@ -131,19 +131,39 @@ GPUProcessManager::EnsureGPUReady()
       return;
     }
   }
 }
 
 void
 GPUProcessManager::EnsureImageBridgeChild()
 {
-  if (!ImageBridgeChild::IsCreated()) {
+  if (ImageBridgeChild::IsCreated()) {
+    return;
+  }
+
+  if (!mGPUChild) {
     ImageBridgeChild::InitSameProcess();
+    return;
   }
+
+  ipc::Endpoint<PImageBridgeParent> parentPipe;
+  ipc::Endpoint<PImageBridgeChild> childPipe;
+  nsresult rv = PImageBridge::CreateEndpoints(
+    mGPUChild->OtherPid(),
+    base::GetCurrentProcId(),
+    &parentPipe,
+    &childPipe);
+  if (NS_FAILED(rv)) {
+    DisableGPUProcess("Failed to create PImageBridge endpoints");
+    return;
+  }
+
+  mGPUChild->SendInitImageBridge(Move(parentPipe));
+  ImageBridgeChild::InitWithGPUProcess(Move(childPipe));
 }
 
 void
 GPUProcessManager::OnProcessLaunchComplete(GPUProcessHost* aHost)
 {
   MOZ_ASSERT(mProcess && mProcess == aHost);
 
   if (!mProcess->IsConnected()) {
@@ -301,28 +321,31 @@ GPUProcessManager::CreateRemoteSession(n
   CompositorWidgetInitData initData;
   aWidget->GetCompositorWidgetInitData(&initData);
 
   bool ok = mGPUChild->SendNewWidgetCompositor(
     Move(parentPipe),
     aScale,
     aUseExternalSurfaceSize,
     aSurfaceSize);
-  if (!ok)
+  if (!ok) {
     return nullptr;
+  }
 
   RefPtr<CompositorVsyncDispatcher> dispatcher = aWidget->GetCompositorVsyncDispatcher();
   RefPtr<CompositorWidgetVsyncObserver> observer =
     new CompositorWidgetVsyncObserver(mVsyncBridge, aRootLayerTreeId);
 
   CompositorWidgetChild* widget = new CompositorWidgetChild(dispatcher, observer);
-  if (!child->SendPCompositorWidgetConstructor(widget, initData))
+  if (!child->SendPCompositorWidgetConstructor(widget, initData)) {
     return nullptr;
-  if (!child->SendInitialize(aRootLayerTreeId))
+  }
+  if (!child->SendInitialize(aRootLayerTreeId)) {
     return nullptr;
+  }
 
   RefPtr<RemoteCompositorSession> session =
     new RemoteCompositorSession(child, widget, aRootLayerTreeId);
   return session.forget();
 #else
   gfxCriticalNote << "Platform does not support out-of-process compositing";
   return nullptr;
 #endif
@@ -347,46 +370,54 @@ GPUProcessManager::CreateContentComposit
   if (NS_FAILED(rv)) {
     gfxCriticalNote << "Could not create content compositor bridge: " << hexa(int(rv));
     return false;
   }
 
   if (mGPUChild) {
     mGPUChild->SendNewContentCompositorBridge(Move(parentPipe));
   } else {
-    if (!CompositorBridgeParent::CreateForContent(Move(parentPipe)))
+    if (!CompositorBridgeParent::CreateForContent(Move(parentPipe))) {
       return false;
+    }
   }
 
   *aOutEndpoint = Move(childPipe);
   return true;
 }
 
 bool
 GPUProcessManager::CreateContentImageBridge(base::ProcessId aOtherProcess,
                                             ipc::Endpoint<PImageBridgeChild>* aOutEndpoint)
 {
   EnsureImageBridgeChild();
 
-  base::ProcessId gpuPid = base::GetCurrentProcId();
+  base::ProcessId gpuPid = mGPUChild
+                           ? mGPUChild->OtherPid()
+                           : base::GetCurrentProcId();
 
   ipc::Endpoint<PImageBridgeParent> parentPipe;
   ipc::Endpoint<PImageBridgeChild> childPipe;
   nsresult rv = PImageBridge::CreateEndpoints(
     gpuPid,
     aOtherProcess,
     &parentPipe,
     &childPipe);
   if (NS_FAILED(rv)) {
     gfxCriticalNote << "Could not create content compositor bridge: " << hexa(int(rv));
     return false;
   }
 
-  if (!ImageBridgeParent::CreateForContent(Move(parentPipe)))
-    return false;
+  if (mGPUChild) {
+    mGPUChild->SendNewContentImageBridge(Move(parentPipe));
+  } else {
+    if (!ImageBridgeParent::CreateForContent(Move(parentPipe))) {
+      return false;
+    }
+  }
 
   *aOutEndpoint = Move(childPipe);
   return true;
 }
 
 already_AddRefed<APZCTreeManager>
 GPUProcessManager::GetAPZCTreeManagerForLayers(uint64_t aLayersId)
 {
--- a/gfx/ipc/PGPU.ipdl
+++ b/gfx/ipc/PGPU.ipdl
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; 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 protocol PCompositorBridge;
+include protocol PImageBridge;
 include protocol PVsyncBridge;
 
 using mozilla::CSSToLayoutDeviceScale from "Units.h";
 using mozilla::gfx::IntSize from "mozilla/gfx/2D.h";
 
 namespace mozilla {
 namespace gfx {
 
@@ -25,25 +26,27 @@ struct GfxPrefSetting {
 };
 
 sync protocol PGPU
 {
 parent:
   // Sent by the UI process to initiate core settings.
   async Init(GfxPrefSetting[] prefs);
 
-  async InitVsyncBridge(Endpoint<PVsyncBridgeParent> vsyncEndpoint);
+  async InitVsyncBridge(Endpoint<PVsyncBridgeParent> endpoint);
+  async InitImageBridge(Endpoint<PImageBridgeParent> endpoint);
 
   // Called to update a gfx preference.
   async UpdatePref(GfxPrefSetting pref);
 
   // Create a new top-level compositor.
   async NewWidgetCompositor(Endpoint<PCompositorBridgeParent> endpoint,
                             CSSToLayoutDeviceScale scale,
                             bool useExternalSurface,
                             IntSize surfaceSize);
 
   // Create a new content-process compositor bridge.
   async NewContentCompositorBridge(Endpoint<PCompositorBridgeParent> endpoint);
+  async NewContentImageBridge(Endpoint<PImageBridgeParent> endpoint);
 };
 
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -386,23 +386,18 @@ ImageBridgeChild::CancelWaitForRecycle(u
   if (!client) {
     return;
   }
   mTexturesWaitingRecycled.Remove(aTextureId);
 }
 
 // Singleton
 static StaticRefPtr<ImageBridgeChild> sImageBridgeChildSingleton;
-static StaticRefPtr<ImageBridgeParent> sImageBridgeParentSingleton;
 static Thread *sImageBridgeChildThread = nullptr;
 
-void ReleaseImageBridgeParentSingleton() {
-  sImageBridgeParentSingleton = nullptr;
-}
-
 void
 ImageBridgeChild::FallbackDestroyActors() {
   if (mTxn && !mTxn->mDestroyedActors.IsEmpty()) {
     mTxn->FallbackDestroyActors();
   }
 }
 
 // dispatched function
@@ -976,23 +971,43 @@ ImageBridgeChild::InitSameProcess()
   MOZ_ASSERT(!sImageBridgeChildThread);
 
   sImageBridgeChildThread = new ImageBridgeThread();
   if (!sImageBridgeChildThread->IsRunning()) {
     sImageBridgeChildThread->Start();
   }
 
   sImageBridgeChildSingleton = new ImageBridgeChild();
-  sImageBridgeParentSingleton = ImageBridgeParent::CreateSameProcess();
-  sImageBridgeChildSingleton->ConnectAsync(sImageBridgeParentSingleton);
+  RefPtr<ImageBridgeParent> parent = ImageBridgeParent::CreateSameProcess();
+
+  sImageBridgeChildSingleton->ConnectAsync(parent);
   sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
     NewRunnableFunction(CallSendImageBridgeThreadId,
                         sImageBridgeChildSingleton.get()));
 }
 
+/* static */ void
+ImageBridgeChild::InitWithGPUProcess(Endpoint<PImageBridgeChild>&& aEndpoint)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!sImageBridgeChildSingleton);
+  MOZ_ASSERT(!sImageBridgeChildThread);
+
+  sImageBridgeChildThread = new ImageBridgeThread();
+  if (!sImageBridgeChildThread->IsRunning()) {
+    sImageBridgeChildThread->Start();
+  }
+
+  sImageBridgeChildSingleton = new ImageBridgeChild();
+
+  MessageLoop* loop = sImageBridgeChildSingleton->GetMessageLoop();
+  loop->PostTask(NewRunnableMethod<Endpoint<PImageBridgeChild>&&>(
+    sImageBridgeChildSingleton, &ImageBridgeChild::Bind, Move(aEndpoint)));
+}
+
 bool InImageBridgeChildThread()
 {
   return ImageBridgeChild::IsCreated() &&
     sImageBridgeChildThread->thread_id() == PlatformThread::CurrentId();
 }
 
 MessageLoop * ImageBridgeChild::GetMessageLoop() const
 {
--- a/gfx/layers/ipc/ImageBridgeChild.h
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -116,16 +116,17 @@ public:
   /**
    * Creates the image bridge with a dedicated thread for ImageBridgeChild.
    *
    * We may want to use a specifi thread in the future. In this case, use
    * CreateWithThread instead.
    */
   static void InitSameProcess();
 
+  static void InitWithGPUProcess(Endpoint<PImageBridgeChild>&& aEndpoint);
   static bool InitForContent(Endpoint<PImageBridgeChild>&& aEndpoint);
 
   /**
    * Destroys the image bridge by calling DestroyBridge, and destroys the
    * ImageBridge's thread.
    *
    * If you don't want to destroy the thread, call DestroyBridge directly
    * instead.
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -71,25 +71,48 @@ ImageBridgeParent::~ImageBridgeParent()
   ManagedPImageContainerParent(parents);
   for (PImageContainerParent* p : parents) {
     delete p;
   }
 
   sImageBridges.erase(OtherPid());
 }
 
+static StaticRefPtr<ImageBridgeParent> sImageBridgeParentSingleton;
+
+void ReleaseImageBridgeParentSingleton() {
+  sImageBridgeParentSingleton = nullptr;
+}
+
 /* static */ ImageBridgeParent*
 ImageBridgeParent::CreateSameProcess()
 {
   RefPtr<ImageBridgeParent> parent =
     new ImageBridgeParent(CompositorThreadHolder::Loop(), base::GetCurrentProcId());
   parent->mSelfRef = parent;
+
+  sImageBridgeParentSingleton = parent;
   return parent;
 }
 
+/* static */ bool
+ImageBridgeParent::CreateForGPUProcess(Endpoint<PImageBridgeParent>&& aEndpoint)
+{
+  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
+
+  MessageLoop* loop = CompositorThreadHolder::Loop();
+  RefPtr<ImageBridgeParent> parent = new ImageBridgeParent(loop, aEndpoint.OtherPid());
+
+  loop->PostTask(NewRunnableMethod<Endpoint<PImageBridgeParent>&&>(
+    parent, &ImageBridgeParent::Bind, Move(aEndpoint)));
+
+  sImageBridgeParentSingleton = parent;
+  return true;
+}
+
 void
 ImageBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   // Can't alloc/dealloc shmems from now on.
   mClosed = true;
 
   MessageLoop::current()->PostTask(NewRunnableMethod(this, &ImageBridgeParent::DeferredDestroy));
 
--- a/gfx/layers/ipc/ImageBridgeParent.h
+++ b/gfx/layers/ipc/ImageBridgeParent.h
@@ -48,17 +48,17 @@ public:
 
 protected:
   ImageBridgeParent(MessageLoop* aLoop, ProcessId aChildProcessId);
 
 public:
   ~ImageBridgeParent();
 
   static ImageBridgeParent* CreateSameProcess();
-
+  static bool CreateForGPUProcess(Endpoint<PImageBridgeParent>&& aEndpoint);
   static bool CreateForContent(Endpoint<PImageBridgeParent>&& aEndpoint);
 
   virtual ShmemAllocator* AsShmemAllocator() override { return this; }
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
   // CompositableParentManager
   virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) override;