From 45cfd23cbd42aa6f110be7b45ed85fdc7e8d3bed Mon Sep 17 00:00:00 2001 From: danakj Date: Wed, 18 Oct 2017 19:31:31 +0000 Subject: [PATCH] Report fatal vs transient errors when initializing contexts Currently context creation and initialization reports back just true/false for if the process succeeded. This expands that information to a tri-state of success, fatal error, transient error. In the latter case, the client should retry making the context as it may succeed next time. This happens when, for instance, another client crashes the gpu process at the same time the context is being constructed. In the case of a fatal error, the context can not be made given the current inputs so either the gpu is not usable, or the client has a bug and is requesting an invalid context of some sort, but it will not make progress by retrying. So in this case the client should not retry and just fail back to a non-gpu mode. This information will allow us to remove the retry count when making the compositor context for the display compositor, removing the state machine in that code (as retry becomes a local decision from the result). TBR=raymes Bug: 772574 Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel;master.tryserver.chromium.android:android_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel Change-Id: Ic3574de9fccae42ac34ff8a5755d4cfa5f0dd2b0 Reviewed-on: https://chromium-review.googlesource.com/717548 Reviewed-by: danakj Reviewed-by: Sadrul Chowdhury Reviewed-by: Ken Buchanan Reviewed-by: Antoine Labour Commit-Queue: danakj Cr-Commit-Position: refs/heads/master@{#509836} --- .../aw_render_thread_context_provider.cc | 20 +-- .../aw_render_thread_context_provider.h | 2 +- cc/raster/raster_buffer_provider_perftest.cc | 4 +- cc/raster/scoped_gpu_raster_unittest.cc | 2 +- cc/resources/scoped_resource_unittest.cc | 9 +- cc/test/test_context_provider.cc | 21 ++- cc/test/test_context_provider.h | 2 +- cc/test/test_in_process_context_provider.cc | 16 +- cc/test/test_in_process_context_provider.h | 2 +- cc/tiles/picture_layer_tiling_set_unittest.cc | 3 +- cc/trees/layer_tree_frame_sink.cc | 3 +- cc/trees/layer_tree_host_unittest_context.cc | 3 +- .../layer_tree_host_unittest_copyrequest.cc | 3 +- .../vr_shell/mailbox_to_surface_bridge.cc | 3 +- components/viz/common/gl_helper_benchmark.cc | 21 +-- components/viz/common/gl_helper_unittest.cc | 21 +-- components/viz/common/gpu/context_provider.h | 3 +- .../common/gpu/in_process_context_provider.cc | 39 ++--- .../common/gpu/in_process_context_provider.h | 3 +- .../viz/common/yuv_readback_unittest.cc | 23 +-- .../service/display/gl_renderer_unittest.cc | 11 +- .../display_embedder/gpu_display_provider.cc | 4 +- .../gpu_process_transport_factory.cc | 13 +- content/browser/gpu/gpu_ipc_browsertests.cc | 19 ++- .../renderer_host/compositor_impl_android.cc | 4 +- .../render_widget_host_view_android.cc | 3 +- .../pepper/pepper_video_encoder_host.cc | 12 +- .../renderer/pepper/ppb_graphics_3d_impl.cc | 12 +- content/renderer/render_thread_impl.cc | 9 +- .../webgraphicscontext3d_provider_impl.cc | 4 +- .../client/cmd_buffer_helper.cc | 9 +- gpu/command_buffer/client/cmd_buffer_helper.h | 3 +- .../client/gles2_implementation.cc | 23 +-- .../client/gles2_implementation.h | 3 +- .../client/gles2_implementation_unittest.cc | 2 +- gpu/command_buffer/client/transfer_buffer.cc | 9 +- .../client/transfer_buffer_unittest.cc | 6 +- gpu/command_buffer/common/BUILD.gn | 1 + gpu/command_buffer/common/context_result.h | 28 ++++ gpu/command_buffer/service/context_group.cc | 100 ++++++++----- gpu/command_buffer/service/context_group.h | 7 +- .../service/context_group_unittest.cc | 25 ++-- gpu/command_buffer/service/feature_info.cc | 15 +- gpu/command_buffer/service/feature_info.h | 8 +- .../service/gles2_cmd_decoder.cc | 46 +++--- .../service/gles2_cmd_decoder.h | 19 ++- .../service/gles2_cmd_decoder_mock.h | 14 +- .../service/gles2_cmd_decoder_passthrough.cc | 62 ++++---- .../service/gles2_cmd_decoder_passthrough.h | 18 ++- .../gles2_cmd_decoder_passthrough_doers.cc | 16 +- .../gles2_cmd_decoder_unittest_base.cc | 24 +-- gpu/command_buffer/service/texture_manager.cc | 4 +- gpu/command_buffer/service/texture_manager.h | 2 +- gpu/command_buffer/tests/fuzzer_main.cc | 4 +- gpu/command_buffer/tests/gl_manager.cc | 13 +- gpu/command_buffer/tests/gl_unittest.cc | 2 +- gpu/gles2_conform_support/egl/context.cc | 41 ++--- gpu/gles2_conform_support/egl/context.h | 2 +- gpu/ipc/client/command_buffer_proxy_impl.cc | 141 ++++++++---------- gpu/ipc/client/command_buffer_proxy_impl.h | 27 ++-- .../client/gpu_in_process_context_tests.cc | 21 +-- gpu/ipc/common/gpu_messages.h | 2 +- gpu/ipc/common/gpu_param_traits_macros.h | 3 + gpu/ipc/gl_in_process_context.cc | 131 +++++++--------- gpu/ipc/gl_in_process_context.h | 12 +- gpu/ipc/in_process_command_buffer.cc | 39 ++--- gpu/ipc/in_process_command_buffer.h | 21 +-- gpu/ipc/service/gpu_channel.cc | 55 +++---- gpu/ipc/service/gpu_channel.h | 8 +- .../service/gpu_channel_manager_unittest.cc | 4 +- gpu/ipc/service/gpu_channel_unittest.cc | 44 +++--- gpu/ipc/service/gpu_command_buffer_stub.cc | 76 +++++----- gpu/ipc/service/gpu_command_buffer_stub.h | 29 ++-- ppapi/shared_impl/ppb_graphics_3d_shared.cc | 24 ++- .../gpu/context_provider_command_buffer.cc | 110 +++++++------- .../cpp/gpu/context_provider_command_buffer.h | 6 +- ui/aura/mus/mus_context_factory.cc | 7 +- .../test/in_process_context_factory.cc | 8 +- .../test/in_process_context_provider.cc | 33 ++-- .../test/in_process_context_provider.h | 5 +- 80 files changed, 840 insertions(+), 766 deletions(-) create mode 100644 gpu/command_buffer/common/context_result.h diff --git a/android_webview/browser/aw_render_thread_context_provider.cc b/android_webview/browser/aw_render_thread_context_provider.cc index 8f713ade9456bb..2741a4e2037b48 100644 --- a/android_webview/browser/aw_render_thread_context_provider.cc +++ b/android_webview/browser/aw_render_thread_context_provider.cc @@ -64,10 +64,10 @@ AwRenderThreadContextProvider::AwRenderThreadContextProvider( limits.start_transfer_buffer_size = 64 * 1024; limits.min_transfer_buffer_size = 64 * 1024; - context_.reset(gpu::GLInProcessContext::Create( - service, surface, surface->IsOffscreen(), gpu::kNullSurfaceHandle, - nullptr /* share_context */, attributes, limits, nullptr, nullptr, - nullptr)); + context_ = gpu::GLInProcessContext::CreateWithoutInit(); + context_->Initialize(service, surface, surface->IsOffscreen(), + gpu::kNullSurfaceHandle, nullptr /* share_context */, + attributes, limits, nullptr, nullptr, nullptr); context_->GetImplementation()->SetLostContextCallback(base::Bind( &AwRenderThreadContextProvider::OnLostContext, base::Unretained(this))); @@ -76,12 +76,12 @@ AwRenderThreadContextProvider::AwRenderThreadContextProvider( switches::kEnableGpuClientTracing)) { // This wraps the real GLES2Implementation and we should always use this // instead when it's present. - trace_impl_.reset(new gpu::gles2::GLES2TraceImplementation( - context_->GetImplementation())); + trace_impl_ = std::make_unique( + context_->GetImplementation()); } - cache_controller_.reset( - new viz::ContextCacheController(context_->GetImplementation(), nullptr)); + cache_controller_ = std::make_unique( + context_->GetImplementation(), nullptr); } AwRenderThreadContextProvider::~AwRenderThreadContextProvider() { @@ -95,11 +95,11 @@ uint32_t AwRenderThreadContextProvider::GetCopyTextureInternalFormat() { return GL_RGBA; } -bool AwRenderThreadContextProvider::BindToCurrentThread() { +gpu::ContextResult AwRenderThreadContextProvider::BindToCurrentThread() { // This is called on the thread the context will be used. DCHECK(main_thread_checker_.CalledOnValidThread()); - return true; + return gpu::ContextResult::kSuccess; } const gpu::Capabilities& AwRenderThreadContextProvider::ContextCapabilities() diff --git a/android_webview/browser/aw_render_thread_context_provider.h b/android_webview/browser/aw_render_thread_context_provider.h index 95e2c37f0bc86e..66cb0541594096 100644 --- a/android_webview/browser/aw_render_thread_context_provider.h +++ b/android_webview/browser/aw_render_thread_context_provider.h @@ -46,7 +46,7 @@ class AwRenderThreadContextProvider : public viz::ContextProvider { ~AwRenderThreadContextProvider() override; // viz::ContextProvider: - bool BindToCurrentThread() override; + gpu::ContextResult BindToCurrentThread() override; const gpu::Capabilities& ContextCapabilities() const override; const gpu::GpuFeatureInfo& GetGpuFeatureInfo() const override; gpu::gles2::GLES2Interface* ContextGL() override; diff --git a/cc/raster/raster_buffer_provider_perftest.cc b/cc/raster/raster_buffer_provider_perftest.cc index 1bdd7144f45aa6..a5502271bfbe95 100644 --- a/cc/raster/raster_buffer_provider_perftest.cc +++ b/cc/raster/raster_buffer_provider_perftest.cc @@ -87,7 +87,9 @@ class PerfContextProvider : public viz::ContextProvider { capabilities_.sync_query = true; } - bool BindToCurrentThread() override { return true; } + gpu::ContextResult BindToCurrentThread() override { + return gpu::ContextResult::kSuccess; + } const gpu::Capabilities& ContextCapabilities() const override { return capabilities_; } diff --git a/cc/raster/scoped_gpu_raster_unittest.cc b/cc/raster/scoped_gpu_raster_unittest.cc index 0451d412fc2f62..7fb2dab71f850c 100644 --- a/cc/raster/scoped_gpu_raster_unittest.cc +++ b/cc/raster/scoped_gpu_raster_unittest.cc @@ -17,7 +17,7 @@ class ScopedGpuRasterTest : public testing::Test { // Releasing ScopedGpuRaster should restore GL_UNPACK_ALIGNMENT == 4. TEST(ScopedGpuRasterTest, RestoresUnpackAlignment) { scoped_refptr provider = TestContextProvider::Create(); - EXPECT_TRUE(provider->BindToCurrentThread()); + ASSERT_EQ(provider->BindToCurrentThread(), gpu::ContextResult::kSuccess); gpu::gles2::GLES2Interface* gl = provider->ContextGL(); GLint unpack_alignment = 0; gl->GetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_alignment); diff --git a/cc/resources/scoped_resource_unittest.cc b/cc/resources/scoped_resource_unittest.cc index 73cedf27ae0f8e..e9f6724b52994c 100644 --- a/cc/resources/scoped_resource_unittest.cc +++ b/cc/resources/scoped_resource_unittest.cc @@ -17,7 +17,8 @@ namespace { TEST(ScopedResourceTest, NewScopedResource) { scoped_refptr context_provider = TestContextProvider::Create(); - ASSERT_TRUE(context_provider->BindToCurrentThread()); + ASSERT_EQ(context_provider->BindToCurrentThread(), + gpu::ContextResult::kSuccess); std::unique_ptr shared_bitmap_manager( new TestSharedBitmapManager()); @@ -38,7 +39,8 @@ TEST(ScopedResourceTest, NewScopedResource) { TEST(ScopedResourceTest, CreateScopedResource) { scoped_refptr context_provider = TestContextProvider::Create(); - ASSERT_TRUE(context_provider->BindToCurrentThread()); + ASSERT_EQ(context_provider->BindToCurrentThread(), + gpu::ContextResult::kSuccess); std::unique_ptr shared_bitmap_manager( new TestSharedBitmapManager()); @@ -62,7 +64,8 @@ TEST(ScopedResourceTest, CreateScopedResource) { TEST(ScopedResourceTest, ScopedResourceIsDeleted) { scoped_refptr context_provider = TestContextProvider::Create(); - ASSERT_TRUE(context_provider->BindToCurrentThread()); + ASSERT_EQ(context_provider->BindToCurrentThread(), + gpu::ContextResult::kSuccess); std::unique_ptr shared_bitmap_manager( new TestSharedBitmapManager()); diff --git a/cc/test/test_context_provider.cc b/cc/test/test_context_provider.cc index f4a389134f08ad..58e17fcdd11238 100644 --- a/cc/test/test_context_provider.cc +++ b/cc/test/test_context_provider.cc @@ -106,7 +106,8 @@ scoped_refptr TestContextProvider::CreateWorker() { std::make_unique(), TestWebGraphicsContext3D::Create())); // Worker contexts are bound to the thread they are created on. - if (!worker_context_provider->BindToCurrentThread()) + auto result = worker_context_provider->BindToCurrentThread(); + if (result != gpu::ContextResult::kSuccess) return nullptr; return worker_context_provider; } @@ -168,23 +169,19 @@ TestContextProvider::~TestContextProvider() { context_thread_checker_.CalledOnValidThread()); } -bool TestContextProvider::BindToCurrentThread() { +gpu::ContextResult TestContextProvider::BindToCurrentThread() { // This is called on the thread the context will be used. DCHECK(context_thread_checker_.CalledOnValidThread()); - if (bound_) - return true; + if (!bound_) { + if (context_gl_->GetGraphicsResetStatusKHR() != GL_NO_ERROR) + return gpu::ContextResult::kTransientFailure; - if (context_gl_->GetGraphicsResetStatusKHR() != GL_NO_ERROR) { - return false; + context3d_->set_context_lost_callback(base::Bind( + &TestContextProvider::OnLostContext, base::Unretained(this))); } bound_ = true; - - context3d_->set_context_lost_callback( - base::Bind(&TestContextProvider::OnLostContext, - base::Unretained(this))); - - return true; + return gpu::ContextResult::kSuccess; } void TestContextProvider::DetachFromThread() { diff --git a/cc/test/test_context_provider.h b/cc/test/test_context_provider.h index 7861e9a286e9a3..2c7c3dd5e84d71 100644 --- a/cc/test/test_context_provider.h +++ b/cc/test/test_context_provider.h @@ -46,7 +46,7 @@ class TestContextProvider : public viz::ContextProvider { static scoped_refptr Create( std::unique_ptr gl); - bool BindToCurrentThread() override; + gpu::ContextResult BindToCurrentThread() override; void DetachFromThread() override; const gpu::Capabilities& ContextCapabilities() const override; const gpu::GpuFeatureInfo& GetGpuFeatureInfo() const override; diff --git a/cc/test/test_in_process_context_provider.cc b/cc/test/test_in_process_context_provider.cc index d5258df0ef181d..3c67ccda491352 100644 --- a/cc/test/test_in_process_context_provider.cc +++ b/cc/test/test_in_process_context_provider.cc @@ -43,13 +43,13 @@ std::unique_ptr CreateTestInProcessContext( attribs.fail_if_major_perf_caveat = false; attribs.bind_generates_resource = false; - std::unique_ptr context = - base::WrapUnique(gpu::GLInProcessContext::Create( - nullptr, nullptr, is_offscreen, gpu::kNullSurfaceHandle, - shared_context, attribs, gpu::SharedMemoryLimits(), - gpu_memory_buffer_manager, image_factory, std::move(task_runner))); + auto context = gpu::GLInProcessContext::CreateWithoutInit(); + auto result = context->Initialize( + nullptr, nullptr, is_offscreen, gpu::kNullSurfaceHandle, shared_context, + attribs, gpu::SharedMemoryLimits(), gpu_memory_buffer_manager, + image_factory, std::move(task_runner)); - DCHECK(context); + DCHECK_EQ(result, gpu::ContextResult::kSuccess); return context; } @@ -83,8 +83,8 @@ TestInProcessContextProvider::TestInProcessContextProvider( TestInProcessContextProvider::~TestInProcessContextProvider() { } -bool TestInProcessContextProvider::BindToCurrentThread() { - return true; +gpu::ContextResult TestInProcessContextProvider::BindToCurrentThread() { + return gpu::ContextResult::kSuccess; } gpu::gles2::GLES2Interface* TestInProcessContextProvider::ContextGL() { diff --git a/cc/test/test_in_process_context_provider.h b/cc/test/test_in_process_context_provider.h index ec7ad9dba6e729..f7be9fd95aa653 100644 --- a/cc/test/test_in_process_context_provider.h +++ b/cc/test/test_in_process_context_provider.h @@ -40,7 +40,7 @@ class TestInProcessContextProvider : public viz::ContextProvider { explicit TestInProcessContextProvider( TestInProcessContextProvider* shared_context); - bool BindToCurrentThread() override; + gpu::ContextResult BindToCurrentThread() override; gpu::gles2::GLES2Interface* ContextGL() override; gpu::ContextSupport* ContextSupport() override; class GrContext* GrContext() override; diff --git a/cc/tiles/picture_layer_tiling_set_unittest.cc b/cc/tiles/picture_layer_tiling_set_unittest.cc index d7e37b3dea2c00..167bcb9843c454 100644 --- a/cc/tiles/picture_layer_tiling_set_unittest.cc +++ b/cc/tiles/picture_layer_tiling_set_unittest.cc @@ -247,7 +247,8 @@ class PictureLayerTilingSetTestWithResources : public testing::Test { float expected_scale) { scoped_refptr context_provider = TestContextProvider::Create(); - ASSERT_TRUE(context_provider->BindToCurrentThread()); + ASSERT_EQ(context_provider->BindToCurrentThread(), + gpu::ContextResult::kSuccess); auto shared_bitmap_manager = std::make_unique(); std::unique_ptr resource_provider = FakeResourceProvider::CreateLayerTreeResourceProvider( diff --git a/cc/trees/layer_tree_frame_sink.cc b/cc/trees/layer_tree_frame_sink.cc index 795476973c541c..8cc8fd34be53de 100644 --- a/cc/trees/layer_tree_frame_sink.cc +++ b/cc/trees/layer_tree_frame_sink.cc @@ -46,7 +46,8 @@ bool LayerTreeFrameSink::BindToClient(LayerTreeFrameSinkClient* client) { bool success = true; if (context_provider_.get()) { - success = context_provider_->BindToCurrentThread(); + auto result = context_provider_->BindToCurrentThread(); + success = result == gpu::ContextResult::kSuccess; if (success) { context_provider_->SetLostContextCallback( base::Bind(&LayerTreeFrameSink::DidLoseLayerTreeFrameSink, diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc index 4aa3c7fe4730e0..9d40a77a434758 100644 --- a/cc/trees/layer_tree_host_unittest_context.cc +++ b/cc/trees/layer_tree_host_unittest_context.cc @@ -880,7 +880,8 @@ class LayerTreeHostContextTestDontUseLostResources context_should_support_io_surface_ = true; child_context_provider_ = TestContextProvider::Create(); - CHECK(child_context_provider_->BindToCurrentThread()); + auto result = child_context_provider_->BindToCurrentThread(); + CHECK_EQ(result, gpu::ContextResult::kSuccess); shared_bitmap_manager_.reset(new TestSharedBitmapManager); child_resource_provider_ = FakeResourceProvider::CreateLayerTreeResourceProvider( diff --git a/cc/trees/layer_tree_host_unittest_copyrequest.cc b/cc/trees/layer_tree_host_unittest_copyrequest.cc index 0bc9295339b78b..593cbb75a1d794 100644 --- a/cc/trees/layer_tree_host_unittest_copyrequest.cc +++ b/cc/trees/layer_tree_host_unittest_copyrequest.cc @@ -1026,7 +1026,8 @@ class LayerTreeHostCopyRequestTestProvideTexture protected: void BeginTest() override { external_context_provider_ = TestContextProvider::Create(); - EXPECT_TRUE(external_context_provider_->BindToCurrentThread()); + EXPECT_EQ(external_context_provider_->BindToCurrentThread(), + gpu::ContextResult::kSuccess); LayerTreeHostCopyRequestTestCountTextures::BeginTest(); } diff --git a/chrome/browser/android/vr_shell/mailbox_to_surface_bridge.cc b/chrome/browser/android/vr_shell/mailbox_to_surface_bridge.cc index e47f47fd4101bd..5a27caab33fb3f 100644 --- a/chrome/browser/android/vr_shell/mailbox_to_surface_bridge.cc +++ b/chrome/browser/android/vr_shell/mailbox_to_surface_bridge.cc @@ -156,7 +156,8 @@ void MailboxToSurfaceBridge::OnContextAvailable( // otherwise the GL context created from it becomes invalid. context_provider_ = std::move(provider); - if (!context_provider_->BindToCurrentThread()) { + auto result = context_provider_->BindToCurrentThread(); + if (result != gpu::ContextResult::kSuccess) { DLOG(ERROR) << "Failed to init viz::ContextProvider"; return; } diff --git a/components/viz/common/gl_helper_benchmark.cc b/components/viz/common/gl_helper_benchmark.cc index 84bcd07679e46f..238cc1b0a0f29e 100644 --- a/components/viz/common/gl_helper_benchmark.cc +++ b/components/viz/common/gl_helper_benchmark.cc @@ -66,16 +66,17 @@ class GLHelperBenchmark : public testing::Test { attributes.bind_generates_resource = false; attributes.gpu_preference = gl::PreferDiscreteGpu; - context_.reset( - gpu::GLInProcessContext::Create(nullptr, /* service */ - nullptr, /* surface */ - true, /* offscreen */ - gpu::kNullSurfaceHandle, /* window */ - nullptr, /* share_context */ - attributes, gpu::SharedMemoryLimits(), - nullptr, /* gpu_memory_buffer_manager */ - nullptr, /* image_factory */ - base::ThreadTaskRunnerHandle::Get())); + context_ = gpu::GLInProcessContext::CreateWithoutInit(); + auto result = context_->Initialize(nullptr, /* service */ + nullptr, /* surface */ + true, /* offscreen */ + gpu::kNullSurfaceHandle, /* window */ + nullptr, /* share_context */ + attributes, gpu::SharedMemoryLimits(), + nullptr, /* gpu_memory_buffer_manager */ + nullptr, /* image_factory */ + base::ThreadTaskRunnerHandle::Get()); + DCHECK_EQ(result, gpu::ContextResult::kSuccess); gl_ = context_->GetImplementation(); gpu::ContextSupport* support = context_->GetImplementation(); diff --git a/components/viz/common/gl_helper_unittest.cc b/components/viz/common/gl_helper_unittest.cc index 4b90313206e7f9..f00af7a2be6e2a 100644 --- a/components/viz/common/gl_helper_unittest.cc +++ b/components/viz/common/gl_helper_unittest.cc @@ -60,16 +60,17 @@ class GLHelperTest : public testing::Test { attributes.sample_buffers = 1; attributes.bind_generates_resource = false; - context_.reset( - gpu::GLInProcessContext::Create(nullptr, /* service */ - nullptr, /* surface */ - true, /* offscreen */ - gpu::kNullSurfaceHandle, /* window */ - nullptr, /* share_context */ - attributes, gpu::SharedMemoryLimits(), - nullptr, /* gpu_memory_buffer_manager */ - nullptr, /* image_factory */ - base::ThreadTaskRunnerHandle::Get())); + context_ = gpu::GLInProcessContext::CreateWithoutInit(); + auto result = context_->Initialize(nullptr, /* service */ + nullptr, /* surface */ + true, /* offscreen */ + gpu::kNullSurfaceHandle, /* window */ + nullptr, /* share_context */ + attributes, gpu::SharedMemoryLimits(), + nullptr, /* gpu_memory_buffer_manager */ + nullptr, /* image_factory */ + base::ThreadTaskRunnerHandle::Get()); + DCHECK_EQ(result, gpu::ContextResult::kSuccess); gl_ = context_->GetImplementation(); gpu::ContextSupport* support = context_->GetImplementation(); diff --git a/components/viz/common/gpu/context_provider.h b/components/viz/common/gpu/context_provider.h index 8b8f03eed5f97a..e7166ad0d7927a 100644 --- a/components/viz/common/gpu/context_provider.h +++ b/components/viz/common/gpu/context_provider.h @@ -14,6 +14,7 @@ #include "components/viz/common/gpu/context_cache_controller.h" #include "components/viz/common/viz_common_export.h" #include "gpu/command_buffer/common/capabilities.h" +#include "gpu/command_buffer/common/context_result.h" class GrContext; @@ -60,7 +61,7 @@ class VIZ_COMMON_EXPORT ContextProvider // from the same thread unless the function has some explicitly specified // rules for access on a different thread. See SetupLockOnMainThread(), which // can be used to provide access from multiple threads. - virtual bool BindToCurrentThread() = 0; + virtual gpu::ContextResult BindToCurrentThread() = 0; virtual gpu::gles2::GLES2Interface* ContextGL() = 0; virtual gpu::ContextSupport* ContextSupport() = 0; diff --git a/components/viz/common/gpu/in_process_context_provider.cc b/components/viz/common/gpu/in_process_context_provider.cc index 0a1455316bef5c..5c9858bcf877bf 100644 --- a/components/viz/common/gpu/in_process_context_provider.cc +++ b/components/viz/common/gpu/in_process_context_provider.cc @@ -48,21 +48,6 @@ gpu::gles2::ContextCreationAttribHelper CreateAttributes() { return attributes; } -std::unique_ptr CreateInProcessContext( - scoped_refptr service, - const gpu::gles2::ContextCreationAttribHelper& attributes, - gpu::SurfaceHandle widget, - gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, - gpu::ImageFactory* image_factory, - const gpu::SharedMemoryLimits& limits, - gpu::GLInProcessContext* shared_context) { - const bool is_offscreen = widget == gpu::kNullSurfaceHandle; - return base::WrapUnique(gpu::GLInProcessContext::Create( - service, nullptr, is_offscreen, widget, shared_context, attributes, - limits, gpu_memory_buffer_manager, image_factory, - base::ThreadTaskRunnerHandle::Get())); -} - } // namespace InProcessContextProvider::InProcessContextProvider( @@ -73,22 +58,26 @@ InProcessContextProvider::InProcessContextProvider( const gpu::SharedMemoryLimits& limits, InProcessContextProvider* shared_context) : attributes_(CreateAttributes()), - context_(CreateInProcessContext( - service, - attributes_, + context_(gpu::GLInProcessContext::CreateWithoutInit()), + context_result_(context_->Initialize( + std::move(service), + nullptr, + (widget == gpu::kNullSurfaceHandle), widget, + (shared_context ? shared_context->context_.get() : nullptr), + attributes_, + limits, gpu_memory_buffer_manager, image_factory, - limits, - (shared_context ? shared_context->context_.get() : nullptr))) { - cache_controller_.reset(new ContextCacheController( - context_->GetImplementation(), base::ThreadTaskRunnerHandle::Get())); -} + base::ThreadTaskRunnerHandle::Get())), + cache_controller_(std::make_unique( + context_->GetImplementation(), + base::ThreadTaskRunnerHandle::Get())) {} InProcessContextProvider::~InProcessContextProvider() = default; -bool InProcessContextProvider::BindToCurrentThread() { - return !!context_; +gpu::ContextResult InProcessContextProvider::BindToCurrentThread() { + return context_result_; } gpu::gles2::GLES2Interface* InProcessContextProvider::ContextGL() { diff --git a/components/viz/common/gpu/in_process_context_provider.h b/components/viz/common/gpu/in_process_context_provider.h index 6b108b4b96ff5a..bab7660bc794b3 100644 --- a/components/viz/common/gpu/in_process_context_provider.h +++ b/components/viz/common/gpu/in_process_context_provider.h @@ -43,7 +43,7 @@ class VIZ_COMMON_EXPORT InProcessContextProvider : public ContextProvider { const gpu::SharedMemoryLimits& limits, InProcessContextProvider* shared_context); - bool BindToCurrentThread() override; + gpu::ContextResult BindToCurrentThread() override; gpu::gles2::GLES2Interface* ContextGL() override; gpu::ContextSupport* ContextSupport() override; class GrContext* GrContext() override; @@ -74,6 +74,7 @@ class VIZ_COMMON_EXPORT InProcessContextProvider : public ContextProvider { base::Lock context_lock_; std::unique_ptr context_; + gpu::ContextResult context_result_; std::unique_ptr gr_context_; std::unique_ptr cache_controller_; }; diff --git a/components/viz/common/yuv_readback_unittest.cc b/components/viz/common/yuv_readback_unittest.cc index 7361dec7982006..eb80d88b8ba437 100644 --- a/components/viz/common/yuv_readback_unittest.cc +++ b/components/viz/common/yuv_readback_unittest.cc @@ -41,20 +41,21 @@ class YUVReadbackTest : public testing::Test { attributes.sample_buffers = 1; attributes.bind_generates_resource = false; - context_.reset( - gpu::GLInProcessContext::Create(nullptr, /* service */ - nullptr, /* surface */ - true, /* offscreen */ - gpu::kNullSurfaceHandle, /* window */ - nullptr, /* share_context */ - attributes, gpu::SharedMemoryLimits(), - nullptr, /* gpu_memory_buffer_manager */ - nullptr, /* image_factory */ - base::ThreadTaskRunnerHandle::Get())); + context_ = gpu::GLInProcessContext::CreateWithoutInit(); + auto result = context_->Initialize(nullptr, /* service */ + nullptr, /* surface */ + true, /* offscreen */ + gpu::kNullSurfaceHandle, /* window */ + nullptr, /* share_context */ + attributes, gpu::SharedMemoryLimits(), + nullptr, /* gpu_memory_buffer_manager */ + nullptr, /* image_factory */ + base::ThreadTaskRunnerHandle::Get()); + DCHECK_EQ(result, gpu::ContextResult::kSuccess); gl_ = context_->GetImplementation(); gpu::ContextSupport* support = context_->GetImplementation(); - helper_.reset(new GLHelper(gl_, support)); + helper_ = std::make_unique(gl_, support); } void TearDown() override { diff --git a/components/viz/service/display/gl_renderer_unittest.cc b/components/viz/service/display/gl_renderer_unittest.cc index eefd9889b84c81..391a3cfa0e5f6e 100644 --- a/components/viz/service/display/gl_renderer_unittest.cc +++ b/components/viz/service/display/gl_renderer_unittest.cc @@ -890,7 +890,7 @@ TEST_F(GLRendererTest, ActiveTextureState) { auto child_context_provider = cc::TestContextProvider::Create(std::move(child_context_owned)); - ASSERT_TRUE(child_context_provider->BindToCurrentThread()); + child_context_provider->BindToCurrentThread(); auto child_resource_provider = cc::FakeResourceProvider::CreateLayerTreeResourceProvider( child_context_provider.get(), shared_bitmap_manager.get()); @@ -1950,7 +1950,7 @@ TEST_F(GLRendererTest, DontOverlayWithCopyRequests) { new TextureMailboxDeleter(base::ThreadTaskRunnerHandle::Get())); auto child_context_provider = cc::TestContextProvider::Create(); - ASSERT_TRUE(child_context_provider->BindToCurrentThread()); + child_context_provider->BindToCurrentThread(); auto child_resource_provider = cc::FakeResourceProvider::CreateLayerTreeResourceProvider( child_context_provider.get(), shared_bitmap_manager.get()); @@ -2140,7 +2140,7 @@ TEST_F(GLRendererTest, OverlaySyncTokensAreProcessed) { new TextureMailboxDeleter(base::ThreadTaskRunnerHandle::Get())); auto child_context_provider = cc::TestContextProvider::Create(); - ASSERT_TRUE(child_context_provider->BindToCurrentThread()); + child_context_provider->BindToCurrentThread(); auto child_resource_provider = cc::FakeResourceProvider::CreateLayerTreeResourceProvider( child_context_provider.get(), shared_bitmap_manager.get()); @@ -2377,7 +2377,7 @@ TEST_F(GLRendererTest, DCLayerOverlaySwitch) { output_surface->context_provider(), nullptr); auto child_context_provider = cc::TestContextProvider::Create(); - ASSERT_TRUE(child_context_provider->BindToCurrentThread()); + child_context_provider->BindToCurrentThread(); auto child_resource_provider = cc::FakeResourceProvider::CreateLayerTreeResourceProvider( child_context_provider.get(), nullptr); @@ -2486,7 +2486,8 @@ class GLRendererWithMockContextTest : public ::testing::Test { context_support_ptr_ = context_support.get(); auto context_provider = cc::TestContextProvider::Create( cc::TestWebGraphicsContext3D::Create(), std::move(context_support)); - context_provider->BindToCurrentThread(); + ASSERT_EQ(context_provider->BindToCurrentThread(), + gpu::ContextResult::kSuccess); output_surface_ = cc::FakeOutputSurface::Create3d(std::move(context_provider)); output_surface_->BindToClient(&output_surface_client_); diff --git a/components/viz/service/display_embedder/gpu_display_provider.cc b/components/viz/service/display_embedder/gpu_display_provider.cc index 0798823266ee65..4b46371e2009e5 100644 --- a/components/viz/service/display_embedder/gpu_display_provider.cc +++ b/components/viz/service/display_embedder/gpu_display_provider.cc @@ -69,7 +69,9 @@ std::unique_ptr GpuDisplayProvider::CreateDisplay( nullptr /* shared_context */); // TODO(rjkroege): If there is something better to do than CHECK, add it. - CHECK(context_provider->BindToCurrentThread()); + // TODO(danakj): Should retry if the result is kTransientFailure. + auto result = context_provider->BindToCurrentThread(); + CHECK_EQ(result, gpu::ContextResult::kSuccess); std::unique_ptr display_output_surface; if (context_provider->ContextCapabilities().surfaceless) { diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc index c768823a8df439..5d3493dc400434 100644 --- a/content/browser/compositor/gpu_process_transport_factory.cc +++ b/content/browser/compositor/gpu_process_transport_factory.cc @@ -462,7 +462,10 @@ void GpuProcessTransportFactory::EstablishedGpuChannel( gpu_channel_host, gpu::kNullSurfaceHandle, need_alpha_channel, false /* support_stencil */, support_locking, nullptr, ui::command_buffer_metrics::BROWSER_WORKER_CONTEXT); - if (!shared_worker_context_provider_->BindToCurrentThread()) + auto result = shared_worker_context_provider_->BindToCurrentThread(); + // TODO(danakj): Only retry context creation if kTransientFailure. Don't + // retry at all if kFatalFailure. + if (result != gpu::ContextResult::kSuccess) shared_worker_context_provider_ = nullptr; } @@ -485,7 +488,10 @@ void GpuProcessTransportFactory::EstablishedGpuChannel( // On Mac, GpuCommandBufferMsg_SwapBuffersCompleted must be handled in // a nested run loop during resize. context_provider->SetDefaultTaskRunner(resize_task_runner_); - if (!context_provider->BindToCurrentThread()) + auto result = context_provider->BindToCurrentThread(); + // TODO(danakj): Only retry context creation if kTransientFailure. Don't + // retry at all if kFatalFailure. + if (result != gpu::ContextResult::kSuccess) context_provider = nullptr; } } @@ -943,7 +949,8 @@ GpuProcessTransportFactory::SharedMainThreadContextProvider() { shared_main_thread_contexts_->SetLostContextCallback(base::Bind( &GpuProcessTransportFactory::OnLostMainThreadSharedContextInsideCallback, callback_factory_.GetWeakPtr())); - if (!shared_main_thread_contexts_->BindToCurrentThread()) + auto result = shared_main_thread_contexts_->BindToCurrentThread(); + if (result != gpu::ContextResult::kSuccess) shared_main_thread_contexts_ = nullptr; return shared_main_thread_contexts_; } diff --git a/content/browser/gpu/gpu_ipc_browsertests.cc b/content/browser/gpu/gpu_ipc_browsertests.cc index 352efffcf854d8..fed5c9dd643188 100644 --- a/content/browser/gpu/gpu_ipc_browsertests.cc +++ b/content/browser/gpu/gpu_ipc_browsertests.cc @@ -91,8 +91,8 @@ class ContextTestBase : public content::ContentBrowserTest { CHECK(gpu_channel_host); provider_ = CreateContext(std::move(gpu_channel_host)); - bool bound = provider_->BindToCurrentThread(); - CHECK(bound); + auto result = provider_->BindToCurrentThread(); + CHECK_EQ(result, gpu::ContextResult::kSuccess); gl_ = provider_->ContextGL(); context_support_ = provider_->ContextSupport(); @@ -227,7 +227,7 @@ IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest, // retain the host after provider is destroyed. scoped_refptr provider = CreateContext(GetGpuChannel()); - EXPECT_TRUE(provider->BindToCurrentThread()); + ASSERT_EQ(provider->BindToCurrentThread(), gpu::ContextResult::kSuccess); sk_sp gr_context = sk_ref_sp(provider->GrContext()); @@ -279,7 +279,7 @@ IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest, provider->SetLostContextCallback( base::Bind(&BrowserGpuChannelHostFactoryTest::OnContextLost, base::Unretained(this), run_loop.QuitClosure(), &counter)); - EXPECT_TRUE(provider->BindToCurrentThread()); + ASSERT_EQ(provider->BindToCurrentThread(), gpu::ContextResult::kSuccess); GpuProcessHost::CallOnIO(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED, false /* force_create */, base::Bind([](GpuProcessHost* host) { @@ -320,10 +320,13 @@ IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest, CreateTransferBuffer) { attributes.sample_buffers = 0; attributes.bind_generates_resource = false; - auto impl = gpu::CommandBufferProxyImpl::Create( - GetGpuChannel(), gpu::kNullSurfaceHandle, nullptr, - content::kGpuStreamIdDefault, content::kGpuStreamPriorityDefault, - attributes, GURL(), base::ThreadTaskRunnerHandle::Get()); + auto impl = std::make_unique( + GetGpuChannel(), content::kGpuStreamIdDefault, + base::ThreadTaskRunnerHandle::Get()); + ASSERT_EQ( + impl->Initialize(gpu::kNullSurfaceHandle, nullptr, + content::kGpuStreamPriorityDefault, attributes, GURL()), + gpu::ContextResult::kSuccess); // Creating a transfer buffer works normally. int32_t id = -1; diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc index dc6723d2413a87..a4938794239602 100644 --- a/content/browser/renderer_host/compositor_impl_android.cc +++ b/content/browser/renderer_host/compositor_impl_android.cc @@ -779,7 +779,9 @@ void CompositorImpl::OnGpuChannelEstablished( requires_alpha_channel_), shared_context, ui::command_buffer_metrics::DISPLAY_COMPOSITOR_ONSCREEN_CONTEXT); - if (!context_provider->BindToCurrentThread()) { + auto result = context_provider->BindToCurrentThread(); + if (result != gpu::ContextResult::kSuccess) { + // TODO(danakj): Give up on fatal error instead of after 2 tries. LOG(ERROR) << "Failed to init viz::ContextProvider for compositor."; LOG_IF(FATAL, ++num_successive_context_creation_failures_ >= 2) << "Too many context creation failures. Giving up... "; diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index fed4a9a2a3a01d..ff7cd0497e072f 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc @@ -219,7 +219,8 @@ void GLHelperHolder::Initialize() { gpu::kNullSurfaceHandle, url, automatic_flushes, support_locking, limits, attributes, nullptr, ui::command_buffer_metrics::BROWSER_OFFSCREEN_MAINTHREAD_CONTEXT); - if (!provider_->BindToCurrentThread()) + auto result = provider_->BindToCurrentThread(); + if (result != gpu::ContextResult::kSuccess) return; provider_->ContextGL()->TraceBeginCHROMIUM( "gpu_toplevel", diff --git a/content/renderer/pepper/pepper_video_encoder_host.cc b/content/renderer/pepper/pepper_video_encoder_host.cc index a9c7fe1685573c..08fc906f42b4e8 100644 --- a/content/renderer/pepper/pepper_video_encoder_host.cc +++ b/content/renderer/pepper/pepper_video_encoder_host.cc @@ -530,11 +530,13 @@ bool PepperVideoEncoderHost::EnsureGpuChannel() { if (!channel) return false; - command_buffer_ = gpu::CommandBufferProxyImpl::Create( - std::move(channel), gpu::kNullSurfaceHandle, nullptr, kGpuStreamIdDefault, - kGpuStreamPriorityDefault, gpu::gles2::ContextCreationAttribHelper(), - GURL::EmptyGURL(), base::ThreadTaskRunnerHandle::Get()); - if (!command_buffer_) { + command_buffer_ = std::make_unique( + std::move(channel), kGpuStreamIdDefault, + base::ThreadTaskRunnerHandle::Get()); + auto result = command_buffer_->Initialize( + gpu::kNullSurfaceHandle, nullptr, kGpuStreamPriorityDefault, + gpu::gles2::ContextCreationAttribHelper(), GURL::EmptyGURL()); + if (result != gpu::ContextResult::kSuccess) { Close(); return false; } diff --git a/content/renderer/pepper/ppb_graphics_3d_impl.cc b/content/renderer/pepper/ppb_graphics_3d_impl.cc index 040fa5e4f45344..828a1fc1db286d 100644 --- a/content/renderer/pepper/ppb_graphics_3d_impl.cc +++ b/content/renderer/pepper/ppb_graphics_3d_impl.cc @@ -265,11 +265,13 @@ bool PPB_Graphics3D_Impl::InitRaw( share_buffer = share_graphics->GetCommandBufferProxy(); } - command_buffer_ = gpu::CommandBufferProxyImpl::Create( - std::move(channel), gpu::kNullSurfaceHandle, share_buffer, - kGpuStreamIdDefault, kGpuStreamPriorityDefault, attrib_helper, - GURL::EmptyGURL(), base::ThreadTaskRunnerHandle::Get()); - if (!command_buffer_) + command_buffer_ = std::make_unique( + std::move(channel), kGpuStreamIdDefault, + base::ThreadTaskRunnerHandle::Get()); + auto result = command_buffer_->Initialize( + gpu::kNullSurfaceHandle, share_buffer, kGpuStreamPriorityDefault, + attrib_helper, GURL::EmptyGURL()); + if (result != gpu::ContextResult::kSuccess) return false; command_buffer_->SetGpuControlClient(this); diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index 13eeab3a946337..3770df66306cb0 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc @@ -1450,7 +1450,8 @@ media::GpuVideoAcceleratorFactories* RenderThreadImpl::GetGpuFactories() { support_oop_rasterization, ui::command_buffer_metrics::MEDIA_CONTEXT, kGpuStreamIdDefault, kGpuStreamPriorityDefault); - if (!media_context_provider->BindToCurrentThread()) + auto result = media_context_provider->BindToCurrentThread(); + if (result != gpu::ContextResult::kSuccess) return nullptr; scoped_refptr media_task_runner = @@ -1505,7 +1506,8 @@ RenderThreadImpl::SharedMainThreadContextProvider() { support_oop_rasterization, ui::command_buffer_metrics::RENDERER_MAINTHREAD_CONTEXT, kGpuStreamIdDefault, kGpuStreamPriorityDefault); - if (!shared_main_thread_contexts_->BindToCurrentThread()) + auto result = shared_main_thread_contexts_->BindToCurrentThread(); + if (result != gpu::ContextResult::kSuccess) shared_main_thread_contexts_ = nullptr; return shared_main_thread_contexts_; } @@ -2396,7 +2398,8 @@ RenderThreadImpl::SharedCompositorWorkerContextProvider() { support_oop_rasterization, ui::command_buffer_metrics::RENDER_WORKER_CONTEXT, stream_id, stream_priority); - if (!shared_worker_context_provider_->BindToCurrentThread()) + auto result = shared_worker_context_provider_->BindToCurrentThread(); + if (result != gpu::ContextResult::kSuccess) shared_worker_context_provider_ = nullptr; return shared_worker_context_provider_; } diff --git a/content/renderer/webgraphicscontext3d_provider_impl.cc b/content/renderer/webgraphicscontext3d_provider_impl.cc index 4795bc15139c5e..19fa1b55e65a9d 100644 --- a/content/renderer/webgraphicscontext3d_provider_impl.cc +++ b/content/renderer/webgraphicscontext3d_provider_impl.cc @@ -17,7 +17,9 @@ WebGraphicsContext3DProviderImpl::WebGraphicsContext3DProviderImpl( WebGraphicsContext3DProviderImpl::~WebGraphicsContext3DProviderImpl() {} bool WebGraphicsContext3DProviderImpl::BindToCurrentThread() { - return provider_->BindToCurrentThread(); + // TODO(danakj): Could plumb this result out to the caller so they know to + // retry or not, if any client cared to know if it should retry or not. + return provider_->BindToCurrentThread() == gpu::ContextResult::kSuccess; } gpu::gles2::GLES2Interface* WebGraphicsContext3DProviderImpl::ContextGL() { diff --git a/gpu/command_buffer/client/cmd_buffer_helper.cc b/gpu/command_buffer/client/cmd_buffer_helper.cc index f29f7449bb5a33..6e172ec9943f13 100644 --- a/gpu/command_buffer/client/cmd_buffer_helper.cc +++ b/gpu/command_buffer/client/cmd_buffer_helper.cc @@ -150,9 +150,14 @@ void CommandBufferHelper::FreeRingBuffer() { } } -bool CommandBufferHelper::Initialize(int32_t ring_buffer_size) { +gpu::ContextResult CommandBufferHelper::Initialize(int32_t ring_buffer_size) { ring_buffer_size_ = ring_buffer_size; - return AllocateRingBuffer(); + if (!AllocateRingBuffer()) { + // This would fail if CreateTransferBuffer fails, which will not fail for + // transient reasons such as context loss. See http://crrev.com/c/720269 + return gpu::ContextResult::kFatalFailure; + } + return gpu::ContextResult::kSuccess; } CommandBufferHelper::~CommandBufferHelper() { diff --git a/gpu/command_buffer/client/cmd_buffer_helper.h b/gpu/command_buffer/client/cmd_buffer_helper.h index 5c38d0ed0f508b..a7fbbc9b59cfb5 100644 --- a/gpu/command_buffer/client/cmd_buffer_helper.h +++ b/gpu/command_buffer/client/cmd_buffer_helper.h @@ -19,6 +19,7 @@ #include "build/build_config.h" #include "gpu/command_buffer/common/cmd_buffer_common.h" #include "gpu/command_buffer/common/command_buffer.h" +#include "gpu/command_buffer/common/context_result.h" #include "gpu/gpu_export.h" namespace gpu { @@ -60,7 +61,7 @@ class GPU_EXPORT CommandBufferHelper // Parameters: // ring_buffer_size: The size of the ring buffer portion of the command // buffer. - bool Initialize(int32_t ring_buffer_size); + gpu::ContextResult Initialize(int32_t ring_buffer_size); // Sets whether the command buffer should automatically flush periodically // to try to increase performance. Defaults to true. diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc index 9d63f5f174c105..f87129f6298a0b 100644 --- a/gpu/command_buffer/client/gles2_implementation.cc +++ b/gpu/command_buffer/client/gles2_implementation.cc @@ -192,7 +192,8 @@ GLES2Implementation::GLES2Implementation( memset(&reserved_ids_, 0, sizeof(reserved_ids_)); } -bool GLES2Implementation::Initialize(const SharedMemoryLimits& limits) { +gpu::ContextResult GLES2Implementation::Initialize( + const SharedMemoryLimits& limits) { TRACE_EVENT0("gpu", "GLES2Implementation::Initialize"); DCHECK_GE(limits.start_transfer_buffer_size, limits.min_transfer_buffer_size); DCHECK_LE(limits.start_transfer_buffer_size, limits.max_transfer_buffer_size); @@ -204,12 +205,14 @@ bool GLES2Implementation::Initialize(const SharedMemoryLimits& limits) { limits.start_transfer_buffer_size, kStartingOffset, limits.min_transfer_buffer_size, limits.max_transfer_buffer_size, kAlignment, kSizeToFlush)) { - return false; + // TransferBuffer::Initialize doesn't fail for transient reasons such as if + // the context was lost. See http://crrev.com/c/720269 + return gpu::ContextResult::kFatalFailure; } max_extra_transfer_buffer_size_ = limits.max_mapped_memory_for_texture_upload; - mapped_memory_.reset( - new MappedMemoryManager(helper_, limits.mapped_memory_reclaim_limit)); + mapped_memory_ = std::make_unique( + helper_, limits.mapped_memory_reclaim_limit); mapped_memory_->set_chunk_size_multiple(limits.mapped_memory_chunk_size); GLStaticState::ShaderPrecisionMap* shader_precisions = @@ -226,11 +229,11 @@ bool GLES2Implementation::Initialize(const SharedMemoryLimits& limits) { capabilities_.num_compressed_texture_formats); util_.set_num_shader_binary_formats(capabilities_.num_shader_binary_formats); - texture_units_.reset( - new TextureUnit[capabilities_.max_combined_texture_image_units]); + texture_units_ = std::make_unique( + capabilities_.max_combined_texture_image_units); - query_tracker_.reset(new QueryTracker(mapped_memory_.get())); - buffer_tracker_.reset(new BufferTracker(mapped_memory_.get())); + query_tracker_ = std::make_unique(mapped_memory_.get()); + buffer_tracker_ = std::make_unique(mapped_memory_.get()); for (int i = 0; i < static_cast(IdNamespaces::kNumIdNamespaces); ++i) id_allocators_[i].reset(new IdAllocator()); @@ -252,10 +255,10 @@ bool GLES2Implementation::Initialize(const SharedMemoryLimits& limits) { SetGLError(GL_INVALID_OPERATION, "Initialize", "Service bind_generates_resource mismatch."); - return false; + return gpu::ContextResult::kFatalFailure; } - return true; + return gpu::ContextResult::kSuccess; } GLES2Implementation::~GLES2Implementation() { diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h index 8ce0179fbef962..9002b3d8ddfe2e 100644 --- a/gpu/command_buffer/client/gles2_implementation.h +++ b/gpu/command_buffer/client/gles2_implementation.h @@ -31,6 +31,7 @@ #include "gpu/command_buffer/client/ref_counted.h" #include "gpu/command_buffer/client/share_group.h" #include "gpu/command_buffer/common/capabilities.h" +#include "gpu/command_buffer/common/context_result.h" #include "gpu/command_buffer/common/debug_marker_manager.h" #include "gpu/command_buffer/common/gles2_cmd_utils.h" @@ -171,7 +172,7 @@ class GLES2_IMPL_EXPORT GLES2Implementation ~GLES2Implementation() override; - bool Initialize(const SharedMemoryLimits& limits); + gpu::ContextResult Initialize(const SharedMemoryLimits& limits); // The GLES2CmdHelper being used by this GLES2Implementation. You can use // this to issue cmds at a lower level for certain kinds of optimization. diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc index d724023c4e586a..656354a9058151 100644 --- a/gpu/command_buffer/client/gles2_implementation_unittest.cc +++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc @@ -499,7 +499,7 @@ class GLES2ImplementationTest : public testing::Test { // The client should be set to something non-null. EXPECT_CALL(*gpu_control_, SetGpuControlClient(gl_.get())).Times(1); - if (!gl_->Initialize(limits)) + if (gl_->Initialize(limits) != gpu::ContextResult::kSuccess) return false; helper_->CommandBufferHelper::Finish(); diff --git a/gpu/command_buffer/client/transfer_buffer.cc b/gpu/command_buffer/client/transfer_buffer.cc index 76afc59f6eb28b..76dde8140da807 100644 --- a/gpu/command_buffer/client/transfer_buffer.cc +++ b/gpu/command_buffer/client/transfer_buffer.cc @@ -117,12 +117,9 @@ void TransferBuffer::AllocateRingBuffer(unsigned int size) { if (id != -1) { DCHECK(buffer.get()); buffer_ = buffer; - ring_buffer_.reset(new RingBuffer( - alignment_, - result_size_, - buffer_->size() - result_size_, - helper_, - static_cast(buffer_->memory()) + result_size_)); + ring_buffer_ = std::make_unique( + alignment_, result_size_, buffer_->size() - result_size_, helper_, + static_cast(buffer_->memory()) + result_size_); buffer_id_ = id; result_buffer_ = buffer_->memory(); result_shm_offset_ = 0; diff --git a/gpu/command_buffer/client/transfer_buffer_unittest.cc b/gpu/command_buffer/client/transfer_buffer_unittest.cc index c83e1d3e4a8d6e..595798a5d79bad 100644 --- a/gpu/command_buffer/client/transfer_buffer_unittest.cc +++ b/gpu/command_buffer/client/transfer_buffer_unittest.cc @@ -68,7 +68,8 @@ void TransferBufferTest::SetUp() { command_buffer_.reset(new StrictMock()); helper_.reset(new CommandBufferHelper(command_buffer())); - ASSERT_TRUE(helper_->Initialize(kCommandBufferSizeBytes)); + ASSERT_EQ(helper_->Initialize(kCommandBufferSizeBytes), + gpu::ContextResult::kSuccess); transfer_buffer_id_ = command_buffer()->GetNextFreeTransferBufferId(); @@ -308,7 +309,8 @@ void TransferBufferExpandContractTest::SetUp() { .RetiresOnSaturation(); helper_.reset(new CommandBufferHelper(command_buffer())); - ASSERT_TRUE(helper_->Initialize(kCommandBufferSizeBytes)); + ASSERT_EQ(helper_->Initialize(kCommandBufferSizeBytes), + gpu::ContextResult::kSuccess); transfer_buffer_id_ = command_buffer()->GetNextFreeTransferBufferId(); diff --git a/gpu/command_buffer/common/BUILD.gn b/gpu/command_buffer/common/BUILD.gn index 061318b3f1ca94..b7b3dc6a1cbc28 100644 --- a/gpu/command_buffer/common/BUILD.gn +++ b/gpu/command_buffer/common/BUILD.gn @@ -35,6 +35,7 @@ source_set("common_sources") { "command_buffer.h", "command_buffer_id.h", "constants.h", + "context_result.h", "debug_marker_manager.cc", "debug_marker_manager.h", "discardable_handle.cc", diff --git a/gpu/command_buffer/common/context_result.h b/gpu/command_buffer/common/context_result.h new file mode 100644 index 00000000000000..db592665e8e3dc --- /dev/null +++ b/gpu/command_buffer/common/context_result.h @@ -0,0 +1,28 @@ +// Copyright 2017 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 GPU_COMMAND_BUFFER_COMMON_CONTEXT_RESULT_H_ +#define GPU_COMMAND_BUFFER_COMMON_CONTEXT_RESULT_H_ + +namespace gpu { + +// The result of trying to create a gpu context. Also the result of intermediate +// steps which bubble up to the final result. If any fatal error occurs, the +// entire result should be fatal - as any attempt to retry is expected to get +// the same fatal result. +enum class ContextResult { + // The context was created and initialized successfully. + kSuccess, + // A failure occured that prevented the context from being initialized, + // but it can be retried and expect to make progress. + kTransientFailure, + // An error occured that will recur in future attempts too with the + // same inputs, retrying would not be productive. + kFatalFailure, + kLastContextResult = kFatalFailure +}; + +} // namespace gpu + +#endif // GPU_COMMAND_BUFFER_COMMON_CONTEXT_RESULT_H_ diff --git a/gpu/command_buffer/service/context_group.cc b/gpu/command_buffer/service/context_group.cc index f43e913dbcf59b..68da0c796d11ea 100644 --- a/gpu/command_buffer/service/context_group.cc +++ b/gpu/command_buffer/service/context_group.cc @@ -125,15 +125,16 @@ ContextGroup::ContextGroup( gpu_preferences_.use_passthrough_cmd_decoder; } -bool ContextGroup::Initialize(GLES2Decoder* decoder, - ContextType context_type, - const DisallowedFeatures& disallowed_features) { +gpu::ContextResult ContextGroup::Initialize( + GLES2Decoder* decoder, + ContextType context_type, + const DisallowedFeatures& disallowed_features) { switch (context_type) { case CONTEXT_TYPE_WEBGL1: if (kGpuFeatureStatusBlacklisted == gpu_feature_info_.status_values[GPU_FEATURE_TYPE_ACCELERATED_WEBGL]) { DLOG(ERROR) << "ContextGroup::Initialize failed: WebGL1 baclklisted"; - return false; + return gpu::ContextResult::kFatalFailure; } break; case CONTEXT_TYPE_WEBGL2: @@ -141,7 +142,7 @@ bool ContextGroup::Initialize(GLES2Decoder* decoder, gpu_feature_info_ .status_values[GPU_FEATURE_TYPE_ACCELERATED_WEBGL2]) { DLOG(ERROR) << "ContextGroup::Initialize failed: WebGL2 blacklisted"; - return false; + return gpu::ContextResult::kFatalFailure; } break; default: @@ -151,21 +152,17 @@ bool ContextGroup::Initialize(GLES2Decoder* decoder, if (context_type != feature_info_->context_type()) { DLOG(ERROR) << "ContextGroup::Initialize failed because the type of " << "the context does not fit with the group."; - return false; + return gpu::ContextResult::kFatalFailure; } // If we've already initialized the group just add the context. decoders_.push_back(decoder->AsWeakPtr()); - return true; + return gpu::ContextResult::kSuccess; } DisallowedFeatures adjusted_disallowed_features = AdjustDisallowedFeatures(context_type, disallowed_features); - if (!feature_info_->Initialize(context_type, adjusted_disallowed_features)) { - DLOG(ERROR) << "ContextGroup::Initialize failed because FeatureInfo " - << "initialization failed."; - return false; - } + feature_info_->Initialize(context_type, adjusted_disallowed_features); const GLint kMinRenderbufferSize = 512; // GL says 1 pixel! GLint max_renderbuffer_size = 0; @@ -175,7 +172,9 @@ bool ContextGroup::Initialize(GLES2Decoder* decoder, DLOG(ERROR) << "ContextGroup::Initialize failed because maximum " << "renderbuffer size too small (" << max_renderbuffer_size << ", should be " << kMinRenderbufferSize << ")."; - return false; + bool was_lost = decoder->CheckResetStatus(); + return was_lost ? gpu::ContextResult::kTransientFailure + : gpu::ContextResult::kFatalFailure; } GLint max_samples = 0; if (feature_info_->feature_flags().chromium_framebuffer_multisample || @@ -217,7 +216,9 @@ bool ContextGroup::Initialize(GLES2Decoder* decoder, << "transform feedback separate attribs is too small (" << max_transform_feedback_separate_attribs_ << ", should be " << kMinTransformFeedbackSeparateAttribs << ")."; - return false; + bool was_lost = decoder->CheckResetStatus(); + return was_lost ? gpu::ContextResult::kTransientFailure + : gpu::ContextResult::kFatalFailure; } const GLint kMinUniformBufferBindings = 24; @@ -228,7 +229,9 @@ bool ContextGroup::Initialize(GLES2Decoder* decoder, << "uniform buffer bindings is too small (" << max_uniform_buffer_bindings_ << ", should be " << kMinUniformBufferBindings << ")."; - return false; + bool was_lost = decoder->CheckResetStatus(); + return was_lost ? gpu::ContextResult::kTransientFailure + : gpu::ContextResult::kFatalFailure; } // TODO(zmo): Should we check max UNIFORM_BUFFER_OFFSET_ALIGNMENT is 256? @@ -252,7 +255,9 @@ bool ContextGroup::Initialize(GLES2Decoder* decoder, DLOG(ERROR) << "ContextGroup::Initialize failed because too few " << "vertex attributes supported (" << max_vertex_attribs_ << ", should be " << kGLES2RequiredMinimumVertexAttribs << ")."; - return false; + bool was_lost = decoder->CheckResetStatus(); + return was_lost ? gpu::ContextResult::kTransientFailure + : gpu::ContextResult::kFatalFailure; } const GLuint kGLES2RequiredMinimumTextureUnits = 8u; @@ -262,7 +267,9 @@ bool ContextGroup::Initialize(GLES2Decoder* decoder, DLOG(ERROR) << "ContextGroup::Initialize failed because too few " << "texture units supported (" << max_texture_units_ << ", should be " << kGLES2RequiredMinimumTextureUnits << ")."; - return false; + bool was_lost = decoder->CheckResetStatus(); + return was_lost ? gpu::ContextResult::kTransientFailure + : gpu::ContextResult::kFatalFailure; } GLint max_texture_size = 0; @@ -282,7 +289,9 @@ bool ContextGroup::Initialize(GLES2Decoder* decoder, DLOG(ERROR) << "ContextGroup::Initialize failed because maximum " << "2d texture size is too small (" << max_texture_size << ", should be " << kMinTextureSize << ")."; - return false; + bool was_lost = decoder->CheckResetStatus(); + return was_lost ? gpu::ContextResult::kTransientFailure + : gpu::ContextResult::kFatalFailure; } if (!QueryGLFeature(GL_MAX_CUBE_MAP_TEXTURE_SIZE, kMinCubeMapSize, &max_cube_map_texture_size)) { @@ -290,7 +299,9 @@ bool ContextGroup::Initialize(GLES2Decoder* decoder, << "cube texture size is too small (" << max_cube_map_texture_size << ", should be " << kMinCubeMapSize << ")."; - return false; + bool was_lost = decoder->CheckResetStatus(); + return was_lost ? gpu::ContextResult::kTransientFailure + : gpu::ContextResult::kFatalFailure; } if (feature_info_->gl_version_info().is_es3_capable && !QueryGLFeature(GL_MAX_3D_TEXTURE_SIZE, kMin3DTextureSize, @@ -298,7 +309,9 @@ bool ContextGroup::Initialize(GLES2Decoder* decoder, DLOG(ERROR) << "ContextGroup::Initialize failed because maximum " << "3d texture size is too small (" << max_3d_texture_size << ", should be " << kMin3DTextureSize << ")."; - return false; + bool was_lost = decoder->CheckResetStatus(); + return was_lost ? gpu::ContextResult::kTransientFailure + : gpu::ContextResult::kFatalFailure; } if (feature_info_->gl_version_info().is_es3_capable && !QueryGLFeature(GL_MAX_ARRAY_TEXTURE_LAYERS, kMinArrayTextureLayers, @@ -307,7 +320,9 @@ bool ContextGroup::Initialize(GLES2Decoder* decoder, << "array texture layers is too small (" << max_array_texture_layers << ", should be " << kMinArrayTextureLayers << ")."; - return false; + bool was_lost = decoder->CheckResetStatus(); + return was_lost ? gpu::ContextResult::kTransientFailure + : gpu::ContextResult::kFatalFailure; } if (feature_info_->feature_flags().arb_texture_rectangle && !QueryGLFeature(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, @@ -316,7 +331,9 @@ bool ContextGroup::Initialize(GLES2Decoder* decoder, << "rectangle texture size is too small (" << max_rectangle_texture_size << ", should be " << kMinRectangleTextureSize << ")."; - return false; + bool was_lost = decoder->CheckResetStatus(); + return was_lost ? gpu::ContextResult::kTransientFailure + : gpu::ContextResult::kFatalFailure; } if (feature_info_->workarounds().max_texture_size) { @@ -342,6 +359,9 @@ bool ContextGroup::Initialize(GLES2Decoder* decoder, << "texture image units supported (" << max_texture_image_units_ << ", should be " << kMinTextureImageUnits << ")."; + bool was_lost = decoder->CheckResetStatus(); + return was_lost ? gpu::ContextResult::kTransientFailure + : gpu::ContextResult::kFatalFailure; } if (!QueryGLFeatureU(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, kMinVertexTextureImageUnits, @@ -350,7 +370,9 @@ bool ContextGroup::Initialize(GLES2Decoder* decoder, << "vertex texture image units supported (" << max_vertex_texture_image_units_ << ", should be " << kMinTextureImageUnits << ")."; - return false; + bool was_lost = decoder->CheckResetStatus(); + return was_lost ? gpu::ContextResult::kTransientFailure + : gpu::ContextResult::kFatalFailure; } if (feature_info_->gl_version_info().BehavesLikeGLES()) { @@ -378,7 +400,9 @@ bool ContextGroup::Initialize(GLES2Decoder* decoder, kMinVertexUniformVectors, &max_vertex_uniform_vectors_)) { DLOG(ERROR) << "ContextGroup::Initialize failed because too few " << "uniforms or varyings supported."; - return false; + bool was_lost = decoder->CheckResetStatus(); + return was_lost ? gpu::ContextResult::kTransientFailure + : gpu::ContextResult::kFatalFailure; } // Some shaders in Skia need more than the min available vertex and @@ -416,7 +440,9 @@ bool ContextGroup::Initialize(GLES2Decoder* decoder, << "vertex output components is too small (" << max_vertex_output_components_ << ", should be " << kMinVertexOutputComponents << ")."; - return false; + bool was_lost = decoder->CheckResetStatus(); + return was_lost ? gpu::ContextResult::kTransientFailure + : gpu::ContextResult::kFatalFailure; } if (!QueryGLFeatureU(GL_MAX_FRAGMENT_INPUT_COMPONENTS, kMinFragmentInputComponents, @@ -425,7 +451,9 @@ bool ContextGroup::Initialize(GLES2Decoder* decoder, << "fragment input components is too small (" << max_fragment_input_components_ << ", should be " << kMinFragmentInputComponents << ")."; - return false; + bool was_lost = decoder->CheckResetStatus(); + return was_lost ? gpu::ContextResult::kTransientFailure + : gpu::ContextResult::kFatalFailure; } if (!QueryGLFeature(GL_MAX_PROGRAM_TEXEL_OFFSET, kMin_MaxProgramTexelOffset, &max_program_texel_offset_)) { @@ -433,7 +461,9 @@ bool ContextGroup::Initialize(GLES2Decoder* decoder, << "program texel offset is too small (" << max_program_texel_offset_ << ", should be " << kMin_MaxProgramTexelOffset << ")."; - return false; + bool was_lost = decoder->CheckResetStatus(); + return was_lost ? gpu::ContextResult::kTransientFailure + : gpu::ContextResult::kFatalFailure; } glGetIntegerv(GL_MIN_PROGRAM_TEXEL_OFFSET, &min_program_texel_offset_); if (enforce_gl_minimums_) { @@ -445,7 +475,9 @@ bool ContextGroup::Initialize(GLES2Decoder* decoder, << "program texel offset is too big (" << min_program_texel_offset_ << ", should be " << kMax_MinProgramTexelOffset << ")."; - return false; + bool was_lost = decoder->CheckResetStatus(); + return was_lost ? gpu::ContextResult::kTransientFailure + : gpu::ContextResult::kFatalFailure; } const GLint kES3MinCubeMapSize = 2048; @@ -454,7 +486,9 @@ bool ContextGroup::Initialize(GLES2Decoder* decoder, << "cube texture size is too small (" << max_cube_map_texture_size << ", should be " << kES3MinCubeMapSize << ")."; - return false; + bool was_lost = decoder->CheckResetStatus(); + return was_lost ? gpu::ContextResult::kTransientFailure + : gpu::ContextResult::kFatalFailure; } } @@ -465,14 +499,10 @@ bool ContextGroup::Initialize(GLES2Decoder* decoder, max_dual_source_draw_buffers_, max_vertex_attribs_, gpu_preferences_, feature_info_.get(), progress_reporter_)); - if (!texture_manager_->Initialize()) { - DLOG(ERROR) << "Context::Group::Initialize failed because texture manager " - << "failed to initialize."; - return false; - } + texture_manager_->Initialize(); decoders_.push_back(decoder->AsWeakPtr()); - return true; + return gpu::ContextResult::kSuccess; } namespace { diff --git a/gpu/command_buffer/service/context_group.h b/gpu/command_buffer/service/context_group.h index b072dbe937ec05..d467f8bf0fd244 100644 --- a/gpu/command_buffer/service/context_group.h +++ b/gpu/command_buffer/service/context_group.h @@ -73,10 +73,9 @@ class GPU_EXPORT ContextGroup : public base::RefCounted { // This should only be called by GLES2Decoder. This must be paired with a // call to destroy if it succeeds. - bool Initialize( - GLES2Decoder* decoder, - ContextType context_type, - const DisallowedFeatures& disallowed_features); + gpu::ContextResult Initialize(GLES2Decoder* decoder, + ContextType context_type, + const DisallowedFeatures& disallowed_features); // Destroys all the resources when called for the last context in the group. // It should only be called by GLES2Decoder. diff --git a/gpu/command_buffer/service/context_group_unittest.cc b/gpu/command_buffer/service/context_group_unittest.cc index 0cb509858f7802..58c5951b21666d 100644 --- a/gpu/command_buffer/service/context_group_unittest.cc +++ b/gpu/command_buffer/service/context_group_unittest.cc @@ -124,16 +124,21 @@ TEST_F(ContextGroupTest, MultipleContexts) { TestHelper::SetupContextGroupInitExpectations( gl_.get(), DisallowedFeatures(), "", "", CONTEXT_TYPE_OPENGLES2, kBindGeneratesResource); - EXPECT_TRUE(group_->Initialize(decoder_.get(), CONTEXT_TYPE_OPENGLES2, - DisallowedFeatures())); - EXPECT_FALSE(group_->Initialize(decoder2_.get(), CONTEXT_TYPE_WEBGL1, - DisallowedFeatures())); - EXPECT_FALSE(group_->Initialize(decoder2_.get(), CONTEXT_TYPE_WEBGL2, - DisallowedFeatures())); - EXPECT_FALSE(group_->Initialize(decoder2_.get(), CONTEXT_TYPE_OPENGLES3, - DisallowedFeatures())); - EXPECT_TRUE(group_->Initialize(decoder2_.get(), CONTEXT_TYPE_OPENGLES2, - DisallowedFeatures())); + EXPECT_EQ(group_->Initialize(decoder_.get(), CONTEXT_TYPE_OPENGLES2, + DisallowedFeatures()), + gpu::ContextResult::kSuccess); + EXPECT_EQ(group_->Initialize(decoder2_.get(), CONTEXT_TYPE_WEBGL1, + DisallowedFeatures()), + gpu::ContextResult::kFatalFailure); + EXPECT_EQ(group_->Initialize(decoder2_.get(), CONTEXT_TYPE_WEBGL2, + DisallowedFeatures()), + gpu::ContextResult::kFatalFailure); + EXPECT_EQ(group_->Initialize(decoder2_.get(), CONTEXT_TYPE_OPENGLES3, + DisallowedFeatures()), + gpu::ContextResult::kFatalFailure); + EXPECT_EQ(group_->Initialize(decoder2_.get(), CONTEXT_TYPE_OPENGLES2, + DisallowedFeatures()), + gpu::ContextResult::kSuccess); EXPECT_TRUE(group_->buffer_manager() != NULL); EXPECT_TRUE(group_->renderbuffer_manager() != NULL); diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc index a1fdad76035e09..8c427755944954 100644 --- a/gpu/command_buffer/service/feature_info.cc +++ b/gpu/command_buffer/service/feature_info.cc @@ -250,25 +250,24 @@ void FeatureInfo::InitializeBasicState(const base::CommandLine* command_line) { command_line->HasSwitch(switches::kDisableGLSLTranslator); } -bool FeatureInfo::Initialize(ContextType context_type, +void FeatureInfo::Initialize(ContextType context_type, const DisallowedFeatures& disallowed_features) { disallowed_features_ = disallowed_features; context_type_ = context_type; InitializeFeatures(); - return true; } -bool FeatureInfo::InitializeForTesting( +void FeatureInfo::InitializeForTesting( const DisallowedFeatures& disallowed_features) { - return Initialize(CONTEXT_TYPE_OPENGLES2, disallowed_features); + Initialize(CONTEXT_TYPE_OPENGLES2, disallowed_features); } -bool FeatureInfo::InitializeForTesting() { - return Initialize(CONTEXT_TYPE_OPENGLES2, DisallowedFeatures()); +void FeatureInfo::InitializeForTesting() { + Initialize(CONTEXT_TYPE_OPENGLES2, DisallowedFeatures()); } -bool FeatureInfo::InitializeForTesting(ContextType context_type) { - return Initialize(context_type, DisallowedFeatures()); +void FeatureInfo::InitializeForTesting(ContextType context_type) { + Initialize(context_type, DisallowedFeatures()); } bool IsGL_REDSupportedOnFBOs() { diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h index 05fb1cbbd2ef4c..578ec82a9dffa1 100644 --- a/gpu/command_buffer/service/feature_info.h +++ b/gpu/command_buffer/service/feature_info.h @@ -132,15 +132,15 @@ class GPU_EXPORT FeatureInfo : public base::RefCounted { const GpuDriverBugWorkarounds& gpu_driver_bug_workarounds); // Initializes the feature information. Needs a current GL context. - bool Initialize(ContextType context_type, + void Initialize(ContextType context_type, const DisallowedFeatures& disallowed_features); // Helper that defaults to no disallowed features and a GLES2 context. - bool InitializeForTesting(); + void InitializeForTesting(); // Helper that defaults to no disallowed Features. - bool InitializeForTesting(ContextType context_type); + void InitializeForTesting(ContextType context_type); // Helper that defaults to a GLES2 context. - bool InitializeForTesting(const DisallowedFeatures& disallowed_features); + void InitializeForTesting(const DisallowedFeatures& disallowed_features); const Validators* validators() const { return &validators_; diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 5dc8721a947f24..27c756d8cd9a3c 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -536,11 +536,12 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient { // Overridden from GLES2Decoder. base::WeakPtr AsWeakPtr() override; - bool Initialize(const scoped_refptr& surface, - const scoped_refptr& context, - bool offscreen, - const DisallowedFeatures& disallowed_features, - const ContextCreationAttribHelper& attrib_helper) override; + gpu::ContextResult Initialize( + const scoped_refptr& surface, + const scoped_refptr& context, + bool offscreen, + const DisallowedFeatures& disallowed_features, + const ContextCreationAttribHelper& attrib_helper) override; void Destroy(bool have_context) override; void SetSurface(const scoped_refptr& surface) override; void ReleaseSurface() override; @@ -2069,7 +2070,7 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient { bool WasContextLost() const override; bool WasContextLostByRobustnessExtension() const override; void MarkContextLost(error::ContextLostReason reason) override; - bool CheckResetStatus(); + bool CheckResetStatus() override; bool GetCompressedTexSizeInBytes( const char* function_name, GLsizei width, GLsizei height, GLsizei depth, @@ -3188,7 +3189,7 @@ base::WeakPtr GLES2DecoderImpl::AsWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); } -bool GLES2DecoderImpl::Initialize( +gpu::ContextResult GLES2DecoderImpl::Initialize( const scoped_refptr& surface, const scoped_refptr& context, bool offscreen, @@ -3240,14 +3241,15 @@ bool GLES2DecoderImpl::Initialize( feature_info_->feature_flags().is_swiftshader_for_webgl) { group_ = NULL; // Must not destroy ContextGroup if it is not initialized. Destroy(true); - return false; + return gpu::ContextResult::kFatalFailure; } - if (!group_->Initialize(this, attrib_helper.context_type, - disallowed_features)) { + auto result = + group_->Initialize(this, attrib_helper.context_type, disallowed_features); + if (result != gpu::ContextResult::kSuccess) { group_ = NULL; // Must not destroy ContextGroup if it is not initialized. Destroy(true); - return false; + return result; } CHECK_GL_ERROR(); @@ -3274,7 +3276,7 @@ bool GLES2DecoderImpl::Initialize( if (!supported) { Destroy(true); - return false; + return gpu::ContextResult::kFatalFailure; } } @@ -3289,7 +3291,7 @@ bool GLES2DecoderImpl::Initialize( if (!feature_info_->IsES3Capable()) { LOG(ERROR) << "ES3 is blacklisted/disabled/unsupported by driver."; Destroy(true); - return false; + return gpu::ContextResult::kFatalFailure; } feature_info_->EnableES3Validators(); @@ -3625,7 +3627,7 @@ bool GLES2DecoderImpl::Initialize( gfx::Size(state_.viewport_width, state_.viewport_height))) { LOG(ERROR) << "Could not allocate offscreen buffer storage."; Destroy(true); - return false; + return gpu::ContextResult::kFatalFailure; } if (!offscreen_single_buffer_) { // Allocate the offscreen saved color texture. @@ -3638,8 +3640,10 @@ bool GLES2DecoderImpl::Initialize( if (offscreen_saved_frame_buffer_->CheckStatus() != GL_FRAMEBUFFER_COMPLETE) { LOG(ERROR) << "Offscreen saved FBO was incomplete."; + bool was_lost = CheckResetStatus(); Destroy(true); - return false; + return was_lost ? gpu::ContextResult::kTransientFailure + : gpu::ContextResult::kFatalFailure; } } } @@ -3705,7 +3709,7 @@ bool GLES2DecoderImpl::Initialize( LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glClearWorkaroundInit"); clear_framebuffer_blit_.reset(new ClearFramebufferResourceManager(this)); if (LOCAL_PEEK_GL_ERROR("glClearWorkaroundInit") != GL_NO_ERROR) - return false; + return gpu::ContextResult::kFatalFailure; } if (group_->gpu_preferences().enable_gpu_driver_debug_logging && @@ -3720,21 +3724,23 @@ bool GLES2DecoderImpl::Initialize( if (attrib_helper.enable_oop_rasterization) { if (!features().chromium_raster_transport) - return false; + return gpu::ContextResult::kFatalFailure; sk_sp interface( CreateGrGLInterface(gl_version_info())); // TODO(enne): if this or gr_context creation below fails in practice for // different reasons than the ones the renderer would fail on for gpu // raster, expose this in gpu::Capabilities so the renderer can handle it. if (!interface) - return false; + return gpu::ContextResult::kFatalFailure; gr_context_ = sk_sp( GrContext::Create(kOpenGL_GrBackend, reinterpret_cast(interface.get()))); if (!gr_context_) { LOG(ERROR) << "Could not create GrContext"; - return false; + bool was_lost = CheckResetStatus(); + return was_lost ? gpu::ContextResult::kTransientFailure + : gpu::ContextResult::kFatalFailure; } // TODO(enne): this cache is for this decoder only and each decoder has @@ -3748,7 +3754,7 @@ bool GLES2DecoderImpl::Initialize( kMaxGaneshResourceCacheBytes); } - return true; + return gpu::ContextResult::kSuccess; } Capabilities GLES2DecoderImpl::GetCapabilities() { diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h index b7a07e3f478d80..f860d390f369e4 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder.h @@ -21,6 +21,7 @@ #include "gpu/command_buffer/common/capabilities.h" #include "gpu/command_buffer/common/command_buffer_id.h" #include "gpu/command_buffer/common/constants.h" +#include "gpu/command_buffer/common/context_result.h" #include "gpu/command_buffer/service/common_decoder.h" #include "gpu/gpu_export.h" @@ -175,11 +176,12 @@ class GPU_EXPORT GLES2Decoder : public CommonDecoder, public AsyncAPIInterface { // offscreen_size: the size if the GL context is offscreen. // Returns: // true if successful. - virtual bool Initialize(const scoped_refptr& surface, - const scoped_refptr& context, - bool offscreen, - const DisallowedFeatures& disallowed_features, - const ContextCreationAttribHelper& attrib_helper) = 0; + virtual gpu::ContextResult Initialize( + const scoped_refptr& surface, + const scoped_refptr& context, + bool offscreen, + const DisallowedFeatures& disallowed_features, + const ContextCreationAttribHelper& attrib_helper) = 0; // Destroys the graphics context. virtual void Destroy(bool have_context) = 0; @@ -331,6 +333,13 @@ class GPU_EXPORT GLES2Decoder : public CommonDecoder, public AsyncAPIInterface { // Lose this context. virtual void MarkContextLost(error::ContextLostReason reason) = 0; + // Updates context lost state and returns true if lost. Most callers can use + // WasContextLost() as the GLES2Decoder will update the state internally. But + // if making GL calls directly, to the context then this state would not be + // updated and the caller can use this to determine if their calls failed due + // to context loss. + virtual bool CheckResetStatus() = 0; + virtual Logger* GetLogger() = 0; void BeginDecoding() override; diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h index 5a85501e7d141e..07d05041a3768c 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h @@ -42,12 +42,13 @@ class MockGLES2Decoder : public GLES2Decoder { base::WeakPtr AsWeakPtr() override; - MOCK_METHOD5(Initialize, - bool(const scoped_refptr& surface, - const scoped_refptr& context, - bool offscreen, - const DisallowedFeatures& disallowed_features, - const ContextCreationAttribHelper& attrib_helper)); + MOCK_METHOD5( + Initialize, + gpu::ContextResult(const scoped_refptr& surface, + const scoped_refptr& context, + bool offscreen, + const DisallowedFeatures& disallowed_features, + const ContextCreationAttribHelper& attrib_helper)); MOCK_METHOD1(Destroy, void(bool have_context)); MOCK_METHOD1(SetSurface, void(const scoped_refptr& surface)); MOCK_METHOD0(ReleaseSurface, void()); @@ -145,6 +146,7 @@ class MockGLES2Decoder : public GLES2Decoder { MOCK_CONST_METHOD0(WasContextLost, bool()); MOCK_CONST_METHOD0(WasContextLostByRobustnessExtension, bool()); MOCK_METHOD1(MarkContextLost, void(gpu::error::ContextLostReason reason)); + MOCK_METHOD0(CheckResetStatus, bool()); MOCK_METHOD4(BindImage, void(uint32_t client_texture_id, uint32_t texture_target, diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc index 4d427bec788dba..92cac07606aaa8 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc @@ -204,11 +204,10 @@ GLES2DecoderPassthroughImpl::EmulatedColorBuffer::EmulatedColorBuffer( GLES2DecoderPassthroughImpl::EmulatedColorBuffer::~EmulatedColorBuffer() = default; -bool GLES2DecoderPassthroughImpl::EmulatedColorBuffer::Resize( +void GLES2DecoderPassthroughImpl::EmulatedColorBuffer::Resize( const gfx::Size& new_size) { - if (size == new_size) { - return true; - } + if (size == new_size) + return; size = new_size; ScopedTexture2DBindingReset scoped_texture_reset; @@ -220,8 +219,6 @@ bool GLES2DecoderPassthroughImpl::EmulatedColorBuffer::Resize( glTexImage2D(texture->target(), 0, format.color_texture_internal_format, size.width(), size.height(), 0, format.color_texture_format, format.color_texture_type, nullptr); - - return true; } void GLES2DecoderPassthroughImpl::EmulatedColorBuffer::Destroy( @@ -344,11 +341,8 @@ bool GLES2DecoderPassthroughImpl::EmulatedDefaultFramebuffer::Resize( ResizeRenderbuffer(color_buffer_service_id, size, format.samples, format.color_renderbuffer_internal_format, feature_info); } - if (color_texture) { - if (!color_texture->Resize(size)) { - return false; - } - } + if (color_texture) + color_texture->Resize(size); if (depth_stencil_buffer_service_id != 0) { ResizeRenderbuffer(depth_stencil_buffer_service_id, size, format.samples, format.depth_stencil_internal_format, feature_info); @@ -547,7 +541,7 @@ base::WeakPtr GLES2DecoderPassthroughImpl::AsWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); } -bool GLES2DecoderPassthroughImpl::Initialize( +gpu::ContextResult GLES2DecoderPassthroughImpl::Initialize( const scoped_refptr& surface, const scoped_refptr& context, bool offscreen, @@ -562,11 +556,13 @@ bool GLES2DecoderPassthroughImpl::Initialize( // Create GPU Tracer for timing values. gpu_tracer_.reset(new GPUTracer(this)); - if (!group_->Initialize(this, attrib_helper.context_type, - disallowed_features)) { - group_ = NULL; // Must not destroy ContextGroup if it is not initialized. + auto result = + group_->Initialize(this, attrib_helper.context_type, disallowed_features); + if (result != gpu::ContextResult::kSuccess) { + // Must not destroy ContextGroup if it is not initialized. + group_ = nullptr; Destroy(true); - return false; + return result; } // Extensions that are enabled via emulation on the client side or needed for @@ -627,11 +623,7 @@ bool GLES2DecoderPassthroughImpl::Initialize( // Each context initializes its own feature info because some extensions may // be enabled dynamically. Don't disallow any features, leave it up to ANGLE // to dynamically enable extensions. - if (!feature_info_->Initialize(attrib_helper.context_type, - DisallowedFeatures())) { - Destroy(true); - return false; - } + feature_info_->Initialize(attrib_helper.context_type, DisallowedFeatures()); // Check for required extensions // TODO(geofflang): verify @@ -646,12 +638,12 @@ bool GLES2DecoderPassthroughImpl::Initialize( IsWebGLContextType(attrib_helper.context_type) || !feature_info_->feature_flags().angle_request_extension) { Destroy(true); - return false; + return gpu::ContextResult::kFatalFailure; } if (attrib_helper.enable_oop_rasterization) { Destroy(true); - return false; + return gpu::ContextResult::kFatalFailure; } bind_generates_resource_ = group_->bind_generates_resource(); @@ -772,19 +764,22 @@ bool GLES2DecoderPassthroughImpl::Initialize( } FlushErrors(); - emulated_back_buffer_.reset(new EmulatedDefaultFramebuffer( - emulated_default_framebuffer_format_, feature_info_.get())); + emulated_back_buffer_ = std::make_unique( + emulated_default_framebuffer_format_, feature_info_.get()); if (!emulated_back_buffer_->Resize(attrib_helper.offscreen_framebuffer_size, feature_info_.get())) { + bool was_lost = CheckResetStatus(); Destroy(true); - return false; + return was_lost ? gpu::ContextResult::kTransientFailure + : gpu::ContextResult::kFatalFailure; } if (FlushErrors()) { LOG(ERROR) << "Creation of the offscreen framebuffer failed because " "errors were generated."; Destroy(true); - return false; + // Errors are considered fatal, including OOM. + return gpu::ContextResult::kFatalFailure; } framebuffer_id_map_.SetIDMapping( @@ -798,7 +793,7 @@ bool GLES2DecoderPassthroughImpl::Initialize( } set_initialized(); - return true; + return gpu::ContextResult::kSuccess; } void GLES2DecoderPassthroughImpl::Destroy(bool have_context) { @@ -912,7 +907,7 @@ void GLES2DecoderPassthroughImpl::TakeFrontBuffer(const Mailbox& mailbox) { return; } - if (!emulated_front_buffer_.get()) { + if (!emulated_front_buffer_) { DLOG(ERROR) << "Called TakeFrontBuffer on a non-offscreen context"; return; } @@ -924,12 +919,9 @@ void GLES2DecoderPassthroughImpl::TakeFrontBuffer(const Mailbox& mailbox) { if (available_color_textures_.empty()) { // Create a new color texture to use as the front buffer - emulated_front_buffer_.reset( - new EmulatedColorBuffer(emulated_default_framebuffer_format_)); - if (!emulated_front_buffer_->Resize(emulated_back_buffer_->size)) { - DLOG(ERROR) << "Failed to create a new emulated front buffer texture."; - return; - } + emulated_front_buffer_ = std::make_unique( + emulated_default_framebuffer_format_); + emulated_front_buffer_->Resize(emulated_back_buffer_->size); create_color_buffer_count_for_test_++; } else { emulated_front_buffer_ = std::move(available_color_textures_.back()); diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h index 8b209280a1e6be..d54b40a12ef086 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h @@ -124,11 +124,12 @@ class GPU_EXPORT GLES2DecoderPassthroughImpl : public GLES2Decoder { base::WeakPtr AsWeakPtr() override; - bool Initialize(const scoped_refptr& surface, - const scoped_refptr& context, - bool offscreen, - const DisallowedFeatures& disallowed_features, - const ContextCreationAttribHelper& attrib_helper) override; + gpu::ContextResult Initialize( + const scoped_refptr& surface, + const scoped_refptr& context, + bool offscreen, + const DisallowedFeatures& disallowed_features, + const ContextCreationAttribHelper& attrib_helper) override; // Destroys the graphics context. void Destroy(bool have_context) override; @@ -275,6 +276,10 @@ class GPU_EXPORT GLES2DecoderPassthroughImpl : public GLES2Decoder { // Lose this context. void MarkContextLost(error::ContextLostReason reason) override; + // Update lost context state for use when making calls to the GL context + // directly, and needing to know if they failed due to loss. + bool CheckResetStatus() override; + Logger* GetLogger() override; void BeginDecoding() override; @@ -348,7 +353,6 @@ class GPU_EXPORT GLES2DecoderPassthroughImpl : public GLES2Decoder { // call to glGetError void InjectDriverError(GLenum error); - bool CheckResetStatus(); bool IsRobustnessSupported(); bool IsEmulatedQueryTarget(GLenum target) const; @@ -525,7 +529,7 @@ class GPU_EXPORT GLES2DecoderPassthroughImpl : public GLES2Decoder { const EmulatedDefaultFramebufferFormat& format_in); ~EmulatedColorBuffer(); - bool Resize(const gfx::Size& new_size); + void Resize(const gfx::Size& new_size); void Destroy(bool have_context); scoped_refptr texture; diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc index 194bffac84eed2..9d34393efbe634 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc @@ -3141,13 +3141,9 @@ error::Error GLES2DecoderPassthroughImpl::DoSwapBuffers() { emulated_front_buffer_ = std::move(available_color_textures_.back()); available_color_textures_.pop_back(); } else { - emulated_front_buffer_.reset( - new EmulatedColorBuffer(emulated_default_framebuffer_format_)); - if (!emulated_front_buffer_->Resize(emulated_back_buffer_->size)) { - DLOG(ERROR) - << "Failed to create a new emulated front buffer texture."; - return error::kLostContext; - } + emulated_front_buffer_ = std::make_unique( + emulated_default_framebuffer_format_); + emulated_front_buffer_->Resize(emulated_back_buffer_->size); } } @@ -3371,10 +3367,8 @@ error::Error GLES2DecoderPassthroughImpl::DoRequestExtensionCHROMIUM( // Make sure newly enabled extensions are exposed and usable. context_->ReinitializeDynamicBindings(); - if (!feature_info_->Initialize(feature_info_->context_type(), - feature_info_->disallowed_features())) { - return error::kLostContext; - } + feature_info_->Initialize(feature_info_->context_type(), + feature_info_->disallowed_features()); return error::kNoError; } diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc index 5fdc10d2d44d90..1960215c1149b6 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc @@ -246,8 +246,9 @@ void GLES2DecoderTestBase::InitDecoderWithWorkarounds( mock_decoder_.reset( new MockGLES2Decoder(command_buffer_service_.get(), &outputter_)); - EXPECT_TRUE(group_->Initialize(mock_decoder_.get(), init.context_type, - DisallowedFeatures())); + EXPECT_EQ(group_->Initialize(mock_decoder_.get(), init.context_type, + DisallowedFeatures()), + gpu::ContextResult::kSuccess); if (init.context_type == CONTEXT_TYPE_WEBGL2 || init.context_type == CONTEXT_TYPE_OPENGLES3) { @@ -490,8 +491,9 @@ void GLES2DecoderTestBase::InitDecoderWithWorkarounds( &outputter_, group_.get())); decoder_->SetIgnoreCachedStateForTest(ignore_cached_state_for_test_); decoder_->GetLogger()->set_log_synthesized_gl_errors(false); - ASSERT_TRUE(decoder_->Initialize(surface_, context_, false, - DisallowedFeatures(), attribs)); + ASSERT_EQ(decoder_->Initialize(surface_, context_, false, + DisallowedFeatures(), attribs), + gpu::ContextResult::kSuccess); EXPECT_CALL(*context_, MakeCurrent(surface_.get())).WillOnce(Return(true)); if (context_->WasAllocatedUsingRobustnessExtension()) { @@ -2273,12 +2275,14 @@ void GLES2DecoderPassthroughTestBase::SetUp() { decoder_.reset(new GLES2DecoderPassthroughImpl( this, command_buffer_service_.get(), &outputter_, group_.get())); - ASSERT_TRUE(group_->Initialize(decoder_.get(), - context_creation_attribs_.context_type, - DisallowedFeatures())); - ASSERT_TRUE(decoder_->Initialize(surface_, context_, false, - DisallowedFeatures(), - context_creation_attribs_)); + ASSERT_EQ( + group_->Initialize(decoder_.get(), context_creation_attribs_.context_type, + DisallowedFeatures()), + gpu::ContextResult::kSuccess); + ASSERT_EQ( + decoder_->Initialize(surface_, context_, false, DisallowedFeatures(), + context_creation_attribs_), + gpu::ContextResult::kSuccess); scoped_refptr buffer = command_buffer_service_->CreateTransferBufferHelper(kSharedBufferSize, diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc index 9dafeeaed650df..c1b4475f79bfaa 100644 --- a/gpu/command_buffer/service/texture_manager.cc +++ b/gpu/command_buffer/service/texture_manager.cc @@ -2009,7 +2009,7 @@ void TextureManager::RemoveFramebufferManager( NOTREACHED(); } -bool TextureManager::Initialize() { +void TextureManager::Initialize() { // Reset PIXEL_UNPACK_BUFFER to avoid unrelated GL error on some GL drivers. if (feature_info_->gl_version_info().is_es3_capable) { glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); @@ -2048,8 +2048,6 @@ bool TextureManager::Initialize() { base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( this, "gpu::TextureManager", base::ThreadTaskRunnerHandle::Get()); } - - return true; } scoped_refptr diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h index 77b7e7fef5c9dc..776d528785b0b0 100644 --- a/gpu/command_buffer/service/texture_manager.h +++ b/gpu/command_buffer/service/texture_manager.h @@ -771,7 +771,7 @@ class GPU_EXPORT TextureManager : public base::trace_event::MemoryDumpProvider { void RemoveFramebufferManager(FramebufferManager* framebuffer_manager); // Init the texture manager. - bool Initialize(); + void Initialize(); // Must call before destruction. void Destroy(bool have_context); diff --git a/gpu/command_buffer/tests/fuzzer_main.cc b/gpu/command_buffer/tests/fuzzer_main.cc index 4f9d6effa04b11..f6863b4835a025 100644 --- a/gpu/command_buffer/tests/fuzzer_main.cc +++ b/gpu/command_buffer/tests/fuzzer_main.cc @@ -184,10 +184,10 @@ class CommandBufferSetup { attrib_helper.context_type = gles2::CONTEXT_TYPE_OPENGLES3; #endif - bool result = + auto result = decoder_->Initialize(surface_.get(), context_.get(), true, gles2::DisallowedFeatures(), attrib_helper); - CHECK(result); + CHECK_EQ(result, gpu::ContextResult::kSuccess); decoder_->set_max_bucket_size(8 << 20); context_group->buffer_manager()->set_max_buffer_size(8 << 20); if (!vertex_translator_) { diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc index 23c1fbb421d015..f66bc55df068e7 100644 --- a/gpu/command_buffer/tests/gl_manager.cc +++ b/gpu/command_buffer/tests/gl_manager.cc @@ -369,17 +369,19 @@ void GLManager::InitializeWithWorkaroundsImpl( ASSERT_TRUE(context_->MakeCurrent(surface_.get())); - if (!decoder_->Initialize(surface_.get(), context_.get(), true, - ::gpu::gles2::DisallowedFeatures(), attribs)) { + auto result = + decoder_->Initialize(surface_.get(), context_.get(), true, + ::gpu::gles2::DisallowedFeatures(), attribs); + if (result != gpu::ContextResult::kSuccess) return; - } // Client side Capabilities queries return reference, service side return // value. Here two sides are joined together. capabilities_ = decoder_->GetCapabilities(); // Create the GLES2 helper, which writes the command buffer protocol. gles2_helper_.reset(new gles2::GLES2CmdHelper(command_buffer_.get())); - ASSERT_TRUE(gles2_helper_->Initialize(limits.command_buffer_size)); + ASSERT_EQ(gles2_helper_->Initialize(limits.command_buffer_size), + gpu::ContextResult::kSuccess); // Create a transfer buffer. transfer_buffer_.reset(new TransferBuffer(gles2_helper_.get())); @@ -392,7 +394,8 @@ void GLManager::InitializeWithWorkaroundsImpl( options.lose_context_when_out_of_memory, support_client_side_arrays, this)); - ASSERT_TRUE(gles2_implementation_->Initialize(limits)) + ASSERT_EQ(gles2_implementation_->Initialize(limits), + gpu::ContextResult::kSuccess) << "Could not init GLES2Implementation"; MakeCurrent(); diff --git a/gpu/command_buffer/tests/gl_unittest.cc b/gpu/command_buffer/tests/gl_unittest.cc index 344e888d93f69f..7acc5e9314f321 100644 --- a/gpu/command_buffer/tests/gl_unittest.cc +++ b/gpu/command_buffer/tests/gl_unittest.cc @@ -104,7 +104,7 @@ TEST_F(GLTest, SimpleShader) { TEST_F(GLTest, FeatureFlagsMatchCapabilities) { scoped_refptr features = new gles2::FeatureInfo(gl_.workarounds()); - EXPECT_TRUE(features->InitializeForTesting()); + features->InitializeForTesting(); const auto& caps = gl_.GetCapabilities(); const auto& flags = features->feature_flags(); EXPECT_EQ(caps.egl_image_external, flags.oes_egl_image_external); diff --git a/gpu/gles2_conform_support/egl/context.cc b/gpu/gles2_conform_support/egl/context.cc index 02faa6d1675fff..12b09e60812e10 100644 --- a/gpu/gles2_conform_support/egl/context.cc +++ b/gpu/gles2_conform_support/egl/context.cc @@ -303,15 +303,16 @@ bool Context::CreateService(gl::GLSurface* gl_surface) { helper.context_type = gpu::gles2::CONTEXT_TYPE_OPENGLES2; helper.offscreen_framebuffer_size = gl_surface->GetSize(); - if (!decoder->Initialize(gl_surface, gl_context.get(), - gl_surface->IsOffscreen(), - gpu::gles2::DisallowedFeatures(), helper)) { + auto result = decoder->Initialize(gl_surface, gl_context.get(), + gl_surface->IsOffscreen(), + gpu::gles2::DisallowedFeatures(), helper); + if (result != gpu::ContextResult::kSuccess) return false; - } - std::unique_ptr gles2_cmd_helper( - new gpu::gles2::GLES2CmdHelper(command_buffer.get())); - if (!gles2_cmd_helper->Initialize(limits.command_buffer_size)) { + auto gles2_cmd_helper = + std::make_unique(command_buffer.get()); + result = gles2_cmd_helper->Initialize(limits.command_buffer_size); + if (result != gpu::ContextResult::kSuccess) { decoder->Destroy(true); return false; } @@ -319,29 +320,29 @@ bool Context::CreateService(gl::GLSurface* gl_surface) { // value. Here two sides are joined together. capabilities_ = decoder->GetCapabilities(); - std::unique_ptr transfer_buffer( - new gpu::TransferBuffer(gles2_cmd_helper.get())); + auto transfer_buffer = + std::make_unique(gles2_cmd_helper.get()); - gles2_cmd_helper_.reset(gles2_cmd_helper.release()); - transfer_buffer_.reset(transfer_buffer.release()); - command_buffer_.reset(command_buffer.release()); - decoder_.reset(decoder.release()); + gles2_cmd_helper_ = std::move(gles2_cmd_helper); + transfer_buffer_ = std::move(transfer_buffer); + command_buffer_ = std::move(command_buffer); + decoder_ = std::move(decoder); gl_context_ = gl_context.get(); - std::unique_ptr context( - new gpu::gles2::GLES2Implementation( - gles2_cmd_helper_.get(), nullptr, transfer_buffer_.get(), - kBindGeneratesResources, kLoseContextWhenOutOfMemory, - kSupportClientSideArrays, this)); + auto context = std::make_unique( + gles2_cmd_helper_.get(), nullptr, transfer_buffer_.get(), + kBindGeneratesResources, kLoseContextWhenOutOfMemory, + kSupportClientSideArrays, this); - if (!context->Initialize(limits)) { + result = context->Initialize(limits); + if (result != gpu::ContextResult::kSuccess) { DestroyService(); return false; } context->EnableFeatureCHROMIUM("pepper3d_allow_buffers_on_multiple_targets"); context->EnableFeatureCHROMIUM("pepper3d_support_fixed_attribs"); - client_gl_context_.reset(context.release()); + client_gl_context_ = std::move(context); return true; } diff --git a/gpu/gles2_conform_support/egl/context.h b/gpu/gles2_conform_support/egl/context.h index a998c2c4f948f9..9d7bd3ef183148 100644 --- a/gpu/gles2_conform_support/egl/context.h +++ b/gpu/gles2_conform_support/egl/context.h @@ -40,7 +40,7 @@ class Surface; class Config; class Context : public base::RefCountedThreadSafe, - private gpu::GpuControl { + public gpu::GpuControl { public: Context(Display* display, const Config* config); bool is_current_in_some_thread() const { return is_current_in_some_thread_; } diff --git a/gpu/ipc/client/command_buffer_proxy_impl.cc b/gpu/ipc/client/command_buffer_proxy_impl.cc index 4e9e5bfbe04eaa..f4af674a6778b0 100644 --- a/gpu/ipc/client/command_buffer_proxy_impl.cc +++ b/gpu/ipc/client/command_buffer_proxy_impl.cc @@ -49,54 +49,93 @@ int GetChannelID(gpu::CommandBufferId command_buffer_id) { } // namespace -CommandBufferProxyImpl::CommandBufferProxyImpl(int channel_id, - int32_t route_id, - int32_t stream_id) - : command_buffer_id_(CommandBufferProxyID(channel_id, route_id)), - channel_id_(channel_id), - route_id_(route_id), +CommandBufferProxyImpl::CommandBufferProxyImpl( + scoped_refptr channel, + int32_t stream_id, + scoped_refptr task_runner) + : channel_(std::move(channel)), + channel_id_(channel_->channel_id()), + route_id_(channel_->GenerateRouteID()), stream_id_(stream_id), + command_buffer_id_(CommandBufferProxyID(channel_id_, route_id_)), + callback_thread_(std::move(task_runner)), weak_ptr_factory_(this) { - DCHECK(route_id); + DCHECK(route_id_); } -// static -std::unique_ptr CommandBufferProxyImpl::Create( - scoped_refptr host, +CommandBufferProxyImpl::~CommandBufferProxyImpl() { + for (auto& observer : deletion_observers_) + observer.OnWillDeleteImpl(); + DisconnectChannel(); +} + +ContextResult CommandBufferProxyImpl::Initialize( gpu::SurfaceHandle surface_handle, CommandBufferProxyImpl* share_group, - int32_t stream_id, gpu::SchedulingPriority stream_priority, const gpu::gles2::ContextCreationAttribHelper& attribs, - const GURL& active_url, - scoped_refptr task_runner) { - DCHECK(!share_group || (stream_id == share_group->stream_id_)); + const GURL& active_url) { + DCHECK(!share_group || (stream_id_ == share_group->stream_id_)); TRACE_EVENT1("gpu", "GpuChannelHost::CreateViewCommandBuffer", "surface_handle", surface_handle); + // Drop the |channel_| if this method does not succeed and early-outs, to + // prevent cleanup on destruction. + auto channel = std::move(channel_); + GPUCreateCommandBufferConfig init_params; init_params.surface_handle = surface_handle; init_params.share_group_id = share_group ? share_group->route_id_ : MSG_ROUTING_NONE; - init_params.stream_id = stream_id; + init_params.stream_id = stream_id_; init_params.stream_priority = stream_priority; init_params.attribs = attribs; init_params.active_url = active_url; - int32_t route_id = host->GenerateRouteID(); - std::unique_ptr command_buffer = base::WrapUnique( - new CommandBufferProxyImpl(host->channel_id(), route_id, stream_id)); - if (!command_buffer->Initialize(std::move(host), std::move(init_params), - std::move(task_runner))) - return nullptr; + TRACE_EVENT0("gpu", "CommandBufferProxyImpl::Initialize"); + shared_state_shm_ = + channel->factory()->AllocateSharedMemory(sizeof(*shared_state())); + if (!shared_state_shm_) + return ContextResult::kFatalFailure; - return command_buffer; -} + if (!shared_state_shm_->Map(sizeof(*shared_state()))) + return ContextResult::kFatalFailure; -CommandBufferProxyImpl::~CommandBufferProxyImpl() { - for (auto& observer : deletion_observers_) - observer.OnWillDeleteImpl(); - DisconnectChannel(); + shared_state()->Initialize(); + + // This handle is owned by the GPU process and must be passed to it or it + // will leak. In otherwords, do not early out on error between here and the + // sending of the CreateCommandBuffer IPC below. + base::SharedMemoryHandle handle = + channel->ShareToGpuProcess(shared_state_shm_->handle()); + if (!base::SharedMemory::IsHandleValid(handle)) + return ContextResult::kFatalFailure; + + // Route must be added before sending the message, otherwise messages sent + // from the GPU process could race against adding ourselves to the filter. + channel->AddRouteWithTaskRunner(route_id_, weak_ptr_factory_.GetWeakPtr(), + callback_thread_); + + // We're blocking the UI thread, which is generally undesirable. + // In this case we need to wait for this before we can show any UI /anyway/, + // so it won't cause additional jank. + // TODO(piman): Make this asynchronous (http://crbug.com/125248). + ContextResult result = ContextResult::kSuccess; + bool sent = channel->Send(new GpuChannelMsg_CreateCommandBuffer( + init_params, route_id_, handle, &result, &capabilities_)); + if (!sent) { + DLOG(ERROR) << "Failed to send GpuChannelMsg_CreateCommandBuffer."; + channel->RemoveRoute(route_id_); + return ContextResult::kTransientFailure; + } + if (result != ContextResult::kSuccess) { + DLOG(ERROR) << "Failure processing GpuChannelMsg_CreateCommandBuffer."; + channel->RemoveRoute(route_id_); + return result; + } + + channel_ = std::move(channel); + return result; } bool CommandBufferProxyImpl::OnMessageReceived(const IPC::Message& message) { @@ -191,54 +230,6 @@ void CommandBufferProxyImpl::OnSignalAck(uint32_t id, callback.Run(); } -bool CommandBufferProxyImpl::Initialize( - scoped_refptr channel, - const GPUCreateCommandBufferConfig& config, - scoped_refptr task_runner) { - DCHECK(!channel_); - TRACE_EVENT0("gpu", "CommandBufferProxyImpl::Initialize"); - shared_state_shm_ = - channel->factory()->AllocateSharedMemory(sizeof(*shared_state())); - if (!shared_state_shm_) - return false; - - if (!shared_state_shm_->Map(sizeof(*shared_state()))) - return false; - - shared_state()->Initialize(); - - // This handle is owned by the GPU process and must be passed to it or it - // will leak. In otherwords, do not early out on error between here and the - // sending of the CreateCommandBuffer IPC below. - base::SharedMemoryHandle handle = - channel->ShareToGpuProcess(shared_state_shm_->handle()); - if (!base::SharedMemory::IsHandleValid(handle)) - return false; - - // Route must be added before sending the message, otherwise messages sent - // from the GPU process could race against adding ourselves to the filter. - channel->AddRouteWithTaskRunner(route_id_, weak_ptr_factory_.GetWeakPtr(), - task_runner); - - // We're blocking the UI thread, which is generally undesirable. - // In this case we need to wait for this before we can show any UI /anyway/, - // so it won't cause additional jank. - // TODO(piman): Make this asynchronous (http://crbug.com/125248). - bool result = false; - bool sent = channel->Send(new GpuChannelMsg_CreateCommandBuffer( - config, route_id_, handle, &result, &capabilities_)); - if (!sent || !result) { - DLOG(ERROR) << "Failed to send GpuChannelMsg_CreateCommandBuffer."; - channel->RemoveRoute(route_id_); - return false; - } - - channel_ = std::move(channel); - callback_thread_ = std::move(task_runner); - - return true; -} - CommandBuffer::State CommandBufferProxyImpl::GetLastState() { base::AutoLock lock(last_state_lock_); TryUpdateState(); diff --git a/gpu/ipc/client/command_buffer_proxy_impl.h b/gpu/ipc/client/command_buffer_proxy_impl.h index 873d5a1e04ccf1..433e8bac3f2866 100644 --- a/gpu/ipc/client/command_buffer_proxy_impl.h +++ b/gpu/ipc/client/command_buffer_proxy_impl.h @@ -26,6 +26,7 @@ #include "gpu/command_buffer/common/command_buffer.h" #include "gpu/command_buffer/common/command_buffer_id.h" #include "gpu/command_buffer/common/command_buffer_shared.h" +#include "gpu/command_buffer/common/context_result.h" #include "gpu/command_buffer/common/gpu_memory_allocation.h" #include "gpu/command_buffer/common/scheduling_priority.h" #include "gpu/gpu_export.h" @@ -36,7 +37,6 @@ #include "ui/latency/latency_info.h" struct GPUCommandBufferConsoleMessage; -struct GPUCreateCommandBufferConfig; struct GpuCommandBufferMsg_SwapBuffersCompleted_Params; class GURL; @@ -75,17 +75,19 @@ class GPU_EXPORT CommandBufferProxyImpl : public gpu::CommandBuffer, typedef base::Callback GpuConsoleMessageCallback; - // Create and connect to a command buffer in the GPU process. - static std::unique_ptr Create( - scoped_refptr host, + CommandBufferProxyImpl( + scoped_refptr channel, + int32_t stream_id, + scoped_refptr task_runner); + ~CommandBufferProxyImpl() override; + + // Connect to a command buffer in the GPU process. + ContextResult Initialize( gpu::SurfaceHandle surface_handle, CommandBufferProxyImpl* share_group, - int32_t stream_id, gpu::SchedulingPriority stream_priority, const gpu::gles2::ContextCreationAttribHelper& attribs, - const GURL& active_url, - scoped_refptr task_runner); - ~CommandBufferProxyImpl() override; + const GURL& active_url); // IPC::Listener implementation: bool OnMessageReceived(const IPC::Message& message) override; @@ -167,11 +169,6 @@ class GPU_EXPORT CommandBufferProxyImpl : public gpu::CommandBuffer, typedef std::map> TransferBufferMap; typedef base::hash_map SignalTaskMap; - CommandBufferProxyImpl(int channel_id, int32_t route_id, int32_t stream_id); - bool Initialize(scoped_refptr channel, - const GPUCreateCommandBufferConfig& config, - scoped_refptr task_runner); - void CheckLock() { if (lock_) { lock_->AssertAcquired(); @@ -256,10 +253,10 @@ class GPU_EXPORT CommandBufferProxyImpl : public gpu::CommandBuffer, scoped_refptr channel_; bool disconnected_ = false; - const gpu::CommandBufferId command_buffer_id_; const int channel_id_; const int32_t route_id_; const int32_t stream_id_; + const gpu::CommandBufferId command_buffer_id_; uint32_t last_flush_id_ = 0; int32_t last_put_offset_ = -1; bool has_buffer_ = false; @@ -289,7 +286,7 @@ class GPU_EXPORT CommandBufferProxyImpl : public gpu::CommandBuffer, SwapBuffersCompletionCallback swap_buffers_completion_callback_; UpdateVSyncParametersCallback update_vsync_parameters_completion_callback_; - scoped_refptr callback_thread_; + scoped_refptr callback_thread_; base::WeakPtrFactory weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(CommandBufferProxyImpl); diff --git a/gpu/ipc/client/gpu_in_process_context_tests.cc b/gpu/ipc/client/gpu_in_process_context_tests.cc index ce6919349aee43..dba3e7e3ff580f 100644 --- a/gpu/ipc/client/gpu_in_process_context_tests.cc +++ b/gpu/ipc/client/gpu_in_process_context_tests.cc @@ -35,15 +35,18 @@ class ContextTestBase : public testing::Test { attributes.sample_buffers = 1; attributes.bind_generates_resource = false; - return base::WrapUnique(gpu::GLInProcessContext::Create( - nullptr, /* service */ - nullptr, /* surface */ - true, /* offscreen */ - gpu::kNullSurfaceHandle, /* window */ - nullptr, /* share_context */ - attributes, gpu::SharedMemoryLimits(), gpu_memory_buffer_manager_.get(), - nullptr, /* image_factory */ - base::ThreadTaskRunnerHandle::Get())); + auto context = gpu::GLInProcessContext::CreateWithoutInit(); + auto result = context->Initialize(nullptr, /* service */ + nullptr, /* surface */ + true, /* offscreen */ + gpu::kNullSurfaceHandle, /* window */ + nullptr, /* share_context */ + attributes, gpu::SharedMemoryLimits(), + gpu_memory_buffer_manager_.get(), + nullptr, /* image_factory */ + base::ThreadTaskRunnerHandle::Get()); + DCHECK_EQ(result, gpu::ContextResult::kSuccess); + return context; } void SetUp() override { diff --git a/gpu/ipc/common/gpu_messages.h b/gpu/ipc/common/gpu_messages.h index c147bdb8240f0a..7e201ea83d9532 100644 --- a/gpu/ipc/common/gpu_messages.h +++ b/gpu/ipc/common/gpu_messages.h @@ -105,7 +105,7 @@ IPC_SYNC_MESSAGE_CONTROL3_2(GpuChannelMsg_CreateCommandBuffer, GPUCreateCommandBufferConfig /* init_params */, int32_t /* route_id */, base::SharedMemoryHandle /* shared_state */, - bool /* result */, + gpu::ContextResult, gpu::Capabilities /* capabilities */) // The CommandBufferProxy sends this to the GpuCommandBufferStub in its diff --git a/gpu/ipc/common/gpu_param_traits_macros.h b/gpu/ipc/common/gpu_param_traits_macros.h index 02c3f5a2739825..f7d61ee3528604 100644 --- a/gpu/ipc/common/gpu_param_traits_macros.h +++ b/gpu/ipc/common/gpu_param_traits_macros.h @@ -6,6 +6,7 @@ #define GPU_IPC_COMMON_GPU_PARAM_TRAITS_MACROS_H_ #include "gpu/command_buffer/common/constants.h" +#include "gpu/command_buffer/common/context_result.h" #include "gpu/command_buffer/common/scheduling_priority.h" #include "gpu/gpu_export.h" #include "gpu/ipc/common/flush_params.h" @@ -27,5 +28,7 @@ IPC_STRUCT_TRAITS_END() IPC_ENUM_TRAITS_MAX_VALUE(gpu::SchedulingPriority, gpu::SchedulingPriority::kLast) +IPC_ENUM_TRAITS_MAX_VALUE(gpu::ContextResult, + gpu::ContextResult::kLastContextResult); #endif // GPU_IPC_COMMON_GPU_PARAM_TRAITS_MACROS_H_ diff --git a/gpu/ipc/gl_in_process_context.cc b/gpu/ipc/gl_in_process_context.cc index 59a5ee21e2ecf6..39b4faa4bd26cb 100644 --- a/gpu/ipc/gl_in_process_context.cc +++ b/gpu/ipc/gl_in_process_context.cc @@ -52,18 +52,18 @@ class GLInProcessContextImpl GLInProcessContextImpl(); ~GLInProcessContextImpl() override; - bool Initialize(scoped_refptr surface, - bool is_offscreen, - GLInProcessContext* share_context, - SurfaceHandle window, - const gpu::gles2::ContextCreationAttribHelper& attribs, - const scoped_refptr& service, - const SharedMemoryLimits& mem_limits, - GpuMemoryBufferManager* gpu_memory_buffer_manager, - ImageFactory* image_factory, - scoped_refptr task_runner); - // GLInProcessContext implementation: + gpu::ContextResult Initialize( + scoped_refptr service, + scoped_refptr surface, + bool is_offscreen, + SurfaceHandle window, + GLInProcessContext* share_context, + const gpu::gles2::ContextCreationAttribHelper& attribs, + const SharedMemoryLimits& mem_limits, + GpuMemoryBufferManager* gpu_memory_buffer_manager, + ImageFactory* image_factory, + scoped_refptr task_runner) override; const gpu::Capabilities& GetCapabilities() const override; const gpu::GpuFeatureInfo& GetGpuFeatureInfo() const override; gles2::GLES2Implementation* GetImplementation() override; @@ -76,7 +76,6 @@ class GLInProcessContextImpl void SetLock(base::Lock* lock) override; private: - void Destroy(); void OnSignalSyncPoint(const base::Closure& callback); std::unique_ptr gles2_helper_; @@ -90,7 +89,20 @@ class GLInProcessContextImpl GLInProcessContextImpl::GLInProcessContextImpl() = default; GLInProcessContextImpl::~GLInProcessContextImpl() { - Destroy(); + if (gles2_implementation_) { + // First flush the context to ensure that any pending frees of resources + // are completed. Otherwise, if this context is part of a share group, + // those resources might leak. Also, any remaining side effects of commands + // issued on this context might not be visible to other contexts in the + // share group. + gles2_implementation_->Flush(); + + gles2_implementation_.reset(); + } + + transfer_buffer_.reset(); + gles2_helper_.reset(); + command_buffer_.reset(); } const Capabilities& GLInProcessContextImpl::GetCapabilities() const { @@ -121,21 +133,28 @@ void GLInProcessContextImpl::SetLock(base::Lock* lock) { NOTREACHED(); } -bool GLInProcessContextImpl::Initialize( +gpu::ContextResult GLInProcessContextImpl::Initialize( + scoped_refptr service, scoped_refptr surface, bool is_offscreen, - GLInProcessContext* share_context, SurfaceHandle window, + GLInProcessContext* share_context, const gles2::ContextCreationAttribHelper& attribs, - const scoped_refptr& service, const SharedMemoryLimits& mem_limits, GpuMemoryBufferManager* gpu_memory_buffer_manager, ImageFactory* image_factory, scoped_refptr task_runner) { + // If a surface is provided, we are running in a webview and should not have + // a task runner. We must have a task runner in all other cases. + DCHECK_EQ(!!surface, !task_runner); + if (surface) { + DCHECK_EQ(surface->IsOffscreen(), is_offscreen); + DCHECK_EQ(kNullSurfaceHandle, window); + } DCHECK_GE(attribs.offscreen_framebuffer_size.width(), 0); DCHECK_GE(attribs.offscreen_framebuffer_size.height(), 0); - command_buffer_.reset(new InProcessCommandBuffer(service)); + command_buffer_ = std::make_unique(service); scoped_refptr share_group; InProcessCommandBuffer* share_command_buffer = nullptr; @@ -148,23 +167,25 @@ bool GLInProcessContextImpl::Initialize( DCHECK(share_command_buffer); } - if (!command_buffer_->Initialize( - surface, is_offscreen, window, attribs, share_command_buffer, - gpu_memory_buffer_manager, image_factory, std::move(task_runner))) { + auto result = command_buffer_->Initialize( + surface, is_offscreen, window, attribs, share_command_buffer, + gpu_memory_buffer_manager, image_factory, std::move(task_runner)); + if (result != gpu::ContextResult::kSuccess) { DLOG(ERROR) << "Failed to initialize InProcessCommmandBuffer"; - return false; + return result; } // Create the GLES2 helper, which writes the command buffer protocol. - gles2_helper_.reset(new gles2::GLES2CmdHelper(command_buffer_.get())); - if (!gles2_helper_->Initialize(mem_limits.command_buffer_size)) { + gles2_helper_ = + std::make_unique(command_buffer_.get()); + result = gles2_helper_->Initialize(mem_limits.command_buffer_size); + if (result != gpu::ContextResult::kSuccess) { LOG(ERROR) << "Failed to initialize GLES2CmdHelper"; - Destroy(); - return false; + return result; } // Create a transfer buffer. - transfer_buffer_.reset(new TransferBuffer(gles2_helper_.get())); + transfer_buffer_ = std::make_unique(gles2_helper_.get()); // Check for consistency. DCHECK(!attribs.bind_generates_resource); @@ -172,66 +193,20 @@ bool GLInProcessContextImpl::Initialize( const bool support_client_side_arrays = false; // Create the object exposing the OpenGL API. - gles2_implementation_.reset(new gles2::GLES2Implementation( + gles2_implementation_ = std::make_unique( gles2_helper_.get(), share_group.get(), transfer_buffer_.get(), bind_generates_resource, attribs.lose_context_when_out_of_memory, - support_client_side_arrays, command_buffer_.get())); - - if (!gles2_implementation_->Initialize(mem_limits)) { - return false; - } + support_client_side_arrays, command_buffer_.get()); - return true; -} - -void GLInProcessContextImpl::Destroy() { - if (gles2_implementation_) { - // First flush the context to ensure that any pending frees of resources - // are completed. Otherwise, if this context is part of a share group, - // those resources might leak. Also, any remaining side effects of commands - // issued on this context might not be visible to other contexts in the - // share group. - gles2_implementation_->Flush(); - - gles2_implementation_.reset(); - } - - transfer_buffer_.reset(); - gles2_helper_.reset(); - command_buffer_.reset(); + result = gles2_implementation_->Initialize(mem_limits); + return result; } } // anonymous namespace // static -GLInProcessContext* GLInProcessContext::Create( - scoped_refptr service, - scoped_refptr surface, - bool is_offscreen, - SurfaceHandle window, - GLInProcessContext* share_context, - const ::gpu::gles2::ContextCreationAttribHelper& attribs, - const SharedMemoryLimits& memory_limits, - GpuMemoryBufferManager* gpu_memory_buffer_manager, - ImageFactory* image_factory, - scoped_refptr task_runner) { - // If a surface is provided, we are running in a webview and should not have - // a task runner. We must have a task runner in all other cases. - DCHECK_EQ(!!surface, !task_runner); - - if (surface) { - DCHECK_EQ(surface->IsOffscreen(), is_offscreen); - DCHECK_EQ(kNullSurfaceHandle, window); - } - - std::unique_ptr context(new GLInProcessContextImpl); - if (!context->Initialize(surface, is_offscreen, share_context, window, - attribs, service, memory_limits, - gpu_memory_buffer_manager, image_factory, - std::move(task_runner))) - return NULL; - - return context.release(); +std::unique_ptr GLInProcessContext::CreateWithoutInit() { + return std::make_unique(); } } // namespace gpu diff --git a/gpu/ipc/gl_in_process_context.h b/gpu/ipc/gl_in_process_context.h index c8ea9a2c9f0ff4..8de4defd862e56 100644 --- a/gpu/ipc/gl_in_process_context.h +++ b/gpu/ipc/gl_in_process_context.h @@ -29,9 +29,13 @@ class GLES2Implementation; class GL_IN_PROCESS_CONTEXT_EXPORT GLInProcessContext { public: - virtual ~GLInProcessContext() {} + virtual ~GLInProcessContext() = default; - // Create a GLInProcessContext, if |is_offscreen| is true, renders to an + // TODO(danakj): Devirtualize this class and remove this, just call the + // constructor. + static std::unique_ptr CreateWithoutInit(); + + // Initialize the GLInProcessContext, if |is_offscreen| is true, renders to an // offscreen context. |attrib_list| must be NULL or a NONE-terminated list // of attribute/value pairs. // If |surface| is not NULL, then it must match |is_offscreen|, @@ -39,7 +43,7 @@ class GL_IN_PROCESS_CONTEXT_EXPORT GLInProcessContext { // service must run on the same thread as this client because GLSurface is // not thread safe. If |surface| is NULL, then the other parameters are used // to correctly create a surface. - static GLInProcessContext* Create( + virtual gpu::ContextResult Initialize( scoped_refptr service, scoped_refptr surface, bool is_offscreen, @@ -49,7 +53,7 @@ class GL_IN_PROCESS_CONTEXT_EXPORT GLInProcessContext { const SharedMemoryLimits& memory_limits, GpuMemoryBufferManager* gpu_memory_buffer_manager, ImageFactory* image_factory, - scoped_refptr task_runner); + scoped_refptr task_runner) = 0; virtual const gpu::Capabilities& GetCapabilities() const = 0; virtual const gpu::GpuFeatureInfo& GetGpuFeatureInfo() const = 0; diff --git a/gpu/ipc/in_process_command_buffer.cc b/gpu/ipc/in_process_command_buffer.cc index 4eacb60209ef51..c57f142562198e 100644 --- a/gpu/ipc/in_process_command_buffer.cc +++ b/gpu/ipc/in_process_command_buffer.cc @@ -246,7 +246,7 @@ bool InProcessCommandBuffer::MakeCurrent() { return true; } -bool InProcessCommandBuffer::Initialize( +gpu::ContextResult InProcessCommandBuffer::Initialize( scoped_refptr surface, bool is_offscreen, SurfaceHandle window, @@ -276,27 +276,27 @@ bool InProcessCommandBuffer::Initialize( InitializeOnGpuThreadParams params(is_offscreen, window, attribs, &capabilities, share_group, image_factory); - base::Callback init_task = + base::Callback init_task = base::Bind(&InProcessCommandBuffer::InitializeOnGpuThread, base::Unretained(this), params); base::WaitableEvent completion( base::WaitableEvent::ResetPolicy::MANUAL, base::WaitableEvent::InitialState::NOT_SIGNALED); - bool result = false; - QueueTask(true, base::Bind(&RunTaskWithResult, init_task, &result, - &completion)); + gpu::ContextResult result = gpu::ContextResult::kSuccess; + QueueTask(true, base::Bind(&RunTaskWithResult, init_task, + &result, &completion)); completion.Wait(); gpu_memory_buffer_manager_ = gpu_memory_buffer_manager; - if (result) + if (result == gpu::ContextResult::kSuccess) capabilities_ = capabilities; return result; } -bool InProcessCommandBuffer::InitializeOnGpuThread( +gpu::ContextResult InProcessCommandBuffer::InitializeOnGpuThread( const InitializeOnGpuThreadParams& params) { CheckSequencedThread(); gpu_thread_weak_ptr_ = gpu_thread_weak_ptr_factory_.GetWeakPtr(); @@ -309,8 +309,7 @@ bool InProcessCommandBuffer::InitializeOnGpuThread( bool bind_generates_resource = false; gpu::GpuDriverBugWorkarounds workarounds( service_->gpu_feature_info().enabled_gpu_driver_bug_workarounds); - scoped_refptr feature_info = - new gles2::FeatureInfo(workarounds); + auto feature_info = base::MakeRefCounted(workarounds); context_group_ = params.context_group @@ -331,7 +330,7 @@ bool InProcessCommandBuffer::InitializeOnGpuThread( service_->outputter(), context_group_.get())); - if (!surface_.get()) { + if (!surface_) { if (params.is_offscreen) { surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size()); } else { @@ -341,15 +340,15 @@ bool InProcessCommandBuffer::InitializeOnGpuThread( if (!surface_ || !surface_->Initialize(gl::GLSurfaceFormat())) { surface_ = nullptr; DLOG(ERROR) << "Failed to create surface."; - return false; + return gpu::ContextResult::kFatalFailure; } } } if (!surface_.get()) { - LOG(ERROR) << "Could not create GLSurface."; + DLOG(ERROR) << "Could not create GLSurface."; DestroyOnGpuThread(); - return false; + return gpu::ContextResult::kFatalFailure; } sync_point_order_data_ = @@ -403,13 +402,14 @@ bool InProcessCommandBuffer::InitializeOnGpuThread( if (!context_.get()) { LOG(ERROR) << "Could not create GLContext."; DestroyOnGpuThread(); - return false; + return gpu::ContextResult::kFatalFailure; } if (!context_->MakeCurrent(surface_.get())) { LOG(ERROR) << "Could not make context current."; DestroyOnGpuThread(); - return false; + // The caller should retry making a context, but this one won't work. + return gpu::ContextResult::kTransientFailure; } if (!decoder_->GetContextGroup()->has_program_cache() && @@ -422,17 +422,18 @@ bool InProcessCommandBuffer::InitializeOnGpuThread( gles2::DisallowedFeatures disallowed_features; disallowed_features.gpu_memory_manager = true; - if (!decoder_->Initialize(surface_, context_, params.is_offscreen, - disallowed_features, params.attribs)) { + auto result = decoder_->Initialize(surface_, context_, params.is_offscreen, + disallowed_features, params.attribs); + if (result != gpu::ContextResult::kSuccess) { LOG(ERROR) << "Could not initialize decoder."; DestroyOnGpuThread(); - return false; + return result; } *params.capabilities = decoder_->GetCapabilities(); image_factory_ = params.image_factory; - return true; + return gpu::ContextResult::kSuccess; } void InProcessCommandBuffer::Destroy() { diff --git a/gpu/ipc/in_process_command_buffer.h b/gpu/ipc/in_process_command_buffer.h index a402761f89601b..06943391683886 100644 --- a/gpu/ipc/in_process_command_buffer.h +++ b/gpu/ipc/in_process_command_buffer.h @@ -25,6 +25,7 @@ #include "gpu/command_buffer/client/gpu_control.h" #include "gpu/command_buffer/common/activity_flags.h" #include "gpu/command_buffer/common/command_buffer.h" +#include "gpu/command_buffer/common/context_result.h" #include "gpu/command_buffer/service/command_buffer_service.h" #include "gpu/command_buffer/service/context_group.h" #include "gpu/command_buffer/service/gles2_cmd_decoder.h" @@ -94,14 +95,15 @@ class GPU_EXPORT InProcessCommandBuffer : public CommandBuffer, // If |surface| is not null, use it directly; in this case, the command // buffer gpu thread must be the same as the client thread. Otherwise create // a new GLSurface. - bool Initialize(scoped_refptr surface, - bool is_offscreen, - SurfaceHandle window, - const gles2::ContextCreationAttribHelper& attribs, - InProcessCommandBuffer* share_group, - GpuMemoryBufferManager* gpu_memory_buffer_manager, - ImageFactory* image_factory, - scoped_refptr task_runner); + gpu::ContextResult Initialize( + scoped_refptr surface, + bool is_offscreen, + SurfaceHandle window, + const gles2::ContextCreationAttribHelper& attribs, + InProcessCommandBuffer* share_group, + GpuMemoryBufferManager* gpu_memory_buffer_manager, + ImageFactory* image_factory, + scoped_refptr task_runner); // CommandBuffer implementation: State GetLastState() override; @@ -277,7 +279,8 @@ class GPU_EXPORT InProcessCommandBuffer : public CommandBuffer, image_factory(image_factory) {} }; - bool InitializeOnGpuThread(const InitializeOnGpuThreadParams& params); + gpu::ContextResult InitializeOnGpuThread( + const InitializeOnGpuThreadParams& params); void Destroy(); bool DestroyOnGpuThread(); void FlushOnGpuThread(int32_t put_offset, diff --git a/gpu/ipc/service/gpu_channel.cc b/gpu/ipc/service/gpu_channel.cc index 58452ddf397ee2..4b505442467e7a 100644 --- a/gpu/ipc/service/gpu_channel.cc +++ b/gpu/ipc/service/gpu_channel.cc @@ -1067,32 +1067,22 @@ void GpuChannel::OnCreateCommandBuffer( const GPUCreateCommandBufferConfig& init_params, int32_t route_id, base::SharedMemoryHandle shared_state_handle, - bool* result, + ContextResult* result, gpu::Capabilities* capabilities) { TRACE_EVENT2("gpu", "GpuChannel::OnCreateCommandBuffer", "route_id", route_id, "offscreen", (init_params.surface_handle == kNullSurfaceHandle)); std::unique_ptr shared_state_shm( new base::SharedMemory(shared_state_handle, false)); - std::unique_ptr stub = - CreateCommandBuffer(init_params, route_id, std::move(shared_state_shm)); - if (stub) { - *result = true; - *capabilities = stub->decoder()->GetCapabilities(); - stubs_[route_id] = std::move(stub); - } else { - *result = false; - *capabilities = gpu::Capabilities(); - } -} -std::unique_ptr GpuChannel::CreateCommandBuffer( - const GPUCreateCommandBufferConfig& init_params, - int32_t route_id, - std::unique_ptr shared_state_shm) { + // Default result on failure. Override with a more accurate failure if needed, + // or with success. + *result = ContextResult::kFatalFailure; + *capabilities = gpu::Capabilities(); + if (init_params.surface_handle != kNullSurfaceHandle && !is_gpu_host_) { DLOG(ERROR) << "GpuChannel::CreateCommandBuffer(): attempt to create a " "view context on a non-privileged channel"; - return nullptr; + return; } int32_t share_group_id = init_params.share_group_id; @@ -1100,21 +1090,21 @@ std::unique_ptr GpuChannel::CreateCommandBuffer( if (!share_group && share_group_id != MSG_ROUTING_NONE) { DLOG(ERROR) << "GpuChannel::CreateCommandBuffer(): invalid share group id"; - return nullptr; + return; } int32_t stream_id = init_params.stream_id; if (share_group && stream_id != share_group->stream_id()) { DLOG(ERROR) << "GpuChannel::CreateCommandBuffer(): stream id does not " "match share group stream id"; - return nullptr; + return; } SchedulingPriority stream_priority = init_params.stream_priority; if (stream_priority <= SchedulingPriority::kHigh && !is_gpu_host_) { DLOG(ERROR) << "GpuChannel::CreateCommandBuffer(): high priority stream " "not allowed on a non-privileged channel"; - return nullptr; + return; } if (share_group && !share_group->decoder()) { @@ -1122,13 +1112,15 @@ std::unique_ptr GpuChannel::CreateCommandBuffer( // share_group's CommandBuffer. DLOG(ERROR) << "GpuChannel::CreateCommandBuffer(): shared context was " "not initialized"; - return nullptr; + return; } if (share_group && share_group->decoder()->WasContextLost()) { DLOG(ERROR) << "GpuChannel::CreateCommandBuffer(): shared context was " "already lost"; - return nullptr; + // The caller should retry to get a context. + *result = gpu::ContextResult::kTransientFailure; + return; } CommandBufferId command_buffer_id = @@ -1145,16 +1137,25 @@ std::unique_ptr GpuChannel::CreateCommandBuffer( sequence_id = message_queue_->sequence_id(); } - std::unique_ptr stub(GpuCommandBufferStub::Create( - this, share_group, init_params, command_buffer_id, sequence_id, stream_id, - route_id, std::move(shared_state_shm))); + auto stub = std::make_unique( + this, init_params, command_buffer_id, sequence_id, stream_id, route_id); + auto stub_result = + stub->Initialize(share_group, init_params, std::move(shared_state_shm)); + if (stub_result != gpu::ContextResult::kSuccess) { + DLOG(ERROR) << "GpuChannel::CreateCommandBuffer(): failed to initialize " + "GpuCommandBufferStub"; + *result = stub_result; + return; + } if (!AddRoute(route_id, sequence_id, stub.get())) { DLOG(ERROR) << "GpuChannel::CreateCommandBuffer(): failed to add route"; - return nullptr; + return; } - return stub; + *result = ContextResult::kSuccess; + *capabilities = stub->decoder()->GetCapabilities(); + stubs_[route_id] = std::move(stub); } void GpuChannel::OnDestroyCommandBuffer(int32_t route_id) { diff --git a/gpu/ipc/service/gpu_channel.h b/gpu/ipc/service/gpu_channel.h index 7843514e0d7dde..d4dc043a1852e4 100644 --- a/gpu/ipc/service/gpu_channel.h +++ b/gpu/ipc/service/gpu_channel.h @@ -19,6 +19,7 @@ #include "base/single_thread_task_runner.h" #include "base/trace_event/memory_dump_provider.h" #include "build/build_config.h" +#include "gpu/command_buffer/common/context_result.h" #include "gpu/command_buffer/service/sync_point_manager.h" #include "gpu/gpu_export.h" #include "gpu/ipc/service/gpu_command_buffer_stub.h" @@ -197,17 +198,12 @@ class GPU_EXPORT GpuChannel : public IPC::Listener, public FilteredSender { void OnCreateCommandBuffer(const GPUCreateCommandBufferConfig& init_params, int32_t route_id, base::SharedMemoryHandle shared_state_shm, - bool* result, + gpu::ContextResult* result, gpu::Capabilities* capabilities); void OnDestroyCommandBuffer(int32_t route_id); void OnGetDriverBugWorkArounds( std::vector* gpu_driver_bug_workarounds); - std::unique_ptr CreateCommandBuffer( - const GPUCreateCommandBufferConfig& init_params, - int32_t route_id, - std::unique_ptr shared_state_shm); - std::unique_ptr channel_; base::ProcessId peer_pid_ = base::kNullProcessId; diff --git a/gpu/ipc/service/gpu_channel_manager_unittest.cc b/gpu/ipc/service/gpu_channel_manager_unittest.cc index bd83ae6749bb85..67c1e46c25c718 100644 --- a/gpu/ipc/service/gpu_channel_manager_unittest.cc +++ b/gpu/ipc/service/gpu_channel_manager_unittest.cc @@ -38,12 +38,12 @@ class GpuChannelManagerTest : public GpuChannelTestCommon { init_params.attribs = gles2::ContextCreationAttribHelper(); init_params.attribs.context_type = type; init_params.active_url = GURL(); - bool result = false; + gpu::ContextResult result = gpu::ContextResult::kFatalFailure; gpu::Capabilities capabilities; HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer( init_params, kRouteId, GetSharedHandle(), &result, &capabilities)); - EXPECT_TRUE(result); + EXPECT_EQ(result, gpu::ContextResult::kSuccess); GpuCommandBufferStub* stub = channel->LookupCommandBuffer(kRouteId); EXPECT_TRUE(stub); diff --git a/gpu/ipc/service/gpu_channel_unittest.cc b/gpu/ipc/service/gpu_channel_unittest.cc index abf605b0ca3f6a..c73b8298cff562 100644 --- a/gpu/ipc/service/gpu_channel_unittest.cc +++ b/gpu/ipc/service/gpu_channel_unittest.cc @@ -35,12 +35,12 @@ TEST_F(GpuChannelTest, CreateViewCommandBufferAllowed) { init_params.stream_priority = SchedulingPriority::kNormal; init_params.attribs = gles2::ContextCreationAttribHelper(); init_params.active_url = GURL(); - bool result = false; + gpu::ContextResult result = gpu::ContextResult::kSuccess; gpu::Capabilities capabilities; HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer( init_params, kRouteId, GetSharedHandle(), &result, &capabilities)); - EXPECT_TRUE(result); + EXPECT_EQ(result, gpu::ContextResult::kSuccess); GpuCommandBufferStub* stub = channel->LookupCommandBuffer(kRouteId); ASSERT_TRUE(stub); @@ -63,12 +63,12 @@ TEST_F(GpuChannelTest, CreateViewCommandBufferDisallowed) { init_params.stream_priority = SchedulingPriority::kNormal; init_params.attribs = gles2::ContextCreationAttribHelper(); init_params.active_url = GURL(); - bool result = false; + gpu::ContextResult result = gpu::ContextResult::kSuccess; gpu::Capabilities capabilities; HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer( init_params, kRouteId, GetSharedHandle(), &result, &capabilities)); - EXPECT_FALSE(result); + EXPECT_EQ(result, gpu::ContextResult::kFatalFailure); GpuCommandBufferStub* stub = channel->LookupCommandBuffer(kRouteId); EXPECT_FALSE(stub); @@ -87,12 +87,12 @@ TEST_F(GpuChannelTest, CreateOffscreenCommandBuffer) { init_params.stream_priority = SchedulingPriority::kNormal; init_params.attribs = gles2::ContextCreationAttribHelper(); init_params.active_url = GURL(); - bool result = false; + gpu::ContextResult result = gpu::ContextResult::kSuccess; gpu::Capabilities capabilities; HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer( init_params, kRouteId, GetSharedHandle(), &result, &capabilities)); - EXPECT_TRUE(result); + EXPECT_EQ(result, gpu::ContextResult::kSuccess); GpuCommandBufferStub* stub = channel->LookupCommandBuffer(kRouteId); EXPECT_TRUE(stub); @@ -113,12 +113,12 @@ TEST_F(GpuChannelTest, IncompatibleStreamIds) { init_params.stream_priority = SchedulingPriority::kNormal; init_params.attribs = gles2::ContextCreationAttribHelper(); init_params.active_url = GURL(); - bool result = false; + gpu::ContextResult result = gpu::ContextResult::kSuccess; gpu::Capabilities capabilities; HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer( init_params, kRouteId1, GetSharedHandle(), &result, &capabilities)); - EXPECT_TRUE(result); + EXPECT_EQ(result, gpu::ContextResult::kSuccess); GpuCommandBufferStub* stub = channel->LookupCommandBuffer(kRouteId1); EXPECT_TRUE(stub); @@ -135,7 +135,7 @@ TEST_F(GpuChannelTest, IncompatibleStreamIds) { HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer( init_params, kRouteId2, GetSharedHandle(), &result, &capabilities)); - EXPECT_FALSE(result); + EXPECT_EQ(result, gpu::ContextResult::kFatalFailure); stub = channel->LookupCommandBuffer(kRouteId2); EXPECT_FALSE(stub); @@ -157,12 +157,12 @@ TEST_F(GpuChannelTest, HighPriorityStreamsDisallowed) { init_params.stream_priority = SchedulingPriority::kHigh; init_params.attribs = gles2::ContextCreationAttribHelper(); init_params.active_url = GURL(); - bool result = false; + gpu::ContextResult result = gpu::ContextResult::kSuccess; gpu::Capabilities capabilities; HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer( init_params, kRouteId, GetSharedHandle(), &result, &capabilities)); - EXPECT_FALSE(result); + EXPECT_EQ(result, gpu::ContextResult::kFatalFailure); EXPECT_FALSE(channel->LookupCommandBuffer(kRouteId)); // High priority is also disallowed. @@ -170,7 +170,7 @@ TEST_F(GpuChannelTest, HighPriorityStreamsDisallowed) { HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer( init_params, kRouteId, GetSharedHandle(), &result, &capabilities)); - EXPECT_FALSE(result); + EXPECT_EQ(result, gpu::ContextResult::kFatalFailure); EXPECT_FALSE(channel->LookupCommandBuffer(kRouteId)); } @@ -189,23 +189,23 @@ TEST_F(GpuChannelTest, HighPriorityStreamsAllowed) { init_params.stream_priority = SchedulingPriority::kHigh; init_params.attribs = gles2::ContextCreationAttribHelper(); init_params.active_url = GURL(); - bool result = false; + gpu::ContextResult result = gpu::ContextResult::kSuccess; gpu::Capabilities capabilities; HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer( init_params, kRouteId1, GetSharedHandle(), &result, &capabilities)); - EXPECT_TRUE(result); + EXPECT_EQ(result, gpu::ContextResult::kSuccess); EXPECT_TRUE(channel->LookupCommandBuffer(kRouteId1)); // High priority is also allowed. int32_t kRouteId2 = 2; init_params.stream_id = 2; init_params.stream_priority = SchedulingPriority::kHigh; - result = false; + result = gpu::ContextResult::kSuccess; HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer( init_params, kRouteId2, GetSharedHandle(), &result, &capabilities)); - EXPECT_TRUE(result); + EXPECT_EQ(result, gpu::ContextResult::kSuccess); EXPECT_TRUE(channel->LookupCommandBuffer(kRouteId2)); } @@ -225,12 +225,12 @@ TEST_F(GpuChannelTest, CreateFailsIfSharedContextIsLost) { init_params.stream_priority = SchedulingPriority::kNormal; init_params.attribs = gles2::ContextCreationAttribHelper(); init_params.active_url = GURL(); - bool result = false; + gpu::ContextResult result = gpu::ContextResult::kSuccess; gpu::Capabilities capabilities; HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer( init_params, kSharedRouteId, GetSharedHandle(), &result, &capabilities)); - EXPECT_TRUE(result); + EXPECT_EQ(result, gpu::ContextResult::kSuccess); } EXPECT_TRUE(channel->LookupCommandBuffer(kSharedRouteId)); @@ -245,12 +245,12 @@ TEST_F(GpuChannelTest, CreateFailsIfSharedContextIsLost) { init_params.stream_priority = SchedulingPriority::kNormal; init_params.attribs = gles2::ContextCreationAttribHelper(); init_params.active_url = GURL(); - bool result = false; + gpu::ContextResult result = gpu::ContextResult::kSuccess; gpu::Capabilities capabilities; HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer( init_params, kFriendlyRouteId, GetSharedHandle(), &result, &capabilities)); - EXPECT_TRUE(result); + EXPECT_EQ(result, gpu::ContextResult::kSuccess); } EXPECT_TRUE(channel->LookupCommandBuffer(kFriendlyRouteId)); @@ -269,12 +269,12 @@ TEST_F(GpuChannelTest, CreateFailsIfSharedContextIsLost) { init_params.stream_priority = SchedulingPriority::kNormal; init_params.attribs = gles2::ContextCreationAttribHelper(); init_params.active_url = GURL(); - bool result = false; + gpu::ContextResult result = gpu::ContextResult::kSuccess; gpu::Capabilities capabilities; HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer( init_params, kAnotherRouteId, GetSharedHandle(), &result, &capabilities)); - EXPECT_FALSE(result); + EXPECT_EQ(result, gpu::ContextResult::kTransientFailure); } EXPECT_FALSE(channel->LookupCommandBuffer(kAnotherRouteId)); diff --git a/gpu/ipc/service/gpu_command_buffer_stub.cc b/gpu/ipc/service/gpu_command_buffer_stub.cc index c3e1615327ca32..b13203c33f4635 100644 --- a/gpu/ipc/service/gpu_command_buffer_stub.cc +++ b/gpu/ipc/service/gpu_command_buffer_stub.cc @@ -219,24 +219,6 @@ DevToolsChannelData::CreateForChannel(GpuChannel* channel) { } // namespace -std::unique_ptr GpuCommandBufferStub::Create( - GpuChannel* channel, - GpuCommandBufferStub* share_command_buffer_stub, - const GPUCreateCommandBufferConfig& init_params, - CommandBufferId command_buffer_id, - SequenceId sequence_id, - int32_t stream_id, - int32_t route_id, - std::unique_ptr shared_state_shm) { - std::unique_ptr stub( - new GpuCommandBufferStub(channel, init_params, command_buffer_id, - sequence_id, stream_id, route_id)); - if (!stub->Initialize(share_command_buffer_stub, init_params, - std::move(shared_state_shm))) - return nullptr; - return stub; -} - GpuCommandBufferStub::GpuCommandBufferStub( GpuChannel* channel, const GPUCreateCommandBufferConfig& init_params, @@ -565,14 +547,14 @@ void GpuCommandBufferStub::Destroy() { command_buffer_.reset(); } -bool GpuCommandBufferStub::Initialize( +gpu::ContextResult GpuCommandBufferStub::Initialize( GpuCommandBufferStub* share_command_buffer_stub, const GPUCreateCommandBufferConfig& init_params, std::unique_ptr shared_state_shm) { #if defined(OS_FUCHSIA) // TODO(crbug.com/707031): Implement this. NOTIMPLEMENTED(); - return false; + return gpu::ContextResult::kFatalFailure; #else TRACE_EVENT0("gpu", "GpuCommandBufferStub::Initialize"); FastSetActiveURL(active_url_, active_url_hash_, channel_); @@ -622,7 +604,7 @@ bool GpuCommandBufferStub::Initialize( gl::GLSurface* default_surface = manager->GetDefaultOffscreenSurface(); if (!default_surface) { DLOG(ERROR) << "Failed to create default offscreen surface."; - return false; + return gpu::ContextResult::kFatalFailure; } // On low-spec Android devices, the default offscreen surface is // RGB565, but WebGL rendering contexts still ask for RGBA8888 mode. @@ -654,8 +636,8 @@ bool GpuCommandBufferStub::Initialize( use_virtualized_gl_context_ = false; #endif - command_buffer_.reset(new CommandBufferService( - this, context_group_->transfer_buffer_manager())); + command_buffer_ = std::make_unique( + this, context_group_->transfer_buffer_manager()); decoder_.reset(gles2::GLES2Decoder::Create( this, command_buffer_.get(), manager->outputter(), context_group_.get())); @@ -694,7 +676,7 @@ bool GpuCommandBufferStub::Initialize( surface_format); if (!surface_) { DLOG(ERROR) << "Failed to create surface."; - return false; + return gpu::ContextResult::kFatalFailure; } } else { surface_ = default_surface; @@ -718,7 +700,7 @@ bool GpuCommandBufferStub::Initialize( if (!surface_ || !surface_->Initialize(surface_format)) { surface_ = nullptr; DLOG(ERROR) << "Failed to create surface."; - return false; + return gpu::ContextResult::kFatalFailure; } } @@ -743,13 +725,16 @@ bool GpuCommandBufferStub::Initialize( scoped_refptr context; if (use_virtualized_gl_context_ && share_group_) { context = share_group_->GetSharedContext(surface_.get()); - if (!context.get()) { + if (!context) { context = gl::init::CreateGLContext( share_group_.get(), surface_.get(), GenerateGLContextAttribs(init_params.attribs, context_group_.get())); - if (!context.get()) { + if (!context) { DLOG(ERROR) << "Failed to create shared context for virtualization."; - return false; + // TODO(piman): This might not be fatal, we could recurse into + // CreateGLContext to get more info, tho it should be exceedingly + // rare and may not be recoverable anyway. + return gpu::ContextResult::kFatalFailure; } // Ensure that context creation did not lose track of the intended share // group. @@ -766,24 +751,30 @@ bool GpuCommandBufferStub::Initialize( DCHECK(context->GetHandle() || gl::GetGLImplementation() == gl::kGLImplementationMockGL || gl::GetGLImplementation() == gl::kGLImplementationStubGL); - context = new GLContextVirtual(share_group_.get(), context.get(), - decoder_->AsWeakPtr()); + context = base::MakeRefCounted( + share_group_.get(), context.get(), decoder_->AsWeakPtr()); if (!context->Initialize(surface_.get(), GenerateGLContextAttribs(init_params.attribs, context_group_.get()))) { // The real context created above for the default offscreen surface // might not be compatible with this surface. - context = NULL; + context = nullptr; DLOG(ERROR) << "Failed to initialize virtual GL context."; - return false; + // TODO(piman): This might not be fatal, we could recurse into + // CreateGLContext to get more info, tho it should be exceedingly + // rare and may not be recoverable anyway. + return gpu::ContextResult::kFatalFailure; } } else { context = gl::init::CreateGLContext( share_group_.get(), surface_.get(), GenerateGLContextAttribs(init_params.attribs, context_group_.get())); - if (!context.get()) { + if (!context) { DLOG(ERROR) << "Failed to create context."; - return false; + // TODO(piman): This might not be fatal, we could recurse into + // CreateGLContext to get more info, tho it should be exceedingly + // rare and may not be recoverable anyway. + return gpu::ContextResult::kFatalFailure; } manager->gpu_feature_info().ApplyToGLContext(context.get()); @@ -791,7 +782,7 @@ bool GpuCommandBufferStub::Initialize( if (!context->MakeCurrent(surface_.get())) { LOG(ERROR) << "Failed to make context current."; - return false; + return gpu::ContextResult::kTransientFailure; } if (!context->GetGLStateRestorer()) { @@ -804,11 +795,12 @@ bool GpuCommandBufferStub::Initialize( } // Initialize the decoder with either the view or pbuffer GLContext. - if (!decoder_->Initialize(surface_, context, offscreen, - gpu::gles2::DisallowedFeatures(), - init_params.attribs)) { + auto result = decoder_->Initialize(surface_, context, offscreen, + gpu::gles2::DisallowedFeatures(), + init_params.attribs); + if (result != gpu::ContextResult::kSuccess) { DLOG(ERROR) << "Failed to initialize decoder."; - return false; + return result; } if (manager->gpu_preferences().enable_gpu_service_logging) { @@ -818,7 +810,7 @@ bool GpuCommandBufferStub::Initialize( const size_t kSharedStateSize = sizeof(CommandBufferSharedState); if (!shared_state_shm->Map(kSharedStateSize)) { DLOG(ERROR) << "Failed to map shared state buffer."; - return false; + return gpu::ContextResult::kFatalFailure; } command_buffer_->SetSharedStateBuffer(MakeBackingFromSharedMemory( std::move(shared_state_shm), kSharedStateSize)); @@ -837,12 +829,12 @@ bool GpuCommandBufferStub::Initialize( context->ForceReleaseVirtuallyCurrent(); if (!context->MakeCurrent(surface_.get())) { LOG(ERROR) << "Failed to make context current after initialization."; - return false; + return gpu::ContextResult::kTransientFailure; } } initialized_ = true; - return true; + return gpu::ContextResult::kSuccess; #endif // defined(OS_FUCHSIA) } diff --git a/gpu/ipc/service/gpu_command_buffer_stub.h b/gpu/ipc/service/gpu_command_buffer_stub.h index 1e8150476a1274..0623c05b2326bd 100644 --- a/gpu/ipc/service/gpu_command_buffer_stub.h +++ b/gpu/ipc/service/gpu_command_buffer_stub.h @@ -71,21 +71,23 @@ class GPU_EXPORT GpuCommandBufferStub typedef base::Callback&)> LatencyInfoCallback; + GpuCommandBufferStub(GpuChannel* channel, + const GPUCreateCommandBufferConfig& init_params, + CommandBufferId command_buffer_id, + SequenceId sequence_id, + int32_t stream_id, + int32_t route_id); + + ~GpuCommandBufferStub() override; + // This must leave the GL context associated with the newly-created // GpuCommandBufferStub current, so the GpuChannel can initialize // the gpu::Capabilities. - static std::unique_ptr Create( - GpuChannel* channel, + gpu::ContextResult Initialize( GpuCommandBufferStub* share_group, const GPUCreateCommandBufferConfig& init_params, - CommandBufferId command_buffer_id, - SequenceId sequence_id, - int32_t stream_id, - int32_t route_id, std::unique_ptr shared_state_shm); - ~GpuCommandBufferStub() override; - // IPC::Listener implementation: bool OnMessageReceived(const IPC::Message& message) override; @@ -146,17 +148,6 @@ class GPU_EXPORT GpuCommandBufferStub void MarkContextLost(); private: - GpuCommandBufferStub(GpuChannel* channel, - const GPUCreateCommandBufferConfig& init_params, - CommandBufferId command_buffer_id, - SequenceId sequence_id, - int32_t stream_id, - int32_t route_id); - - bool Initialize(GpuCommandBufferStub* share_group, - const GPUCreateCommandBufferConfig& init_params, - std::unique_ptr shared_state_shm); - GpuMemoryManager* GetMemoryManager() const; void Destroy(); diff --git a/ppapi/shared_impl/ppb_graphics_3d_shared.cc b/ppapi/shared_impl/ppb_graphics_3d_shared.cc index 886a08fe587fbb..cc6a3d9ced06bd 100644 --- a/ppapi/shared_impl/ppb_graphics_3d_shared.cc +++ b/ppapi/shared_impl/ppb_graphics_3d_shared.cc @@ -123,29 +123,27 @@ bool PPB_Graphics3D_Shared::CreateGLES2Impl( DCHECK(command_buffer); // Create the GLES2 helper, which writes the command buffer protocol. - gles2_helper_.reset(new gpu::gles2::GLES2CmdHelper(command_buffer)); - if (!gles2_helper_->Initialize(limits.command_buffer_size)) + gles2_helper_ = std::make_unique(command_buffer); + if (gles2_helper_->Initialize(limits.command_buffer_size) != + gpu::ContextResult::kSuccess) return false; // Create a transfer buffer used to copy resources between the renderer // process and the GPU process. - transfer_buffer_.reset(new gpu::TransferBuffer(gles2_helper_.get())); + transfer_buffer_ = std::make_unique(gles2_helper_.get()); const bool bind_creates_resources = true; const bool lose_context_when_out_of_memory = false; const bool support_client_side_arrays = true; // Create the object exposing the OpenGL API. - gles2_impl_.reset(new gpu::gles2::GLES2Implementation( - gles2_helper_.get(), - share_gles2 ? share_gles2->share_group() : NULL, - transfer_buffer_.get(), - bind_creates_resources, - lose_context_when_out_of_memory, - support_client_side_arrays, - GetGpuControl())); - - if (!gles2_impl_->Initialize(limits)) + gles2_impl_ = std::make_unique( + gles2_helper_.get(), share_gles2 ? share_gles2->share_group() : nullptr, + transfer_buffer_.get(), bind_creates_resources, + lose_context_when_out_of_memory, support_client_side_arrays, + GetGpuControl()); + + if (gles2_impl_->Initialize(limits) != gpu::ContextResult::kSuccess) return false; gles2_impl_->TraceBeginCHROMIUM("gpu_toplevel", "PPAPIContext"); diff --git a/services/ui/public/cpp/gpu/context_provider_command_buffer.cc b/services/ui/public/cpp/gpu/context_provider_command_buffer.cc index 28a70ad15218a1..5bb0331308e059 100644 --- a/services/ui/public/cpp/gpu/context_provider_command_buffer.cc +++ b/services/ui/public/cpp/gpu/context_provider_command_buffer.cc @@ -36,23 +36,6 @@ class SkDiscardableMemory; namespace { -// Similar to base::AutoReset but it sets the variable to the new value -// when it is destroyed. Use Reset() to cancel setting the variable. -class AutoSet { - public: - AutoSet(bool* b, bool set) : b_(b), set_(set) {} - ~AutoSet() { - if (b_) - *b_ = set_; - } - // Stops us from setting b_ on destruction. - void Reset() { b_ = nullptr; } - - private: - bool* b_; - const bool set_; -}; - // Derives from SkTraceMemoryDump and implements graphics specific memory // backing functionality. class SkiaGpuTraceMemoryDump : public SkTraceMemoryDump { @@ -190,7 +173,7 @@ ContextProviderCommandBuffer::~ContextProviderCommandBuffer() { shared_providers_->list.erase(it); } - if (bind_succeeded_) { + if (bind_tried_ && bind_result_ == gpu::ContextResult::kSuccess) { // Clear the lock to avoid DCHECKs that the lock is being held during // shutdown. command_buffer_->SetLock(nullptr); @@ -216,17 +199,16 @@ uint32_t ContextProviderCommandBuffer::GetCopyTextureInternalFormat() { return GL_RGB; } -bool ContextProviderCommandBuffer::BindToCurrentThread() { +gpu::ContextResult ContextProviderCommandBuffer::BindToCurrentThread() { // This is called on the thread the context will be used. DCHECK(context_thread_checker_.CalledOnValidThread()); - if (bind_failed_) - return false; - if (bind_succeeded_) - return true; + if (bind_tried_) + return bind_result_; - // Early outs should report failure. - AutoSet set_bind_failed(&bind_failed_, true); + bind_tried_ = true; + // Any early-out should set this to a failure code and return it. + bind_result_ = gpu::ContextResult::kSuccess; scoped_refptr task_runner = default_task_runner_; @@ -254,44 +236,54 @@ bool ContextProviderCommandBuffer::BindToCurrentThread() { // This command buffer is a client-side proxy to the command buffer in the // GPU process. - command_buffer_ = gpu::CommandBufferProxyImpl::Create( - std::move(channel_), surface_handle_, shared_command_buffer, stream_id_, - stream_priority_, attributes_, active_url_, task_runner); - if (!command_buffer_) { + command_buffer_ = std::make_unique( + std::move(channel_), stream_id_, task_runner); + bind_result_ = + command_buffer_->Initialize(surface_handle_, shared_command_buffer, + stream_priority_, attributes_, active_url_); + if (bind_result_ != gpu::ContextResult::kSuccess) { DLOG(ERROR) << "GpuChannelHost failed to create command buffer."; command_buffer_metrics::UmaRecordContextInitFailed(context_type_); - return false; + return bind_result_; } // The GLES2 helper writes the command buffer protocol. - gles2_helper_.reset(new gpu::gles2::GLES2CmdHelper(command_buffer_.get())); + gles2_helper_ = + std::make_unique(command_buffer_.get()); gles2_helper_->SetAutomaticFlushes(automatic_flushes_); - if (!gles2_helper_->Initialize(memory_limits_.command_buffer_size)) { + bind_result_ = + gles2_helper_->Initialize(memory_limits_.command_buffer_size); + if (bind_result_ != gpu::ContextResult::kSuccess) { DLOG(ERROR) << "Failed to initialize GLES2CmdHelper."; - return false; + return bind_result_; } // The transfer buffer is used to copy resources between the client // process and the GPU process. - transfer_buffer_.reset(new gpu::TransferBuffer(gles2_helper_.get())); + transfer_buffer_ = + std::make_unique(gles2_helper_.get()); // The GLES2Implementation exposes the OpenGLES2 API, as well as the // gpu::ContextSupport interface. constexpr bool support_client_side_arrays = false; - gles2_impl_.reset(new gpu::gles2::GLES2Implementation( + gles2_impl_ = std::make_unique( gles2_helper_.get(), share_group, transfer_buffer_.get(), attributes_.bind_generates_resource, attributes_.lose_context_when_out_of_memory, support_client_side_arrays, - command_buffer_.get())); - if (!gles2_impl_->Initialize(memory_limits_)) { + command_buffer_.get()); + bind_result_ = gles2_impl_->Initialize(memory_limits_); + if (bind_result_ != gpu::ContextResult::kSuccess) { DLOG(ERROR) << "Failed to initialize GLES2Implementation."; - return false; + return bind_result_; } if (command_buffer_->GetLastState().error != gpu::error::kNoError) { DLOG(ERROR) << "Context dead on arrival. Last error: " << command_buffer_->GetLastState().error; - return false; + // The context was DOA, which can be caused by other contexts and we + // could try again. + bind_result_ = gpu::ContextResult::kTransientFailure; + return bind_result_; } // If any context in the share group has been lost, then abort and don't @@ -307,16 +299,18 @@ bool ContextProviderCommandBuffer::BindToCurrentThread() { // context provider. If we check sooner, the shared context may be lost in // between these two states and our context here would be left in an orphan // share group. - if (share_group && share_group->IsLost()) - return false; + if (share_group && share_group->IsLost()) { + // The context was DOA, which can be caused by other contexts and we + // could try again. + bind_result_ = gpu::ContextResult::kTransientFailure; + return bind_result_; + } shared_providers_->list.push_back(this); - cache_controller_.reset( - new viz::ContextCacheController(gles2_impl_.get(), task_runner)); + cache_controller_ = std::make_unique( + gles2_impl_.get(), task_runner); } - set_bind_failed.Reset(); - bind_succeeded_ = true; gles2_impl_->SetLostContextCallback( base::Bind(&ContextProviderCommandBuffer::OnLostContext, @@ -328,8 +322,8 @@ bool ContextProviderCommandBuffer::BindToCurrentThread() { switches::kEnableGpuClientTracing)) { // This wraps the real GLES2Implementation and we should always use this // instead when it's present. - trace_impl_.reset( - new gpu::gles2::GLES2TraceImplementation(gles2_impl_.get())); + trace_impl_ = std::make_unique( + gles2_impl_.get()); } // Do this last once the context is set up. @@ -349,7 +343,7 @@ bool ContextProviderCommandBuffer::BindToCurrentThread() { } base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( this, "ContextProviderCommandBuffer", std::move(task_runner)); - return true; + return bind_result_; } void ContextProviderCommandBuffer::DetachFromThread() { @@ -357,7 +351,8 @@ void ContextProviderCommandBuffer::DetachFromThread() { } gpu::gles2::GLES2Interface* ContextProviderCommandBuffer::ContextGL() { - DCHECK(bind_succeeded_); + DCHECK(bind_tried_); + DCHECK_EQ(bind_result_, gpu::ContextResult::kSuccess); DCHECK(context_thread_checker_.CalledOnValidThread()); if (trace_impl_) @@ -370,7 +365,8 @@ gpu::ContextSupport* ContextProviderCommandBuffer::ContextSupport() { } class GrContext* ContextProviderCommandBuffer::GrContext() { - DCHECK(bind_succeeded_); + DCHECK(bind_tried_); + DCHECK_EQ(bind_result_, gpu::ContextResult::kSuccess); DCHECK(context_thread_checker_.CalledOnValidThread()); if (gr_context_) @@ -395,7 +391,8 @@ viz::ContextCacheController* ContextProviderCommandBuffer::CacheController() { void ContextProviderCommandBuffer::InvalidateGrContext(uint32_t state) { if (gr_context_) { - DCHECK(bind_succeeded_); + DCHECK(bind_tried_); + DCHECK_EQ(bind_result_, gpu::ContextResult::kSuccess); DCHECK(context_thread_checker_.CalledOnValidThread()); gr_context_->ResetContext(state); } @@ -403,7 +400,7 @@ void ContextProviderCommandBuffer::InvalidateGrContext(uint32_t state) { void ContextProviderCommandBuffer::SetDefaultTaskRunner( scoped_refptr default_task_runner) { - DCHECK(!bind_succeeded_); + DCHECK(!bind_tried_); default_task_runner_ = std::move(default_task_runner); } @@ -414,7 +411,8 @@ base::Lock* ContextProviderCommandBuffer::GetLock() { const gpu::Capabilities& ContextProviderCommandBuffer::ContextCapabilities() const { - DCHECK(bind_succeeded_); + DCHECK(bind_tried_); + DCHECK_EQ(bind_result_, gpu::ContextResult::kSuccess); DCHECK(context_thread_checker_.CalledOnValidThread()); // Skips past the trace_impl_ as it doesn't have capabilities. return gles2_impl_->capabilities(); @@ -422,7 +420,8 @@ const gpu::Capabilities& ContextProviderCommandBuffer::ContextCapabilities() const gpu::GpuFeatureInfo& ContextProviderCommandBuffer::GetGpuFeatureInfo() const { - DCHECK(bind_succeeded_); + DCHECK(bind_tried_); + DCHECK_EQ(bind_result_, gpu::ContextResult::kSuccess); DCHECK(context_thread_checker_.CalledOnValidThread()); if (!command_buffer_ || !command_buffer_->channel()) { static const gpu::GpuFeatureInfo default_gpu_feature_info; @@ -454,7 +453,8 @@ void ContextProviderCommandBuffer::SetLostContextCallback( bool ContextProviderCommandBuffer::OnMemoryDump( const base::trace_event::MemoryDumpArgs& args, base::trace_event::ProcessMemoryDump* pmd) { - DCHECK(bind_succeeded_); + DCHECK(bind_tried_); + DCHECK_EQ(bind_result_, gpu::ContextResult::kSuccess); base::Optional hold; if (support_locking_) diff --git a/services/ui/public/cpp/gpu/context_provider_command_buffer.h b/services/ui/public/cpp/gpu/context_provider_command_buffer.h index 34b81a51816b13..8f6007e5438a55 100644 --- a/services/ui/public/cpp/gpu/context_provider_command_buffer.h +++ b/services/ui/public/cpp/gpu/context_provider_command_buffer.h @@ -67,7 +67,7 @@ class ContextProviderCommandBuffer uint32_t GetCopyTextureInternalFormat(); // viz::ContextProvider implementation. - bool BindToCurrentThread() override; + gpu::ContextResult BindToCurrentThread() override; void DetachFromThread() override; gpu::gles2::GLES2Interface* ContextGL() override; gpu::ContextSupport* ContextSupport() override; @@ -110,8 +110,8 @@ class ContextProviderCommandBuffer base::ThreadChecker main_thread_checker_; base::ThreadChecker context_thread_checker_; - bool bind_succeeded_ = false; - bool bind_failed_ = false; + bool bind_tried_ = false; + gpu::ContextResult bind_result_; const int32_t stream_id_; const gpu::SchedulingPriority stream_priority_; diff --git a/ui/aura/mus/mus_context_factory.cc b/ui/aura/mus/mus_context_factory.cc index 6cab93e481348e..c5b2bf082672b4 100644 --- a/ui/aura/mus/mus_context_factory.cc +++ b/ui/aura/mus/mus_context_factory.cc @@ -59,8 +59,10 @@ void MusContextFactory::OnEstablishedGpuChannel( gpu_->CreateContextProvider(std::move(gpu_channel)); // If the binding fails, then we need to return early since the compositor // expects a successfully initialized/bound provider. - if (!context_provider->BindToCurrentThread()) + if (context_provider->BindToCurrentThread() != gpu::ContextResult::kSuccess) { + // TODO(danakj): We should retry if the result was not kFatalFailure. return; + } std::unique_ptr layer_tree_frame_sink = window_port->RequestLayerTreeFrameSink(std::move(context_provider), gpu_->gpu_memory_buffer_manager()); @@ -81,7 +83,8 @@ MusContextFactory::SharedMainThreadContextProvider() { gpu_->EstablishGpuChannelSync(); shared_main_thread_context_provider_ = gpu_->CreateContextProvider(std::move(gpu_channel)); - if (!shared_main_thread_context_provider_->BindToCurrentThread()) + if (shared_main_thread_context_provider_->BindToCurrentThread() != + gpu::ContextResult::kSuccess) shared_main_thread_context_provider_ = nullptr; } return shared_main_thread_context_provider_; diff --git a/ui/compositor/test/in_process_context_factory.cc b/ui/compositor/test/in_process_context_factory.cc index 91a28ca507996f..0efbcba6642f21 100644 --- a/ui/compositor/test/in_process_context_factory.cc +++ b/ui/compositor/test/in_process_context_factory.cc @@ -203,8 +203,8 @@ void InProcessContextFactory::CreateLayerTreeFrameSink( if (!shared_worker_context_provider_ || shared_worker_context_provider_lost) { shared_worker_context_provider_ = InProcessContextProvider::CreateOffscreen( &gpu_memory_buffer_manager_, &image_factory_, nullptr); - if (shared_worker_context_provider_ && - !shared_worker_context_provider_->BindToCurrentThread()) + auto result = shared_worker_context_provider_->BindToCurrentThread(); + if (result != gpu::ContextResult::kSuccess) shared_worker_context_provider_ = nullptr; } @@ -299,8 +299,8 @@ InProcessContextFactory::SharedMainThreadContextProvider() { shared_main_thread_contexts_ = InProcessContextProvider::CreateOffscreen( &gpu_memory_buffer_manager_, &image_factory_, nullptr); - if (shared_main_thread_contexts_.get() && - !shared_main_thread_contexts_->BindToCurrentThread()) + auto result = shared_main_thread_contexts_->BindToCurrentThread(); + if (result != gpu::ContextResult::kSuccess) shared_main_thread_contexts_ = NULL; return shared_main_thread_contexts_; diff --git a/ui/compositor/test/in_process_context_provider.cc b/ui/compositor/test/in_process_context_provider.cc index f110b69baf4edc..69a8b6709b5faa 100644 --- a/ui/compositor/test/in_process_context_provider.cc +++ b/ui/compositor/test/in_process_context_provider.cc @@ -79,32 +79,35 @@ InProcessContextProvider::~InProcessContextProvider() { context_thread_checker_.CalledOnValidThread()); } -bool InProcessContextProvider::BindToCurrentThread() { +gpu::ContextResult InProcessContextProvider::BindToCurrentThread() { // This is called on the thread the context will be used. DCHECK(context_thread_checker_.CalledOnValidThread()); - if (!context_) { - context_.reset(gpu::GLInProcessContext::Create( - nullptr, /* service */ - nullptr, /* surface */ - !window_, /* is_offscreen */ - window_, (shared_context_ ? shared_context_->context_.get() : nullptr), - attribs_, gpu::SharedMemoryLimits(), gpu_memory_buffer_manager_, - image_factory_, base::ThreadTaskRunnerHandle::Get())); + if (bind_tried_) + return bind_result_; + bind_tried_ = true; - if (!context_) - return false; + context_ = gpu::GLInProcessContext::CreateWithoutInit(); + bind_result_ = context_->Initialize( + nullptr, /* service */ + nullptr, /* surface */ + !window_, /* is_offscreen */ + window_, (shared_context_ ? shared_context_->context_.get() : nullptr), + attribs_, gpu::SharedMemoryLimits(), gpu_memory_buffer_manager_, + image_factory_, base::ThreadTaskRunnerHandle::Get()); - cache_controller_.reset(new viz::ContextCacheController( - context_->GetImplementation(), base::ThreadTaskRunnerHandle::Get())); - } + if (bind_result_ != gpu::ContextResult::kSuccess) + return bind_result_; + + cache_controller_ = std::make_unique( + context_->GetImplementation(), base::ThreadTaskRunnerHandle::Get()); std::string unique_context_name = base::StringPrintf("%s-%p", debug_name_.c_str(), context_.get()); context_->GetImplementation()->TraceBeginCHROMIUM( "gpu_toplevel", unique_context_name.c_str()); - return true; + return bind_result_; } void InProcessContextProvider::DetachFromThread() { diff --git a/ui/compositor/test/in_process_context_provider.h b/ui/compositor/test/in_process_context_provider.h index 7e0c0952719472..6c9d5e1f295d7c 100644 --- a/ui/compositor/test/in_process_context_provider.h +++ b/ui/compositor/test/in_process_context_provider.h @@ -47,7 +47,7 @@ class InProcessContextProvider : public viz::ContextProvider { InProcessContextProvider* shared_context); // cc::ContextProvider implementation. - bool BindToCurrentThread() override; + gpu::ContextResult BindToCurrentThread() override; void DetachFromThread() override; const gpu::Capabilities& ContextCapabilities() const override; const gpu::GpuFeatureInfo& GetGpuFeatureInfo() const override; @@ -81,6 +81,9 @@ class InProcessContextProvider : public viz::ContextProvider { std::unique_ptr gr_context_; std::unique_ptr cache_controller_; + bool bind_tried_ = false; + gpu::ContextResult bind_result_; + gpu::gles2::ContextCreationAttribHelper attribs_; InProcessContextProvider* shared_context_; gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_;