blob: 1da6aecf2f3c82608fc57654592fc22c5d557c85 [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/common/gpu/gpu_channel_manager.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "content/common/child_thread.h"
#include "content/common/gpu/gpu_channel.h"
#include "content/common/gpu/gpu_memory_manager.h"
#include "content/common/gpu/gpu_messages.h"
#include "content/common/gpu/sync_point_manager.h"
#include "gpu/command_buffer/service/feature_info.h"
#include "gpu/command_buffer/service/gpu_switches.h"
#include "gpu/command_buffer/service/mailbox_manager.h"
#include "gpu/command_buffer/service/memory_program_cache.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_share_group.h"
GpuChannelManager::GpuChannelManager(ChildThread* gpu_child_thread,
GpuWatchdog* watchdog,
base::MessageLoopProxy* io_message_loop,
base::WaitableEvent* shutdown_event)
: ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
io_message_loop_(io_message_loop),
shutdown_event_(shutdown_event),
gpu_child_thread_(gpu_child_thread),
ALLOW_THIS_IN_INITIALIZER_LIST(gpu_memory_manager_(this,
GpuMemoryManager::kDefaultMaxSurfacesWithFrontbufferSoftLimit)),
watchdog_(watchdog),
sync_point_manager_(new SyncPointManager),
program_cache_(NULL) {
DCHECK(gpu_child_thread);
DCHECK(io_message_loop);
DCHECK(shutdown_event);
}
GpuChannelManager::~GpuChannelManager() {
gpu_channels_.clear();
if (default_offscreen_surface_.get()) {
default_offscreen_surface_->Destroy();
default_offscreen_surface_ = NULL;
}
}
gpu::gles2::ProgramCache* GpuChannelManager::program_cache() {
if (!program_cache_.get() &&
(gfx::g_ARB_get_program_binary || gfx::g_OES_get_program_binary) &&
!CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableGpuProgramCache)) {
program_cache_.reset(new gpu::gles2::MemoryProgramCache());
}
return program_cache_.get();
}
void GpuChannelManager::RemoveChannel(int client_id) {
gpu_channels_.erase(client_id);
}
int GpuChannelManager::GenerateRouteID() {
static int last_id = 0;
return ++last_id;
}
void GpuChannelManager::AddRoute(int32 routing_id, IPC::Listener* listener) {
gpu_child_thread_->AddRoute(routing_id, listener);
}
void GpuChannelManager::RemoveRoute(int32 routing_id) {
gpu_child_thread_->RemoveRoute(routing_id);
}
GpuChannel* GpuChannelManager::LookupChannel(int32 client_id) {
GpuChannelMap::const_iterator iter = gpu_channels_.find(client_id);
if (iter == gpu_channels_.end())
return NULL;
else
return iter->second;
}
void GpuChannelManager::AppendAllCommandBufferStubs(
std::vector<GpuCommandBufferStubBase*>& stubs) {
for (GpuChannelMap::const_iterator it = gpu_channels_.begin();
it != gpu_channels_.end(); ++it ) {
it->second->AppendAllCommandBufferStubs(stubs);
}
}
bool GpuChannelManager::OnMessageReceived(const IPC::Message& msg) {
bool msg_is_ok = true;
bool handled = true;
IPC_BEGIN_MESSAGE_MAP_EX(GpuChannelManager, msg, msg_is_ok)
IPC_MESSAGE_HANDLER(GpuMsg_EstablishChannel, OnEstablishChannel)
IPC_MESSAGE_HANDLER(GpuMsg_CloseChannel, OnCloseChannel)
IPC_MESSAGE_HANDLER(GpuMsg_CreateViewCommandBuffer,
OnCreateViewCommandBuffer)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP_EX()
return handled;
}
bool GpuChannelManager::Send(IPC::Message* msg) {
return gpu_child_thread_->Send(msg);
}
void GpuChannelManager::OnEstablishChannel(int client_id, bool share_context) {
IPC::ChannelHandle channel_handle;
gfx::GLShareGroup* share_group = NULL;
gpu::gles2::MailboxManager* mailbox_manager = NULL;
if (share_context) {
if (!share_group_) {
share_group_ = new gfx::GLShareGroup;
DCHECK(!mailbox_manager_);
mailbox_manager_ = new gpu::gles2::MailboxManager;
}
share_group = share_group_;
mailbox_manager = mailbox_manager_;
}
scoped_refptr<GpuChannel> channel = new GpuChannel(this,
watchdog_,
share_group,
mailbox_manager,
client_id,
false);
if (channel->Init(io_message_loop_, shutdown_event_)) {
gpu_channels_[client_id] = channel;
channel_handle.name = channel->GetChannelName();
#if defined(OS_POSIX)
// On POSIX, pass the renderer-side FD. Also mark it as auto-close so
// that it gets closed after it has been sent.
int renderer_fd = channel->TakeRendererFileDescriptor();
DCHECK_NE(-1, renderer_fd);
channel_handle.socket = base::FileDescriptor(renderer_fd, true);
#endif
}
Send(new GpuHostMsg_ChannelEstablished(channel_handle));
}
void GpuChannelManager::OnCloseChannel(
const IPC::ChannelHandle& channel_handle) {
for (GpuChannelMap::iterator iter = gpu_channels_.begin();
iter != gpu_channels_.end(); ++iter) {
if (iter->second->GetChannelName() == channel_handle.name) {
gpu_channels_.erase(iter);
return;
}
}
}
void GpuChannelManager::OnCreateViewCommandBuffer(
const gfx::GLSurfaceHandle& window,
int32 surface_id,
int32 client_id,
const GPUCreateCommandBufferConfig& init_params) {
DCHECK(surface_id);
int32 route_id = MSG_ROUTING_NONE;
GpuChannelMap::const_iterator iter = gpu_channels_.find(client_id);
if (iter != gpu_channels_.end()) {
iter->second->CreateViewCommandBuffer(
window, surface_id, init_params, &route_id);
}
Send(new GpuHostMsg_CommandBufferCreated(route_id));
}
void GpuChannelManager::LoseAllContexts() {
MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&GpuChannelManager::OnLoseAllContexts,
weak_factory_.GetWeakPtr()));
}
void GpuChannelManager::OnLoseAllContexts() {
gpu_channels_.clear();
}
gfx::GLSurface* GpuChannelManager::GetDefaultOffscreenSurface() {
if (!default_offscreen_surface_.get()) {
default_offscreen_surface_ = gfx::GLSurface::CreateOffscreenGLSurface(
false, gfx::Size(1, 1));
}
return default_offscreen_surface_.get();
}