Bug 1381095 - Fallback correctly to non-WebRender if the GPU process/WebRender are disabled when creating a remote compositor session. r=dvander
authorAndrew Osmond <aosmond@mozilla.com>
Thu, 20 Jul 2017 09:20:22 -0400
changeset 369878 05e705204d3bced8e56631b0ef6fe2abe65710c7
parent 369877 e4e7f0468271b6bdc8c703d1d52c9de6e2325be3
child 369879 59cca9197907954aa01b13087ba7be60eab5d318
push id92767
push useraosmond@gmail.com
push dateThu, 20 Jul 2017 13:20:32 +0000
treeherdermozilla-inbound@05e705204d3b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander
bugs1381095
milestone56.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 1381095 - Fallback correctly to non-WebRender if the GPU process/WebRender are disabled when creating a remote compositor session. r=dvander
gfx/ipc/GPUProcessManager.cpp
gfx/ipc/GPUProcessManager.h
widget/nsBaseWidget.cpp
widget/nsBaseWidget.h
--- a/gfx/ipc/GPUProcessManager.cpp
+++ b/gfx/ipc/GPUProcessManager.cpp
@@ -182,16 +182,21 @@ GPUProcessManager::DisableGPUProcess(con
   ShutdownVsyncIOThread();
 
   // We may have been in the middle of guaranteeing our various services are
   // available when one failed. Some callers may fallback to using the same
   // process equivalent, and we need to make sure those services are setup
   // correctly. We cannot re-enter DisableGPUProcess from this call because we
   // know that it is disabled in the config above.
   EnsureProtocolsReady();
+
+  // If we disable the GPU process during reinitialization after a previous
+  // crash, then we need to tell the content processes again, because they
+  // need to rebind to the UI process.
+  HandleProcessLost();
 }
 
 bool
 GPUProcessManager::EnsureGPUReady()
 {
   if (mProcess && !mProcess->IsConnected()) {
     if (!mProcess->WaitForLaunch()) {
       // If this fails, we should have fired OnProcessLaunchComplete and
@@ -476,22 +481,22 @@ GPUProcessManager::OnProcessUnexpectedSh
     SprintfLiteral(disableMessage, "GPU process disabled after %d attempts",
                    mNumProcessAttempts);
     DisableGPUProcess(disableMessage);
   } else if (mNumProcessAttempts > uint32_t(gfxPrefs::GPUProcessMaxRestartsWithDecoder()) &&
              mDecodeVideoOnGpuProcess) {
     mDecodeVideoOnGpuProcess = false;
     Telemetry::Accumulate(Telemetry::GPU_PROCESS_CRASH_FALLBACKS,
                                      uint32_t(FallbackType::DECODINGDISABLED));
+    HandleProcessLost();
   } else {
     Telemetry::Accumulate(Telemetry::GPU_PROCESS_CRASH_FALLBACKS,
                                      uint32_t(FallbackType::NONE));
+    HandleProcessLost();
   }
-
-  HandleProcessLost();
 }
 
 void
 GPUProcessManager::HandleProcessLost()
 {
   if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
     LaunchGPUProcess();
   }
@@ -661,24 +666,27 @@ GPUProcessManager::DestroyProcess()
 
 #ifdef MOZ_CRASHREPORTER
   CrashReporter::AnnotateCrashReport(
     NS_LITERAL_CSTRING("GPUProcessStatus"),
     NS_LITERAL_CSTRING("Destroyed"));
 #endif
 }
 
