Recreate PLayerTransactions for TabChildren when the compositor restarts. (bug 1300936 part 4, r=mattwoodrow, r=billm)
authorDavid Anderson <danderson@mozilla.com>
Tue, 20 Sep 2016 01:19:32 -0700
changeset 314603 101e8160640228dcc0e59429d27a2f3a3a6a957d
parent 314602 9a6f5fac405ffd3ab59163bf4c5ec866a1bb142b
child 314604 ca56b87ab094316069d793db86b1300a8ce25370
push id30732
push usercbook@mozilla.com
push dateWed, 21 Sep 2016 10:04:03 +0000
treeherdermozilla-central@560b2c805bf7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow, billm
bugs1300936
milestone52.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
Recreate PLayerTransactions for TabChildren when the compositor restarts. (bug 1300936 part 4, r=mattwoodrow, r=billm)
dom/ipc/ContentChild.cpp
dom/ipc/PBrowser.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
gfx/layers/ipc/CompositorBridgeParent.cpp
gfx/layers/ipc/CompositorBridgeParent.h
gfx/layers/ipc/PCompositorBridge.ipdl
layout/ipc/RenderFrameParent.cpp
layout/ipc/RenderFrameParent.h
widget/PuppetWidget.cpp
widget/PuppetWidget.h
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1186,25 +1186,42 @@ ContentChild::RecvInitRendering(Endpoint
   return true;
 }
 
 bool
 ContentChild::RecvReinitRendering(Endpoint<PCompositorBridgeChild>&& aCompositor,
                                   Endpoint<PImageBridgeChild>&& aImageBridge,
                                   Endpoint<PVRManagerChild>&& aVRBridge)
 {
+  nsTArray<RefPtr<TabChild>> tabs = TabChild::GetAll();
+
+  // Zap all the old layer managers we have lying around.
+  for (const auto& tabChild : tabs) {
+    if (tabChild->LayersId()) {
+      tabChild->InvalidateLayers();
+    }
+  }
+
+  // Re-establish singleton bridges to the compositor.
   if (!CompositorBridgeChild::ReinitForContent(Move(aCompositor))) {
     return false;
   }
   if (!ImageBridgeChild::ReinitForContent(Move(aImageBridge))) {
     return false;
   }
   if (!gfx::VRManagerChild::ReinitForContent(Move(aVRBridge))) {
     return false;
   }
+
+  // Establish new PLayerTransactions.
+  for (const auto& tabChild : tabs) {
+    if (tabChild->LayersId()) {
+      tabChild->ReinitRendering();
+    }
+  }
   return true;
 }
 
 PSharedBufferManagerChild*
 ContentChild::AllocPSharedBufferManagerChild(mozilla::ipc::Transport* aTransport,
                                               base::ProcessId aOtherProcess)
 {
   return SharedBufferManagerChild::StartUpInChildProcess(aTransport, aOtherProcess);
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -578,16 +578,23 @@ parent:
                             OptionalShmem visualData,
                             uint32_t width, uint32_t height,
                             uint32_t stride, uint8_t format,
                             int32_t dragAreaX, int32_t dragAreaY);
 
     async AudioChannelActivityNotification(uint32_t aAudioChannel,
                                            bool aActive);
 
+    // After a compositor reset, it is necessary to reconnect each layers ID to
+    // the compositor of the widget that will render those layers. Note that
+    // this is sync so we can ensure that messages to the window compositor
+    // arrive before the TabChild attempts to use its cross-process compositor
+    // bridge.
+    sync EnsureLayersConnected();
+
 child:
     /**
      * Notify the remote browser that it has been Show()n on this
      * side, with the given |visibleRect|.  This message is expected
      * to trigger creation of the remote browser's "widget".
      *
      * |Show()| and |Move()| take IntSizes rather than Rects because
      * content processes always render to a virtual <0, 0> top-left
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -3098,16 +3098,31 @@ TabChild::DoSendAsyncMessage(JSContext* 
   }
   if (!SendAsyncMessage(PromiseFlatString(aMessage), cpows,
                         Principal(aPrincipal), data)) {
     return NS_ERROR_UNEXPECTED;
   }
   return NS_OK;
 }
 
+/* static */ nsTArray<RefPtr<TabChild>>
+TabChild::GetAll()
+{
+  nsTArray<RefPtr<TabChild>> list;
+  if (!sTabChildren) {
+    return list;
+  }
+
+  for (auto iter = sTabChildren->Iter(); !iter.Done(); iter.Next()) {
+    list.AppendElement(iter.Data());
+  }
+
+  return list;
+}
+
 TabChild*
 TabChild::GetFrom(nsIPresShell* aPresShell)
 {
   nsIDocument* doc = aPresShell->GetDocument();
   if (!doc) {
       return nullptr;
   }
   nsCOMPtr<nsIDocShell> docShell(doc->GetDocShell());
@@ -3178,16 +3193,56 @@ TabChild::InvalidateLayers()
   MOZ_ASSERT(mPuppetWidget->GetLayerManager()->GetBackendType() ==
                LayersBackend::LAYERS_CLIENT);
 
   RefPtr<LayerManager> lm = mPuppetWidget->GetLayerManager();
   FrameLayerBuilder::InvalidateAllLayers(lm);
 }
 
 void
