blob: 385bb4f403ef500e967d500d75a7f4ce7969786a [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/android/in_process/synchronous_compositor_factory_impl.h"
#include <stdint.h>
#include <utility>
#include "base/command_line.h"
#include "base/macros.h"
#include "base/observer_list.h"
#include "base/sys_info.h"
#include "base/thread_task_runner_handle.h"
#include "content/browser/android/in_process/context_provider_in_process.h"
#include "content/browser/android/in_process/synchronous_compositor_impl.h"
#include "content/browser/android/in_process/synchronous_compositor_registry_in_proc.h"
#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
#include "content/common/gpu/client/context_provider_command_buffer.h"
#include "content/common/gpu/client/gpu_channel_host.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_switches.h"
#include "content/renderer/android/synchronous_compositor_external_begin_frame_source.h"
#include "content/renderer/android/synchronous_compositor_output_surface.h"
#include "content/renderer/gpu/frame_swap_message_queue.h"
#include "content/renderer/render_thread_impl.h"
#include "gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h"
#include "gpu/command_buffer/client/gl_in_process_context.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/common/gles2_cmd_utils.h"
#include "ui/gl/android/surface_texture.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/gl_surface_stub.h"
using cc_blink::ContextProviderWebContext;
using gpu_blink::WebGraphicsContext3DImpl;
using gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl;
namespace content {
namespace {
struct ContextHolder {
scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> command_buffer;
gpu::GLInProcessContext* gl_in_process_context;
};
blink::WebGraphicsContext3D::Attributes GetDefaultAttribs() {
blink::WebGraphicsContext3D::Attributes attributes;
attributes.antialias = false;
attributes.depth = false;
attributes.stencil = false;
attributes.shareResources = true;
attributes.noAutomaticFlushes = true;
return attributes;
}
ContextHolder CreateContextHolder(
const blink::WebGraphicsContext3D::Attributes& attributes,
scoped_refptr<gpu::InProcessCommandBuffer::Service> service,
const gpu::GLInProcessContextSharedMemoryLimits& mem_limits,
bool is_offscreen) {
gpu::gles2::ContextCreationAttribHelper in_process_attribs;
WebGraphicsContext3DImpl::ConvertAttributes(attributes, &in_process_attribs);
in_process_attribs.lose_context_when_out_of_memory = true;
scoped_ptr<gpu::GLInProcessContext> context(gpu::GLInProcessContext::Create(
service, NULL /* surface */, is_offscreen, gfx::kNullAcceleratedWidget,
gfx::Size(1, 1), NULL /* share_context */, attributes.shareResources,
in_process_attribs, gfx::PreferDiscreteGpu, mem_limits,
BrowserGpuMemoryBufferManager::current(), nullptr));
gpu::GLInProcessContext* context_ptr = context.get();
ContextHolder holder;
holder.command_buffer =
scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>(
WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
std::move(context), attributes));
holder.gl_in_process_context = context_ptr;
return holder;
}
} // namespace
SynchronousCompositorFactoryImpl::SynchronousCompositorFactoryImpl() {
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kSingleProcess)) {
// TODO(boliu): Figure out how to deal with this more nicely.
SynchronousCompositorFactory::SetInstance(this);
}
}
SynchronousCompositorFactoryImpl::~SynchronousCompositorFactoryImpl() {}
scoped_refptr<base::SingleThreadTaskRunner>
SynchronousCompositorFactoryImpl::GetCompositorTaskRunner() {
return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
}
scoped_ptr<cc::OutputSurface>
SynchronousCompositorFactoryImpl::CreateOutputSurface(
int routing_id,
const scoped_refptr<FrameSwapMessageQueue>& frame_swap_message_queue,
const scoped_refptr<cc::ContextProvider>& onscreen_context,
const scoped_refptr<cc::ContextProvider>& worker_context) {
return make_scoped_ptr(new SynchronousCompositorOutputSurface(
onscreen_context, worker_context, routing_id,
SynchronousCompositorRegistryInProc::GetInstance(),
frame_swap_message_queue));
}
InputHandlerManagerClient*
SynchronousCompositorFactoryImpl::GetInputHandlerManagerClient() {
return synchronous_input_event_filter();
}
scoped_ptr<cc::BeginFrameSource>
SynchronousCompositorFactoryImpl::CreateExternalBeginFrameSource(
int routing_id) {
return make_scoped_ptr(new SynchronousCompositorExternalBeginFrameSource(
routing_id, SynchronousCompositorRegistryInProc::GetInstance()));
}
// SynchronousCompositorStreamTextureFactoryImpl.
class SynchronousCompositorStreamTextureFactoryImpl::VideoContextProvider
: public StreamTextureFactorySynchronousImpl::ContextProvider {
public:
VideoContextProvider(scoped_refptr<cc::ContextProvider> context_provider,
gpu::GLInProcessContext* gl_in_process_context)
: context_provider_(context_provider),
gl_in_process_context_(gl_in_process_context) {
context_provider_->BindToCurrentThread();
}
scoped_refptr<gfx::SurfaceTexture> GetSurfaceTexture(
uint32_t stream_id) override {
return gl_in_process_context_->GetSurfaceTexture(stream_id);
}
uint32_t CreateStreamTexture(uint32_t texture_id) override {
return gl_in_process_context_->CreateStreamTexture(texture_id);
}
gpu::gles2::GLES2Interface* ContextGL() override {
return context_provider_->ContextGL();
}
void AddObserver(StreamTextureFactoryContextObserver* obs) override {
observer_list_.AddObserver(obs);
}
void RemoveObserver(StreamTextureFactoryContextObserver* obs) override {
observer_list_.RemoveObserver(obs);
}
void RestoreContext() {
FOR_EACH_OBSERVER(StreamTextureFactoryContextObserver, observer_list_,
ResetStreamTextureProxy());
}
private:
friend class base::RefCountedThreadSafe<VideoContextProvider>;
~VideoContextProvider() override {}
scoped_refptr<cc::ContextProvider> context_provider_;
gpu::GLInProcessContext* gl_in_process_context_;
base::ObserverList<StreamTextureFactoryContextObserver> observer_list_;
DISALLOW_COPY_AND_ASSIGN(VideoContextProvider);
};
namespace {
base::LazyInstance<SynchronousCompositorStreamTextureFactoryImpl>::Leaky
g_stream_texture_factory = LAZY_INSTANCE_INITIALIZER;
} // namespace
// static
SynchronousCompositorStreamTextureFactoryImpl*
SynchronousCompositorStreamTextureFactoryImpl::GetInstance() {
return g_stream_texture_factory.Pointer();
}
SynchronousCompositorStreamTextureFactoryImpl::
SynchronousCompositorStreamTextureFactoryImpl()
: num_hardware_compositors_(0) {}
scoped_refptr<StreamTextureFactory>
SynchronousCompositorStreamTextureFactoryImpl::CreateStreamTextureFactory() {
return StreamTextureFactorySynchronousImpl::Create(
base::Bind(&SynchronousCompositorStreamTextureFactoryImpl::
TryCreateStreamTextureFactory,
base::Unretained(this)));
}
void SynchronousCompositorStreamTextureFactoryImpl::
CompositorInitializedHardwareDraw() {
base::AutoLock lock(num_hardware_compositor_lock_);
num_hardware_compositors_++;
if (num_hardware_compositors_ == 1 && main_thread_task_runner_.get()) {
main_thread_task_runner_->PostTask(
FROM_HERE, base::Bind(&SynchronousCompositorStreamTextureFactoryImpl::
RestoreContextOnMainThread,
base::Unretained(this)));
}
}
void SynchronousCompositorStreamTextureFactoryImpl::
CompositorReleasedHardwareDraw() {
base::AutoLock lock(num_hardware_compositor_lock_);
DCHECK_GT(num_hardware_compositors_, 0u);
num_hardware_compositors_--;
}
void SynchronousCompositorStreamTextureFactoryImpl::
RestoreContextOnMainThread() {
if (CanCreateMainThreadContext() && video_context_provider_.get())
video_context_provider_->RestoreContext();
}
bool SynchronousCompositorStreamTextureFactoryImpl::
CanCreateMainThreadContext() {
base::AutoLock lock(num_hardware_compositor_lock_);
return num_hardware_compositors_ > 0;
}
scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
SynchronousCompositorStreamTextureFactoryImpl::TryCreateStreamTextureFactory() {
{
base::AutoLock lock(num_hardware_compositor_lock_);
main_thread_task_runner_ = base::ThreadTaskRunnerHandle::Get();
}
// Always fail creation even if |video_context_provider_| is not NULL.
// This is to avoid synchronous calls that may deadlock. Setting
// |video_context_provider_| to null is also not safe since it makes
// synchronous destruction uncontrolled and possibly deadlock.
if (!CanCreateMainThreadContext()) {
return scoped_refptr<
StreamTextureFactorySynchronousImpl::ContextProvider>();
}
if (!video_context_provider_.get()) {
DCHECK(android_view_service_.get());
blink::WebGraphicsContext3D::Attributes attributes = GetDefaultAttribs();
attributes.shareResources = false;
// This needs to run in on-screen |android_view_service_| context due to
// SurfaceTexture limitations.
ContextHolder holder =
CreateContextHolder(attributes, android_view_service_,
gpu::GLInProcessContextSharedMemoryLimits(), false);
video_context_provider_ = new VideoContextProvider(
ContextProviderInProcess::Create(std::move(holder.command_buffer),
"Video-Offscreen-main-thread"),
holder.gl_in_process_context);
}
return video_context_provider_;
}
void SynchronousCompositorStreamTextureFactoryImpl::SetDeferredGpuService(
scoped_refptr<gpu::InProcessCommandBuffer::Service> service) {
DCHECK(!android_view_service_.get());
android_view_service_ = service;
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kSingleProcess)) {
RenderThreadImpl::SetStreamTextureFactory(CreateStreamTextureFactory());
}
}
} // namespace content