Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / common / gpu / client / gpu_channel_host.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/common/gpu/client/gpu_channel_host.h"
6
7 #include <algorithm>
8
9 #include "base/bind.h"
10 #include "base/debug/trace_event.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/message_loop/message_loop_proxy.h"
13 #include "base/posix/eintr_wrapper.h"
14 #include "base/threading/thread_restrictions.h"
15 #include "content/common/gpu/client/command_buffer_proxy_impl.h"
16 #include "content/common/gpu/gpu_messages.h"
17 #include "ipc/ipc_sync_message_filter.h"
18 #include "url/gurl.h"
19
20 #if defined(OS_WIN)
21 #include "content/public/common/sandbox_init.h"
22 #endif
23
24 using base::AutoLock;
25 using base::MessageLoopProxy;
26
27 namespace content {
28
29 GpuListenerInfo::GpuListenerInfo() {}
30
31 GpuListenerInfo::~GpuListenerInfo() {}
32
33 // static
34 scoped_refptr<GpuChannelHost> GpuChannelHost::Create(
35     GpuChannelHostFactory* factory,
36     const gpu::GPUInfo& gpu_info,
37     const IPC::ChannelHandle& channel_handle,
38     base::WaitableEvent* shutdown_event) {
39   DCHECK(factory->IsMainThread());
40   scoped_refptr<GpuChannelHost> host = new GpuChannelHost(factory, gpu_info);
41   host->Connect(channel_handle, shutdown_event);
42   return host;
43 }
44
45 // static
46 bool GpuChannelHost::IsValidGpuMemoryBuffer(
47     gfx::GpuMemoryBufferHandle handle) {
48   switch (handle.type) {
49     case gfx::SHARED_MEMORY_BUFFER:
50 #if defined(OS_MACOSX)
51     case gfx::IO_SURFACE_BUFFER:
52 #endif
53 #if defined(OS_ANDROID)
54     case gfx::SURFACE_TEXTURE_BUFFER:
55 #endif
56 #if defined(USE_X11)
57     case gfx::X11_PIXMAP_BUFFER:
58 #endif
59       return true;
60     default:
61       return false;
62   }
63 }
64
65 GpuChannelHost::GpuChannelHost(GpuChannelHostFactory* factory,
66                                const gpu::GPUInfo& gpu_info)
67     : factory_(factory),
68       gpu_info_(gpu_info) {
69   next_transfer_buffer_id_.GetNext();
70   next_gpu_memory_buffer_id_.GetNext();
71   next_route_id_.GetNext();
72 }
73
74 void GpuChannelHost::Connect(const IPC::ChannelHandle& channel_handle,
75                              base::WaitableEvent* shutdown_event) {
76   // Open a channel to the GPU process. We pass NULL as the main listener here
77   // since we need to filter everything to route it to the right thread.
78   scoped_refptr<base::MessageLoopProxy> io_loop = factory_->GetIOLoopProxy();
79   channel_ = IPC::SyncChannel::Create(channel_handle,
80                                       IPC::Channel::MODE_CLIENT,
81                                       NULL,
82                                       io_loop.get(),
83                                       true,
84                                       shutdown_event);
85
86   sync_filter_ = new IPC::SyncMessageFilter(shutdown_event);
87
88   channel_->AddFilter(sync_filter_.get());
89
90   channel_filter_ = new MessageFilter();
91
92   // Install the filter last, because we intercept all leftover
93   // messages.
94   channel_->AddFilter(channel_filter_.get());
95 }
96
97 bool GpuChannelHost::Send(IPC::Message* msg) {
98   // Callee takes ownership of message, regardless of whether Send is
99   // successful. See IPC::Sender.
100   scoped_ptr<IPC::Message> message(msg);
101   // The GPU process never sends synchronous IPCs so clear the unblock flag to
102   // preserve order.
103   message->set_unblock(false);
104
105   // Currently we need to choose between two different mechanisms for sending.
106   // On the main thread we use the regular channel Send() method, on another
107   // thread we use SyncMessageFilter. We also have to be careful interpreting
108   // IsMainThread() since it might return false during shutdown,
109   // impl we are actually calling from the main thread (discard message then).
110   //
111   // TODO: Can we just always use sync_filter_ since we setup the channel
112   //       without a main listener?
113   if (factory_->IsMainThread()) {
114     // http://crbug.com/125264
115     base::ThreadRestrictions::ScopedAllowWait allow_wait;
116     bool result = channel_->Send(message.release());
117     if (!result)
118       DVLOG(1) << "GpuChannelHost::Send failed: Channel::Send failed";
119     return result;
120   } else if (base::MessageLoop::current()) {
121     bool result = sync_filter_->Send(message.release());
122     if (!result)
123       DVLOG(1) << "GpuChannelHost::Send failed: SyncMessageFilter::Send failed";
124     return result;
125   }
126
127   return false;
128 }
129
130 CommandBufferProxyImpl* GpuChannelHost::CreateViewCommandBuffer(
131     int32 surface_id,
132     CommandBufferProxyImpl* share_group,
133     const std::vector<int32>& attribs,
134     const GURL& active_url,
135     gfx::GpuPreference gpu_preference) {
136   TRACE_EVENT1("gpu",
137                "GpuChannelHost::CreateViewCommandBuffer",
138                "surface_id",
139                surface_id);
140
141   GPUCreateCommandBufferConfig init_params;
142   init_params.share_group_id =
143       share_group ? share_group->GetRouteID() : MSG_ROUTING_NONE;
144   init_params.attribs = attribs;
145   init_params.active_url = active_url;
146   init_params.gpu_preference = gpu_preference;
147   int32 route_id = GenerateRouteID();
148   CreateCommandBufferResult result = factory_->CreateViewCommandBuffer(
149       surface_id, init_params, route_id);
150   if (result != CREATE_COMMAND_BUFFER_SUCCEEDED) {
151     LOG(ERROR) << "GpuChannelHost::CreateViewCommandBuffer failed.";
152
153     if (result == CREATE_COMMAND_BUFFER_FAILED_AND_CHANNEL_LOST) {
154       // The GPU channel needs to be considered lost. The caller will
155       // then set up a new connection, and the GPU channel and any
156       // view command buffers will all be associated with the same GPU
157       // process.
158       DCHECK(MessageLoopProxy::current().get());
159
160       scoped_refptr<base::MessageLoopProxy> io_loop =
161           factory_->GetIOLoopProxy();
162       io_loop->PostTask(
163           FROM_HERE,
164           base::Bind(&GpuChannelHost::MessageFilter::OnChannelError,
165                      channel_filter_.get()));
166     }
167
168     return NULL;
169   }
170
171   CommandBufferProxyImpl* command_buffer =
172       new CommandBufferProxyImpl(this, route_id);
173   AddRoute(route_id, command_buffer->AsWeakPtr());
174
175   AutoLock lock(context_lock_);
176   proxies_[route_id] = command_buffer;
177   return command_buffer;
178 }
179
180 CommandBufferProxyImpl* GpuChannelHost::CreateOffscreenCommandBuffer(
181     const gfx::Size& size,
182     CommandBufferProxyImpl* share_group,
183     const std::vector<int32>& attribs,
184     const GURL& active_url,
185     gfx::GpuPreference gpu_preference) {
186   TRACE_EVENT0("gpu", "GpuChannelHost::CreateOffscreenCommandBuffer");
187
188   GPUCreateCommandBufferConfig init_params;
189   init_params.share_group_id =
190       share_group ? share_group->GetRouteID() : MSG_ROUTING_NONE;
191   init_params.attribs = attribs;
192   init_params.active_url = active_url;
193   init_params.gpu_preference = gpu_preference;
194   int32 route_id = GenerateRouteID();
195   bool succeeded = false;
196   if (!Send(new GpuChannelMsg_CreateOffscreenCommandBuffer(size,
197                                                            init_params,
198                                                            route_id,
199                                                            &succeeded))) {
200     LOG(ERROR) << "Failed to send GpuChannelMsg_CreateOffscreenCommandBuffer.";
201     return NULL;
202   }
203
204   if (!succeeded) {
205     LOG(ERROR)
206         << "GpuChannelMsg_CreateOffscreenCommandBuffer returned failure.";
207     return NULL;
208   }
209
210   CommandBufferProxyImpl* command_buffer =
211       new CommandBufferProxyImpl(this, route_id);
212   AddRoute(route_id, command_buffer->AsWeakPtr());
213
214   AutoLock lock(context_lock_);
215   proxies_[route_id] = command_buffer;
216   return command_buffer;
217 }
218
219 scoped_ptr<media::VideoDecodeAccelerator> GpuChannelHost::CreateVideoDecoder(
220     int command_buffer_route_id) {
221   TRACE_EVENT0("gpu", "GpuChannelHost::CreateVideoDecoder");
222   AutoLock lock(context_lock_);
223   ProxyMap::iterator it = proxies_.find(command_buffer_route_id);
224   DCHECK(it != proxies_.end());
225   return it->second->CreateVideoDecoder();
226 }
227
228 scoped_ptr<media::VideoEncodeAccelerator> GpuChannelHost::CreateVideoEncoder(
229     int command_buffer_route_id) {
230   TRACE_EVENT0("gpu", "GpuChannelHost::CreateVideoEncoder");
231   AutoLock lock(context_lock_);
232   ProxyMap::iterator it = proxies_.find(command_buffer_route_id);
233   DCHECK(it != proxies_.end());
234   return it->second->CreateVideoEncoder();
235 }
236
237 void GpuChannelHost::DestroyCommandBuffer(
238     CommandBufferProxyImpl* command_buffer) {
239   TRACE_EVENT0("gpu", "GpuChannelHost::DestroyCommandBuffer");
240
241   int route_id = command_buffer->GetRouteID();
242   Send(new GpuChannelMsg_DestroyCommandBuffer(route_id));
243   RemoveRoute(route_id);
244
245   AutoLock lock(context_lock_);
246   proxies_.erase(route_id);
247   delete command_buffer;
248 }
249
250 void GpuChannelHost::AddRoute(
251     int route_id, base::WeakPtr<IPC::Listener> listener) {
252   DCHECK(MessageLoopProxy::current().get());
253
254   scoped_refptr<base::MessageLoopProxy> io_loop = factory_->GetIOLoopProxy();
255   io_loop->PostTask(FROM_HERE,
256                     base::Bind(&GpuChannelHost::MessageFilter::AddRoute,
257                                channel_filter_.get(), route_id, listener,
258                                MessageLoopProxy::current()));
259 }
260
261 void GpuChannelHost::RemoveRoute(int route_id) {
262   scoped_refptr<base::MessageLoopProxy> io_loop = factory_->GetIOLoopProxy();
263   io_loop->PostTask(FROM_HERE,
264                     base::Bind(&GpuChannelHost::MessageFilter::RemoveRoute,
265                                channel_filter_.get(), route_id));
266 }
267
268 base::SharedMemoryHandle GpuChannelHost::ShareToGpuProcess(
269     base::SharedMemoryHandle source_handle) {
270   if (IsLost())
271     return base::SharedMemory::NULLHandle();
272
273 #if defined(OS_WIN)
274   // Windows needs to explicitly duplicate the handle out to another process.
275   base::SharedMemoryHandle target_handle;
276   if (!BrokerDuplicateHandle(source_handle,
277                              channel_->GetPeerPID(),
278                              &target_handle,
279                              FILE_GENERIC_READ | FILE_GENERIC_WRITE,
280                              0)) {
281     return base::SharedMemory::NULLHandle();
282   }
283
284   return target_handle;
285 #else
286   int duped_handle = HANDLE_EINTR(dup(source_handle.fd));
287   if (duped_handle < 0)
288     return base::SharedMemory::NULLHandle();
289
290   return base::FileDescriptor(duped_handle, true);
291 #endif
292 }
293
294 int32 GpuChannelHost::ReserveTransferBufferId() {
295   return next_transfer_buffer_id_.GetNext();
296 }
297
298 gfx::GpuMemoryBufferHandle GpuChannelHost::ShareGpuMemoryBufferToGpuProcess(
299     gfx::GpuMemoryBufferHandle source_handle) {
300   switch (source_handle.type) {
301     case gfx::SHARED_MEMORY_BUFFER: {
302       gfx::GpuMemoryBufferHandle handle;
303       handle.type = gfx::SHARED_MEMORY_BUFFER;
304       handle.handle = ShareToGpuProcess(source_handle.handle);
305       return handle;
306     }
307 #if defined(OS_MACOSX)
308     case gfx::IO_SURFACE_BUFFER:
309       return source_handle;
310 #endif
311 #if defined(OS_ANDROID)
312     case gfx::SURFACE_TEXTURE_BUFFER:
313       return source_handle;
314 #endif
315 #if defined(USE_X11)
316     case gfx::X11_PIXMAP_BUFFER:
317       return source_handle;
318 #endif
319     default:
320       NOTREACHED();
321       return gfx::GpuMemoryBufferHandle();
322   }
323 }
324
325 int32 GpuChannelHost::ReserveGpuMemoryBufferId() {
326   return next_gpu_memory_buffer_id_.GetNext();
327 }
328
329 int32 GpuChannelHost::GenerateRouteID() {
330   return next_route_id_.GetNext();
331 }
332
333 GpuChannelHost::~GpuChannelHost() {
334   // channel_ must be destroyed on the main thread.
335   if (!factory_->IsMainThread())
336     factory_->GetMainLoop()->DeleteSoon(FROM_HERE, channel_.release());
337 }
338
339
340 GpuChannelHost::MessageFilter::MessageFilter()
341     : lost_(false) {
342 }
343
344 GpuChannelHost::MessageFilter::~MessageFilter() {}
345
346 void GpuChannelHost::MessageFilter::AddRoute(
347     int route_id,
348     base::WeakPtr<IPC::Listener> listener,
349     scoped_refptr<MessageLoopProxy> loop) {
350   DCHECK(listeners_.find(route_id) == listeners_.end());
351   GpuListenerInfo info;
352   info.listener = listener;
353   info.loop = loop;
354   listeners_[route_id] = info;
355 }
356
357 void GpuChannelHost::MessageFilter::RemoveRoute(int route_id) {
358   ListenerMap::iterator it = listeners_.find(route_id);
359   if (it != listeners_.end())
360     listeners_.erase(it);
361 }
362
363 bool GpuChannelHost::MessageFilter::OnMessageReceived(
364     const IPC::Message& message) {
365   // Never handle sync message replies or we will deadlock here.
366   if (message.is_reply())
367     return false;
368
369   ListenerMap::iterator it = listeners_.find(message.routing_id());
370   if (it == listeners_.end())
371     return false;
372
373   const GpuListenerInfo& info = it->second;
374   info.loop->PostTask(
375       FROM_HERE,
376       base::Bind(
377           base::IgnoreResult(&IPC::Listener::OnMessageReceived),
378           info.listener,
379           message));
380   return true;
381 }
382
383 void GpuChannelHost::MessageFilter::OnChannelError() {
384   // Set the lost state before signalling the proxies. That way, if they
385   // themselves post a task to recreate the context, they will not try to re-use
386   // this channel host.
387   {
388     AutoLock lock(lock_);
389     lost_ = true;
390   }
391
392   // Inform all the proxies that an error has occurred. This will be reported
393   // via OpenGL as a lost context.
394   for (ListenerMap::iterator it = listeners_.begin();
395        it != listeners_.end();
396        it++) {
397     const GpuListenerInfo& info = it->second;
398     info.loop->PostTask(
399         FROM_HERE,
400         base::Bind(&IPC::Listener::OnChannelError, info.listener));
401   }
402
403   listeners_.clear();
404 }
405
406 bool GpuChannelHost::MessageFilter::IsLost() const {
407   AutoLock lock(lock_);
408   return lost_;
409 }
410
411 }  // namespace content