+TabChild::ReinitRendering()
+{
+  MOZ_ASSERT(mLayersId);
+
+  // Before we establish a new PLayerTransaction, we must connect our layer tree
+  // id, CompositorBridge, and the widget compositor all together again.
+  // Normally this happens in TabParent before TabChild is given rendering
+  // information.
+  //
+  // In this case, we will send a sync message to our TabParent, which in turn
+  // will send a sync message to the Compositor of the widget owning this tab.
+  // This guarantees the correct association is in place before our
+  // PLayerTransaction constructor message arrives on the cross-process
+  // compositor bridge.
+  SendEnsureLayersConnected();
+
+  RefPtr<CompositorBridgeChild> cb = CompositorBridgeChild::Get();
+
+  bool success;
+  nsTArray<LayersBackend> ignored;
+  PLayerTransactionChild* shadowManager =
+    cb->SendPLayerTransactionConstructor(ignored, LayersId(), &mTextureFactoryIdentifier, &success);
+  if (!success) {
+    NS_WARNING("failed to re-allocate layer transaction");
+    return;
+  }
+
+  if (!shadowManager) {
+    NS_WARNING("failed to re-construct LayersChild");
+    return;
+  }
+
+  RefPtr<LayerManager> lm = mPuppetWidget->RecreateLayerManager(shadowManager);
+  ShadowLayerForwarder* lf = lm->AsShadowForwarder();
+  lf->IdentifyTextureHost(mTextureFactoryIdentifier);
+
+  mApzcTreeManager = CompositorBridgeChild::Get()->GetAPZCTreeManager(mLayersId);
+}
+
+void
 TabChild::CompositorUpdated(const TextureFactoryIdentifier& aNewIdentifier)
 {
   gfxPlatform::GetPlatform()->CompositorUpdated();
 
   RefPtr<LayerManager> lm = mPuppetWidget->GetLayerManager();
   ClientLayerManager* clm = lm->AsClientLayerManager();
 
   mTextureFactoryIdentifier = aNewIdentifier;
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -238,16 +238,19 @@ class TabChild final : public TabChildBa
 
 public:
   /**
    * Find TabChild of aTabId in the same content process of the
    * caller.
    */
   static already_AddRefed<TabChild> FindTabChild(const TabId& aTabId);
 
+  // Return a list of all active TabChildren.
+  static nsTArray<RefPtr<TabChild>> GetAll();
+
 public:
   /**
    * Create a new TabChild object.
    */
   TabChild(nsIContentChild* aManager,
            const TabId& aTabId,
            const TabContext& aContext,
            uint32_t aChromeFlags);
@@ -553,16 +556,17 @@ public:
                     const TimeStamp& aCompositeStart,
                     const TimeStamp& aCompositeEnd);
 
   void DidRequestComposite(const TimeStamp& aCompositeReqStart,
                            const TimeStamp& aCompositeReqEnd);
 
   void ClearCachedResources();
   void InvalidateLayers();
+  void ReinitRendering();
   void CompositorUpdated(const TextureFactoryIdentifier& aNewIdentifier);
 
   static inline TabChild* GetFrom(nsIDOMWindow* aWindow)
   {
     nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow);
     nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(webNav);
     return GetFrom(docShell);
   }
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -569,16 +569,25 @@ TabParent::Attach(nsFrameLoader* aFrameL
   if (RenderFrameParent* frame = GetRenderFrame()) {
     AddTabParentToTable(frame->GetLayersId(), this);
     frame->OwnerContentChanged(ownerElement);
   }
   mIsDetached = false;
 }
 
 bool
+TabParent::RecvEnsureLayersConnected()
+{
+  if (RenderFrameParent* frame = GetRenderFrame()) {
+    frame->EnsureLayersConnected();
+  }
+  return true;
+}
+
+bool
 TabParent::Recv__delete__()
 {
   if (XRE_IsParentProcess()) {
     ContentParent::DeallocateTabId(mTabId,
                                    Manager()->AsContentParent()->ChildID(),
                                    mMarkedDestroying);
   }
   else {
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -581,16 +581,18 @@ public:
   void AudioChannelChangeNotification(nsPIDOMWindowOuter* aWindow,
                                       AudioChannel aAudioChannel,
                                       float aVolume,
                                       bool aMuted);
   bool SetRenderFrame(PRenderFrameParent* aRFParent);
   bool GetRenderFrameInfo(TextureFactoryIdentifier* aTextureFactoryIdentifier,
                           uint64_t* aLayersId);
 
+  bool RecvEnsureLayersConnected() override;
+
 protected:
   bool ReceiveMessage(const nsString& aMessage,
                       bool aSync,
                       ipc::StructuredCloneData* aData,
                       mozilla::jsipc::CpowHolder* aCpows,
                       nsIPrincipal* aPrincipal,
                       nsTArray<ipc::StructuredCloneData>* aJSONRetVal = nullptr);
 
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -1877,16 +1877,30 @@ CompositorBridgeParent::NotifyVsync(cons
 bool
 CompositorBridgeParent::RecvNotifyChildCreated(const uint64_t& child)
 {
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
   NotifyChildCreated(child);
   return true;
 }
 
+bool
+CompositorBridgeParent::RecvNotifyChildRecreated(const uint64_t& aChild)
+{
+  MonitorAutoLock lock(*sIndirectLayerTreesLock);
+
+  if (sIndirectLayerTrees.find(aChild) != sIndirectLayerTrees.end()) {
+    // Invalid to register the same layer tree twice.
+    return false;
+  }
+
+  NotifyChildCreated(aChild);
+  return true;
+}
+
 void
 CompositorBridgeParent::NotifyChildCreated(uint64_t aChild)
 {
   sIndirectLayerTreesLock->AssertCurrentThreadOwns();
   sIndirectLayerTrees[aChild].mParent = this;
   sIndirectLayerTrees[aChild].mLayerManager = mLayerManager;
 }
 
@@ -2100,16 +2114,17 @@ public:
 
   // FIXME/bug 774388: work out what shutdown protocol we need.
   virtual bool RecvInitialize(const uint64_t& aRootLayerTreeId) override { return false; }
   virtual bool RecvRequestOverfill() override { return true; }
   virtual bool RecvWillClose() override { return true; }
   virtual bool RecvPause() override { return true; }
   virtual bool RecvResume() override { return true; }
   virtual bool RecvNotifyChildCreated(const uint64_t& child) override;
+  virtual bool RecvNotifyChildRecreated(const uint64_t& child) override { return false; }
   virtual bool RecvAdoptChild(const uint64_t& child) override { return false; }
   virtual bool RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
                                 const gfx::IntRect& aRect) override
   { return true; }
   virtual bool RecvFlushRendering() override { return true; }
   virtual bool RecvForcePresent() override { return true; }
   virtual bool RecvNotifyRegionInvalidated(const nsIntRegion& aRegion) override { return true; }
   virtual bool RecvStartFrameTimeRecording(const int32_t& aBufferSize, uint32_t* aOutStartIndex) override { return true; }
--- a/gfx/layers/ipc/CompositorBridgeParent.h
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -269,16 +269,17 @@ public:
 
   virtual bool RecvInitialize(const uint64_t& aRootLayerTreeId) override;
   virtual bool RecvGetFrameUniformity(FrameUniformityData* aOutData) override;
   virtual bool RecvRequestOverfill() override;
   virtual bool RecvWillClose() override;
   virtual bool RecvPause() override;
   virtual bool RecvResume() override;
   virtual bool RecvNotifyChildCreated(const uint64_t& child) override;
+  virtual bool RecvNotifyChildRecreated(const uint64_t& child) override;
   virtual bool RecvAdoptChild(const uint64_t& child) override;
   virtual bool RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
                                 const gfx::IntRect& aRect) override;
   virtual bool RecvFlushRendering() override;
   virtual bool RecvForcePresent() override;
 
   virtual bool RecvAcknowledgeCompositorUpdate(const uint64_t& aLayersId) override {
     MOZ_ASSERT_UNREACHABLE("This message is only sent cross-process");
--- a/gfx/layers/ipc/PCompositorBridge.ipdl
+++ b/gfx/layers/ipc/PCompositorBridge.ipdl
@@ -150,16 +150,22 @@ 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();
   sync Resume();
 
   async NotifyChildCreated(uint64_t id);
   async AdoptChild(uint64_t id);
 
+  // Same as NotifyChildCreated, but used when child processes need to
+  // reassociate layers. This must be synchronous to ensure that the
+  // association happens before PLayerTransactions are sent over the
+  // cross-process bridge.
+  sync NotifyChildRecreated(uint64_t id);
+
   // Make a snapshot of the content that would have been drawn to our
   // render target at the time this message is received.  If the size
   // or format of |inSnapshot| doesn't match our render target,
   // results are undefined.
   //
   // NB: this message will result in animations, transforms, effects,
   // and so forth being interpolated.  That's what we want to happen.
   sync MakeSnapshot(SurfaceDescriptor inSnapshot, IntRect dirtyRect);
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -328,16 +328,32 @@ RenderFrameParent::TakeFocusForClickFrom
 
 bool
 RenderFrameParent::RecvTakeFocusForClickFromTap()
 {
   TakeFocusForClickFromTap();
   return true;
 }
 
+void
+RenderFrameParent::EnsureLayersConnected()
+{
+  RefPtr<LayerManager> lm = GetFrom(mFrameLoader);
+  if (!lm) {
+    return;
+  }
+
+  ClientLayerManager* client = lm->AsClientLayerManager();
+  if (!client) {
+    return;
+  }
+
+  client->GetRemoteRenderer()->SendNotifyChildRecreated(mLayersId);
+}
+
 } // namespace layout
 } // namespace mozilla
 
 nsDisplayRemote::nsDisplayRemote(nsDisplayListBuilder* aBuilder,
                                  nsSubDocumentFrame* aFrame,
                                  RenderFrameParent* aRemoteFrame)
   : nsDisplayItem(aBuilder, aFrame)
   , mRemoteFrame(aRemoteFrame)
