Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / common / gpu / client / gpu_channel_host.cc
blobd0ceecd26211e2c255ad48504a0c40dd459782a7
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.
5 #include "content/common/gpu/client/gpu_channel_host.h"
7 #include <algorithm>
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"
20 #if defined(OS_WIN)
21 #include "content/public/common/sandbox_init.h"
22 #endif
24 using base::AutoLock;
25 using base::MessageLoopProxy;
27 namespace content {
29 GpuListenerInfo::GpuListenerInfo() {}
31 GpuListenerInfo::~GpuListenerInfo() {}
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;
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;
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();
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);
86 sync_filter_ = new IPC::SyncMessageFilter(shutdown_event);
88 channel_->AddFilter(sync_filter_.get());
90 channel_filter_ = new MessageFilter();
92 // Install the filter last, because we intercept all leftover
93 // messages.
94 channel_->AddFilter(channel_filter_.get());
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);
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).
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;
127 return false;
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);
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.";
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());
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()));
168 return NULL;
171 CommandBufferProxyImpl* command_buffer =
172 new CommandBufferProxyImpl(this, route_id);
173 AddRoute(route_id, command_buffer->AsWeakPtr());
175 AutoLock lock(context_lock_);
176 proxies_[route_id] = command_buffer;
177 return command_buffer;
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");
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;
204 if (!succeeded) {
205 LOG(ERROR)
206 << "GpuChannelMsg_CreateOffscreenCommandBuffer returned failure.";
207 return NULL;
210 CommandBufferProxyImpl* command_buffer =
211 new CommandBufferProxyImpl(this, route_id);
212 AddRoute(route_id, command_buffer->AsWeakPtr());
214 AutoLock lock(context_lock_);
215 proxies_[route_id] = command_buffer;
216 return command_buffer;
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();
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();
237 void GpuChannelHost::DestroyCommandBuffer(
238 CommandBufferProxyImpl* command_buffer) {
239 TRACE_EVENT0("gpu", "GpuChannelHost::DestroyCommandBuffer");
241 int route_id = command_buffer->GetRouteID();
242 Send(new GpuChannelMsg_DestroyCommandBuffer(route_id));
243 RemoveRoute(route_id);
245 AutoLock lock(context_lock_);
246 proxies_.erase(route_id);
247 delete command_buffer;
250 void GpuChannelHost::AddRoute(
251 int route_id, base::WeakPtr<IPC::Listener> listener) {
252 DCHECK(MessageLoopProxy::current().get());
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()));
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));
268 base::SharedMemoryHandle GpuChannelHost::ShareToGpuProcess(
269 base::SharedMemoryHandle source_handle) {
270 if (IsLost())
271 return base::SharedMemory::NULLHandle();
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();
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();
290 return base::FileDescriptor(duped_handle, true);
291 #endif
294 int32 GpuChannelHost::ReserveTransferBufferId() {
295 return next_transfer_buffer_id_.GetNext();
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;
307 #if defined(USE_OZONE)
308 case gfx::OZONE_NATIVE_BUFFER:
309 return source_handle;
310 #endif
311 #if defined(OS_MACOSX)
312 case gfx::IO_SURFACE_BUFFER:
313 return source_handle;
314 #endif
315 #if defined(OS_ANDROID)
316 case gfx::SURFACE_TEXTURE_BUFFER:
317 return source_handle;
318 #endif
319 #if defined(USE_X11)
320 case gfx::X11_PIXMAP_BUFFER:
321 return source_handle;
322 #endif
323 default:
324 NOTREACHED();
325 return gfx::GpuMemoryBufferHandle();
329 int32 GpuChannelHost::ReserveGpuMemoryBufferId() {
330 return next_gpu_memory_buffer_id_.GetNext();
333 int32 GpuChannelHost::GenerateRouteID() {
334 return next_route_id_.GetNext();
337 GpuChannelHost::~GpuChannelHost() {
338 // channel_ must be destroyed on the main thread.
339 if (!factory_->IsMainThread())
340 factory_->GetMainLoop()->DeleteSoon(FROM_HERE, channel_.release());
344 GpuChannelHost::MessageFilter::MessageFilter()
345 : lost_(false) {
348 GpuChannelHost::MessageFilter::~MessageFilter() {}
350 void GpuChannelHost::MessageFilter::AddRoute(
351 int route_id,
352 base::WeakPtr<IPC::Listener> listener,
353 scoped_refptr<MessageLoopProxy> loop) {
354 DCHECK(listeners_.find(route_id) == listeners_.end());
355 GpuListenerInfo info;
356 info.listener = listener;
357 info.loop = loop;
358 listeners_[route_id] = info;
361 void GpuChannelHost::MessageFilter::RemoveRoute(int route_id) {
362 ListenerMap::iterator it = listeners_.find(route_id);
363 if (it != listeners_.end())
364 listeners_.erase(it);
367 bool GpuChannelHost::MessageFilter::OnMessageReceived(
368 const IPC::Message& message) {
369 // Never handle sync message replies or we will deadlock here.
370 if (message.is_reply())
371 return false;
373 ListenerMap::iterator it = listeners_.find(message.routing_id());
374 if (it == listeners_.end())
375 return false;
377 const GpuListenerInfo& info = it->second;
378 info.loop->PostTask(
379 FROM_HERE,
380 base::Bind(
381 base::IgnoreResult(&IPC::Listener::OnMessageReceived),
382 info.listener,
383 message));
384 return true;
387 void GpuChannelHost::MessageFilter::OnChannelError() {
388 // Set the lost state before signalling the proxies. That way, if they
389 // themselves post a task to recreate the context, they will not try to re-use
390 // this channel host.
392 AutoLock lock(lock_);
393 lost_ = true;
396 // Inform all the proxies that an error has occurred. This will be reported
397 // via OpenGL as a lost context.
398 for (ListenerMap::iterator it = listeners_.begin();
399 it != listeners_.end();
400 it++) {
401 const GpuListenerInfo& info = it->second;
402 info.loop->PostTask(
403 FROM_HERE,
404 base::Bind(&IPC::Listener::OnChannelError, info.listener));
407 listeners_.clear();
410 bool GpuChannelHost::MessageFilter::IsLost() const {
411 AutoLock lock(lock_);
412 return lost_;
415 } // namespace content