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/browser/gpu/browser_gpu_channel_host_factory.h" 6 7 #include "base/bind.h" 8 #include "base/threading/thread_restrictions.h" 9 #include "content/browser/gpu/gpu_data_manager_impl.h" 10 #include "content/browser/gpu/gpu_process_host.h" 11 #include "content/browser/gpu/gpu_surface_tracker.h" 12 #include "content/common/gpu/gpu_messages.h" 13 #include "content/common/child_process_host_impl.h" 14 #include "content/public/browser/browser_thread.h" 15 #include "content/public/common/content_client.h" 16 #include "ipc/ipc_forwarding_message_filter.h" 17 18 namespace content { 19 20 BrowserGpuChannelHostFactory* BrowserGpuChannelHostFactory::instance_ = NULL; 21 22 BrowserGpuChannelHostFactory::CreateRequest::CreateRequest() 23 : event(false, false), 24 gpu_host_id(0), 25 route_id(MSG_ROUTING_NONE) { 26 } 27 28 BrowserGpuChannelHostFactory::CreateRequest::~CreateRequest() { 29 } 30 31 BrowserGpuChannelHostFactory::EstablishRequest::EstablishRequest( 32 CauseForGpuLaunch cause) 33 : event(false, false), 34 cause_for_gpu_launch(cause), 35 gpu_host_id(0), 36 reused_gpu_process(true) { 37 } 38 39 BrowserGpuChannelHostFactory::EstablishRequest::~EstablishRequest() { 40 } 41 42 void BrowserGpuChannelHostFactory::Initialize() { 43 instance_ = new BrowserGpuChannelHostFactory(); 44 } 45 46 void BrowserGpuChannelHostFactory::Terminate() { 47 delete instance_; 48 instance_ = NULL; 49 } 50 51 BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory() 52 : gpu_client_id_(ChildProcessHostImpl::GenerateChildProcessUniqueId()), 53 shutdown_event_(new base::WaitableEvent(true, false)), 54 gpu_host_id_(0) { 55 } 56 57 BrowserGpuChannelHostFactory::~BrowserGpuChannelHostFactory() { 58 shutdown_event_->Signal(); 59 } 60 61 bool BrowserGpuChannelHostFactory::IsMainThread() { 62 return BrowserThread::CurrentlyOn(BrowserThread::UI); 63 } 64 65 base::MessageLoop* BrowserGpuChannelHostFactory::GetMainLoop() { 66 return BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::UI); 67 } 68 69 scoped_refptr<base::MessageLoopProxy> 70 BrowserGpuChannelHostFactory::GetIOLoopProxy() { 71 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO); 72 } 73 74 base::WaitableEvent* BrowserGpuChannelHostFactory::GetShutDownEvent() { 75 return shutdown_event_.get(); 76 } 77 78 scoped_ptr<base::SharedMemory> 79 BrowserGpuChannelHostFactory::AllocateSharedMemory(size_t size) { 80 scoped_ptr<base::SharedMemory> shm(new base::SharedMemory()); 81 if (!shm->CreateAnonymous(size)) 82 return scoped_ptr<base::SharedMemory>(); 83 return shm.Pass(); 84 } 85 86 void BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO( 87 CreateRequest* request, 88 int32 surface_id, 89 const GPUCreateCommandBufferConfig& init_params) { 90 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_); 91 if (!host) { 92 request->event.Signal(); 93 return; 94 } 95 96 gfx::GLSurfaceHandle surface = 97 GpuSurfaceTracker::Get()->GetSurfaceHandle(surface_id); 98 99 host->CreateViewCommandBuffer( 100 surface, 101 surface_id, 102 gpu_client_id_, 103 init_params, 104 base::Bind(&BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO, 105 request)); 106 } 107 108 // static 109 void BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO( 110 CreateRequest* request, int32 route_id) { 111 request->route_id = route_id; 112 request->event.Signal(); 113 } 114 115 int32 BrowserGpuChannelHostFactory::CreateViewCommandBuffer( 116 int32 surface_id, 117 const GPUCreateCommandBufferConfig& init_params) { 118 CreateRequest request; 119 GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind( 120 &BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO, 121 base::Unretained(this), 122 &request, 123 surface_id, 124 init_params)); 125 // We're blocking the UI thread, which is generally undesirable. 126 // In this case we need to wait for this before we can show any UI /anyway/, 127 // so it won't cause additional jank. 128 // TODO(piman): Make this asynchronous (http://crbug.com/125248). 129 base::ThreadRestrictions::ScopedAllowWait allow_wait; 130 request.event.Wait(); 131 return request.route_id; 132 } 133 134 void BrowserGpuChannelHostFactory::CreateImageOnIO( 135 gfx::PluginWindowHandle window, 136 int32 image_id, 137 const CreateImageCallback& callback) { 138 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_); 139 if (!host) { 140 ImageCreatedOnIO(callback, gfx::Size()); 141 return; 142 } 143 144 host->CreateImage( 145 window, 146 gpu_client_id_, 147 image_id, 148 base::Bind(&BrowserGpuChannelHostFactory::ImageCreatedOnIO, callback)); 149 } 150 151 // static 152 void BrowserGpuChannelHostFactory::ImageCreatedOnIO( 153 const CreateImageCallback& callback, const gfx::Size size) { 154 BrowserThread::PostTask( 155 BrowserThread::UI, 156 FROM_HERE, 157 base::Bind(&BrowserGpuChannelHostFactory::OnImageCreated, 158 callback, size)); 159 } 160 161 // static 162 void BrowserGpuChannelHostFactory::OnImageCreated( 163 const CreateImageCallback& callback, const gfx::Size size) { 164 callback.Run(size); 165 } 166 167 void BrowserGpuChannelHostFactory::CreateImage( 168 gfx::PluginWindowHandle window, 169 int32 image_id, 170 const CreateImageCallback& callback) { 171 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 172 GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind( 173 &BrowserGpuChannelHostFactory::CreateImageOnIO, 174 base::Unretained(this), 175 window, 176 image_id, 177 callback)); 178 } 179 180 void BrowserGpuChannelHostFactory::DeleteImageOnIO( 181 int32 image_id, int32 sync_point) { 182 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_); 183 if (!host) { 184 return; 185 } 186 187 host->DeleteImage(gpu_client_id_, image_id, sync_point); 188 } 189 190 void BrowserGpuChannelHostFactory::DeleteImage( 191 int32 image_id, int32 sync_point) { 192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 193 GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind( 194 &BrowserGpuChannelHostFactory::DeleteImageOnIO, 195 base::Unretained(this), 196 image_id, 197 sync_point)); 198 } 199 200 void BrowserGpuChannelHostFactory::EstablishGpuChannelOnIO( 201 EstablishRequest* request) { 202 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_); 203 if (!host) { 204 host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED, 205 request->cause_for_gpu_launch); 206 if (!host) { 207 request->event.Signal(); 208 return; 209 } 210 gpu_host_id_ = host->host_id(); 211 request->reused_gpu_process = false; 212 } else { 213 if (host->host_id() == request->gpu_host_id) { 214 // We come here if we retried to establish the channel because of a 215 // failure in GpuChannelEstablishedOnIO, but we ended up with the same 216 // process ID, meaning the failure was not because of a channel error, but 217 // another reason. So fail now. 218 request->event.Signal(); 219 return; 220 } 221 request->reused_gpu_process = true; 222 } 223 request->gpu_host_id = gpu_host_id_; 224 225 host->EstablishGpuChannel( 226 gpu_client_id_, 227 true, 228 base::Bind(&BrowserGpuChannelHostFactory::GpuChannelEstablishedOnIO, 229 base::Unretained(this), 230 request)); 231 } 232 233 void BrowserGpuChannelHostFactory::GpuChannelEstablishedOnIO( 234 EstablishRequest* request, 235 const IPC::ChannelHandle& channel_handle, 236 const gpu::GPUInfo& gpu_info) { 237 if (channel_handle.name.empty() && request->reused_gpu_process) { 238 // We failed after re-using the GPU process, but it may have died in the 239 // mean time. Retry to have a chance to create a fresh GPU process. 240 EstablishGpuChannelOnIO(request); 241 } else { 242 request->channel_handle = channel_handle; 243 request->gpu_info = gpu_info; 244 request->event.Signal(); 245 } 246 } 247 248 GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync( 249 CauseForGpuLaunch cause_for_gpu_launch) { 250 if (gpu_channel_.get()) { 251 // Recreate the channel if it has been lost. 252 if (gpu_channel_->IsLost()) 253 gpu_channel_ = NULL; 254 else 255 return gpu_channel_.get(); 256 } 257 // Ensure initialization on the main thread. 258 GpuDataManagerImpl::GetInstance(); 259 260 EstablishRequest request(cause_for_gpu_launch); 261 GetIOLoopProxy()->PostTask( 262 FROM_HERE, 263 base::Bind( 264 &BrowserGpuChannelHostFactory::EstablishGpuChannelOnIO, 265 base::Unretained(this), 266 &request)); 267 268 { 269 // We're blocking the UI thread, which is generally undesirable. 270 // In this case we need to wait for this before we can show any UI /anyway/, 271 // so it won't cause additional jank. 272 // TODO(piman): Make this asynchronous (http://crbug.com/125248). 273 base::ThreadRestrictions::ScopedAllowWait allow_wait; 274 request.event.Wait(); 275 } 276 277 if (request.channel_handle.name.empty()) 278 return NULL; 279 280 GetContentClient()->SetGpuInfo(request.gpu_info); 281 gpu_channel_ = GpuChannelHost::Create( 282 this, request.gpu_host_id, gpu_client_id_, 283 request.gpu_info, request.channel_handle); 284 return gpu_channel_.get(); 285 } 286 287 // static 288 void BrowserGpuChannelHostFactory::AddFilterOnIO( 289 int host_id, 290 scoped_refptr<IPC::ChannelProxy::MessageFilter> filter) { 291 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 292 293 GpuProcessHost* host = GpuProcessHost::FromID(host_id); 294 if (host) 295 host->AddFilter(filter.get()); 296 } 297 298 void BrowserGpuChannelHostFactory::SetHandlerForControlMessages( 299 const uint32* message_ids, 300 size_t num_messages, 301 const base::Callback<void(const IPC::Message&)>& handler, 302 base::TaskRunner* target_task_runner) { 303 DCHECK(gpu_host_id_) 304 << "Do not call" 305 << " BrowserGpuChannelHostFactory::SetHandlerForControlMessages()" 306 << " until the GpuProcessHost has been set up."; 307 308 scoped_refptr<IPC::ForwardingMessageFilter> filter = 309 new IPC::ForwardingMessageFilter(message_ids, 310 num_messages, 311 target_task_runner); 312 filter->AddRoute(MSG_ROUTING_CONTROL, handler); 313 314 GetIOLoopProxy()->PostTask( 315 FROM_HERE, 316 base::Bind(&BrowserGpuChannelHostFactory::AddFilterOnIO, 317 gpu_host_id_, 318 filter)); 319 } 320 321 } // namespace content 322