blob: d9e3f9a383ddf2e87dc27cfc11286f7c95baa918 [file] [log] [blame]
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
#include "base/synchronization/waitable_event.h"
#include "base/task/single_thread_task_runner.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/client/raster_interface.h"
#include "gpu/config/gpu_driver_bug_workaround_type.h"
#include "gpu/config/gpu_feature_info.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_graphics_context_3d_provider.h"
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/renderer/platform/scheduler/public/main_thread.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
namespace blink {
SharedGpuContext* SharedGpuContext::GetInstanceForCurrentThread() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadSpecific<SharedGpuContext>,
thread_specific_instance, ());
return thread_specific_instance;
}
SharedGpuContext::SharedGpuContext() = default;
// static
bool SharedGpuContext::IsGpuCompositingEnabled() {
SharedGpuContext* this_ptr = GetInstanceForCurrentThread();
// The check for gpu compositing enabled implies a context will
// desired, so we combine them into a single trip to the main thread.
// This also ensures that the compositing mode does not change before
// the context is created, so if it does change the context will be lost
// and this class will know to check the compositing mode again.
bool only_if_gpu_compositing = true;
this_ptr->CreateContextProviderIfNeeded(only_if_gpu_compositing);
return !this_ptr->is_gpu_compositing_disabled_;
}
base::WeakPtr<WebGraphicsContext3DProviderWrapper>
SharedGpuContext::ContextProviderWrapper() {
SharedGpuContext* this_ptr = GetInstanceForCurrentThread();
bool only_if_gpu_compositing = false;
this_ptr->CreateContextProviderIfNeeded(only_if_gpu_compositing);
if (!this_ptr->context_provider_wrapper_)
return nullptr;
return this_ptr->context_provider_wrapper_->GetWeakPtr();
}
static void CreateContextProviderOnMainThread(
bool only_if_gpu_compositing,
bool* gpu_compositing_disabled,
std::unique_ptr<WebGraphicsContext3DProviderWrapper>* wrapper,
base::WaitableEvent* waitable_event) {
DCHECK(IsMainThread());
Platform::ContextAttributes context_attributes;
context_attributes.enable_raster_interface = true;
context_attributes.support_grcontext = true;
// The shared GPU context should not trigger a switch to the high-performance
// GPU.
context_attributes.prefer_low_power_gpu = true;
*gpu_compositing_disabled = Platform::Current()->IsGpuCompositingDisabled();
if (*gpu_compositing_disabled && only_if_gpu_compositing) {
waitable_event->Signal();
return;
}
Platform::GraphicsInfo graphics_info;
auto context_provider =
Platform::Current()->CreateOffscreenGraphicsContext3DProvider(
context_attributes, WebURL(), &graphics_info);
if (context_provider) {
*wrapper = std::make_unique<WebGraphicsContext3DProviderWrapper>(
std::move(context_provider));
}
waitable_event->Signal();
}
void SharedGpuContext::CreateContextProviderIfNeeded(
bool only_if_gpu_compositing) {
// Once true, |is_gpu_compositing_disabled_| will always stay true.
if (is_gpu_compositing_disabled_ && only_if_gpu_compositing)
return;
// TODO(danakj): This needs to check that the context is being used on the
// thread it was made on, or else lock it.
if (context_provider_wrapper_ &&
!context_provider_wrapper_->ContextProvider()->IsContextLost()) {
// If the context isn't lost then |is_gpu_compositing_disabled_| state
// hasn't changed yet. RenderThreadImpl::CompositingModeFallbackToSoftware()
// will lose the context to let us know if it changes.
return;
}
is_gpu_compositing_disabled_ = false;
context_provider_wrapper_ = nullptr;
if (context_provider_factory_) {
// This path should only be used in unit tests.
auto context_provider =
context_provider_factory_.Run(&is_gpu_compositing_disabled_);
if (context_provider) {
context_provider_wrapper_ =
std::make_unique<WebGraphicsContext3DProviderWrapper>(
std::move(context_provider));
}
} else if (IsMainThread()) {
is_gpu_compositing_disabled_ =
Platform::Current()->IsGpuCompositingDisabled();
if (is_gpu_compositing_disabled_ && only_if_gpu_compositing)
return;
std::unique_ptr<blink::WebGraphicsContext3DProvider> context_provider;
context_provider =
Platform::Current()->CreateSharedOffscreenGraphicsContext3DProvider();
if (context_provider) {
context_provider_wrapper_ =
std::make_unique<WebGraphicsContext3DProviderWrapper>(
std::move(context_provider));
}
} else {
// This synchronous round-trip to the main thread is the reason why
// SharedGpuContext encasulates the context provider: so we only have to do
// this once per thread.
base::WaitableEvent waitable_event;
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
Thread::MainThread()->GetTaskRunner(MainThreadTaskRunnerRestricted());
PostCrossThreadTask(
*task_runner, FROM_HERE,
CrossThreadBindOnce(
&CreateContextProviderOnMainThread, only_if_gpu_compositing,
CrossThreadUnretained(&is_gpu_compositing_disabled_),
CrossThreadUnretained(&context_provider_wrapper_),
CrossThreadUnretained(&waitable_event)));
waitable_event.Wait();
if (context_provider_wrapper_ &&
!context_provider_wrapper_->ContextProvider()->BindToCurrentSequence())
context_provider_wrapper_ = nullptr;
}
}
// static
void SharedGpuContext::SetContextProviderFactoryForTesting(
ContextProviderFactory factory) {
SharedGpuContext* this_ptr = GetInstanceForCurrentThread();
DCHECK(!this_ptr->context_provider_wrapper_);
this_ptr->context_provider_factory_ = std::move(factory);
}
// static
void SharedGpuContext::ResetForTesting() {
SharedGpuContext* this_ptr = GetInstanceForCurrentThread();
this_ptr->is_gpu_compositing_disabled_ = false;
this_ptr->context_provider_wrapper_.reset();
this_ptr->context_provider_factory_.Reset();
}
bool SharedGpuContext::IsValidWithoutRestoring() {
SharedGpuContext* this_ptr = GetInstanceForCurrentThread();
if (!this_ptr->context_provider_wrapper_)
return false;
return this_ptr->context_provider_wrapper_->ContextProvider()
->ContextGL()
->GetGraphicsResetStatusKHR() == GL_NO_ERROR;
}
bool SharedGpuContext::AllowSoftwareToAcceleratedCanvasUpgrade() {
SharedGpuContext* this_ptr = GetInstanceForCurrentThread();
bool only_if_gpu_compositing = false;
this_ptr->CreateContextProviderIfNeeded(only_if_gpu_compositing);
if (!this_ptr->context_provider_wrapper_)
return false;
return !this_ptr->context_provider_wrapper_->ContextProvider()
->GetGpuFeatureInfo()
.IsWorkaroundEnabled(
gpu::DISABLE_SOFTWARE_TO_ACCELERATED_CANVAS_UPGRADE);
}
} // blink