Commit baf79d9d authored by Jonathan Backer's avatar Jonathan Backer Committed by Commit Bot

Check the device reset status more often

Sometimes a device driver signals an internal error and we just need to
reset. This CL checks for reset more aggressively on all
{SharedContextState,SharedImageStub}::MakeCurrent calls. This
will hopefully turn some crashes into restarts.

Bug: 1079161,1081806
Change-Id: I260f90b4ed2ba63be3cf7ca6759c5aa086f0c46f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2214919
Commit-Queue: Jonathan Backer <backer@chromium.org>
Reviewed-by: default avatarPeng Huang <penghuang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#773838}
parent 6aa19a2a
...@@ -1640,9 +1640,10 @@ bool SkiaOutputSurfaceImplOnGpu::MakeCurrent(bool need_fbo0) { ...@@ -1640,9 +1640,10 @@ bool SkiaOutputSurfaceImplOnGpu::MakeCurrent(bool need_fbo0) {
if (!context_state_->MakeCurrent(gl_surface, need_gl)) { if (!context_state_->MakeCurrent(gl_surface, need_gl)) {
LOG(ERROR) << "Failed to make current."; LOG(ERROR) << "Failed to make current.";
dependency_->DidLoseContext( dependency_->DidLoseContext(
gpu::error::kMakeCurrentFailed, *context_state_->context_lost_reason(),
GURL("chrome://gpu/SkiaOutputSurfaceImplOnGpu::MakeCurrent")); GURL("chrome://gpu/SkiaOutputSurfaceImplOnGpu::MakeCurrent"));
MarkContextLost(CONTEXT_LOST_MAKECURRENT_FAILED); MarkContextLost(GetContextLostReason(
gpu::error::kLostContext, *context_state_->context_lost_reason()));
return false; return false;
} }
context_state_->set_need_context_state_reset(true); context_state_->set_need_context_state_reset(true);
......
...@@ -208,7 +208,8 @@ bool AllowedBetweenBeginEndRaster(CommandId command) { ...@@ -208,7 +208,8 @@ bool AllowedBetweenBeginEndRaster(CommandId command) {
// avoid it as much as possible. // avoid it as much as possible.
class RasterDecoderImpl final : public RasterDecoder, class RasterDecoderImpl final : public RasterDecoder,
public gles2::ErrorStateClient, public gles2::ErrorStateClient,
public ServiceFontManager::Client { public ServiceFontManager::Client,
public SharedContextState::ContextLostObserver {
public: public:
RasterDecoderImpl(DecoderClient* client, RasterDecoderImpl(DecoderClient* client,
CommandBufferServiceBase* command_buffer_service, CommandBufferServiceBase* command_buffer_service,
...@@ -365,6 +366,9 @@ class RasterDecoderImpl final : public RasterDecoder, ...@@ -365,6 +366,9 @@ class RasterDecoderImpl final : public RasterDecoder,
scoped_refptr<Buffer> GetShmBuffer(uint32_t shm_id) override; scoped_refptr<Buffer> GetShmBuffer(uint32_t shm_id) override;
void ReportProgress() override; void ReportProgress() override;
// SharedContextState::ContextLostObserver implementation.
void OnContextLost() override;
private: private:
gles2::ContextState* state() const { gles2::ContextState* state() const {
if (use_passthrough_) { if (use_passthrough_) {
...@@ -583,8 +587,6 @@ class RasterDecoderImpl final : public RasterDecoder, ...@@ -583,8 +587,6 @@ class RasterDecoderImpl final : public RasterDecoder,
bool use_passthrough_ = false; bool use_passthrough_ = false;
bool use_ddl_ = false; bool use_ddl_ = false;
bool reset_by_robustness_extension_ = false;
// The current decoder error communicates the decoder error through command // The current decoder error communicates the decoder error through command
// processing functions that do not return the error value. Should be set // processing functions that do not return the error value. Should be set
// only if not returning an error. // only if not returning an error.
...@@ -756,9 +758,12 @@ RasterDecoderImpl::RasterDecoderImpl( ...@@ -756,9 +758,12 @@ RasterDecoderImpl::RasterDecoderImpl(
font_manager_(base::MakeRefCounted<ServiceFontManager>(this)), font_manager_(base::MakeRefCounted<ServiceFontManager>(this)),
is_privileged_(is_privileged) { is_privileged_(is_privileged) {
DCHECK(shared_context_state_); DCHECK(shared_context_state_);
shared_context_state_->AddContextLostObserver(this);
} }
RasterDecoderImpl::~RasterDecoderImpl() = default; RasterDecoderImpl::~RasterDecoderImpl() {
shared_context_state_->RemoveContextLostObserver(this);
}
base::WeakPtr<DecoderContext> RasterDecoderImpl::AsWeakPtr() { base::WeakPtr<DecoderContext> RasterDecoderImpl::AsWeakPtr() {
return weak_ptr_factory_.GetWeakPtr(); return weak_ptr_factory_.GetWeakPtr();
...@@ -893,18 +898,11 @@ bool RasterDecoderImpl::MakeCurrent() { ...@@ -893,18 +898,11 @@ bool RasterDecoderImpl::MakeCurrent() {
if (shared_context_state_->context_lost() || if (shared_context_state_->context_lost() ||
!shared_context_state_->MakeCurrent(nullptr)) { !shared_context_state_->MakeCurrent(nullptr)) {
LOG(ERROR) << " RasterDecoderImpl: Context lost during MakeCurrent."; LOG(ERROR) << " RasterDecoderImpl: Context lost during MakeCurrent.";
MarkContextLost(error::kMakeCurrentFailed);
return false; return false;
} }
DCHECK_EQ(api(), gl::g_current_gl_context); DCHECK_EQ(api(), gl::g_current_gl_context);
if (CheckResetStatus()) {
LOG(ERROR)
<< " RasterDecoderImpl: Context reset detected after MakeCurrent.";
return false;
}
// Rebind textures if the service ids may have changed. // Rebind textures if the service ids may have changed.
RestoreAllExternalTextureBindingsIfNeeded(); RestoreAllExternalTextureBindingsIfNeeded();
...@@ -1115,55 +1113,27 @@ void RasterDecoderImpl::SetLevelInfo(uint32_t client_id, ...@@ -1115,55 +1113,27 @@ void RasterDecoderImpl::SetLevelInfo(uint32_t client_id,
} }
bool RasterDecoderImpl::WasContextLost() const { bool RasterDecoderImpl::WasContextLost() const {
return context_lost_; return shared_context_state_->context_lost();
} }
bool RasterDecoderImpl::WasContextLostByRobustnessExtension() const { bool RasterDecoderImpl::WasContextLostByRobustnessExtension() const {
return WasContextLost() && reset_by_robustness_extension_; return shared_context_state_->device_needs_reset();
} }
void RasterDecoderImpl::MarkContextLost(error::ContextLostReason reason) { void RasterDecoderImpl::MarkContextLost(error::ContextLostReason reason) {
// Only lose the context once. shared_context_state_->MarkContextLost(reason);
if (WasContextLost()) }
return;
// Don't make GL calls in here, the context might not be current. void RasterDecoderImpl::OnContextLost() {
context_lost_ = true; DCHECK(shared_context_state_->context_lost());
command_buffer_service()->SetContextLostReason(reason); command_buffer_service()->SetContextLostReason(
*shared_context_state_->context_lost_reason());
current_decoder_error_ = error::kLostContext; current_decoder_error_ = error::kLostContext;
} }
bool RasterDecoderImpl::CheckResetStatus() { bool RasterDecoderImpl::CheckResetStatus() {
DCHECK(!WasContextLost()); DCHECK(!WasContextLost());
DCHECK(shared_context_state_->context()->IsCurrent(nullptr)); return shared_context_state_->CheckResetStatus(/*needs_gl=*/false);
// If the reason for the call was a GL error, we can try to determine the
// reset status more accurately.
GLenum driver_status =
shared_context_state_->context()->CheckStickyGraphicsResetStatus();
if (driver_status == GL_NO_ERROR)
return false;
LOG(ERROR) << "RasterDecoder context lost via ARB/EXT_robustness. Reset "
"status = "
<< gles2::GLES2Util::GetStringEnum(driver_status);
switch (driver_status) {
case GL_GUILTY_CONTEXT_RESET_ARB:
MarkContextLost(error::kGuilty);
break;
case GL_INNOCENT_CONTEXT_RESET_ARB:
MarkContextLost(error::kInnocent);
break;
case GL_UNKNOWN_CONTEXT_RESET_ARB:
MarkContextLost(error::kUnknown);
break;
default:
NOTREACHED();
return false;
}
reset_by_robustness_extension_ = true;
return true;
} }
gles2::Logger* RasterDecoderImpl::GetLogger() { gles2::Logger* RasterDecoderImpl::GetLogger() {
...@@ -1502,14 +1472,13 @@ void RasterDecoderImpl::DisableFlushWorkaroundForTest() { ...@@ -1502,14 +1472,13 @@ void RasterDecoderImpl::DisableFlushWorkaroundForTest() {
void RasterDecoderImpl::OnContextLostError() { void RasterDecoderImpl::OnContextLostError() {
if (!WasContextLost()) { if (!WasContextLost()) {
// Need to lose current context before broadcasting! // Need to lose current context before broadcasting!
CheckResetStatus(); shared_context_state_->CheckResetStatus(/*needs_gl=*/false);
reset_by_robustness_extension_ = true;
} }
} }
void RasterDecoderImpl::OnOutOfMemoryError() { void RasterDecoderImpl::OnOutOfMemoryError() {
if (lose_context_when_out_of_memory_ && !WasContextLost()) { if (lose_context_when_out_of_memory_ && !WasContextLost()) {
if (!CheckResetStatus()) { if (!shared_context_state_->CheckResetStatus(/*needs_gl=*/false)) {
MarkContextLost(error::kOutOfMemory); MarkContextLost(error::kOutOfMemory);
} }
} }
......
...@@ -69,7 +69,7 @@ size_t MaxNumSkSurface() { ...@@ -69,7 +69,7 @@ size_t MaxNumSkSurface() {
namespace gpu { namespace gpu {
void SharedContextState::compileError(const char* shader, const char* errors) { void SharedContextState::compileError(const char* shader, const char* errors) {
if (!context_lost_) { if (!context_lost()) {
LOG(ERROR) << "Skia shader compilation error\n" LOG(ERROR) << "Skia shader compilation error\n"
<< "------------------------\n" << "------------------------\n"
<< shader << "\nErrors:\n" << shader << "\nErrors:\n"
...@@ -163,7 +163,7 @@ SharedContextState::~SharedContextState() { ...@@ -163,7 +163,7 @@ SharedContextState::~SharedContextState() {
// The context should be current so that texture deletes that result from // The context should be current so that texture deletes that result from
// destroying the cache happen in the right context (unless the context is // destroying the cache happen in the right context (unless the context is
// lost in which case we don't delete the textures). // lost in which case we don't delete the textures).
DCHECK(IsCurrent(nullptr) || context_lost_); DCHECK(IsCurrent(nullptr) || context_lost());
transfer_cache_.reset(); transfer_cache_.reset();
// We should have the last ref on this GrContext to ensure we're not holding // We should have the last ref on this GrContext to ensure we're not holding
...@@ -425,28 +425,23 @@ bool SharedContextState::InitializeGL( ...@@ -425,28 +425,23 @@ bool SharedContextState::InitializeGL(
} }
bool SharedContextState::MakeCurrent(gl::GLSurface* surface, bool needs_gl) { bool SharedContextState::MakeCurrent(gl::GLSurface* surface, bool needs_gl) {
if (context_lost_) if (context_lost())
return false; return false;
if (gr_context_ && gr_context_->abandoned()) { const bool using_gl = GrContextIsGL() || needs_gl;
MarkContextLost(); if (using_gl) {
return false;
}
if (!GrContextIsGL() && !needs_gl)
return true;
gl::GLSurface* dont_care_surface = gl::GLSurface* dont_care_surface =
last_current_surface_ ? last_current_surface_ : surface_.get(); last_current_surface_ ? last_current_surface_ : surface_.get();
surface = surface ? surface : dont_care_surface; surface = surface ? surface : dont_care_surface;
if (!context_->MakeCurrent(surface)) { if (!context_->MakeCurrent(surface)) {
MarkContextLost(); MarkContextLost(error::kMakeCurrentFailed);
return false; return false;
} }
last_current_surface_ = surface; last_current_surface_ = surface;
}
return true; return !CheckResetStatus(needs_gl);
} }
void SharedContextState::ReleaseCurrent(gl::GLSurface* surface) { void SharedContextState::ReleaseCurrent(gl::GLSurface* surface) {
...@@ -457,14 +452,14 @@ void SharedContextState::ReleaseCurrent(gl::GLSurface* surface) { ...@@ -457,14 +452,14 @@ void SharedContextState::ReleaseCurrent(gl::GLSurface* surface) {
return; return;
last_current_surface_ = nullptr; last_current_surface_ = nullptr;
if (!context_lost_) if (!context_lost())
context_->ReleaseCurrent(surface); context_->ReleaseCurrent(surface);
} }
void SharedContextState::MarkContextLost() { void SharedContextState::MarkContextLost(error::ContextLostReason reason) {
if (!context_lost_) { if (!context_lost()) {
scoped_refptr<SharedContextState> prevent_last_ref_drop = this; scoped_refptr<SharedContextState> prevent_last_ref_drop = this;
context_lost_ = true; context_lost_reason_ = reason;
// context_state_ could be nullptr for some unittests. // context_state_ could be nullptr for some unittests.
if (context_state_) if (context_state_)
context_state_->MarkContextLost(); context_state_->MarkContextLost();
...@@ -487,7 +482,7 @@ void SharedContextState::MarkContextLost() { ...@@ -487,7 +482,7 @@ void SharedContextState::MarkContextLost() {
bool SharedContextState::IsCurrent(gl::GLSurface* surface) { bool SharedContextState::IsCurrent(gl::GLSurface* surface) {
if (!GrContextIsGL()) if (!GrContextIsGL())
return true; return true;
if (context_lost_) if (context_lost())
return false; return false;
return context_->IsCurrent(surface); return context_->IsCurrent(surface);
} }
...@@ -670,4 +665,46 @@ QueryManager* SharedContextState::GetQueryManager() { ...@@ -670,4 +665,46 @@ QueryManager* SharedContextState::GetQueryManager() {
return nullptr; return nullptr;
} }
bool SharedContextState::CheckResetStatus(bool needs_gl) {
DCHECK(!context_lost());
if (device_needs_reset_)
return true;
// Maybe Skia detected VK_ERROR_DEVICE_LOST.
if (gr_context_ && gr_context_->abandoned()) {
LOG(ERROR) << "SharedContextState context lost via Skia.";
device_needs_reset_ = true;
MarkContextLost(error::kUnknown);
return true;
}
if (!GrContextIsGL() && !needs_gl)
return false;
GLenum driver_status = context()->CheckStickyGraphicsResetStatus();
if (driver_status == GL_NO_ERROR)
return false;
LOG(ERROR) << "SharedContextState context lost via ARB/EXT_robustness. Reset "
"status = "
<< gles2::GLES2Util::GetStringEnum(driver_status);
switch (driver_status) {
case GL_GUILTY_CONTEXT_RESET_ARB:
MarkContextLost(error::kGuilty);
break;
case GL_INNOCENT_CONTEXT_RESET_ARB:
MarkContextLost(error::kInnocent);
break;
case GL_UNKNOWN_CONTEXT_RESET_ARB:
MarkContextLost(error::kUnknown);
break;
default:
NOTREACHED();
break;
}
device_needs_reset_ = true;
return false;
}
} // namespace gpu } // namespace gpu
...@@ -13,8 +13,11 @@ ...@@ -13,8 +13,11 @@
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/observer_list.h" #include "base/observer_list.h"
#include "base/optional.h"
#include "base/trace_event/memory_dump_provider.h" #include "base/trace_event/memory_dump_provider.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "gpu/command_buffer/common/constants.h"
#include "gpu/command_buffer/common/gl2_types.h"
#include "gpu/command_buffer/common/skia_utils.h" #include "gpu/command_buffer/common/skia_utils.h"
#include "gpu/command_buffer/service/gl_context_virtual_delegate.h" #include "gpu/command_buffer/service/gl_context_virtual_delegate.h"
#include "gpu/command_buffer/service/memory_tracking.h" #include "gpu/command_buffer/service/memory_tracking.h"
...@@ -92,7 +95,7 @@ class GPU_GLES2_EXPORT SharedContextState ...@@ -92,7 +95,7 @@ class GPU_GLES2_EXPORT SharedContextState
bool MakeCurrent(gl::GLSurface* surface, bool needs_gl = false); bool MakeCurrent(gl::GLSurface* surface, bool needs_gl = false);
void ReleaseCurrent(gl::GLSurface* surface); void ReleaseCurrent(gl::GLSurface* surface);
void MarkContextLost(); void MarkContextLost(error::ContextLostReason reason = error::kUnknown);
bool IsCurrent(gl::GLSurface* surface); bool IsCurrent(gl::GLSurface* surface);
void PurgeMemory( void PurgeMemory(
...@@ -122,7 +125,10 @@ class GPU_GLES2_EXPORT SharedContextState ...@@ -122,7 +125,10 @@ class GPU_GLES2_EXPORT SharedContextState
void compileError(const char* shader, const char* errors) override; void compileError(const char* shader, const char* errors) override;
gles2::FeatureInfo* feature_info() { return feature_info_.get(); } gles2::FeatureInfo* feature_info() { return feature_info_.get(); }
gles2::ContextState* context_state() const { return context_state_.get(); } gles2::ContextState* context_state() const { return context_state_.get(); }
bool context_lost() const { return context_lost_; } bool context_lost() const { return !!context_lost_reason_; }
base::Optional<error::ContextLostReason> context_lost_reason() {
return context_lost_reason_;
}
bool need_context_state_reset() const { return need_context_state_reset_; } bool need_context_state_reset() const { return need_context_state_reset_; }
void set_need_context_state_reset(bool reset) { void set_need_context_state_reset(bool reset) {
need_context_state_reset_ = reset; need_context_state_reset_ = reset;
...@@ -179,6 +185,11 @@ class GPU_GLES2_EXPORT SharedContextState ...@@ -179,6 +185,11 @@ class GPU_GLES2_EXPORT SharedContextState
return found->second->unique(); return found->second->unique();
} }
// Updates |context_lost_reason| and returns true if lost
// (e.g. VK_ERROR_DEVICE_LOST or GL_UNKNOWN_CONTEXT_RESET_ARB).
bool CheckResetStatus(bool needs_gl);
bool device_needs_reset() { return device_needs_reset_; }
private: private:
friend class base::RefCounted<SharedContextState>; friend class base::RefCounted<SharedContextState>;
...@@ -265,11 +276,13 @@ class GPU_GLES2_EXPORT SharedContextState ...@@ -265,11 +276,13 @@ class GPU_GLES2_EXPORT SharedContextState
// driver's GL state. // driver's GL state.
bool need_context_state_reset_ = false; bool need_context_state_reset_ = false;
bool context_lost_ = false; base::Optional<error::ContextLostReason> context_lost_reason_;
base::ObserverList<ContextLostObserver>::Unchecked context_lost_observers_; base::ObserverList<ContextLostObserver>::Unchecked context_lost_observers_;
base::MRUCache<void*, sk_sp<SkSurface>> sk_surface_cache_; base::MRUCache<void*, sk_sp<SkSurface>> sk_surface_cache_;
bool device_needs_reset_ = false;
base::WeakPtrFactory<SharedContextState> weak_ptr_factory_{this}; base::WeakPtrFactory<SharedContextState> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(SharedContextState); DISALLOW_COPY_AND_ASSIGN(SharedContextState);
......
...@@ -83,17 +83,19 @@ void InProcessGpuThreadHolder::InitializeOnGpuThread( ...@@ -83,17 +83,19 @@ void InProcessGpuThreadHolder::InitializeOnGpuThread(
GpuDriverBugWorkarounds gpu_driver_bug_workarounds( GpuDriverBugWorkarounds gpu_driver_bug_workarounds(
gpu_feature_info_.enabled_gpu_driver_bug_workarounds); gpu_feature_info_.enabled_gpu_driver_bug_workarounds);
bool use_virtualized_gl_context_ = false; bool use_virtualized_gl_context = false;
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
// Virtualize GpuPreference:::kLowPower contexts by default on OS X to prevent // Virtualize GpuPreference:::kLowPower contexts by default on OS X to prevent
// performance regressions when enabling FCM. https://crbug.com/180463 // performance regressions when enabling FCM. https://crbug.com/180463
use_virtualized_gl_context_ = true; use_virtualized_gl_context = true;
#endif #endif
use_virtualized_gl_context_ |= use_virtualized_gl_context |=
gpu_driver_bug_workarounds.use_virtualized_gl_contexts; gpu_driver_bug_workarounds.use_virtualized_gl_contexts;
if (use_virtualized_gl_context)
share_group_->SetSharedContext(context_.get());
context_state_ = base::MakeRefCounted<SharedContextState>( context_state_ = base::MakeRefCounted<SharedContextState>(
share_group_, surface_, context_, use_virtualized_gl_context_, share_group_, surface_, context_, use_virtualized_gl_context,
base::DoNothing(), gpu_preferences_.gr_context_type); base::DoNothing(), gpu_preferences_.gr_context_type);
auto feature_info = base::MakeRefCounted<gles2::FeatureInfo>( auto feature_info = base::MakeRefCounted<gles2::FeatureInfo>(
gpu_driver_bug_workarounds, gpu_feature_info_); gpu_driver_bug_workarounds, gpu_feature_info_);
......
...@@ -400,13 +400,9 @@ bool SharedImageStub::MakeContextCurrent() { ...@@ -400,13 +400,9 @@ bool SharedImageStub::MakeContextCurrent() {
// |factory_| never writes to the surface, so pass nullptr to // |factory_| never writes to the surface, so pass nullptr to
// improve performance. https://crbug.com/457431 // improve performance. https://crbug.com/457431
auto* context = context_state_->real_context(); auto* context = context_state_->real_context();
if (context->IsCurrent(nullptr) || if (context->IsCurrent(nullptr))
context->MakeCurrent(context_state_->surface())) { return !context_state_->CheckResetStatus(/*needs_gl=*/true);
return true; return context_state_->MakeCurrent(/*surface=*/nullptr, /*needs_gl=*/true);
}
context_state_->MarkContextLost();
LOG(ERROR) << "SharedImageStub: MakeCurrent failed";
return false;
} }
ContextResult SharedImageStub::MakeContextCurrentAndCreateFactory() { ContextResult SharedImageStub::MakeContextCurrentAndCreateFactory() {
......
...@@ -104,12 +104,9 @@ bool SharedImageInterfaceInProcess::MakeContextCurrent() { ...@@ -104,12 +104,9 @@ bool SharedImageInterfaceInProcess::MakeContextCurrent() {
// |shared_image_factory_| never writes to the surface, so skip unnecessary // |shared_image_factory_| never writes to the surface, so skip unnecessary
// MakeCurrent to improve performance. https://crbug.com/457431 // MakeCurrent to improve performance. https://crbug.com/457431
auto* context = context_state_->real_context(); auto* context = context_state_->real_context();
if (context->IsCurrent(nullptr) || if (context->IsCurrent(nullptr))
context->MakeCurrent(context_state_->surface())) return !context_state_->CheckResetStatus(/*needs_gl=*/true);
return true; return context_state_->MakeCurrent(/*surface=*/nullptr, /*needs_gl=*/true);
context_state_->MarkContextLost();
return false;
} }
void SharedImageInterfaceInProcess::LazyCreateSharedImageFactory() { void SharedImageInterfaceInProcess::LazyCreateSharedImageFactory() {
......
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