--- a/layout/ipc/RenderFrameParent.h
+++ b/layout/ipc/RenderFrameParent.h
@@ -79,16 +79,18 @@ public:
   bool HitTest(const nsRect& aRect);
 
   void GetTextureFactoryIdentifier(TextureFactoryIdentifier* aTextureFactoryIdentifier);
 
   inline uint64_t GetLayersId() { return mLayersId; }
 
   void TakeFocusForClickFromTap();
 
+  void EnsureLayersConnected();
+
 protected:
   void ActorDestroy(ActorDestroyReason why) override;
 
   virtual bool RecvNotifyCompositorTransaction() override;
 
   virtual bool RecvUpdateHitRegion(const nsRegion& aRegion) override;
 
   virtual bool RecvTakeFocusForClickFromTap() override;
--- a/widget/PuppetWidget.cpp
+++ b/widget/PuppetWidget.cpp
@@ -574,16 +574,24 @@ PuppetWidget::GetLayerManager(PLayerTran
   }
   ShadowLayerForwarder* lf = mLayerManager->AsShadowForwarder();
   if (!lf->HasShadowManager() && aShadowManager) {
     lf->SetShadowManager(aShadowManager);
   }
   return mLayerManager;
 }
 
+LayerManager*
+PuppetWidget::RecreateLayerManager(PLayerTransactionChild* aShadowManager)
+{
+  mLayerManager = new ClientLayerManager(this);
+  mLayerManager->AsShadowForwarder()->SetShadowManager(aShadowManager);
+  return mLayerManager;
+}
+
 nsresult
 PuppetWidget::RequestIMEToCommitComposition(bool aCancel)
 {
 #ifdef MOZ_CROSS_PROCESS_IME
   if (!mTabChild) {
     return NS_ERROR_FAILURE;
   }
 
--- a/widget/PuppetWidget.h
+++ b/widget/PuppetWidget.h
@@ -168,16 +168,19 @@ public:
   virtual nsTransparencyMode GetTransparencyMode() override
   { return eTransparencyTransparent; }
 
   virtual LayerManager*
   GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr,
                   LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE,
                   LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT) override;
 
+  // This is used after a compositor reset.
+  LayerManager* RecreateLayerManager(PLayerTransactionChild* aShadowManager);
+
   NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
                                     const InputContextAction& aAction) override;
   NS_IMETHOD_(InputContext) GetInputContext() override;
   NS_IMETHOD_(NativeIMEContext) GetNativeIMEContext() override;
   virtual nsIMEUpdatePreference GetIMEUpdatePreference() override;
 
   NS_IMETHOD SetCursor(nsCursor aCursor) override;
   NS_IMETHOD SetCursor(imgIContainer* aCursor,