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