Commit 899d4811 authored by kylechar's avatar kylechar Committed by Commit Bot

Handle context loss in VizProcessContextProvider.

Register a context loss callback with the GLES2Implementation to find
out about lost context. Implement AddObserver() and RemoveObserver() for
VizProcessContextProvider to notify the observers on context loss.

viz::Display is already registered as the context loss observer for the
ContextProvider. It gets notified and calls out to DisplayClient.
Implement a handler for DisplayOutputSurfaceLost() so the root
CompositorFrameSink shuts down the display on context loss. The client
will see a connection error and reinitialize the display.

Also make VizProcessContextProvider log UMA on context loss. This
requires moving ContextLossReason enum somewhere visible to
VizProcessContextProvider and adding a new histogram for
GPU.ContextLost.DisplayCompositor.

Bug: 859068
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: I4c1fb6f00a893003e9b65dde1a7c5802a8f27692
Reviewed-on: https://chromium-review.googlesource.com/1126482Reviewed-by: default avatarAntoine Labour <piman@chromium.org>
Reviewed-by: default avatarSadrul Chowdhury <sadrul@chromium.org>
Reviewed-by: default avatarRobert Kaplow (slow) <rkaplow@chromium.org>
Commit-Queue: kylechar <kylechar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#575016}
parent 7ac7ed50
...@@ -60,6 +60,8 @@ viz_component("common") { ...@@ -60,6 +60,8 @@ viz_component("common") {
"gpu/context_cache_controller.cc", "gpu/context_cache_controller.cc",
"gpu/context_cache_controller.h", "gpu/context_cache_controller.h",
"gpu/context_lost_observer.h", "gpu/context_lost_observer.h",
"gpu/context_lost_reason.cc",
"gpu/context_lost_reason.h",
"gpu/context_provider.cc", "gpu/context_provider.cc",
"gpu/context_provider.h", "gpu/context_provider.h",
"gpu/raster_context_provider.cc", "gpu/raster_context_provider.cc",
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/viz/common/gpu/context_lost_reason.h"
#include "base/logging.h"
namespace viz {
ContextLostReason GetContextLostReason(gpu::error::Error error,
gpu::error::ContextLostReason reason) {
if (error == gpu::error::kLostContext) {
switch (reason) {
case gpu::error::kGuilty:
return CONTEXT_LOST_GUILTY;
case gpu::error::kInnocent:
return CONTEXT_LOST_INNOCENT;
case gpu::error::kUnknown:
return CONTEXT_LOST_UNKNOWN;
case gpu::error::kOutOfMemory:
return CONTEXT_LOST_OUT_OF_MEMORY;
case gpu::error::kMakeCurrentFailed:
return CONTEXT_LOST_MAKECURRENT_FAILED;
case gpu::error::kGpuChannelLost:
return CONTEXT_LOST_GPU_CHANNEL_ERROR;
case gpu::error::kInvalidGpuMessage:
return CONTEXT_LOST_INVALID_GPU_MESSAGE;
}
}
switch (error) {
case gpu::error::kInvalidSize:
return CONTEXT_PARSE_ERROR_INVALID_SIZE;
case gpu::error::kOutOfBounds:
return CONTEXT_PARSE_ERROR_OUT_OF_BOUNDS;
case gpu::error::kUnknownCommand:
return CONTEXT_PARSE_ERROR_UNKNOWN_COMMAND;
case gpu::error::kInvalidArguments:
return CONTEXT_PARSE_ERROR_INVALID_ARGS;
case gpu::error::kGenericError:
return CONTEXT_PARSE_ERROR_GENERIC_ERROR;
case gpu::error::kDeferCommandUntilLater:
case gpu::error::kDeferLaterCommands:
case gpu::error::kNoError:
case gpu::error::kLostContext:
NOTREACHED();
return CONTEXT_LOST_UNKNOWN;
}
NOTREACHED();
return CONTEXT_LOST_UNKNOWN;
}
} // namespace viz
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_VIZ_COMMON_GPU_CONTEXT_LOST_REASON_H_
#define COMPONENTS_VIZ_COMMON_GPU_CONTEXT_LOST_REASON_H_
#include "components/viz/common/viz_common_export.h"
#include "gpu/command_buffer/common/constants.h"
namespace viz {
enum ContextLostReason {
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
CONTEXT_INIT_FAILED = 0,
CONTEXT_LOST_GPU_CHANNEL_ERROR = 1,
CONTEXT_PARSE_ERROR_INVALID_SIZE = 2,
CONTEXT_PARSE_ERROR_OUT_OF_BOUNDS = 3,
CONTEXT_PARSE_ERROR_UNKNOWN_COMMAND = 4,
CONTEXT_PARSE_ERROR_INVALID_ARGS = 5,
CONTEXT_PARSE_ERROR_GENERIC_ERROR = 6,
CONTEXT_LOST_GUILTY = 7,
CONTEXT_LOST_INNOCENT = 8,
CONTEXT_LOST_UNKNOWN = 9,
CONTEXT_LOST_OUT_OF_MEMORY = 10,
CONTEXT_LOST_MAKECURRENT_FAILED = 11,
CONTEXT_LOST_INVALID_GPU_MESSAGE = 12,
// Update kMaxValue and //tools/metrics/histograms/histograms.xml when adding
// new values.
kMaxValue = CONTEXT_LOST_INVALID_GPU_MESSAGE
};
VIZ_COMMON_EXPORT ContextLostReason
GetContextLostReason(gpu::error::Error error,
gpu::error::ContextLostReason reason);
} // namespace viz
#endif // COMPONENTS_VIZ_COMMON_GPU_CONTEXT_LOST_REASON_H_
...@@ -10,8 +10,11 @@ ...@@ -10,8 +10,11 @@
#include "base/lazy_instance.h" #include "base/lazy_instance.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/metrics/histogram_macros.h"
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "components/viz/common/gpu/context_lost_observer.h"
#include "components/viz/common/gpu/context_lost_reason.h"
#include "components/viz/common/resources/platform_color.h" #include "components/viz/common/resources/platform_color.h"
#include "gpu/GLES2/gl2extchromium.h" #include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/gles2_implementation.h" #include "gpu/command_buffer/client/gles2_implementation.h"
...@@ -48,6 +51,10 @@ gpu::ContextCreationAttribs CreateAttributes() { ...@@ -48,6 +51,10 @@ gpu::ContextCreationAttribs CreateAttributes() {
return attributes; return attributes;
} }
void UmaRecordContextLost(ContextLostReason reason) {
UMA_HISTOGRAM_ENUMERATION("GPU.ContextLost.DisplayCompositor", reason);
}
} // namespace } // namespace
VizProcessContextProvider::VizProcessContextProvider( VizProcessContextProvider::VizProcessContextProvider(
...@@ -69,10 +76,21 @@ VizProcessContextProvider::VizProcessContextProvider( ...@@ -69,10 +76,21 @@ VizProcessContextProvider::VizProcessContextProvider(
gpu_memory_buffer_manager, gpu_memory_buffer_manager,
image_factory, image_factory,
gpu_channel_manager_delegate, gpu_channel_manager_delegate,
base::ThreadTaskRunnerHandle::Get())), base::ThreadTaskRunnerHandle::Get())) {
cache_controller_(std::make_unique<ContextCacheController>( if (context_result_ == gpu::ContextResult::kSuccess) {
context_->GetImplementation(), auto* gles2_implementation = context_->GetImplementation();
base::ThreadTaskRunnerHandle::Get())) {} cache_controller_ = std::make_unique<ContextCacheController>(
gles2_implementation, base::ThreadTaskRunnerHandle::Get());
// |context_| is owned here so bind an unretained pointer or there will be a
// circular reference preventing destruction.
gles2_implementation->SetLostContextCallback(base::BindOnce(
&VizProcessContextProvider::OnContextLost, base::Unretained(this)));
} else {
// Context initialization failed. Record UMA and cleanup.
UmaRecordContextLost(CONTEXT_INIT_FAILED);
context_.reset();
}
}
VizProcessContextProvider::~VizProcessContextProvider() = default; VizProcessContextProvider::~VizProcessContextProvider() = default;
...@@ -105,9 +123,9 @@ class GrContext* VizProcessContextProvider::GrContext() { ...@@ -105,9 +123,9 @@ class GrContext* VizProcessContextProvider::GrContext() {
gpu::raster::DetermineGrCacheLimitsFromAvailableMemory( gpu::raster::DetermineGrCacheLimitsFromAvailableMemory(
&max_resource_cache_bytes, &max_glyph_cache_texture_bytes); &max_resource_cache_bytes, &max_glyph_cache_texture_bytes);
gr_context_.reset(new skia_bindings::GrContextForGLES2Interface( gr_context_ = std::make_unique<skia_bindings::GrContextForGLES2Interface>(
ContextGL(), ContextSupport(), ContextCapabilities(), ContextGL(), ContextSupport(), ContextCapabilities(),
max_resource_cache_bytes, max_glyph_cache_texture_bytes)); max_resource_cache_bytes, max_glyph_cache_texture_bytes);
return gr_context_->get(); return gr_context_->get();
} }
...@@ -129,9 +147,13 @@ const gpu::GpuFeatureInfo& VizProcessContextProvider::GetGpuFeatureInfo() ...@@ -129,9 +147,13 @@ const gpu::GpuFeatureInfo& VizProcessContextProvider::GetGpuFeatureInfo()
return context_->GetGpuFeatureInfo(); return context_->GetGpuFeatureInfo();
} }
void VizProcessContextProvider::AddObserver(ContextLostObserver* obs) {} void VizProcessContextProvider::AddObserver(ContextLostObserver* obs) {
observers_.AddObserver(obs);
}
void VizProcessContextProvider::RemoveObserver(ContextLostObserver* obs) {} void VizProcessContextProvider::RemoveObserver(ContextLostObserver* obs) {
observers_.RemoveObserver(obs);
}
void VizProcessContextProvider::SetUpdateVSyncParametersCallback( void VizProcessContextProvider::SetUpdateVSyncParametersCallback(
const gpu::InProcessCommandBuffer::UpdateVSyncParametersCallback& const gpu::InProcessCommandBuffer::UpdateVSyncParametersCallback&
...@@ -139,4 +161,16 @@ void VizProcessContextProvider::SetUpdateVSyncParametersCallback( ...@@ -139,4 +161,16 @@ void VizProcessContextProvider::SetUpdateVSyncParametersCallback(
context_->SetUpdateVSyncParametersCallback(callback); context_->SetUpdateVSyncParametersCallback(callback);
} }
void VizProcessContextProvider::OnContextLost() {
for (auto& observer : observers_)
observer.OnContextLost();
if (gr_context_)
gr_context_->OnLostContext();
gpu::CommandBuffer::State state =
context_->GetCommandBuffer()->GetLastState();
UmaRecordContextLost(
GetContextLostReason(state.error, state.context_lost_reason));
}
} // namespace viz } // namespace viz
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <memory> #include <memory>
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/observer_list.h"
#include "base/synchronization/lock.h" #include "base/synchronization/lock.h"
#include "components/viz/common/gpu/context_cache_controller.h" #include "components/viz/common/gpu/context_cache_controller.h"
#include "components/viz/common/gpu/context_provider.h" #include "components/viz/common/gpu/context_provider.h"
...@@ -33,6 +34,7 @@ class GrContextForGLES2Interface; ...@@ -33,6 +34,7 @@ class GrContextForGLES2Interface;
} }
namespace viz { namespace viz {
class ContextLostObserver;
// A ContextProvider used in the viz process to setup an InProcessCommandBuffer // A ContextProvider used in the viz process to setup an InProcessCommandBuffer
// for the display compositor. // for the display compositor.
...@@ -71,6 +73,8 @@ class VIZ_SERVICE_EXPORT VizProcessContextProvider ...@@ -71,6 +73,8 @@ class VIZ_SERVICE_EXPORT VizProcessContextProvider
~VizProcessContextProvider() override; ~VizProcessContextProvider() override;
private: private:
void OnContextLost();
const gpu::ContextCreationAttribs attributes_; const gpu::ContextCreationAttribs attributes_;
base::Lock context_lock_; base::Lock context_lock_;
...@@ -78,6 +82,8 @@ class VIZ_SERVICE_EXPORT VizProcessContextProvider ...@@ -78,6 +82,8 @@ class VIZ_SERVICE_EXPORT VizProcessContextProvider
gpu::ContextResult context_result_; gpu::ContextResult context_result_;
std::unique_ptr<skia_bindings::GrContextForGLES2Interface> gr_context_; std::unique_ptr<skia_bindings::GrContextForGLES2Interface> gr_context_;
std::unique_ptr<ContextCacheController> cache_controller_; std::unique_ptr<ContextCacheController> cache_controller_;
base::ObserverList<ContextLostObserver> observers_;
}; };
} // namespace viz } // namespace viz
......
...@@ -231,8 +231,11 @@ void RootCompositorFrameSinkImpl::Initialize(std::unique_ptr<Display> display) { ...@@ -231,8 +231,11 @@ void RootCompositorFrameSinkImpl::Initialize(std::unique_ptr<Display> display) {
} }
void RootCompositorFrameSinkImpl::DisplayOutputSurfaceLost() { void RootCompositorFrameSinkImpl::DisplayOutputSurfaceLost() {
// TODO(staraz): Implement this. Client should hear about context/output // |display_| has encountered an error and needs to be recreated. Close
// surface lost. // message pipes from the client, the client will see the connection error and
// recreate the CompositorFrameSink+Display.
compositor_frame_sink_binding_.Close();
display_private_binding_.Close();
} }
void RootCompositorFrameSinkImpl::DisplayWillDrawAndSwap( void RootCompositorFrameSinkImpl::DisplayWillDrawAndSwap(
......
...@@ -63,6 +63,10 @@ gles2::GLES2Implementation* GLInProcessContext::GetImplementation() { ...@@ -63,6 +63,10 @@ gles2::GLES2Implementation* GLInProcessContext::GetImplementation() {
return gles2_implementation_.get(); return gles2_implementation_.get();
} }
CommandBuffer* GLInProcessContext::GetCommandBuffer() {
return command_buffer_.get();
}
void GLInProcessContext::SetUpdateVSyncParametersCallback( void GLInProcessContext::SetUpdateVSyncParametersCallback(
const InProcessCommandBuffer::UpdateVSyncParametersCallback& callback) { const InProcessCommandBuffer::UpdateVSyncParametersCallback& callback) {
command_buffer_->SetUpdateVSyncParametersCallback(callback); command_buffer_->SetUpdateVSyncParametersCallback(callback);
......
...@@ -60,6 +60,8 @@ class GL_IN_PROCESS_CONTEXT_EXPORT GLInProcessContext { ...@@ -60,6 +60,8 @@ class GL_IN_PROCESS_CONTEXT_EXPORT GLInProcessContext {
// can be used without making it current. // can be used without making it current.
gles2::GLES2Implementation* GetImplementation(); gles2::GLES2Implementation* GetImplementation();
CommandBuffer* GetCommandBuffer();
void SetUpdateVSyncParametersCallback( void SetUpdateVSyncParametersCallback(
const InProcessCommandBuffer::UpdateVSyncParametersCallback& callback); const InProcessCommandBuffer::UpdateVSyncParametersCallback& callback);
......
...@@ -5,77 +5,14 @@ ...@@ -5,77 +5,14 @@
#include "services/ui/public/cpp/gpu/command_buffer_metrics.h" #include "services/ui/public/cpp/gpu/command_buffer_metrics.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "components/viz/common/gpu/context_lost_reason.h"
namespace ui { namespace ui {
namespace command_buffer_metrics { namespace command_buffer_metrics {
namespace { namespace {
enum CommandBufferContextLostReason { void RecordContextLost(ContextType type, viz::ContextLostReason reason) {
// Don't add new values here.
CONTEXT_INIT_FAILED,
CONTEXT_LOST_GPU_CHANNEL_ERROR,
CONTEXT_PARSE_ERROR_INVALID_SIZE,
CONTEXT_PARSE_ERROR_OUT_OF_BOUNDS,
CONTEXT_PARSE_ERROR_UNKNOWN_COMMAND,
CONTEXT_PARSE_ERROR_INVALID_ARGS,
CONTEXT_PARSE_ERROR_GENERIC_ERROR,
CONTEXT_LOST_GUILTY,
CONTEXT_LOST_INNOCENT,
CONTEXT_LOST_UNKNOWN,
CONTEXT_LOST_OUT_OF_MEMORY,
CONTEXT_LOST_MAKECURRENT_FAILED,
CONTEXT_LOST_INVALID_GPU_MESSAGE,
// Add new values here and update kMaxValue.
// Also update //tools/metrics/histograms/histograms.xml
kMaxValue = CONTEXT_LOST_INVALID_GPU_MESSAGE
};
CommandBufferContextLostReason GetContextLostReason(
gpu::error::Error error,
gpu::error::ContextLostReason reason) {
if (error == gpu::error::kLostContext) {
switch (reason) {
case gpu::error::kGuilty:
return CONTEXT_LOST_GUILTY;
case gpu::error::kInnocent:
return CONTEXT_LOST_INNOCENT;
case gpu::error::kUnknown:
return CONTEXT_LOST_UNKNOWN;
case gpu::error::kOutOfMemory:
return CONTEXT_LOST_OUT_OF_MEMORY;
case gpu::error::kMakeCurrentFailed:
return CONTEXT_LOST_MAKECURRENT_FAILED;
case gpu::error::kGpuChannelLost:
return CONTEXT_LOST_GPU_CHANNEL_ERROR;
case gpu::error::kInvalidGpuMessage:
return CONTEXT_LOST_INVALID_GPU_MESSAGE;
}
}
switch (error) {
case gpu::error::kInvalidSize:
return CONTEXT_PARSE_ERROR_INVALID_SIZE;
case gpu::error::kOutOfBounds:
return CONTEXT_PARSE_ERROR_OUT_OF_BOUNDS;
case gpu::error::kUnknownCommand:
return CONTEXT_PARSE_ERROR_UNKNOWN_COMMAND;
case gpu::error::kInvalidArguments:
return CONTEXT_PARSE_ERROR_INVALID_ARGS;
case gpu::error::kGenericError:
return CONTEXT_PARSE_ERROR_GENERIC_ERROR;
case gpu::error::kDeferCommandUntilLater:
case gpu::error::kDeferLaterCommands:
case gpu::error::kNoError:
case gpu::error::kLostContext:
NOTREACHED();
return CONTEXT_LOST_UNKNOWN;
}
NOTREACHED();
return CONTEXT_LOST_UNKNOWN;
}
void RecordContextLost(ContextType type,
CommandBufferContextLostReason reason) {
switch (type) { switch (type) {
case ContextType::BROWSER_COMPOSITOR: case ContextType::BROWSER_COMPOSITOR:
UMA_HISTOGRAM_ENUMERATION("GPU.ContextLost.BrowserCompositor", reason); UMA_HISTOGRAM_ENUMERATION("GPU.ContextLost.BrowserCompositor", reason);
...@@ -153,14 +90,14 @@ std::string ContextTypeToString(ContextType type) { ...@@ -153,14 +90,14 @@ std::string ContextTypeToString(ContextType type) {
} }
void UmaRecordContextInitFailed(ContextType type) { void UmaRecordContextInitFailed(ContextType type) {
RecordContextLost(type, CONTEXT_INIT_FAILED); RecordContextLost(type, viz::CONTEXT_INIT_FAILED);
} }
void UmaRecordContextLost(ContextType type, void UmaRecordContextLost(ContextType type,
gpu::error::Error error, gpu::error::Error error,
gpu::error::ContextLostReason reason) { gpu::error::ContextLostReason reason) {
CommandBufferContextLostReason converted_reason = viz::ContextLostReason converted_reason =
GetContextLostReason(error, reason); viz::GetContextLostReason(error, reason);
RecordContextLost(type, converted_reason); RecordContextLost(type, converted_reason);
} }
......
...@@ -116115,6 +116115,8 @@ uploading your change for review. ...@@ -116115,6 +116115,8 @@ uploading your change for review.
label="A BrowserCompositor GPU command buffer context"/> label="A BrowserCompositor GPU command buffer context"/>
<suffix name="BrowserMainThread" <suffix name="BrowserMainThread"
label="A BrowserMainThread GPU command buffer context"/> label="A BrowserMainThread GPU command buffer context"/>
<suffix name="DisplayCompositor"
label="A display compositor GPU command buffer context"/>
<suffix name="Media" label="The media worker command buffer context"/> <suffix name="Media" label="The media worker command buffer context"/>
<suffix name="MusClient" label="A mus client command buffer context"/> <suffix name="MusClient" label="A mus client command buffer context"/>
<suffix name="RenderCompositor" <suffix name="RenderCompositor"
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment