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);