1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/common/gpu/gpu_channel_manager.h" 6 7 #include "base/bind.h" 8 #include "base/command_line.h" 9 #include "content/child/child_thread.h" 10 #include "content/common/gpu/gpu_channel.h" 11 #include "content/common/gpu/gpu_memory_manager.h" 12 #include "content/common/gpu/gpu_messages.h" 13 #include "content/common/gpu/sync_point_manager.h" 14 #include "gpu/command_buffer/service/feature_info.h" 15 #include "gpu/command_buffer/service/gpu_switches.h" 16 #include "gpu/command_buffer/service/mailbox_manager.h" 17 #include "gpu/command_buffer/service/memory_program_cache.h" 18 #include "ui/gl/gl_bindings.h" 19 #include "ui/gl/gl_share_group.h" 20 21 namespace content { 22 23 GpuChannelManager::ImageOperation::ImageOperation( 24 int32 sync_point, base::Closure callback) 25 : sync_point(sync_point), 26 callback(callback) { 27 } 28 29 GpuChannelManager::ImageOperation::~ImageOperation() { 30 } 31 32 GpuChannelManager::GpuChannelManager(ChildThread* gpu_child_thread, 33 GpuWatchdog* watchdog, 34 base::MessageLoopProxy* io_message_loop, 35 base::WaitableEvent* shutdown_event) 36 : weak_factory_(this), 37 io_message_loop_(io_message_loop), 38 shutdown_event_(shutdown_event), 39 gpu_child_thread_(gpu_child_thread), 40 gpu_memory_manager_( 41 this, 42 GpuMemoryManager::kDefaultMaxSurfacesWithFrontbufferSoftLimit), 43 watchdog_(watchdog), 44 sync_point_manager_(new SyncPointManager) { 45 DCHECK(gpu_child_thread); 46 DCHECK(io_message_loop); 47 DCHECK(shutdown_event); 48 } 49 50 GpuChannelManager::~GpuChannelManager() { 51 gpu_channels_.clear(); 52 if (default_offscreen_surface_.get()) { 53 default_offscreen_surface_->Destroy(); 54 default_offscreen_surface_ = NULL; 55 } 56 DCHECK(image_operations_.empty()); 57 } 58 59 gpu::gles2::ProgramCache* GpuChannelManager::program_cache() { 60 if (!program_cache_.get() && 61 (gfx::g_driver_gl.ext.b_ARB_get_program_binary || 62 gfx::g_driver_gl.ext.b_OES_get_program_binary) && 63 !CommandLine::ForCurrentProcess()->HasSwitch( 64 switches::kDisableGpuProgramCache)) { 65 program_cache_.reset(new gpu::gles2::MemoryProgramCache()); 66 } 67 return program_cache_.get(); 68 } 69 70 void GpuChannelManager::RemoveChannel(int client_id) { 71 Send(new GpuHostMsg_DestroyChannel(client_id)); 72 gpu_channels_.erase(client_id); 73 } 74 75 int GpuChannelManager::GenerateRouteID() { 76 static int last_id = 0; 77 return ++last_id; 78 } 79 80 void GpuChannelManager::AddRoute(int32 routing_id, IPC::Listener* listener) { 81 gpu_child_thread_->AddRoute(routing_id, listener); 82 } 83 84 void GpuChannelManager::RemoveRoute(int32 routing_id) { 85 gpu_child_thread_->RemoveRoute(routing_id); 86 } 87 88 GpuChannel* GpuChannelManager::LookupChannel(int32 client_id) { 89 GpuChannelMap::const_iterator iter = gpu_channels_.find(client_id); 90 if (iter == gpu_channels_.end()) 91 return NULL; 92 else 93 return iter->second.get(); 94 } 95 96 bool GpuChannelManager::OnMessageReceived(const IPC::Message& msg) { 97 bool msg_is_ok = true; 98 bool handled = true; 99 IPC_BEGIN_MESSAGE_MAP_EX(GpuChannelManager, msg, msg_is_ok) 100 IPC_MESSAGE_HANDLER(GpuMsg_EstablishChannel, OnEstablishChannel) 101 IPC_MESSAGE_HANDLER(GpuMsg_CloseChannel, OnCloseChannel) 102 IPC_MESSAGE_HANDLER(GpuMsg_CreateViewCommandBuffer, 103 OnCreateViewCommandBuffer) 104 IPC_MESSAGE_HANDLER(GpuMsg_CreateImage, OnCreateImage) 105 IPC_MESSAGE_HANDLER(GpuMsg_DeleteImage, OnDeleteImage) 106 IPC_MESSAGE_HANDLER(GpuMsg_LoadedShader, OnLoadedShader) 107 IPC_MESSAGE_UNHANDLED(handled = false) 108 IPC_END_MESSAGE_MAP_EX() 109 return handled; 110 } 111 112 bool GpuChannelManager::Send(IPC::Message* msg) { 113 return gpu_child_thread_->Send(msg); 114 } 115 116 void GpuChannelManager::OnEstablishChannel(int client_id, bool share_context) { 117 IPC::ChannelHandle channel_handle; 118 119 gfx::GLShareGroup* share_group = NULL; 120 gpu::gles2::MailboxManager* mailbox_manager = NULL; 121 if (share_context) { 122 if (!share_group_.get()) { 123 share_group_ = new gfx::GLShareGroup; 124 DCHECK(!mailbox_manager_.get()); 125 mailbox_manager_ = new gpu::gles2::MailboxManager; 126 } 127 share_group = share_group_.get(); 128 mailbox_manager = mailbox_manager_.get(); 129 } 130 131 scoped_refptr<GpuChannel> channel = new GpuChannel(this, 132 watchdog_, 133 share_group, 134 mailbox_manager, 135 client_id, 136 false); 137 if (channel->Init(io_message_loop_.get(), shutdown_event_)) { 138 gpu_channels_[client_id] = channel; 139 channel_handle.name = channel->GetChannelName(); 140 141 #if defined(OS_POSIX) 142 // On POSIX, pass the renderer-side FD. Also mark it as auto-close so 143 // that it gets closed after it has been sent. 144 int renderer_fd = channel->TakeRendererFileDescriptor(); 145 DCHECK_NE(-1, renderer_fd); 146 channel_handle.socket = base::FileDescriptor(renderer_fd, true); 147 #endif 148 } 149 150 Send(new GpuHostMsg_ChannelEstablished(channel_handle)); 151 } 152 153 void GpuChannelManager::OnCloseChannel( 154 const IPC::ChannelHandle& channel_handle) { 155 for (GpuChannelMap::iterator iter = gpu_channels_.begin(); 156 iter != gpu_channels_.end(); ++iter) { 157 if (iter->second->GetChannelName() == channel_handle.name) { 158 gpu_channels_.erase(iter); 159 return; 160 } 161 } 162 } 163 164 void GpuChannelManager::OnCreateViewCommandBuffer( 165 const gfx::GLSurfaceHandle& window, 166 int32 surface_id, 167 int32 client_id, 168 const GPUCreateCommandBufferConfig& init_params) { 169 DCHECK(surface_id); 170 int32 route_id = MSG_ROUTING_NONE; 171 172 GpuChannelMap::const_iterator iter = gpu_channels_.find(client_id); 173 if (iter != gpu_channels_.end()) { 174 iter->second->CreateViewCommandBuffer( 175 window, surface_id, init_params, &route_id); 176 } 177 178 Send(new GpuHostMsg_CommandBufferCreated(route_id)); 179 } 180 181 void GpuChannelManager::CreateImage( 182 gfx::PluginWindowHandle window, int32 client_id, int32 image_id) { 183 gfx::Size size; 184 185 GpuChannelMap::const_iterator iter = gpu_channels_.find(client_id); 186 if (iter != gpu_channels_.end()) { 187 iter->second->CreateImage(window, image_id, &size); 188 } 189 190 Send(new GpuHostMsg_ImageCreated(size)); 191 } 192 193 void GpuChannelManager::OnCreateImage( 194 gfx::PluginWindowHandle window, int32 client_id, int32 image_id) { 195 DCHECK(image_id); 196 197 if (image_operations_.empty()) { 198 CreateImage(window, client_id, image_id); 199 } else { 200 image_operations_.push_back( 201 new ImageOperation(0, base::Bind(&GpuChannelManager::CreateImage, 202 base::Unretained(this), 203 window, 204 client_id, 205 image_id))); 206 } 207 } 208 209 void GpuChannelManager::DeleteImage(int32 client_id, int32 image_id) { 210 GpuChannelMap::const_iterator iter = gpu_channels_.find(client_id); 211 if (iter != gpu_channels_.end()) { 212 iter->second->DeleteImage(image_id); 213 } 214 } 215 216 void GpuChannelManager::OnDeleteImage( 217 int32 client_id, int32 image_id, int32 sync_point) { 218 DCHECK(image_id); 219 220 if (!sync_point && image_operations_.empty()) { 221 DeleteImage(client_id, image_id); 222 } else { 223 image_operations_.push_back( 224 new ImageOperation(sync_point, 225 base::Bind(&GpuChannelManager::DeleteImage, 226 base::Unretained(this), 227 client_id, 228 image_id))); 229 if (sync_point) { 230 sync_point_manager()->AddSyncPointCallback( 231 sync_point, 232 base::Bind(&GpuChannelManager::OnDeleteImageSyncPointRetired, 233 base::Unretained(this), 234 image_operations_.back())); 235 } 236 } 237 } 238 239 void GpuChannelManager::OnDeleteImageSyncPointRetired( 240 ImageOperation* image_operation) { 241 // Mark operation as no longer having a pending sync point. 242 image_operation->sync_point = 0; 243 244 // De-queue operations until we reach a pending sync point. 245 while (!image_operations_.empty()) { 246 // Check if operation has a pending sync point. 247 if (image_operations_.front()->sync_point) 248 return; 249 250 image_operations_.front()->callback.Run(); 251 delete image_operations_.front(); 252 image_operations_.pop_front(); 253 } 254 } 255 256 void GpuChannelManager::OnLoadedShader(std::string program_proto) { 257 if (program_cache()) 258 program_cache()->LoadProgram(program_proto); 259 } 260 261 bool GpuChannelManager::HandleMessagesScheduled() { 262 for (GpuChannelMap::iterator iter = gpu_channels_.begin(); 263 iter != gpu_channels_.end(); ++iter) { 264 if (iter->second->handle_messages_scheduled()) 265 return true; 266 } 267 return false; 268 } 269 270 uint64 GpuChannelManager::MessagesProcessed() { 271 uint64 messages_processed = 0; 272 273 for (GpuChannelMap::iterator iter = gpu_channels_.begin(); 274 iter != gpu_channels_.end(); ++iter) { 275 messages_processed += iter->second->messages_processed(); 276 } 277 return messages_processed; 278 } 279 280 void GpuChannelManager::LoseAllContexts() { 281 for (GpuChannelMap::iterator iter = gpu_channels_.begin(); 282 iter != gpu_channels_.end(); ++iter) { 283 iter->second->MarkAllContextsLost(); 284 } 285 base::MessageLoop::current()->PostTask( 286 FROM_HERE, 287 base::Bind(&GpuChannelManager::OnLoseAllContexts, 288 weak_factory_.GetWeakPtr())); 289 } 290 291 void GpuChannelManager::OnLoseAllContexts() { 292 gpu_channels_.clear(); 293 } 294 295 gfx::GLSurface* GpuChannelManager::GetDefaultOffscreenSurface() { 296 if (!default_offscreen_surface_.get()) { 297 default_offscreen_surface_ = 298 gfx::GLSurface::CreateOffscreenGLSurface(gfx::Size(1, 1)); 299 } 300 return default_offscreen_surface_.get(); 301 } 302 303 } // namespace content 304