Commit 6736a9c5 authored by Antoine Labour's avatar Antoine Labour Committed by Commit Bot

Fail decoder / SharedContextState creation if context is lost

When the context is lost during creation, on some drivers we may have had bogus values
during initialization for the static queries, which means we might have constructed a
ContextState that's inconsistent with other ContextStates for the same real context,
which causes problems when doing virtualized context switches.
So check reset state after initialization and fail if the context is lost.

Bug: 946978
Change-Id: I38fb73d819dfcedf0565e6b4345c3700c49fbb07
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1659644
Commit-Queue: Antoine Labour <piman@chromium.org>
Reviewed-by: default avatarZhenyao Mo <zmo@chromium.org>
Auto-Submit: Antoine Labour <piman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#670301}
parent f2e2b06d
...@@ -509,6 +509,7 @@ test("gpu_unittests") { ...@@ -509,6 +509,7 @@ test("gpu_unittests") {
"command_buffer/service/shader_manager_unittest.cc", "command_buffer/service/shader_manager_unittest.cc",
"command_buffer/service/shader_translator_cache_unittest.cc", "command_buffer/service/shader_translator_cache_unittest.cc",
"command_buffer/service/shader_translator_unittest.cc", "command_buffer/service/shader_translator_unittest.cc",
"command_buffer/service/shared_context_state_unittest.cc",
"command_buffer/service/sync_point_manager_unittest.cc", "command_buffer/service/sync_point_manager_unittest.cc",
"command_buffer/service/test_helper.cc", "command_buffer/service/test_helper.cc",
"command_buffer/service/test_helper.h", "command_buffer/service/test_helper.h",
......
...@@ -4082,6 +4082,18 @@ gpu::ContextResult GLES2DecoderImpl::Initialize( ...@@ -4082,6 +4082,18 @@ gpu::ContextResult GLES2DecoderImpl::Initialize(
api()->glHintFn(GL_TEXTURE_FILTERING_HINT_CHROMIUM, GL_NICEST); api()->glHintFn(GL_TEXTURE_FILTERING_HINT_CHROMIUM, GL_NICEST);
} }
if (CheckResetStatus()) {
// If the context was lost at any point before or during initialization, the
// values queried from the driver could be bogus, and potentially
// inconsistent between various ContextStates on the same underlying real GL
// context. Make sure to report the failure early, to not allow virtualized
// context switches in that case.
LOG(ERROR)
<< " GLES2DecoderImpl: Context reset detected after initialization.";
group_->LoseContexts(error::kUnknown);
return gpu::ContextResult::kTransientFailure;
}
return gpu::ContextResult::kSuccess; return gpu::ContextResult::kSuccess;
} }
......
...@@ -582,6 +582,14 @@ TEST_P(GLES3DecoderTest, WaitSyncValidArgs) { ...@@ -582,6 +582,14 @@ TEST_P(GLES3DecoderTest, WaitSyncValidArgs) {
EXPECT_EQ(GL_NO_ERROR, GetGLError()); EXPECT_EQ(GL_NO_ERROR, GetGLError());
} }
TEST_P(GLES2DecoderManualInitTest, InitFailsIfLostContext) {
InitState init;
init.extensions = "GL_KHR_robustness";
init.lose_context_on_init = true;
EXPECT_EQ(ContextResult::kTransientFailure,
MaybeInitDecoderWithWorkarounds(init, GpuDriverBugWorkarounds()));
}
TEST_P(GLES2DecoderManualInitTest, BindGeneratesResourceFalse) { TEST_P(GLES2DecoderManualInitTest, BindGeneratesResourceFalse) {
InitState init; InitState init;
InitDecoder(init); InitDecoder(init);
......
...@@ -169,21 +169,10 @@ void GLES2DecoderTestBase::AddExpectationsForVertexAttribManager() { ...@@ -169,21 +169,10 @@ void GLES2DecoderTestBase::AddExpectationsForVertexAttribManager() {
} }
} }
GLES2DecoderTestBase::InitState::InitState() GLES2DecoderTestBase::InitState::InitState() = default;
: extensions("GL_EXT_framebuffer_object"),
gl_version("2.1"),
has_alpha(false),
has_depth(false),
has_stencil(false),
request_alpha(false),
request_depth(false),
request_stencil(false),
bind_generates_resource(false),
lose_context_when_out_of_memory(false),
use_native_vao(true),
context_type(CONTEXT_TYPE_OPENGLES2) {}
GLES2DecoderTestBase::InitState::InitState(const InitState& other) = default; GLES2DecoderTestBase::InitState::InitState(const InitState& other) = default;
GLES2DecoderTestBase::InitState& GLES2DecoderTestBase::InitState::operator=(
const InitState& other) = default;
void GLES2DecoderTestBase::InitDecoder(const InitState& init) { void GLES2DecoderTestBase::InitDecoder(const InitState& init) {
gpu::GpuDriverBugWorkarounds workarounds; gpu::GpuDriverBugWorkarounds workarounds;
...@@ -193,6 +182,13 @@ void GLES2DecoderTestBase::InitDecoder(const InitState& init) { ...@@ -193,6 +182,13 @@ void GLES2DecoderTestBase::InitDecoder(const InitState& init) {
void GLES2DecoderTestBase::InitDecoderWithWorkarounds( void GLES2DecoderTestBase::InitDecoderWithWorkarounds(
const InitState& init, const InitState& init,
const gpu::GpuDriverBugWorkarounds& workarounds) { const gpu::GpuDriverBugWorkarounds& workarounds) {
ContextResult result = MaybeInitDecoderWithWorkarounds(init, workarounds);
ASSERT_EQ(result, gpu::ContextResult::kSuccess);
}
ContextResult GLES2DecoderTestBase::MaybeInitDecoderWithWorkarounds(
const InitState& init,
const gpu::GpuDriverBugWorkarounds& workarounds) {
InitState normalized_init = init; InitState normalized_init = init;
NormalizeInitState(&normalized_init); NormalizeInitState(&normalized_init);
// For easier substring/extension matching // For easier substring/extension matching
...@@ -482,6 +478,12 @@ void GLES2DecoderTestBase::InitDecoderWithWorkarounds( ...@@ -482,6 +478,12 @@ void GLES2DecoderTestBase::InitDecoderWithWorkarounds(
} }
#endif #endif
if (context_->WasAllocatedUsingRobustnessExtension()) {
EXPECT_CALL(*gl_, GetGraphicsResetStatusARB())
.WillOnce(Return(init.lose_context_on_init ? GL_GUILTY_CONTEXT_RESET_ARB
: GL_NO_ERROR));
}
scoped_refptr<gpu::Buffer> buffer = scoped_refptr<gpu::Buffer> buffer =
command_buffer_service_->CreateTransferBufferHelper(kSharedBufferSize, command_buffer_service_->CreateTransferBufferHelper(kSharedBufferSize,
&shared_memory_id_); &shared_memory_id_);
...@@ -512,9 +514,14 @@ void GLES2DecoderTestBase::InitDecoderWithWorkarounds( ...@@ -512,9 +514,14 @@ void GLES2DecoderTestBase::InitDecoderWithWorkarounds(
decoder_->SetCopyTexImageBlitterForTest(copy_tex_image_blitter_); decoder_->SetCopyTexImageBlitterForTest(copy_tex_image_blitter_);
} }
ASSERT_EQ(decoder_->Initialize(surface_, context_, false, gpu::ContextResult result = decoder_->Initialize(
DisallowedFeatures(), attribs), surface_, context_, false, DisallowedFeatures(), attribs);
gpu::ContextResult::kSuccess); if (result != gpu::ContextResult::kSuccess) {
decoder_->Destroy(false /* have_context */);
decoder_.reset();
group_->Destroy(mock_decoder_.get(), false);
return result;
}
EXPECT_CALL(*context_, MakeCurrent(surface_.get())).WillOnce(Return(true)); EXPECT_CALL(*context_, MakeCurrent(surface_.get())).WillOnce(Return(true));
if (context_->WasAllocatedUsingRobustnessExtension()) { if (context_->WasAllocatedUsingRobustnessExtension()) {
...@@ -566,6 +573,7 @@ void GLES2DecoderTestBase::InitDecoderWithWorkarounds( ...@@ -566,6 +573,7 @@ void GLES2DecoderTestBase::InitDecoderWithWorkarounds(
} }
EXPECT_EQ(GL_NO_ERROR, GetGLError()); EXPECT_EQ(GL_NO_ERROR, GetGLError());
return result;
} }
void GLES2DecoderTestBase::ResetDecoder() { void GLES2DecoderTestBase::ResetDecoder() {
......
...@@ -216,24 +216,29 @@ class GLES2DecoderTestBase : public ::testing::TestWithParam<bool>, ...@@ -216,24 +216,29 @@ class GLES2DecoderTestBase : public ::testing::TestWithParam<bool>,
struct InitState { struct InitState {
InitState(); InitState();
InitState(const InitState& other); InitState(const InitState& other);
InitState& operator=(const InitState& other);
std::string extensions;
std::string gl_version; std::string extensions = "GL_EXT_framebuffer_object";
bool has_alpha; std::string gl_version = "2.1";
bool has_depth; bool has_alpha = false;
bool has_stencil; bool has_depth = false;
bool request_alpha; bool has_stencil = false;
bool request_depth; bool request_alpha = false;
bool request_stencil; bool request_depth = false;
bool bind_generates_resource; bool request_stencil = false;
bool lose_context_when_out_of_memory; bool bind_generates_resource = false;
bool use_native_vao; // default is true. bool lose_context_when_out_of_memory = false;
ContextType context_type; bool lose_context_on_init = false;
bool use_native_vao = true;
ContextType context_type = CONTEXT_TYPE_OPENGLES2;
}; };
void InitDecoder(const InitState& init); void InitDecoder(const InitState& init);
void InitDecoderWithWorkarounds(const InitState& init, void InitDecoderWithWorkarounds(const InitState& init,
const GpuDriverBugWorkarounds& workarounds); const GpuDriverBugWorkarounds& workarounds);
ContextResult MaybeInitDecoderWithWorkarounds(
const InitState& init,
const GpuDriverBugWorkarounds& workarounds);
void ResetDecoder(); void ResetDecoder();
......
...@@ -175,6 +175,11 @@ void RasterDecoderTestBase::InitDecoder(const InitState& init) { ...@@ -175,6 +175,11 @@ void RasterDecoderTestBase::InitDecoder(const InitState& init) {
ContextStateTestHelpers::SetupInitState(gl_.get(), feature_info(), ContextStateTestHelpers::SetupInitState(gl_.get(), feature_info(),
gfx::Size(1, 1)); gfx::Size(1, 1));
if (context_->WasAllocatedUsingRobustnessExtension()) {
EXPECT_CALL(*gl_, GetGraphicsResetStatusARB())
.WillOnce(Return(GL_NO_ERROR));
}
shared_context_state_ = base::MakeRefCounted<SharedContextState>( shared_context_state_ = base::MakeRefCounted<SharedContextState>(
new gl::GLShareGroup(), surface_, context_, new gl::GLShareGroup(), surface_, context_,
feature_info()->workarounds().use_virtualized_gl_contexts, feature_info()->workarounds().use_virtualized_gl_contexts,
......
...@@ -211,6 +211,24 @@ bool SharedContextState::InitializeGL( ...@@ -211,6 +211,24 @@ bool SharedContextState::InitializeGL(
context_state_->InitCapabilities(nullptr); context_state_->InitCapabilities(nullptr);
context_state_->InitState(nullptr); context_state_->InitState(nullptr);
bool has_robustness = (feature_info_->feature_flags().arb_robustness ||
feature_info_->feature_flags().khr_robustness ||
feature_info_->feature_flags().ext_robustness) &&
real_context_->WasAllocatedUsingRobustnessExtension();
if (has_robustness) {
GLenum driver_status = api->glGetGraphicsResetStatusARBFn();
if (driver_status != GL_NO_ERROR) {
// If the context was lost at any point before or during initialization,
// the values queried from the driver could be bogus, and potentially
// inconsistent between various ContextStates on the same underlying real
// GL context. Make sure to report the failure early, to not allow
// virtualized context switches in that case.
feature_info_ = nullptr;
context_state_ = nullptr;
return false;
}
}
if (use_virtualized_gl_contexts_) { if (use_virtualized_gl_contexts_) {
auto virtual_context = base::MakeRefCounted<GLContextVirtual>( auto virtual_context = base::MakeRefCounted<GLContextVirtual>(
share_group_.get(), real_context_.get(), share_group_.get(), real_context_.get(),
......
// Copyright 2019 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 "gpu/command_buffer/service/shared_context_state.h"
#include <limits>
#include <memory>
#include <string>
#include <utility>
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/memory/ptr_util.h"
#include "gpu/command_buffer/common/gles2_cmd_utils.h"
#include "gpu/command_buffer/service/context_state_test_helpers.h"
#include "gpu/command_buffer/service/feature_info.h"
#include "gpu/command_buffer/service/gl_context_mock.h"
#include "gpu/command_buffer/service/shared_context_state.h"
#include "gpu/command_buffer/service/test_helper.h"
#include "gpu/config/gpu_driver_bug_workarounds.h"
#include "gpu/config/gpu_feature_info.h"
#include "gpu/config/gpu_preferences.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gl/gl_mock.h"
#include "ui/gl/gl_surface_stub.h"
#include "ui/gl/init/gl_factory.h"
#include "ui/gl/test/gl_surface_test_support.h"
using ::testing::_;
using ::testing::InSequence;
using ::testing::Return;
using ::testing::SetArgPointee;
using ::testing::StrictMock;
namespace gpu {
class SharedContextStateTest : public ::testing::Test {
public:
SharedContextStateTest() = default;
};
TEST_F(SharedContextStateTest, InitFailsIfLostContext) {
const ContextType context_type = CONTEXT_TYPE_OPENGLES2;
// For easier substring/extension matching
gl::SetGLGetProcAddressProc(gl::MockGLInterface::GetGLProcAddress);
gl::GLSurfaceTestSupport::InitializeOneOffWithMockBindings();
StrictMock<gl::MockGLInterface> gl_interface;
gl::MockGLInterface::SetGLInterface(&gl_interface);
InSequence sequence;
auto surface = base::MakeRefCounted<gl::GLSurfaceStub>();
auto context = base::MakeRefCounted<StrictMock<GLContextMock>>();
const char gl_version[] = "2.1";
context->SetGLVersionString(gl_version);
const char gl_extensions[] = "GL_KHR_robustness";
context->SetExtensionsString(gl_extensions);
context->GLContextStub::MakeCurrent(surface.get());
GpuFeatureInfo gpu_feature_info;
GpuDriverBugWorkarounds workarounds;
auto feature_info =
base::MakeRefCounted<gles2::FeatureInfo>(workarounds, gpu_feature_info);
gles2::TestHelper::SetupFeatureInfoInitExpectationsWithGLVersion(
&gl_interface, gl_extensions, "", gl_version, context_type);
feature_info->Initialize(gpu::CONTEXT_TYPE_OPENGLES2, false /* passthrough */,
gles2::DisallowedFeatures());
// Setup expectations for SharedContextState::InitializeGL().
EXPECT_CALL(gl_interface, GetIntegerv(GL_MAX_VERTEX_ATTRIBS, _))
.WillOnce(SetArgPointee<1>(8u))
.RetiresOnSaturation();
ContextStateTestHelpers::SetupInitState(&gl_interface, feature_info.get(),
gfx::Size(1, 1));
EXPECT_TRUE(context->WasAllocatedUsingRobustnessExtension());
EXPECT_CALL(gl_interface, GetGraphicsResetStatusARB())
.WillOnce(Return(GL_GUILTY_CONTEXT_RESET_ARB));
auto shared_context_state = base::MakeRefCounted<SharedContextState>(
new gl::GLShareGroup(), surface, context,
false /* use_virtualized_gl_contexts */, base::DoNothing());
bool result =
shared_context_state->InitializeGL(GpuPreferences(), feature_info);
EXPECT_FALSE(result);
}
} // namespace gpu
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