Bug 1391262 - Do not use remote LayerManager when its initialization fails r=dvander
☠☠ backed out by 21156335f590 ☠ ☠
authorsotaro <sotaro.ikeda.g@gmail.com>
Wed, 11 Oct 2017 10:33:57 +0900
changeset 428075 3dd22fb8666c225285a4e832cd1f95511d67941f
parent 428074 a993d7bc665860b2ea7df689adc6643fa3819815
child 428076 fbd346f1d966245880bfd431954dea9f3ee5381b
push id97
push userfmarier@mozilla.com
push dateSat, 14 Oct 2017 01:12:59 +0000
reviewersdvander
bugs1391262
milestone58.0a1
Bug 1391262 - Do not use remote LayerManager when its initialization fails r=dvander
dom/ipc/TabChild.cpp
widget/PuppetWidget.cpp
widget/PuppetWidget.h
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -2795,27 +2795,29 @@ void
 TabChild::InitRenderingState(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
                              const uint64_t& aLayersId,
                              const CompositorOptions& aCompositorOptions,
                              PRenderFrameChild* aRenderFrame)
 {
     mPuppetWidget->InitIMEState();
 
     if (!aRenderFrame) {
+      mLayersConnected = false;
       NS_WARNING("failed to construct RenderFrame");
       return;
     }
 
     MOZ_ASSERT(aLayersId != 0);
     mTextureFactoryIdentifier = aTextureFactoryIdentifier;
 
     // Pushing layers transactions directly to a separate
     // compositor context.
     PCompositorBridgeChild* compositorChild = CompositorBridgeChild::Get();
     if (!compositorChild) {
+      mLayersConnected = false;
       NS_WARNING("failed to get CompositorBridgeChild instance");
       return;
     }
 
     mCompositorOptions = Some(aCompositorOptions);
 
     mRemoteFrame = static_cast<RenderFrameChild*>(aRenderFrame);
     if (aLayersId != 0) {
@@ -2824,42 +2826,55 @@ TabChild::InitRenderingState(const Textu
       if (!sTabChildren) {
         sTabChildren = new TabChildMap;
       }
       MOZ_ASSERT(!sTabChildren->Get(aLayersId));
       sTabChildren->Put(aLayersId, this);
       mLayersId = aLayersId;
     }
 
-    LayerManager* lm = mPuppetWidget->GetLayerManager();
-    if (lm->AsWebRenderLayerManager()) {
-      lm->AsWebRenderLayerManager()->Initialize(compositorChild,
-                                                wr::AsPipelineId(aLayersId),
-                                                &mTextureFactoryIdentifier);
+    MOZ_ASSERT(!mPuppetWidget->HasLayerManager());
+    bool success = false;
+    if (mLayersConnected && gfxVars::UseWebRender()) {
+      success = mPuppetWidget->CreateRemoteLayerManager([&] (LayerManager* aLayerManager) -> bool {
+        MOZ_ASSERT(aLayerManager->AsWebRenderLayerManager());
+        return aLayerManager->AsWebRenderLayerManager()->Initialize(compositorChild,
+                                                                    wr::AsPipelineId(mLayersId),
+                                                                    &mTextureFactoryIdentifier);
+      });
+    } else if (mLayersConnected) {
+      nsTArray<LayersBackend> ignored;
+      PLayerTransactionChild* shadowManager = compositorChild->SendPLayerTransactionConstructor(ignored, LayersId());
+      if (shadowManager &&
+          shadowManager->SendGetTextureFactoryIdentifier(&mTextureFactoryIdentifier) &&
+          mTextureFactoryIdentifier.mParentBackend != LayersBackend::LAYERS_NONE)
+      {
+        success = true;
+      }
+      if (!success) {
+        NS_WARNING("failed to allocate layer transaction");
+      } else {
+        success = mPuppetWidget->CreateRemoteLayerManager([&] (LayerManager* aLayerManager) -> bool {
+          ShadowLayerForwarder* lf = aLayerManager->AsShadowForwarder();
+          lf->SetShadowManager(shadowManager);
+          lf->IdentifyTextureHost(mTextureFactoryIdentifier);
+          return true;
+        });
+      }
+    }
+
+    if (success) {
+      MOZ_ASSERT(mLayersConnected);
+      // Succeeded to create "remote" layer manager
       ImageBridgeChild::IdentifyCompositorTextureHost(mTextureFactoryIdentifier);
       gfx::VRManagerChild::IdentifyTextureHost(mTextureFactoryIdentifier);
       InitAPZState();
-    }
-
-    ShadowLayerForwarder* lf =
-        mPuppetWidget->GetLayerManager(
-            nullptr, mTextureFactoryIdentifier.mParentBackend)
-                ->AsShadowForwarder();
-    if (lf) {
-      nsTArray<LayersBackend> backends;
-      backends.AppendElement(mTextureFactoryIdentifier.mParentBackend);
-      PLayerTransactionChild* shadowManager =
-          compositorChild->SendPLayerTransactionConstructor(backends, aLayersId);
-      if (shadowManager) {
-        lf->SetShadowManager(shadowManager);
-        lf->IdentifyTextureHost(mTextureFactoryIdentifier);
-        ImageBridgeChild::IdentifyCompositorTextureHost(mTextureFactoryIdentifier);
-        gfx::VRManagerChild::IdentifyTextureHost(mTextureFactoryIdentifier);
-        InitAPZState();
-      }
+    } else {
+      // Fallback to BasicManager
+      mLayersConnected = false;
     }
 
     nsCOMPtr<nsIObserverService> observerService =
         mozilla::services::GetObserverService();
 
     if (observerService) {
         observerService->AddObserver(this,
                                      BEFORE_FIRST_PAINT,
@@ -3160,17 +3175,17 @@ TabChild::ReinitRendering()
   // compositor bridge.
   CompositorOptions options;
   SendEnsureLayersConnected(&options);
   mCompositorOptions = Some(options);
 
   bool success = false;
   RefPtr<CompositorBridgeChild> cb = CompositorBridgeChild::Get();
   if (gfxVars::UseWebRender()) {
-    success = mPuppetWidget->RecreateLayerManager([&] (LayerManager* aLayerManager) -> bool {
+    success = mPuppetWidget->CreateRemoteLayerManager([&] (LayerManager* aLayerManager) -> bool {
       MOZ_ASSERT(aLayerManager->AsWebRenderLayerManager());
       return aLayerManager->AsWebRenderLayerManager()->Initialize(cb,
                                                                   wr::AsPipelineId(mLayersId),
                                                                   &mTextureFactoryIdentifier);
     });
   } else {
     nsTArray<LayersBackend> ignored;
     PLayerTransactionChild* shadowManager = cb->SendPLayerTransactionConstructor(ignored, LayersId());
@@ -3180,17 +3195,17 @@ TabChild::ReinitRendering()
     {
       success = true;
     }
     if (!success) {
       NS_WARNING("failed to re-allocate layer transaction");
       return;
     }
 
-    success = mPuppetWidget->RecreateLayerManager([&] (LayerManager* aLayerManager) -> bool {
+    success = mPuppetWidget->CreateRemoteLayerManager([&] (LayerManager* aLayerManager) -> bool {
       ShadowLayerForwarder* lf = aLayerManager->AsShadowForwarder();
       lf->SetShadowManager(shadowManager);
       lf->IdentifyTextureHost(mTextureFactoryIdentifier);
       return true;
     });
   }
 
   if (!success) {
--- a/widget/PuppetWidget.cpp
+++ b/widget/PuppetWidget.cpp
@@ -591,41 +591,29 @@ PuppetWidget::GetLayerManager(PLayerTran
     if (XRE_IsParentProcess()) {
       // On the parent process there is no CompositorBridgeChild which confuses
       // some layers code, so we use basic layers instead. Note that we create
       // a non-retaining layer manager since we don't care about performance.
       mLayerManager = new BasicLayerManager(BasicLayerManager::BLM_OFFSCREEN);
       return mLayerManager;
     }
 
-    if (mTabChild && !mTabChild->IsLayersConnected()) {
-      // If we know for sure that the parent side of this TabChild is not
-      // connected to the compositor, we don't want to use a "remote" layer
-      // manager like WebRender or Client. Instead we use a Basic one which
-      // can do drawing in this process.
-      mLayerManager = new BasicLayerManager(this);
-    } else if (gfxVars::UseWebRender()) {
-      MOZ_ASSERT(!aShadowManager);
-      mLayerManager = new WebRenderLayerManager(this);
-    } else {
-      mLayerManager = new ClientLayerManager(this);
-    }
-  }
-
-  // Attach a shadow forwarder if none exists.
-  ShadowLayerForwarder* lf = mLayerManager->AsShadowForwarder();
-  if (lf && !lf->HasShadowManager() && aShadowManager) {
-    lf->SetShadowManager(aShadowManager);
+    // If we know for sure that the parent side of this TabChild is not
+    // connected to the compositor, we don't want to use a "remote" layer
+    // manager like WebRender or Client. Instead we use a Basic one which
+    // can do drawing in this process.
+    MOZ_ASSERT(!mTabChild || !mTabChild->IsLayersConnected());
+    mLayerManager = new BasicLayerManager(this);
   }
 
   return mLayerManager;
 }
 
 bool
-PuppetWidget::RecreateLayerManager(const std::function<bool(LayerManager*)>& aInitializeFunc)
+PuppetWidget::CreateRemoteLayerManager(const std::function<bool(LayerManager*)>& aInitializeFunc)
 {
   RefPtr<LayerManager> lm;
   MOZ_ASSERT(mTabChild);
   if (gfxVars::UseWebRender()) {
     lm = new WebRenderLayerManager(this);
   } else {
     lm = new ClientLayerManager(this);
   }
--- a/widget/PuppetWidget.h
+++ b/widget/PuppetWidget.h
@@ -177,21 +177,27 @@ 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. The lambda aInitializeFunc is used
-  // to perform any caller-required initialization for the newly created layer
+  // This is used for creating remote layer managers and for re-creating
+  // them after a compositor reset. The lambda aInitializeFunc is used to perform
+  // any caller-required initialization for the newly created layer
   // manager; in the event of a failure, return false and it will destroy the
   // new layer manager without changing the state of the widget.
-  bool RecreateLayerManager(const std::function<bool(LayerManager*)>& aInitializeFunc);
+  bool CreateRemoteLayerManager(const std::function<bool(LayerManager*)>& aInitializeFunc);
+
+  bool HasLayerManager()
+  {
+    return !!mLayerManager;
+  }
 
   virtual void SetInputContext(const InputContext& aContext,
                                const InputContextAction& aAction) override;
   virtual InputContext GetInputContext() override;
   virtual NativeIMEContext GetNativeIMEContext() override;
   TextEventDispatcherListener* GetNativeTextEventDispatcherListener() override
   {
     return mNativeTextEventDispatcherListener ?