Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / gpu / browser_gpu_channel_host_factory.cc
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/debug/trace_event.h"
9 #include "base/threading/thread_restrictions.h"
10 #include "content/browser/gpu/gpu_data_manager_impl.h"
11 #include "content/browser/gpu/gpu_process_host.h"
12 #include "content/browser/gpu/gpu_surface_tracker.h"
13 #include "content/common/child_process_host_impl.h"
14 #include "content/common/gpu/client/gpu_memory_buffer_impl.h"
15 #include "content/common/gpu/gpu_messages.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/gpu_data_manager.h"
18 #include "content/public/common/content_client.h"
19 #include "ipc/ipc_forwarding_message_filter.h"
20 #include "ipc/message_filter.h"
21
22 namespace content {
23
24 BrowserGpuChannelHostFactory* BrowserGpuChannelHostFactory::instance_ = NULL;
25
26 BrowserGpuChannelHostFactory::CreateRequest::CreateRequest()
27     : event(true, false),
28       gpu_host_id(0),
29       route_id(MSG_ROUTING_NONE) {
30 }
31
32 BrowserGpuChannelHostFactory::CreateRequest::~CreateRequest() {
33 }
34
35 BrowserGpuChannelHostFactory::EstablishRequest::EstablishRequest(
36     CauseForGpuLaunch cause,
37     int gpu_client_id,
38     int gpu_host_id)
39     : event_(false, false),
40       cause_for_gpu_launch_(cause),
41       gpu_client_id_(gpu_client_id),
42       gpu_host_id_(gpu_host_id),
43       reused_gpu_process_(false),
44       finished_(false),
45       main_loop_(base::MessageLoopProxy::current()) {
46   scoped_refptr<base::MessageLoopProxy> loop =
47       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
48   loop->PostTask(
49       FROM_HERE,
50       base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO,
51                  this));
52 }
53
54 BrowserGpuChannelHostFactory::EstablishRequest::~EstablishRequest() {
55 }
56
57 void BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO() {
58   GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
59   if (!host) {
60     host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
61                                cause_for_gpu_launch_);
62     if (!host) {
63       LOG(ERROR) << "Failed to launch GPU process.";
64       FinishOnIO();
65       return;
66     }
67     gpu_host_id_ = host->host_id();
68     reused_gpu_process_ = false;
69   } else {
70     if (reused_gpu_process_) {
71       // We come here if we retried to establish the channel because of a
72       // failure in ChannelEstablishedOnIO, but we ended up with the same
73       // process ID, meaning the failure was not because of a channel error,
74       // but another reason. So fail now.
75       LOG(ERROR) << "Failed to create channel.";
76       FinishOnIO();
77       return;
78     }
79     reused_gpu_process_ = true;
80   }
81
82   host->EstablishGpuChannel(
83       gpu_client_id_,
84       true,
85       base::Bind(
86           &BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO,
87           this));
88 }
89
90 void BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO(
91     const IPC::ChannelHandle& channel_handle,
92     const gpu::GPUInfo& gpu_info) {
93   if (channel_handle.name.empty() && reused_gpu_process_) {
94     // We failed after re-using the GPU process, but it may have died in the
95     // mean time. Retry to have a chance to create a fresh GPU process.
96     DVLOG(1) << "Failed to create channel on existing GPU process. Trying to "
97                 "restart GPU process.";
98     EstablishOnIO();
99   } else {
100     channel_handle_ = channel_handle;
101     gpu_info_ = gpu_info;
102     FinishOnIO();
103   }
104 }
105
106 void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnIO() {
107   event_.Signal();
108   main_loop_->PostTask(
109       FROM_HERE,
110       base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain,
111                  this));
112 }
113
114 void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain() {
115   if (!finished_) {
116     BrowserGpuChannelHostFactory* factory =
117         BrowserGpuChannelHostFactory::instance();
118     factory->GpuChannelEstablished();
119     finished_ = true;
120   }
121 }
122
123 void BrowserGpuChannelHostFactory::EstablishRequest::Wait() {
124   DCHECK(main_loop_->BelongsToCurrentThread());
125   {
126     // We're blocking the UI thread, which is generally undesirable.
127     // In this case we need to wait for this before we can show any UI
128     // /anyway/, so it won't cause additional jank.
129     // TODO(piman): Make this asynchronous (http://crbug.com/125248).
130     TRACE_EVENT0("browser",
131                  "BrowserGpuChannelHostFactory::EstablishGpuChannelSync");
132     base::ThreadRestrictions::ScopedAllowWait allow_wait;
133     event_.Wait();
134   }
135   FinishOnMain();
136 }
137
138 void BrowserGpuChannelHostFactory::EstablishRequest::Cancel() {
139   DCHECK(main_loop_->BelongsToCurrentThread());
140   finished_ = true;
141 }
142
143 bool BrowserGpuChannelHostFactory::CanUseForTesting() {
144   return GpuDataManager::GetInstance()->GpuAccessAllowed(NULL);
145 }
146
147 void BrowserGpuChannelHostFactory::Initialize(bool establish_gpu_channel) {
148   DCHECK(!instance_);
149   instance_ = new BrowserGpuChannelHostFactory(establish_gpu_channel);
150 }
151
152 void BrowserGpuChannelHostFactory::Terminate() {
153   DCHECK(instance_);
154   delete instance_;
155   instance_ = NULL;
156 }
157
158 BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory(
159     bool establish_gpu_channel)
160     : gpu_client_id_(ChildProcessHostImpl::GenerateChildProcessUniqueId()),
161       shutdown_event_(new base::WaitableEvent(true, false)),
162       gpu_host_id_(0) {
163   if (establish_gpu_channel) {
164     pending_request_ = new EstablishRequest(
165         CAUSE_FOR_GPU_LAUNCH_BROWSER_STARTUP, gpu_client_id_, gpu_host_id_);
166   }
167 }
168
169 BrowserGpuChannelHostFactory::~BrowserGpuChannelHostFactory() {
170   DCHECK(IsMainThread());
171   if (pending_request_)
172     pending_request_->Cancel();
173   for (size_t n = 0; n < established_callbacks_.size(); n++)
174     established_callbacks_[n].Run();
175   shutdown_event_->Signal();
176 }
177
178 bool BrowserGpuChannelHostFactory::IsMainThread() {
179   return BrowserThread::CurrentlyOn(BrowserThread::UI);
180 }
181
182 base::MessageLoop* BrowserGpuChannelHostFactory::GetMainLoop() {
183   return BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::UI);
184 }
185
186 scoped_refptr<base::MessageLoopProxy>
187 BrowserGpuChannelHostFactory::GetIOLoopProxy() {
188   return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
189 }
190
191 scoped_ptr<base::SharedMemory>
192 BrowserGpuChannelHostFactory::AllocateSharedMemory(size_t size) {
193   scoped_ptr<base::SharedMemory> shm(new base::SharedMemory());
194   if (!shm->CreateAnonymous(size))
195     return scoped_ptr<base::SharedMemory>();
196   return shm.Pass();
197 }
198
199 void BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO(
200     CreateRequest* request,
201     int32 surface_id,
202     const GPUCreateCommandBufferConfig& init_params) {
203   GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
204   if (!host) {
205     request->event.Signal();
206     return;
207   }
208
209   gfx::GLSurfaceHandle surface =
210       GpuSurfaceTracker::Get()->GetSurfaceHandle(surface_id);
211
212   host->CreateViewCommandBuffer(
213       surface,
214       surface_id,
215       gpu_client_id_,
216       init_params,
217       request->route_id,
218       base::Bind(&BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO,
219                  request));
220 }
221
222 // static
223 void BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO(
224     CreateRequest* request, bool succeeded) {
225   request->succeeded = succeeded;
226   request->event.Signal();
227 }
228
229 bool BrowserGpuChannelHostFactory::CreateViewCommandBuffer(
230       int32 surface_id,
231       const GPUCreateCommandBufferConfig& init_params,
232       int32 route_id) {
233   CreateRequest request;
234   request.route_id = route_id;
235   GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind(
236         &BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO,
237         base::Unretained(this),
238         &request,
239         surface_id,
240         init_params));
241   // We're blocking the UI thread, which is generally undesirable.
242   // In this case we need to wait for this before we can show any UI /anyway/,
243   // so it won't cause additional jank.
244   // TODO(piman): Make this asynchronous (http://crbug.com/125248).
245   TRACE_EVENT0("browser",
246                "BrowserGpuChannelHostFactory::CreateViewCommandBuffer");
247   base::ThreadRestrictions::ScopedAllowWait allow_wait;
248   request.event.Wait();
249   return request.succeeded;
250 }
251
252 void BrowserGpuChannelHostFactory::CreateImageOnIO(
253     gfx::PluginWindowHandle window,
254     int32 image_id,
255     const CreateImageCallback& callback) {
256   GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
257   if (!host) {
258     ImageCreatedOnIO(callback, gfx::Size());
259     return;
260   }
261
262   host->CreateImage(
263       window,
264       gpu_client_id_,
265       image_id,
266       base::Bind(&BrowserGpuChannelHostFactory::ImageCreatedOnIO, callback));
267 }
268
269 // static
270 void BrowserGpuChannelHostFactory::ImageCreatedOnIO(
271     const CreateImageCallback& callback, const gfx::Size size) {
272   BrowserThread::PostTask(
273       BrowserThread::UI,
274       FROM_HERE,
275       base::Bind(&BrowserGpuChannelHostFactory::OnImageCreated,
276                  callback, size));
277 }
278
279 // static
280 void BrowserGpuChannelHostFactory::OnImageCreated(
281     const CreateImageCallback& callback, const gfx::Size size) {
282   callback.Run(size);
283 }
284
285 void BrowserGpuChannelHostFactory::CreateImage(
286     gfx::PluginWindowHandle window,
287     int32 image_id,
288     const CreateImageCallback& callback) {
289   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
290   GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind(
291         &BrowserGpuChannelHostFactory::CreateImageOnIO,
292         base::Unretained(this),
293         window,
294         image_id,
295         callback));
296 }
297
298 void BrowserGpuChannelHostFactory::DeleteImageOnIO(
299     int32 image_id, int32 sync_point) {
300   GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
301   if (!host) {
302     return;
303   }
304
305   host->DeleteImage(gpu_client_id_, image_id, sync_point);
306 }
307
308 void BrowserGpuChannelHostFactory::DeleteImage(
309     int32 image_id, int32 sync_point) {
310   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
311   GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind(
312         &BrowserGpuChannelHostFactory::DeleteImageOnIO,
313         base::Unretained(this),
314         image_id,
315         sync_point));
316 }
317
318 GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
319     CauseForGpuLaunch cause_for_gpu_launch) {
320   EstablishGpuChannel(cause_for_gpu_launch, base::Closure());
321
322   if (pending_request_)
323     pending_request_->Wait();
324
325   return gpu_channel_.get();
326 }
327
328 void BrowserGpuChannelHostFactory::EstablishGpuChannel(
329     CauseForGpuLaunch cause_for_gpu_launch,
330     const base::Closure& callback) {
331   if (gpu_channel_.get() && gpu_channel_->IsLost()) {
332     DCHECK(!pending_request_);
333     // Recreate the channel if it has been lost.
334     gpu_channel_ = NULL;
335   }
336
337   if (!gpu_channel_ && !pending_request_) {
338     // We should only get here if the context was lost.
339     pending_request_ = new EstablishRequest(
340         cause_for_gpu_launch, gpu_client_id_, gpu_host_id_);
341   }
342
343   if (!callback.is_null()) {
344     if (gpu_channel_)
345       callback.Run();
346     else
347       established_callbacks_.push_back(callback);
348   }
349 }
350
351 GpuChannelHost* BrowserGpuChannelHostFactory::GetGpuChannel() {
352   if (gpu_channel_ && !gpu_channel_->IsLost())
353     return gpu_channel_;
354
355   return NULL;
356 }
357
358 void BrowserGpuChannelHostFactory::GpuChannelEstablished() {
359   DCHECK(IsMainThread());
360   DCHECK(pending_request_);
361   if (pending_request_->channel_handle().name.empty())
362     return;
363
364   GetContentClient()->SetGpuInfo(pending_request_->gpu_info());
365   gpu_channel_ = GpuChannelHost::Create(this,
366                                         pending_request_->gpu_info(),
367                                         pending_request_->channel_handle(),
368                                         shutdown_event_.get());
369   gpu_host_id_ = pending_request_->gpu_host_id();
370   pending_request_ = NULL;
371
372   for (size_t n = 0; n < established_callbacks_.size(); n++)
373     established_callbacks_[n].Run();
374
375   established_callbacks_.clear();
376 }
377
378 scoped_ptr<gfx::GpuMemoryBuffer>
379 BrowserGpuChannelHostFactory::AllocateGpuMemoryBuffer(size_t width,
380                                                       size_t height,
381                                                       unsigned internalformat,
382                                                       unsigned usage) {
383   if (!GpuMemoryBufferImpl::IsFormatValid(internalformat) ||
384       !GpuMemoryBufferImpl::IsUsageValid(usage))
385     return scoped_ptr<gfx::GpuMemoryBuffer>();
386
387   return GpuMemoryBufferImpl::Create(gfx::Size(width, height),
388                                      internalformat,
389                                      usage).PassAs<gfx::GpuMemoryBuffer>();
390 }
391
392 // static
393 void BrowserGpuChannelHostFactory::AddFilterOnIO(
394     int host_id,
395     scoped_refptr<IPC::MessageFilter> filter) {
396   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
397
398   GpuProcessHost* host = GpuProcessHost::FromID(host_id);
399   if (host)
400     host->AddFilter(filter.get());
401 }
402
403 void BrowserGpuChannelHostFactory::SetHandlerForControlMessages(
404       const uint32* message_ids,
405       size_t num_messages,
406       const base::Callback<void(const IPC::Message&)>& handler,
407       base::TaskRunner* target_task_runner) {
408   DCHECK(gpu_host_id_)
409       << "Do not call"
410       << " BrowserGpuChannelHostFactory::SetHandlerForControlMessages()"
411       << " until the GpuProcessHost has been set up.";
412
413   scoped_refptr<IPC::ForwardingMessageFilter> filter =
414       new IPC::ForwardingMessageFilter(message_ids,
415                                        num_messages,
416                                        target_task_runner);
417   filter->AddRoute(MSG_ROUTING_CONTROL, handler);
418
419   GetIOLoopProxy()->PostTask(
420       FROM_HERE,
421       base::Bind(&BrowserGpuChannelHostFactory::AddFilterOnIO,
422                  gpu_host_id_,
423                  filter));
424 }
425
426 }  // namespace content