-RefPtr<CompositorSession>
+already_AddRefed<CompositorSession>
 GPUProcessManager::CreateTopLevelCompositor(nsBaseWidget* aWidget,
                                             LayerManager* aLayerManager,
                                             CSSToLayoutDeviceScale aScale,
                                             const CompositorOptions& aOptions,
                                             bool aUseExternalSurfaceSize,
-                                            const gfx::IntSize& aSurfaceSize)
+                                            const gfx::IntSize& aSurfaceSize,
+                                            bool* aRetryOut)
 {
+  MOZ_ASSERT(aRetryOut);
+
   uint64_t layerTreeId = AllocateLayerTreeId();
 
   EnsureProtocolsReady();
 
   RefPtr<CompositorSession> session;
 
   if (EnsureGPUReady()) {
     session = CreateRemoteSession(
@@ -687,20 +695,20 @@ GPUProcessManager::CreateTopLevelComposi
       layerTreeId,
       aScale,
       aOptions,
       aUseExternalSurfaceSize,
       aSurfaceSize);
     if (!session) {
       // We couldn't create a remote compositor, so abort the process.
       DisableGPUProcess("Failed to create remote compositor");
+      *aRetryOut = true;
+      return nullptr;
     }
-  }
-
-  if (!session) {
+  } else {
     session = InProcessCompositorSession::Create(
       aWidget,
       aLayerManager,
       layerTreeId,
       aScale,
       aOptions,
       aUseExternalSurfaceSize,
       aSurfaceSize,
@@ -710,17 +718,18 @@ GPUProcessManager::CreateTopLevelComposi
 #if defined(MOZ_WIDGET_ANDROID)
   if (session) {
     // Nothing to do if controller gets a nullptr
     RefPtr<UiCompositorControllerChild> controller = CreateUiCompositorController(aWidget, session->RootLayerTreeId());
     session->SetUiCompositorControllerChild(controller);
   }
 #endif // defined(MOZ_WIDGET_ANDROID)
 
-  return session;
+  *aRetryOut = false;
+  return session.forget();
 }
 
 RefPtr<CompositorSession>
 GPUProcessManager::CreateRemoteSession(nsBaseWidget* aWidget,
                                        LayerManager* aLayerManager,
                                        const uint64_t& aRootLayerTreeId,
                                        CSSToLayoutDeviceScale aScale,
                                        const CompositorOptions& aOptions,
--- a/gfx/ipc/GPUProcessManager.h
+++ b/gfx/ipc/GPUProcessManager.h
@@ -84,23 +84,24 @@ public:
   // If not using a GPU process, launch a new GPU process asynchronously.
   void LaunchGPUProcess();
 
   // Ensure that GPU-bound methods can be used. If no GPU process is being
   // used, or one is launched and ready, this function returns immediately.
   // Otherwise it blocks until the GPU process has finished launching.
   bool EnsureGPUReady();
 
-  RefPtr<CompositorSession> CreateTopLevelCompositor(
+  already_AddRefed<CompositorSession> CreateTopLevelCompositor(
     nsBaseWidget* aWidget,
     LayerManager* aLayerManager,
     CSSToLayoutDeviceScale aScale,
     const CompositorOptions& aOptions,
     bool aUseExternalSurfaceSize,
-    const gfx::IntSize& aSurfaceSize);
+    const gfx::IntSize& aSurfaceSize,
+    bool* aRetry);
 
   bool CreateContentBridges(
     base::ProcessId aOtherProcess,
     mozilla::ipc::Endpoint<PCompositorManagerChild>* aOutCompositor,
     mozilla::ipc::Endpoint<PImageBridgeChild>* aOutImageBridge,
     mozilla::ipc::Endpoint<PVRManagerChild>* aOutVRBridge,
     mozilla::ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutVideoManager,
     nsTArray<uint32_t>* aNamespaces);
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -1242,16 +1242,66 @@ void nsBaseWidget::CreateCompositorVsync
 }
 
 CompositorVsyncDispatcher*
 nsBaseWidget::GetCompositorVsyncDispatcher()
 {
   return mCompositorVsyncDispatcher;
 }
 
+already_AddRefed<LayerManager>
+nsBaseWidget::CreateCompositorSession(int aWidth,
+                                      int aHeight,
+                                      CompositorOptions* aOptionsOut)
+{
+  MOZ_ASSERT(aOptionsOut);
+
+  do {
+    CreateCompositorVsyncDispatcher();
+
+    bool enableWR = gfx::gfxVars::UseWebRender();
+    if (enableWR && !WidgetTypeSupportsAcceleration()) {
+      // fall back to basic
+      break;
+    }
+    bool enableAPZ = UseAPZ();
+    CompositorOptions options(enableAPZ, enableWR);
+
+    bool enableAL = gfx::gfxConfig::IsEnabled(gfx::Feature::ADVANCED_LAYERS);
+    options.SetUseAdvancedLayers(enableAL);
+
+    RefPtr<LayerManager> lm;
+    if (options.UseWebRender()) {
+      lm = new WebRenderLayerManager(this);
+    } else {
+      lm = new ClientLayerManager(this);
+    }
+
+    bool retry = false;
+    gfx::GPUProcessManager* gpu = gfx::GPUProcessManager::Get();
+    mCompositorSession = gpu->CreateTopLevelCompositor(
+      this,
+      lm,
+      GetDefaultScale(),
+      options,
+      UseExternalCompositingSurface(),
+      gfx::IntSize(aWidth, aHeight),
+      &retry);
+
+    // We need to retry in a loop because the act of failing to create the
+    // compositor can change our state (e.g. disable WebRender).
+    if (mCompositorSession || !retry) {
+      *aOptionsOut = options;
+      return lm.forget();
+    }
+  } while (true);
+
+  return nullptr;
+}
+
 void nsBaseWidget::CreateCompositor(int aWidth, int aHeight)
 {
   // This makes sure that gfxPlatforms gets initialized if it hasn't by now.
   gfxPlatform::GetPlatform();
 
   MOZ_ASSERT(gfxPlatform::UsesOffMainThreadCompositing(),
              "This function assumes OMTC");
 
@@ -1266,44 +1316,24 @@ void nsBaseWidget::CreateCompositor(int 
   // to make sure it's properly destroyed by calling DestroyCompositor!
 
   // If we've already received a shutdown notification, don't try
   // create a new compositor.
   if (!mShutdownObserver) {
     return;
   }
 
-  CreateCompositorVsyncDispatcher();
-
-  bool enableWR = gfx::gfxVars::UseWebRender();
-  if (enableWR && !WidgetTypeSupportsAcceleration()) {
-    // fall back to basic
+  CompositorOptions options;
+  RefPtr<LayerManager> lm =
+    CreateCompositorSession(aWidth, aHeight, &options);
+  if (!lm) {
     return;
   }
-  bool enableAPZ = UseAPZ();
-  CompositorOptions options(enableAPZ, enableWR);
-
-  bool enableAL = gfx::gfxConfig::IsEnabled(gfx::Feature::ADVANCED_LAYERS);
-  options.SetUseAdvancedLayers(enableAL);
-
-  RefPtr<LayerManager> lm;
-  if (options.UseWebRender()) {
-    lm = new WebRenderLayerManager(this);
-  } else {
-    lm = new ClientLayerManager(this);
-  }
-
-  gfx::GPUProcessManager* gpu = gfx::GPUProcessManager::Get();
-  mCompositorSession = gpu->CreateTopLevelCompositor(
-    this,
-    lm,
-    GetDefaultScale(),
-    options,
-    UseExternalCompositingSurface(),
-    gfx::IntSize(aWidth, aHeight));
+
+  MOZ_ASSERT(mCompositorSession);
   mCompositorBridgeChild = mCompositorSession->GetCompositorBridgeChild();
   mCompositorWidgetDelegate = mCompositorSession->GetCompositorWidgetDelegate();
 
   if (options.UseAPZ()) {
     mAPZC = mCompositorSession->GetAPZCTreeManager();
     ConfigureAPZCTreeManager();
   } else {
     mAPZC = nullptr;
--- a/widget/nsBaseWidget.h
+++ b/widget/nsBaseWidget.h
@@ -6,16 +6,17 @@
 #define nsBaseWidget_h__
 
 #include "InputData.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/WidgetUtils.h"
 #include "mozilla/layers/APZCCallbackHelper.h"
+#include "mozilla/layers/CompositorOptions.h"
 #include "nsRect.h"
 #include "nsIWidget.h"
 #include "nsWidgetsCID.h"
 #include "nsIFile.h"
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsIRollupListener.h"
 #include "nsIObserver.h"
@@ -738,11 +739,16 @@ protected:
   static void debug_DumpPaintEvent(FILE *                aFileOut,
                                    nsIWidget *           aWidget,
                                    const nsIntRegion &   aPaintEvent,
                                    const char *          aWidgetName,
                                    int32_t               aWindowID);
 
   static bool debug_GetCachedBoolPref(const char* aPrefName);
 #endif
+
+private:
+  already_AddRefed<LayerManager>
+  CreateCompositorSession(int aWidth, int aHeight,
+                          mozilla::layers::CompositorOptions* aOptionsOut);
 };
 
 #endif // nsBaseWidget_h__