[go: up one dir, main page]

gpu: Detect consecutive surface initialization failures on Android.

If we fail to initialize the GLSurface associated with an ANativeWindow
the error is propagated to the browser so we can retry with a new
window. Add tracking to detect consecutive failures with this retry
to avoid a perpetual retry loop.

R=​boliu@chromium.org, ericrk@chromium.org

(cherry picked from commit a7888b8e05a614c646460569bd3b6d93319066c8)

Bug: 972667
Change-Id: Ieaf0a7c7454f12ffbfa068e7c17c452857776ffd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1654233
Commit-Queue: Khushal <khushalsagar@chromium.org>
Auto-Submit: Khushal <khushalsagar@chromium.org>
Reviewed-by: Bo <boliu@chromium.org>
Reviewed-by: Eric Karl <ericrk@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#668479}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1662497
Reviewed-by: Khushal <khushalsagar@chromium.org>
Cr-Commit-Position: refs/branch-heads/3809@{#349}
Cr-Branched-From: d82dec1a818f378c464ba307ddd9c92133eac355-refs/heads/master@{#665002}
diff --git a/components/viz/service/display_embedder/output_surface_provider_impl.cc b/components/viz/service/display_embedder/output_surface_provider_impl.cc
index 8fe3975..1f81323 100644
--- a/components/viz/service/display_embedder/output_surface_provider_impl.cc
+++ b/components/viz/service/display_embedder/output_surface_provider_impl.cc
@@ -163,17 +163,18 @@
           image_factory_, gpu_channel_manager_delegate_, renderer_settings);
       context_result = context_provider->BindToCurrentThread();
 
-      if (IsFatalOrSurfaceFailure(context_result)) {
 #if defined(OS_ANDROID)
-        display_client->OnFatalOrSurfaceContextCreationFailure(context_result);
-#elif defined(OS_CHROMEOS) || defined(IS_CHROMECAST)
+      display_client->OnContextCreationResult(context_result);
+#endif
+
+      if (IsFatalOrSurfaceFailure(context_result)) {
+#if defined(OS_CHROMEOS) || defined(IS_CHROMECAST)
         // TODO(kylechar): Chrome OS can't disable GPU compositing. This needs
         // to be handled similar to Android.
         CHECK(false);
-#else
+#elif !defined(OS_ANDROID)
         gpu_service_impl_->DisableGpuCompositing();
 #endif
-
         return nullptr;
       }
     }
diff --git a/components/viz/test/mock_display_client.h b/components/viz/test/mock_display_client.h
index f43156e..ebca77f 100644
--- a/components/viz/test/mock_display_client.h
+++ b/components/viz/test/mock_display_client.h
@@ -30,8 +30,7 @@
 #endif
 #if defined(OS_ANDROID)
   MOCK_METHOD1(DidCompleteSwapWithSize, void(const gfx::Size&));
-  MOCK_METHOD1(OnFatalOrSurfaceContextCreationFailure,
-               void(gpu::ContextResult));
+  MOCK_METHOD1(OnContextCreationResult, void(gpu::ContextResult));
   MOCK_METHOD1(SetPreferredRefreshRate, void(float refresh_rate));
 #endif
 #if defined(USE_X11)
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index a0c7d6e..9c0dbd1 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -103,6 +103,11 @@
 
 static const char* kBrowser = "Browser";
 
+// NOINLINE to make sure crashes use this for magic signature.
+NOINLINE void FatalSurfaceFailure() {
+  LOG(FATAL) << "Fatal surface initialization failure";
+}
+
 gfx::OverlayTransform RotationToDisplayTransform(
     display::Display::Rotation rotation) {
   // Note that the angle provided by |rotation| here is the opposite direction
@@ -558,9 +563,8 @@
   void DidCompleteSwapWithSize(const gfx::Size& pixel_size) override {
     compositor_->DidSwapBuffers(pixel_size);
   }
-  void OnFatalOrSurfaceContextCreationFailure(
-      gpu::ContextResult context_result) override {
-    compositor_->OnFatalOrSurfaceContextCreationFailure(context_result);
+  void OnContextCreationResult(gpu::ContextResult context_result) override {
+    compositor_->OnContextCreationResult(context_result);
   }
   void SetPreferredRefreshRate(float refresh_rate) override {
     if (compositor_->root_window_)
@@ -1018,9 +1022,17 @@
                                          requires_alpha_channel_),
           ws::command_buffer_metrics::ContextType::BROWSER_COMPOSITOR);
   auto result = context_provider->BindToCurrentThread();
+
+  if (surface_handle != gpu::kNullSurfaceHandle) {
+    // Only use OnContextCreationResult for onscreen contexts, where recovering
+    // from a surface initialization failure is possible by re-creating the
+    // native window.
+    OnContextCreationResult(result);
+  } else if (result == gpu::ContextResult::kFatalFailure) {
+    LOG(FATAL) << "Fatal failure in creating offscreen context";
+  }
+
   if (result != gpu::ContextResult::kSuccess) {
-    if (gpu::IsFatalOrSurfaceFailure(result))
-      OnFatalOrSurfaceContextCreationFailure(result);
     HandlePendingLayerTreeFrameSinkRequest();
     return;
   }
@@ -1327,12 +1339,26 @@
   return viz::LocalSurfaceIdAllocation();
 }
 
+void CompositorImpl::OnContextCreationResult(
+    gpu::ContextResult context_result) {
+  if (!gpu::IsFatalOrSurfaceFailure(context_result)) {
+    num_of_consecutive_surface_failures_ = 0u;
+    return;
+  }
+
+  OnFatalOrSurfaceContextCreationFailure(context_result);
+}
+
 void CompositorImpl::OnFatalOrSurfaceContextCreationFailure(
     gpu::ContextResult context_result) {
   DCHECK(gpu::IsFatalOrSurfaceFailure(context_result));
   LOG_IF(FATAL, context_result == gpu::ContextResult::kFatalFailure)
       << "Fatal error making Gpu context";
 
+  constexpr size_t kMaxConsecutiveSurfaceFailures = 10u;
+  if (++num_of_consecutive_surface_failures_ > kMaxConsecutiveSurfaceFailures)
+    FatalSurfaceFailure();
+
   if (context_result == gpu::ContextResult::kSurfaceFailure) {
     SetSurface(nullptr, false);
     client_->RecreateSurface();
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h
index 61b97e38..90af50a 100644
--- a/content/browser/renderer_host/compositor_impl_android.h
+++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -208,7 +208,8 @@
   // Registers the root frame sink ID.
   void RegisterRootFrameSink();
 
-  // Called when we fail to create the context for the root frame sink.
+  // Called with the result of context creation for the root frame sink.
+  void OnContextCreationResult(gpu::ContextResult context_result);
   void OnFatalOrSurfaceContextCreationFailure(
       gpu::ContextResult context_result);
 
@@ -281,6 +282,8 @@
   base::RepeatingCallback<void(const gfx::Size&)>
       swap_completed_with_size_for_testing_;
 
+  size_t num_of_consecutive_surface_failures_ = 0u;
+
   base::WeakPtrFactory<CompositorImpl> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(CompositorImpl);
diff --git a/services/viz/privileged/interfaces/compositing/display_private.mojom b/services/viz/privileged/interfaces/compositing/display_private.mojom
index deb327b..cd8dd80 100644
--- a/services/viz/privileged/interfaces/compositing/display_private.mojom
+++ b/services/viz/privileged/interfaces/compositing/display_private.mojom
@@ -94,10 +94,10 @@
   [EnableIf=use_x11]
   DidCompleteSwapWithNewSize(gfx.mojom.Size size);
 
-  // Notifies that context creation failed. On Android we can't fall back to
-  // SW in these cases, so we need to handle this specifically.
+  // Notifies the client of the result of context creation attempt. On Android we can't
+  // fall back to SW in failure cases, so we need to handle this specifically.
   [EnableIf=is_android]
-  OnFatalOrSurfaceContextCreationFailure(gpu.mojom.ContextResult result);
+  OnContextCreationResult(gpu.mojom.ContextResult result);
 
   [EnableIf=is_android]
   SetPreferredRefreshRate(float refresh_rate);