// 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/child/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" namespace content { GpuChannelManager::ImageOperation::ImageOperation( int32 sync_point, base::Closure callback) : sync_point(sync_point), callback(callback) { } GpuChannelManager::ImageOperation::~ImageOperation() { } GpuChannelManager::GpuChannelManager(ChildThread* gpu_child_thread, GpuWatchdog* watchdog, base::MessageLoopProxy* io_message_loop, base::WaitableEvent* shutdown_event) : weak_factory_(this), io_message_loop_(io_message_loop), shutdown_event_(shutdown_event), gpu_child_thread_(gpu_child_thread), gpu_memory_manager_( this, GpuMemoryManager::kDefaultMaxSurfacesWithFrontbufferSoftLimit), watchdog_(watchdog), sync_point_manager_(new SyncPointManager) { 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; } DCHECK(image_operations_.empty()); } gpu::gles2::ProgramCache* GpuChannelManager::program_cache() { if (!program_cache_.get() && (gfx::g_driver_gl.ext.b_ARB_get_program_binary || gfx::g_driver_gl.ext.b_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) { Send(new GpuHostMsg_DestroyChannel(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.get(); } 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_HANDLER(GpuMsg_CreateImage, OnCreateImage) IPC_MESSAGE_HANDLER(GpuMsg_DeleteImage, OnDeleteImage) IPC_MESSAGE_HANDLER(GpuMsg_LoadedShader, OnLoadedShader) 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_.get()) { share_group_ = new gfx::GLShareGroup; DCHECK(!mailbox_manager_.get()); mailbox_manager_ = new gpu::gles2::MailboxManager; } share_group = share_group_.get(); mailbox_manager = mailbox_manager_.get(); } scoped_refptr<GpuChannel> channel = new GpuChannel(this, watchdog_, share_group, mailbox_manager, client_id, false); if (channel->Init(io_message_loop_.get(), 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::CreateImage( gfx::PluginWindowHandle window, int32 client_id, int32 image_id) { gfx::Size size; GpuChannelMap::const_iterator iter = gpu_channels_.find(client_id); if (iter != gpu_channels_.end()) { iter->second->CreateImage(window, image_id, &size); } Send(new GpuHostMsg_ImageCreated(size)); } void GpuChannelManager::OnCreateImage( gfx::PluginWindowHandle window, int32 client_id, int32 image_id) { DCHECK(image_id); if (image_operations_.empty()) { CreateImage(window, client_id, image_id); } else { image_operations_.push_back( new ImageOperation(0, base::Bind(&GpuChannelManager::CreateImage, base::Unretained(this), window, client_id, image_id))); } } void GpuChannelManager::DeleteImage(int32 client_id, int32 image_id) { GpuChannelMap::const_iterator iter = gpu_channels_.find(client_id); if (iter != gpu_channels_.end()) { iter->second->DeleteImage(image_id); } } void GpuChannelManager::OnDeleteImage( int32 client_id, int32 image_id, int32 sync_point) { DCHECK(image_id); if (!sync_point && image_operations_.empty()) { DeleteImage(client_id, image_id); } else { image_operations_.push_back( new ImageOperation(sync_point, base::Bind(&GpuChannelManager::DeleteImage, base::Unretained(this), client_id, image_id))); if (sync_point) { sync_point_manager()->AddSyncPointCallback( sync_point, base::Bind(&GpuChannelManager::OnDeleteImageSyncPointRetired, base::Unretained(this), image_operations_.back())); } } } void GpuChannelManager::OnDeleteImageSyncPointRetired( ImageOperation* image_operation) { // Mark operation as no longer having a pending sync point. image_operation->sync_point = 0; // De-queue operations until we reach a pending sync point. while (!image_operations_.empty()) { // Check if operation has a pending sync point. if (image_operations_.front()->sync_point) return; image_operations_.front()->callback.Run(); delete image_operations_.front(); image_operations_.pop_front(); } } void GpuChannelManager::OnLoadedShader(std::string program_proto) { if (program_cache()) program_cache()->LoadProgram(program_proto); } bool GpuChannelManager::HandleMessagesScheduled() { for (GpuChannelMap::iterator iter = gpu_channels_.begin(); iter != gpu_channels_.end(); ++iter) { if (iter->second->handle_messages_scheduled()) return true; } return false; } uint64 GpuChannelManager::MessagesProcessed() { uint64 messages_processed = 0; for (GpuChannelMap::iterator iter = gpu_channels_.begin(); iter != gpu_channels_.end(); ++iter) { messages_processed += iter->second->messages_processed(); } return messages_processed; } void GpuChannelManager::LoseAllContexts() { for (GpuChannelMap::iterator iter = gpu_channels_.begin(); iter != gpu_channels_.end(); ++iter) { iter->second->MarkAllContextsLost(); } base::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(gfx::Size(1, 1)); } return default_offscreen_surface_.get(); } } // namespace content