blob: bb126e5f88b59a6f4b2a70c409e6187652081db6 [file] [log] [blame]
// Copyright (c) 2012 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/renderer_host/image_transport_factory.h"
#include <algorithm>
#include <map>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
#include "base/strings/string_number_conversions.h"
#include "base/threading/non_thread_safe.h"
#include "cc/output/compositor_frame.h"
#include "cc/output/output_surface.h"
#include "cc/output/output_surface_client.h"
#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/gpu/gpu_process_host.h"
#include "content/browser/gpu/gpu_surface_tracker.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/common/gpu/client/context_provider_command_buffer.h"
#include "content/common/gpu/client/gl_helper.h"
#include "content/common/gpu/client/gpu_channel_host.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
#include "content/common/gpu/gpu_messages.h"
#include "content/common/gpu/gpu_process_launch_causes.h"
#include "content/public/common/content_switches.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/ipc/command_buffer_proxy.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/compositor_setup.h"
#include "ui/compositor/compositor_switches.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/test_web_graphics_context_3d.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/size.h"
#if defined(OS_WIN)
#include "content/browser/renderer_host/software_output_device_win.h"
#include "ui/surface/accelerated_surface_win.h"
#elif defined(USE_X11)
#include "content/browser/renderer_host/software_output_device_x11.h"
#endif
namespace content {
namespace {
ImageTransportFactory* g_factory;
// An ImageTransportFactory that disables transport.
class NoTransportFactory : public ImageTransportFactory {
public:
explicit NoTransportFactory(ui::ContextFactory* context_factory)
: context_factory_(context_factory) {
}
virtual ui::ContextFactory* AsContextFactory() OVERRIDE {
return context_factory_.get();
}
virtual gfx::GLSurfaceHandle CreateSharedSurfaceHandle() OVERRIDE {
return gfx::GLSurfaceHandle();
}
virtual void DestroySharedSurfaceHandle(
gfx::GLSurfaceHandle surface) OVERRIDE {
}
virtual scoped_refptr<ui::Texture> CreateTransportClient(
float device_scale_factor) OVERRIDE {
return NULL;
}
virtual scoped_refptr<ui::Texture> CreateOwnedTexture(
const gfx::Size& size,
float device_scale_factor,
unsigned int texture_id) OVERRIDE {
return NULL;
}
virtual GLHelper* GetGLHelper() OVERRIDE {
return NULL;
}
virtual uint32 InsertSyncPoint() OVERRIDE {
return 0;
}
virtual void WaitSyncPoint(uint32 sync_point) OVERRIDE {
}
// We don't generate lost context events, so we don't need to keep track of
// observers
virtual void AddObserver(ImageTransportFactoryObserver* observer) OVERRIDE {
}
virtual void RemoveObserver(
ImageTransportFactoryObserver* observer) OVERRIDE {
}
private:
scoped_ptr<ui::ContextFactory> context_factory_;
DISALLOW_COPY_AND_ASSIGN(NoTransportFactory);
};
class OwnedTexture : public ui::Texture, ImageTransportFactoryObserver {
public:
OwnedTexture(WebKit::WebGraphicsContext3D* host_context,
const gfx::Size& size,
float device_scale_factor,
unsigned int texture_id)
: ui::Texture(true, size, device_scale_factor),
host_context_(host_context),
texture_id_(texture_id) {
ImageTransportFactory::GetInstance()->AddObserver(this);
}
// ui::Texture overrides:
virtual unsigned int PrepareTexture() OVERRIDE {
return texture_id_;
}
virtual WebKit::WebGraphicsContext3D* HostContext3D() OVERRIDE {
return host_context_;
}
// ImageTransportFactory overrides:
virtual void OnLostResources() OVERRIDE {
DeleteTexture();
}
protected:
virtual ~OwnedTexture() {
ImageTransportFactory::GetInstance()->RemoveObserver(this);
DeleteTexture();
}
protected:
void DeleteTexture() {
if (texture_id_) {
host_context_->deleteTexture(texture_id_);
texture_id_ = 0;
}
}
// A raw pointer. This |ImageTransportClientTexture| will be destroyed
// before the |host_context_| via
// |ImageTransportFactoryObserver::OnLostContext()| handlers.
WebKit::WebGraphicsContext3D* host_context_;
unsigned texture_id_;
DISALLOW_COPY_AND_ASSIGN(OwnedTexture);
};
class ImageTransportClientTexture : public OwnedTexture {
public:
ImageTransportClientTexture(
WebKit::WebGraphicsContext3D* host_context,
float device_scale_factor)
: OwnedTexture(host_context,
gfx::Size(0, 0),
device_scale_factor,
host_context->createTexture()) {
}
virtual void Consume(const std::string& mailbox_name,
const gfx::Size& new_size) OVERRIDE {
DCHECK(mailbox_name.size() == GL_MAILBOX_SIZE_CHROMIUM);
mailbox_name_ = mailbox_name;
if (mailbox_name.empty())
return;
DCHECK(host_context_ && texture_id_);
host_context_->bindTexture(GL_TEXTURE_2D, texture_id_);
host_context_->consumeTextureCHROMIUM(
GL_TEXTURE_2D,
reinterpret_cast<const signed char*>(mailbox_name.c_str()));
size_ = new_size;
host_context_->shallowFlushCHROMIUM();
}
virtual std::string Produce() OVERRIDE {
return mailbox_name_;
}
protected:
virtual ~ImageTransportClientTexture() {}
private:
std::string mailbox_name_;
DISALLOW_COPY_AND_ASSIGN(ImageTransportClientTexture);
};
class GpuProcessTransportFactory;
class CompositorSwapClient
: public base::SupportsWeakPtr<CompositorSwapClient>,
public WebGraphicsContext3DSwapBuffersClient {
public:
CompositorSwapClient(ui::Compositor* compositor,
GpuProcessTransportFactory* factory)
: compositor_(compositor),
factory_(factory) {
}
virtual ~CompositorSwapClient() {
}
virtual void OnViewContextSwapBuffersPosted() OVERRIDE {
compositor_->OnSwapBuffersPosted();
}
virtual void OnViewContextSwapBuffersComplete() OVERRIDE {
compositor_->OnSwapBuffersComplete();
}
virtual void OnViewContextSwapBuffersAborted() OVERRIDE {
// Recreating contexts directly from here causes issues, so post a task
// instead.
// TODO(piman): Fix the underlying issues.
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&CompositorSwapClient::OnLostContext, this->AsWeakPtr()));
}
private:
void OnLostContext();
ui::Compositor* compositor_;
GpuProcessTransportFactory* factory_;
DISALLOW_COPY_AND_ASSIGN(CompositorSwapClient);
};
class BrowserCompositorOutputSurface;
// Directs vsync updates to the appropriate BrowserCompositorOutputSurface.
class BrowserCompositorOutputSurfaceProxy
: public base::RefCountedThreadSafe<BrowserCompositorOutputSurfaceProxy> {
public:
BrowserCompositorOutputSurfaceProxy()
: message_handler_set_(false) {
}
void AddSurface(BrowserCompositorOutputSurface* surface, int surface_id) {
if (!message_handler_set_) {
uint32 messages_to_filter[] = {GpuHostMsg_UpdateVSyncParameters::ID};
BrowserGpuChannelHostFactory::instance()->SetHandlerForControlMessages(
messages_to_filter,
arraysize(messages_to_filter),
base::Bind(&BrowserCompositorOutputSurfaceProxy::OnMessageReceived,
this),
base::MessageLoop::current()->message_loop_proxy().get());
message_handler_set_ = true;
}
surface_map_.AddWithID(surface, surface_id);
}
BrowserCompositorOutputSurface* GetOutputSurface(int surface_id) {
return surface_map_.Lookup(surface_id);
}
void RemoveSurface(int surface_id) {
surface_map_.Remove(surface_id);
}
private:
void OnMessageReceived(const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(BrowserCompositorOutputSurfaceProxy, message)
IPC_MESSAGE_HANDLER(GpuHostMsg_UpdateVSyncParameters,
OnUpdateVSyncParameters);
IPC_END_MESSAGE_MAP()
}
void OnUpdateVSyncParameters(int surface_id,
base::TimeTicks timebase,
base::TimeDelta interval);
friend class
base::RefCountedThreadSafe<BrowserCompositorOutputSurfaceProxy>;
~BrowserCompositorOutputSurfaceProxy() {}
IDMap<BrowserCompositorOutputSurface> surface_map_;
bool message_handler_set_;
DISALLOW_COPY_AND_ASSIGN(BrowserCompositorOutputSurfaceProxy);
};
// A reflector implementation that copies the framebuffer content
// to the texture, then draw it onto the mirroring compositor.
class ReflectorImpl : public ImageTransportFactoryObserver,
public base::SupportsWeakPtr<ReflectorImpl>,
public ui::Reflector {
public:
ReflectorImpl(ui::Compositor* mirrored_compositor,
ui::Layer* mirroring_layer,
BrowserCompositorOutputSurfaceProxy* output_surface_proxy,
int surface_id)
: texture_id_(0),
texture_size_(mirrored_compositor->size()),
output_surface_proxy_(output_surface_proxy),
mirrored_compositor_(mirrored_compositor),
mirroring_compositor_(mirroring_layer->GetCompositor()),
mirroring_layer_(mirroring_layer),
impl_message_loop_(ui::Compositor::GetCompositorMessageLoop()),
main_message_loop_(base::MessageLoopProxy::current()),
surface_id_(surface_id) {
CreateSharedTexture();
impl_message_loop_->PostTask(
FROM_HERE,
base::Bind(&ReflectorImpl::InitOnImplThread,
this));
}
ui::Compositor* mirrored_compositor() {
return mirrored_compositor_;
}
void InitOnImplThread();
void Shutdown() {
mirroring_compositor_ = NULL;
mirroring_layer_ = NULL;
shared_texture_ = NULL;
impl_message_loop_->PostTask(
FROM_HERE,
base::Bind(&ReflectorImpl::ShutdownOnImplThread,
this));
}
void ShutdownOnImplThread();
// This must be called on ImplThread, or before the surface is passed to
// ImplThread.
void AttachToOutputSurface(BrowserCompositorOutputSurface* surface);
// ui::Reflector overrides:
virtual void OnMirroringCompositorResized() OVERRIDE {
mirroring_compositor_->ScheduleFullRedraw();
}
// ImageTransportFactoryObsever overrides:
virtual void OnLostResources() OVERRIDE {
shared_texture_ = NULL;
mirroring_layer_->SetExternalTexture(NULL);
}
// Called when the output surface's size has changed.
// This must be called on ImplThread.
void OnReshape(gfx::Size size) {
if (texture_size_ == size)
return;
texture_size_ = size;
DCHECK(texture_id_);
gl_helper_->ResizeTexture(texture_id_, size);
main_message_loop_->PostTask(
FROM_HERE,
base::Bind(&ReflectorImpl::UpdateTextureSizeOnMainThread,
this->AsWeakPtr(),
texture_size_));
}
// Called in |BrowserCompositorOutputSurface::SwapBuffers| to copy
// the full screen image to the |texture_id_|. This must be called
// on ImplThread.
void OnSwapBuffers() {
DCHECK(texture_id_);
gl_helper_->CopyTextureFullImage(texture_id_, texture_size_);
main_message_loop_->PostTask(
FROM_HERE,
base::Bind(&ReflectorImpl::FullRedrawOnMainThread,
this->AsWeakPtr(),
texture_size_));
}
// Called in |BrowserCompositorOutputSurface::PostSubBuffer| copy
// the sub image given by |rect| to the texture.This must be called
// on ImplThread.
void OnPostSubBuffer(gfx::Rect rect) {
DCHECK(texture_id_);
gl_helper_->CopyTextureSubImage(texture_id_, rect);
main_message_loop_->PostTask(
FROM_HERE,
base::Bind(&ReflectorImpl::UpdateSubBufferOnMainThread,
this->AsWeakPtr(),
texture_size_,
rect));
}
// Create a shared texture that will be used to copy the content of
// mirrored compositor to the mirroring compositor. This must be
// called before the reflector is attached to OutputSurface to avoid
// race with ImplThread accessing |texture_id_|.
void CreateSharedTexture() {
texture_id_ = ImageTransportFactory::GetInstance()->GetGLHelper()->
CreateTexture();
shared_texture_ = ImageTransportFactory::GetInstance()->
CreateOwnedTexture(texture_size_, 1.0f, texture_id_);
mirroring_layer_->SetExternalTexture(shared_texture_.get());
}
private:
virtual ~ReflectorImpl() {
// Make sure the reflector is deleted on main thread.
DCHECK_EQ(main_message_loop_.get(),
base::MessageLoopProxy::current().get());
}
void UpdateTextureSizeOnMainThread(gfx::Size size) {
if (!mirroring_layer_)
return;
mirroring_layer_->SetBounds(gfx::Rect(size));
}
// Request full redraw on mirroring compositor.
void FullRedrawOnMainThread(gfx::Size size) {
if (!mirroring_compositor_)
return;
UpdateTextureSizeOnMainThread(size);
mirroring_compositor_->ScheduleFullRedraw();
}
void UpdateSubBufferOnMainThread(gfx::Size size,
gfx::Rect rect) {
if (!mirroring_compositor_)
return;
UpdateTextureSizeOnMainThread(size);
// Flip the coordinates to compositor's one.
int y = size.height() - rect.y() - rect.height();
gfx::Rect new_rect(rect.x(), y, rect.width(), rect.height());
mirroring_layer_->SchedulePaint(new_rect);
}
// Request full redraw on mirrored compositor so that
// the full content will be copied to mirroring compositor.
void FullRedrawContentOnMainThread() {
mirrored_compositor_->ScheduleFullRedraw();
}
static void DeleteOnMainThread(ReflectorImpl* reflector) {
// reflector gets deleted when the function returns.
}
// These variables are initialized on MainThread before
// the reflector is attached to the output surface. Once
// attached, they must be accessed only on ImplThraed unless
// the context is lost. When the context is lost, these
// will be re-ininitiailzed when the new output-surface
// is created on MainThread.
int texture_id_;
gfx::Size texture_size_;
// Must be accessed only on ImplThread.
scoped_refptr<BrowserCompositorOutputSurfaceProxy> output_surface_proxy_;
scoped_ptr<GLHelper> gl_helper_;
// Must be accessed only on MainThread.
ui::Compositor* mirrored_compositor_;
ui::Compositor* mirroring_compositor_;
ui::Layer* mirroring_layer_;
scoped_refptr<ui::Texture> shared_texture_;
scoped_refptr<base::MessageLoopProxy> impl_message_loop_;
scoped_refptr<base::MessageLoopProxy> main_message_loop_;
int surface_id_;
};
// Adapts a WebGraphicsContext3DCommandBufferImpl into a
// cc::OutputSurface that also handles vsync parameter updates
// arriving from the GPU process.
class BrowserCompositorOutputSurface
: public cc::OutputSurface,
public base::NonThreadSafe {
public:
BrowserCompositorOutputSurface(
scoped_ptr<WebKit::WebGraphicsContext3D> context,
int surface_id,
BrowserCompositorOutputSurfaceProxy* output_surface_proxy,
base::MessageLoopProxy* compositor_message_loop,
base::WeakPtr<ui::Compositor> compositor)
: OutputSurface(context.Pass()),
surface_id_(surface_id),
output_surface_proxy_(output_surface_proxy),
compositor_message_loop_(compositor_message_loop),
compositor_(compositor) {
CommandLine* command_line = CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kUIMaxFramesPending)) {
std::string string_value = command_line->GetSwitchValueASCII(
switches::kUIMaxFramesPending);
int int_value;
if (base::StringToInt(string_value, &int_value))
capabilities_.max_frames_pending = int_value;
else
LOG(ERROR) << "Trouble parsing --" << switches::kUIMaxFramesPending;
}
capabilities_.adjust_deadline_for_parent = false;
DetachFromThread();
}
virtual ~BrowserCompositorOutputSurface() {
DCHECK(CalledOnValidThread());
if (!HasClient())
return;
output_surface_proxy_->RemoveSurface(surface_id_);
}
virtual bool BindToClient(
cc::OutputSurfaceClient* client) OVERRIDE {
DCHECK(CalledOnValidThread());
if (!OutputSurface::BindToClient(client))
return false;
output_surface_proxy_->AddSurface(this, surface_id_);
return true;
}
void OnUpdateVSyncParameters(
base::TimeTicks timebase, base::TimeDelta interval) {
DCHECK(CalledOnValidThread());
DCHECK(HasClient());
OnVSyncParametersChanged(timebase, interval);
compositor_message_loop_->PostTask(
FROM_HERE,
base::Bind(&ui::Compositor::OnUpdateVSyncParameters,
compositor_, timebase, interval));
}
virtual void Reshape(gfx::Size size, float scale_factor) OVERRIDE {
OutputSurface::Reshape(size, scale_factor);
if (reflector_.get())
reflector_->OnReshape(size);
}
virtual void SwapBuffers(cc::CompositorFrame* frame) OVERRIDE {
DCHECK(frame->gl_frame_data);
WebGraphicsContext3DCommandBufferImpl* command_buffer =
static_cast<WebGraphicsContext3DCommandBufferImpl*>(context3d());
CommandBufferProxyImpl* command_buffer_proxy =
command_buffer->GetCommandBufferProxy();
DCHECK(command_buffer_proxy);
context3d()->shallowFlushCHROMIUM();
command_buffer_proxy->SetLatencyInfo(frame->metadata.latency_info);
if (reflector_.get()) {
if (frame->gl_frame_data->sub_buffer_rect ==
gfx::Rect(frame->gl_frame_data->size))
reflector_->OnSwapBuffers();
else
reflector_->OnPostSubBuffer(frame->gl_frame_data->sub_buffer_rect);
}
OutputSurface::SwapBuffers(frame);
}
void SetReflector(ReflectorImpl* reflector) {
reflector_ = reflector;
}
private:
int surface_id_;
scoped_refptr<BrowserCompositorOutputSurfaceProxy> output_surface_proxy_;
scoped_refptr<base::MessageLoopProxy> compositor_message_loop_;
base::WeakPtr<ui::Compositor> compositor_;
scoped_refptr<ReflectorImpl> reflector_;
};
void BrowserCompositorOutputSurfaceProxy::OnUpdateVSyncParameters(
int surface_id, base::TimeTicks timebase, base::TimeDelta interval) {
BrowserCompositorOutputSurface* surface = surface_map_.Lookup(surface_id);
if (surface)
surface->OnUpdateVSyncParameters(timebase, interval);
}
void ReflectorImpl::AttachToOutputSurface(
BrowserCompositorOutputSurface* output_surface) {
gl_helper_.reset(new GLHelper(output_surface->context3d()));
output_surface->SetReflector(this);
}
void ReflectorImpl::InitOnImplThread() {
AttachToOutputSurface(output_surface_proxy_->GetOutputSurface(surface_id_));
gl_helper_->CopyTextureFullImage(texture_id_, texture_size_);
// The shared texture doesn't have the data, so invokes full redraw
// now.
main_message_loop_->PostTask(
FROM_HERE,
base::Bind(&ReflectorImpl::FullRedrawContentOnMainThread,
scoped_refptr<ReflectorImpl>(this)));
}
void ReflectorImpl::ShutdownOnImplThread() {
BrowserCompositorOutputSurface* output_surface =
output_surface_proxy_->GetOutputSurface(surface_id_);
output_surface->SetReflector(NULL);
gl_helper_.reset();
// The instance must be deleted on main thread.
main_message_loop_->PostTask(
FROM_HERE,
base::Bind(&ReflectorImpl::DeleteOnMainThread,
scoped_refptr<ReflectorImpl>(this)));
}
class SoftwareOutputSurface : public cc::OutputSurface {
public:
explicit SoftwareOutputSurface(
scoped_ptr<cc::SoftwareOutputDevice> software_device)
: cc::OutputSurface(software_device.Pass()) {}
virtual void SwapBuffers(cc::CompositorFrame* frame) OVERRIDE {
ui::LatencyInfo latency_info = frame->metadata.latency_info;
latency_info.swap_timestamp = base::TimeTicks::HighResNow();
RenderWidgetHostImpl::CompositorFrameDrawn(latency_info);
cc::OutputSurface::SwapBuffers(frame);
}
};
cc::OutputSurface* CreateSoftwareOutputSurface(ui::Compositor* compositor) {
#if defined(OS_WIN)
scoped_ptr<SoftwareOutputDeviceWin> software_device(
new SoftwareOutputDeviceWin(compositor));
return new SoftwareOutputSurface(
software_device.PassAs<cc::SoftwareOutputDevice>());
#elif defined(USE_X11)
scoped_ptr<SoftwareOutputDeviceX11> software_device(
new SoftwareOutputDeviceX11(compositor));
return new SoftwareOutputSurface(
software_device.PassAs<cc::SoftwareOutputDevice>());
#else
NOTIMPLEMENTED();
return NULL;
#endif
}
class GpuProcessTransportFactory
: public ui::ContextFactory,
public ImageTransportFactory {
public:
GpuProcessTransportFactory()
: callback_factory_(this) {
output_surface_proxy_ = new BrowserCompositorOutputSurfaceProxy();
}
virtual ~GpuProcessTransportFactory() {
DCHECK(per_compositor_data_.empty());
}
scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
CreateOffscreenCommandBufferContext() {
base::WeakPtr<WebGraphicsContext3DSwapBuffersClient> swap_client;
return CreateContextCommon(swap_client, 0);
}
virtual scoped_ptr<WebKit::WebGraphicsContext3D> CreateOffscreenContext()
OVERRIDE {
return CreateOffscreenCommandBufferContext()
.PassAs<WebKit::WebGraphicsContext3D>();
}
virtual cc::OutputSurface* CreateOutputSurface(
ui::Compositor* compositor) OVERRIDE {
PerCompositorData* data = per_compositor_data_[compositor];
if (!data)
data = CreatePerCompositorData(compositor);
scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context;
CommandLine* command_line = CommandLine::ForCurrentProcess();
if (!command_line->HasSwitch(switches::kUIEnableSoftwareCompositing))
context =
CreateContextCommon(data->swap_client->AsWeakPtr(), data->surface_id);
if (!context)
return CreateSoftwareOutputSurface(compositor);
BrowserCompositorOutputSurface* surface =
new BrowserCompositorOutputSurface(
context.PassAs<WebKit::WebGraphicsContext3D>(),
per_compositor_data_[compositor]->surface_id,
output_surface_proxy_.get(),
base::MessageLoopProxy::current().get(),
compositor->AsWeakPtr());
if (data->reflector.get()) {
data->reflector->CreateSharedTexture();
data->reflector->AttachToOutputSurface(surface);
}
return surface;
}
virtual scoped_refptr<ui::Reflector> CreateReflector(
ui::Compositor* source,
ui::Layer* target) OVERRIDE {
PerCompositorData* data = per_compositor_data_[source];
DCHECK(data);
if (data->reflector.get())
RemoveObserver(data->reflector.get());
data->reflector = new ReflectorImpl(
source, target, output_surface_proxy_.get(), data->surface_id);
AddObserver(data->reflector.get());
return data->reflector;
}
virtual void RemoveReflector(
scoped_refptr<ui::Reflector> reflector) OVERRIDE {
ReflectorImpl* reflector_impl =
static_cast<ReflectorImpl*>(reflector.get());
PerCompositorData* data =
per_compositor_data_[reflector_impl->mirrored_compositor()];
DCHECK(data);
RemoveObserver(reflector_impl);
data->reflector->Shutdown();
data->reflector = NULL;
}
virtual void RemoveCompositor(ui::Compositor* compositor) OVERRIDE {
PerCompositorDataMap::iterator it = per_compositor_data_.find(compositor);
if (it == per_compositor_data_.end())
return;
PerCompositorData* data = it->second;
DCHECK(data);
GpuSurfaceTracker::Get()->RemoveSurface(data->surface_id);
delete data;
per_compositor_data_.erase(it);
if (per_compositor_data_.empty()) {
gl_helper_.reset();
callback_factory_.InvalidateWeakPtrs();
}
}
virtual ui::ContextFactory* AsContextFactory() OVERRIDE {
return this;
}
virtual gfx::GLSurfaceHandle CreateSharedSurfaceHandle() OVERRIDE {
CreateSharedContextLazy();
if (!shared_contexts_main_thread_ ||
!shared_contexts_main_thread_->Context3d())
return gfx::GLSurfaceHandle();
gfx::GLSurfaceHandle handle = gfx::GLSurfaceHandle(
gfx::kNullPluginWindow, gfx::TEXTURE_TRANSPORT);
handle.parent_gpu_process_id =
shared_contexts_main_thread_->Context3d()->GetGPUProcessID();
handle.parent_client_id =
shared_contexts_main_thread_->Context3d()->GetChannelID();
return handle;
}
virtual void DestroySharedSurfaceHandle(
gfx::GLSurfaceHandle surface) OVERRIDE {
}
virtual scoped_refptr<ui::Texture> CreateTransportClient(
float device_scale_factor) OVERRIDE {
if (!shared_contexts_main_thread_.get())
return NULL;
scoped_refptr<ImageTransportClientTexture> image(
new ImageTransportClientTexture(
shared_contexts_main_thread_->Context3d(),
device_scale_factor));
return image;
}
virtual scoped_refptr<ui::Texture> CreateOwnedTexture(
const gfx::Size& size,
float device_scale_factor,
unsigned int texture_id) OVERRIDE {
if (!shared_contexts_main_thread_.get())
return NULL;
scoped_refptr<OwnedTexture> image(new OwnedTexture(
shared_contexts_main_thread_->Context3d(),
size,
device_scale_factor,
texture_id));
return image;
}
virtual GLHelper* GetGLHelper() OVERRIDE {
if (!gl_helper_) {
CreateSharedContextLazy();
WebGraphicsContext3DCommandBufferImpl* context_for_main_thread =
shared_contexts_main_thread_->Context3d();
gl_helper_.reset(new GLHelper(context_for_main_thread));
}
return gl_helper_.get();
}
virtual uint32 InsertSyncPoint() OVERRIDE {
if (!shared_contexts_main_thread_.get())
return 0;
return shared_contexts_main_thread_->Context3d()->insertSyncPoint();
}
virtual void WaitSyncPoint(uint32 sync_point) OVERRIDE {
if (!shared_contexts_main_thread_.get())
return;
shared_contexts_main_thread_->Context3d()->waitSyncPoint(sync_point);
}
virtual void AddObserver(ImageTransportFactoryObserver* observer) OVERRIDE {
observer_list_.AddObserver(observer);
}
virtual void RemoveObserver(
ImageTransportFactoryObserver* observer) OVERRIDE {
observer_list_.RemoveObserver(observer);
}
void OnLostContext(ui::Compositor* compositor) {
LOG(ERROR) << "Lost UI compositor context.";
PerCompositorData* data = per_compositor_data_[compositor];
DCHECK(data);
// Prevent callbacks from other contexts in the same share group from
// calling us again.
data->swap_client.reset(new CompositorSwapClient(compositor, this));
compositor->OnSwapBuffersAborted();
}
private:
struct PerCompositorData {
int surface_id;
scoped_ptr<CompositorSwapClient> swap_client;
#if defined(OS_WIN)
scoped_ptr<AcceleratedSurface> accelerated_surface;
#endif
scoped_refptr<ReflectorImpl> reflector;
};
PerCompositorData* CreatePerCompositorData(ui::Compositor* compositor) {
DCHECK(!per_compositor_data_[compositor]);
CreateSharedContextLazy();
gfx::AcceleratedWidget widget = compositor->widget();
GpuSurfaceTracker* tracker = GpuSurfaceTracker::Get();
PerCompositorData* data = new PerCompositorData;
data->surface_id = tracker->AddSurfaceForNativeWidget(widget);
data->swap_client.reset(new CompositorSwapClient(compositor, this));
#if defined(OS_WIN)
if (GpuDataManagerImpl::GetInstance()->IsUsingAcceleratedSurface())
data->accelerated_surface.reset(new AcceleratedSurface(widget));
#endif
tracker->SetSurfaceHandle(
data->surface_id,
gfx::GLSurfaceHandle(widget, gfx::NATIVE_DIRECT));
per_compositor_data_[compositor] = data;
return data;
}
scoped_ptr<WebGraphicsContext3DCommandBufferImpl> CreateContextCommon(
const base::WeakPtr<WebGraphicsContext3DSwapBuffersClient>& swap_client,
int surface_id) {
if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor())
return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
WebKit::WebGraphicsContext3D::Attributes attrs;
attrs.shareResources = true;
attrs.depth = false;
attrs.stencil = false;
attrs.antialias = false;
attrs.noAutomaticFlushes = true;
GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance();
GURL url("chrome://gpu/GpuProcessTransportFactory::CreateContextCommon");
scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
new WebGraphicsContext3DCommandBufferImpl(
surface_id,
url,
factory,
swap_client));
if (!context->InitializeWithDefaultBufferSizes(
attrs,
false,
CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE))
return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
return context.Pass();
}
class MainThreadContextProvider : public ContextProviderCommandBuffer {
public:
static scoped_refptr<MainThreadContextProvider> Create(
GpuProcessTransportFactory* factory) {
scoped_refptr<MainThreadContextProvider> provider =
new MainThreadContextProvider(factory);
if (!provider->InitializeOnMainThread())
return NULL;
return provider;
}
protected:
explicit MainThreadContextProvider(GpuProcessTransportFactory* factory)
: factory_(factory) {}
virtual ~MainThreadContextProvider() {}
virtual scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
CreateOffscreenContext3d() OVERRIDE {
return factory_->CreateOffscreenCommandBufferContext();
}
virtual void OnLostContext() OVERRIDE {
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&GpuProcessTransportFactory::OnLostMainThreadSharedContext,
factory_->callback_factory_.GetWeakPtr()));
}
private:
GpuProcessTransportFactory* factory_;
};
virtual scoped_refptr<cc::ContextProvider>
OffscreenContextProviderForMainThread() OVERRIDE {
if (!shared_contexts_main_thread_.get() ||
shared_contexts_main_thread_->DestroyedOnMainThread()) {
shared_contexts_main_thread_ = MainThreadContextProvider::Create(this);
if (shared_contexts_main_thread_.get() &&
!shared_contexts_main_thread_->BindToCurrentThread())
shared_contexts_main_thread_ = NULL;
}
return shared_contexts_main_thread_;
}
class CompositorThreadContextProvider : public ContextProviderCommandBuffer {
public:
static scoped_refptr<CompositorThreadContextProvider> Create(
GpuProcessTransportFactory* factory) {
scoped_refptr<CompositorThreadContextProvider> provider =
new CompositorThreadContextProvider(factory);
if (!provider->InitializeOnMainThread())
return NULL;
return provider;
}
protected:
explicit CompositorThreadContextProvider(
GpuProcessTransportFactory* factory) : factory_(factory) {}
virtual ~CompositorThreadContextProvider() {}
virtual scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
CreateOffscreenContext3d() OVERRIDE {
return factory_->CreateOffscreenCommandBufferContext();
}
private:
GpuProcessTransportFactory* factory_;
};
virtual scoped_refptr<cc::ContextProvider>
OffscreenContextProviderForCompositorThread() OVERRIDE {
if (!shared_contexts_compositor_thread_.get() ||
shared_contexts_compositor_thread_->DestroyedOnMainThread()) {
shared_contexts_compositor_thread_ =
CompositorThreadContextProvider::Create(this);
}
return shared_contexts_compositor_thread_;
}
void CreateSharedContextLazy() {
scoped_refptr<cc::ContextProvider> provider =
OffscreenContextProviderForMainThread();
}
void OnLostMainThreadSharedContext() {
LOG(ERROR) << "Lost UI shared context.";
// Keep old resources around while we call the observers, but ensure that
// new resources are created if needed.
scoped_refptr<MainThreadContextProvider> old_contexts_main_thread =
shared_contexts_main_thread_;
shared_contexts_main_thread_ = NULL;
scoped_ptr<GLHelper> old_helper(gl_helper_.release());
FOR_EACH_OBSERVER(ImageTransportFactoryObserver,
observer_list_,
OnLostResources());
}
typedef std::map<ui::Compositor*, PerCompositorData*> PerCompositorDataMap;
PerCompositorDataMap per_compositor_data_;
scoped_refptr<MainThreadContextProvider> shared_contexts_main_thread_;
scoped_refptr<CompositorThreadContextProvider>
shared_contexts_compositor_thread_;
scoped_ptr<GLHelper> gl_helper_;
ObserverList<ImageTransportFactoryObserver> observer_list_;
base::WeakPtrFactory<GpuProcessTransportFactory> callback_factory_;
scoped_refptr<BrowserCompositorOutputSurfaceProxy> output_surface_proxy_;
DISALLOW_COPY_AND_ASSIGN(GpuProcessTransportFactory);
};
void CompositorSwapClient::OnLostContext() {
factory_->OnLostContext(compositor_);
// Note: previous line destroyed this. Don't access members from now on.
}
} // anonymous namespace
// static
void ImageTransportFactory::Initialize() {
CommandLine* command_line = CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kTestCompositor)) {
ui::SetupTestCompositor();
}
if (ui::IsTestCompositorEnabled()) {
g_factory = new NoTransportFactory(new ui::TestContextFactory);
} else {
g_factory = new GpuProcessTransportFactory;
}
ui::ContextFactory::SetInstance(g_factory->AsContextFactory());
}
// static
void ImageTransportFactory::Terminate() {
ui::ContextFactory::SetInstance(NULL);
delete g_factory;
g_factory = NULL;
}
// static
ImageTransportFactory* ImageTransportFactory::GetInstance() {
return g_factory;
}
} // namespace content