| Index: content/common/gpu/client/context_provider_command_buffer.cc
|
| diff --git a/content/common/gpu/client/context_provider_command_buffer.cc b/content/common/gpu/client/context_provider_command_buffer.cc
|
| index ae843dc7d40384c921d8bfdc007ba4763b0a8246..20cf26b78a1ca33610e2a5c7e2c1d3e21852d17c 100644
|
| --- a/content/common/gpu/client/context_provider_command_buffer.cc
|
| +++ b/content/common/gpu/client/context_provider_command_buffer.cc
|
| @@ -16,14 +16,37 @@
|
| #include "base/strings/stringprintf.h"
|
| #include "cc/output/managed_memory_policy.h"
|
| #include "content/common/gpu/client/command_buffer_metrics.h"
|
| -#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
|
| +#include "gpu/command_buffer/client/gles2_cmd_helper.h"
|
| #include "gpu/command_buffer/client/gles2_implementation.h"
|
| #include "gpu/command_buffer/client/gles2_trace_implementation.h"
|
| #include "gpu/command_buffer/client/gpu_switches.h"
|
| +#include "gpu/command_buffer/client/transfer_buffer.h"
|
| +#include "gpu/command_buffer/common/constants.h"
|
| +#include "gpu/ipc/client/command_buffer_proxy_impl.h"
|
| #include "gpu/ipc/client/gpu_channel_host.h"
|
| #include "gpu/skia_bindings/grcontext_for_gles2_interface.h"
|
| #include "third_party/skia/include/gpu/GrContext.h"
|
|
|
| +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_;
|
| +};
|
| +}
|
| +
|
| namespace content {
|
|
|
| ContextProviderCommandBuffer::SharedProviders::SharedProviders() = default;
|
| @@ -49,8 +72,7 @@ ContextProviderCommandBuffer::ContextProviderCommandBuffer(
|
| shared_providers_(shared_context_provider
|
| ? shared_context_provider->shared_providers_
|
| : new SharedProviders),
|
| - channel_(std::move(channel)),
|
| - context3d_(new WebGraphicsContext3DCommandBufferImpl) {
|
| + channel_(std::move(channel)) {
|
| DCHECK(main_thread_checker_.CalledOnValidThread());
|
| DCHECK(channel_);
|
| context_thread_checker_.DetachFromThread();
|
| @@ -71,25 +93,28 @@ ContextProviderCommandBuffer::~ContextProviderCommandBuffer() {
|
| if (bind_succeeded_) {
|
| // Clear the lock to avoid DCHECKs that the lock is being held during
|
| // shutdown.
|
| - context3d_->GetCommandBufferProxy()->SetLock(nullptr);
|
| + command_buffer_->SetLock(nullptr);
|
| // Disconnect lost callbacks during destruction.
|
| - context3d_->GetImplementation()->SetLostContextCallback(base::Closure());
|
| + gles2_impl_->SetLostContextCallback(base::Closure());
|
| }
|
| }
|
|
|
| gpu::CommandBufferProxyImpl*
|
| ContextProviderCommandBuffer::GetCommandBufferProxy() {
|
| - return context3d_->GetCommandBufferProxy();
|
| + return command_buffer_.get();
|
| }
|
|
|
| bool ContextProviderCommandBuffer::BindToCurrentThread() {
|
| // This is called on the thread the context will be used.
|
| DCHECK(context_thread_checker_.CalledOnValidThread());
|
|
|
| - if (!context3d_)
|
| - return false; // Already failed.
|
| + if (bind_failed_)
|
| + return false;
|
| if (bind_succeeded_)
|
| - return true; // Already succeeded.
|
| + return true;
|
| +
|
| + // Early outs should report failure.
|
| + AutoSet set_bind_failed(&bind_failed_, true);
|
|
|
| // It's possible to be running BindToCurrentThread on two contexts
|
| // on different threads at the same time, but which will be in the same share
|
| @@ -105,17 +130,62 @@ bool ContextProviderCommandBuffer::BindToCurrentThread() {
|
|
|
| if (!shared_providers_->list.empty()) {
|
| shared_context_provider = shared_providers_->list.front();
|
| - shared_command_buffer =
|
| - shared_context_provider->context3d_->GetCommandBufferProxy();
|
| - share_group = shared_context_provider->context3d_->GetImplementation()
|
| - ->share_group();
|
| + shared_command_buffer = shared_context_provider->command_buffer_.get();
|
| + share_group = shared_context_provider->gles2_impl_->share_group();
|
| + DCHECK_EQ(!!shared_command_buffer, !!share_group);
|
| }
|
|
|
| - if (!context3d_->InitializeOnCurrentThread(
|
| - surface_handle_, active_url_, channel_.get(), gpu_preference_,
|
| - automatic_flushes_, memory_limits_, shared_command_buffer,
|
| - share_group, attributes_, context_type_)) {
|
| - context3d_ = nullptr;
|
| + DCHECK(attributes_.buffer_preserved);
|
| + std::vector<int32_t> serialized_attributes;
|
| + attributes_.Serialize(&serialized_attributes);
|
| +
|
| + // This command buffer is a client-side proxy to the command buffer in the
|
| + // GPU process.
|
| + command_buffer_ = channel_->CreateCommandBuffer(
|
| + surface_handle_, gfx::Size(), shared_command_buffer,
|
| + gpu::GpuChannelHost::kDefaultStreamId,
|
| + gpu::GpuChannelHost::kDefaultStreamPriority, serialized_attributes,
|
| + active_url_, gpu_preference_);
|
| + // The command buffer takes ownership of the |channel_|, so no need to keep
|
| + // a reference around here.
|
| + channel_ = nullptr;
|
| + if (!command_buffer_) {
|
| + DLOG(ERROR) << "GpuChannelHost failed to create command buffer.";
|
| + command_buffer_metrics::UmaRecordContextInitFailed(context_type_);
|
| + return false;
|
| + }
|
| +
|
| + // The GLES2 helper writes the command buffer protocol.
|
| + gles2_helper_.reset(new gpu::gles2::GLES2CmdHelper(command_buffer_.get()));
|
| + gles2_helper_->SetAutomaticFlushes(automatic_flushes_);
|
| + if (!gles2_helper_->Initialize(memory_limits_.command_buffer_size)) {
|
| + DLOG(ERROR) << "Failed to initialize GLES2CmdHelper.";
|
| + return false;
|
| + }
|
| +
|
| + // 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()));
|
| +
|
| + // 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_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_.start_transfer_buffer_size,
|
| + memory_limits_.min_transfer_buffer_size,
|
| + memory_limits_.max_transfer_buffer_size,
|
| + memory_limits_.mapped_memory_reclaim_limit)) {
|
| + DLOG(ERROR) << "Failed to initialize GLES2Implementation.";
|
| + return false;
|
| + }
|
| +
|
| + if (command_buffer_->GetLastError() != gpu::error::kNoError) {
|
| + DLOG(ERROR) << "Context dead on arrival. Last error: "
|
| + << command_buffer_->GetLastError();
|
| return false;
|
| }
|
|
|
| @@ -132,15 +202,15 @@ 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()) {
|
| - context3d_ = nullptr;
|
| + if (share_group && share_group->IsLost())
|
| return false;
|
| - }
|
|
|
| shared_providers_->list.push_back(this);
|
| }
|
| + set_bind_failed.Reset();
|
| + bind_succeeded_ = true;
|
|
|
| - context3d_->GetImplementation()->SetLostContextCallback(
|
| + gles2_impl_->SetLostContextCallback(
|
| base::Bind(&ContextProviderCommandBuffer::OnLostContext,
|
| // |this| owns the GLES2Implementation which holds the
|
| // callback.
|
| @@ -150,17 +220,15 @@ 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(
|
| - context3d_->GetImplementation()));
|
| + trace_impl_.reset(
|
| + new gpu::gles2::GLES2TraceImplementation(gles2_impl_.get()));
|
| }
|
|
|
| - bind_succeeded_ = true;
|
| -
|
| // Do this last once the context is set up.
|
| std::string type_name =
|
| command_buffer_metrics::ContextTypeToString(context_type_);
|
| std::string unique_context_name =
|
| - base::StringPrintf("%s-%p", type_name.c_str(), context3d_.get());
|
| + base::StringPrintf("%s-%p", type_name.c_str(), gles2_impl_.get());
|
| ContextGL()->TraceBeginCHROMIUM("gpu_toplevel", unique_context_name.c_str());
|
| return true;
|
| }
|
| @@ -170,17 +238,16 @@ void ContextProviderCommandBuffer::DetachFromThread() {
|
| }
|
|
|
| gpu::gles2::GLES2Interface* ContextProviderCommandBuffer::ContextGL() {
|
| - DCHECK(context3d_);
|
| DCHECK(bind_succeeded_);
|
| DCHECK(context_thread_checker_.CalledOnValidThread());
|
|
|
| if (trace_impl_)
|
| return trace_impl_.get();
|
| - return context3d_->GetImplementation();
|
| + return gles2_impl_.get();
|
| }
|
|
|
| gpu::ContextSupport* ContextProviderCommandBuffer::ContextSupport() {
|
| - return context3d_->GetImplementation();
|
| + return gles2_impl_.get();
|
| }
|
|
|
| class GrContext* ContextProviderCommandBuffer::GrContext() {
|
| @@ -211,7 +278,7 @@ void ContextProviderCommandBuffer::InvalidateGrContext(uint32_t state) {
|
| void ContextProviderCommandBuffer::SetupLock() {
|
| DCHECK(bind_succeeded_);
|
| DCHECK(context_thread_checker_.CalledOnValidThread());
|
| - context3d_->GetCommandBufferProxy()->SetLock(&context_lock_);
|
| + command_buffer_->SetLock(&context_lock_);
|
| }
|
|
|
| base::Lock* ContextProviderCommandBuffer::GetLock() {
|
| @@ -222,7 +289,7 @@ gpu::Capabilities ContextProviderCommandBuffer::ContextCapabilities() {
|
| DCHECK(bind_succeeded_);
|
| DCHECK(context_thread_checker_.CalledOnValidThread());
|
| // Skips past the trace_impl_ as it doesn't have capabilities.
|
| - return context3d_->GetImplementation()->capabilities();
|
| + return gles2_impl_->capabilities();
|
| }
|
|
|
| void ContextProviderCommandBuffer::DeleteCachedResources() {
|
|
|