Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / browser / gpu / browser_gpu_channel_host_factory.cc
blobde4e791683b05fcc57f8184051c6a49ccacaee56
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/browser/gpu/browser_gpu_channel_host_factory.h"
7 #include "base/bind.h"
8 #include "base/debug/trace_event.h"
9 #include "base/synchronization/waitable_event.h"
10 #include "base/threading/thread_restrictions.h"
11 #include "content/browser/gpu/gpu_data_manager_impl.h"
12 #include "content/browser/gpu/gpu_process_host.h"
13 #include "content/browser/gpu/gpu_surface_tracker.h"
14 #include "content/common/child_process_host_impl.h"
15 #include "content/common/gpu/client/gpu_memory_buffer_impl.h"
16 #include "content/common/gpu/gpu_messages.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/gpu_data_manager.h"
19 #include "content/public/common/content_client.h"
20 #include "ipc/ipc_channel_handle.h"
21 #include "ipc/ipc_forwarding_message_filter.h"
22 #include "ipc/message_filter.h"
24 namespace content {
26 BrowserGpuChannelHostFactory* BrowserGpuChannelHostFactory::instance_ = NULL;
28 struct BrowserGpuChannelHostFactory::CreateRequest {
29 CreateRequest()
30 : event(true, false), gpu_host_id(0), route_id(MSG_ROUTING_NONE),
31 result(CREATE_COMMAND_BUFFER_FAILED) {}
32 ~CreateRequest() {}
33 base::WaitableEvent event;
34 int gpu_host_id;
35 int32 route_id;
36 CreateCommandBufferResult result;
39 class BrowserGpuChannelHostFactory::EstablishRequest
40 : public base::RefCountedThreadSafe<EstablishRequest> {
41 public:
42 static scoped_refptr<EstablishRequest> Create(CauseForGpuLaunch cause,
43 int gpu_client_id,
44 int gpu_host_id);
45 void Wait();
46 void Cancel();
48 int gpu_host_id() { return gpu_host_id_; }
49 IPC::ChannelHandle& channel_handle() { return channel_handle_; }
50 gpu::GPUInfo gpu_info() { return gpu_info_; }
52 private:
53 friend class base::RefCountedThreadSafe<EstablishRequest>;
54 explicit EstablishRequest(CauseForGpuLaunch cause,
55 int gpu_client_id,
56 int gpu_host_id);
57 ~EstablishRequest() {}
58 void EstablishOnIO();
59 void OnEstablishedOnIO(const IPC::ChannelHandle& channel_handle,
60 const gpu::GPUInfo& gpu_info);
61 void FinishOnIO();
62 void FinishOnMain();
64 base::WaitableEvent event_;
65 CauseForGpuLaunch cause_for_gpu_launch_;
66 const int gpu_client_id_;
67 int gpu_host_id_;
68 bool reused_gpu_process_;
69 IPC::ChannelHandle channel_handle_;
70 gpu::GPUInfo gpu_info_;
71 bool finished_;
72 scoped_refptr<base::MessageLoopProxy> main_loop_;
75 scoped_refptr<BrowserGpuChannelHostFactory::EstablishRequest>
76 BrowserGpuChannelHostFactory::EstablishRequest::Create(CauseForGpuLaunch cause,
77 int gpu_client_id,
78 int gpu_host_id) {
79 scoped_refptr<EstablishRequest> establish_request =
80 new EstablishRequest(cause, gpu_client_id, gpu_host_id);
81 scoped_refptr<base::MessageLoopProxy> loop =
82 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
83 // PostTask outside the constructor to ensure at least one reference exists.
84 loop->PostTask(
85 FROM_HERE,
86 base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO,
87 establish_request));
88 return establish_request;
91 BrowserGpuChannelHostFactory::EstablishRequest::EstablishRequest(
92 CauseForGpuLaunch cause,
93 int gpu_client_id,
94 int gpu_host_id)
95 : event_(false, false),
96 cause_for_gpu_launch_(cause),
97 gpu_client_id_(gpu_client_id),
98 gpu_host_id_(gpu_host_id),
99 reused_gpu_process_(false),
100 finished_(false),
101 main_loop_(base::MessageLoopProxy::current()) {
104 void BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO() {
105 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
106 if (!host) {
107 host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
108 cause_for_gpu_launch_);
109 if (!host) {
110 LOG(ERROR) << "Failed to launch GPU process.";
111 FinishOnIO();
112 return;
114 gpu_host_id_ = host->host_id();
115 reused_gpu_process_ = false;
116 } else {
117 if (reused_gpu_process_) {
118 // We come here if we retried to establish the channel because of a
119 // failure in ChannelEstablishedOnIO, but we ended up with the same
120 // process ID, meaning the failure was not because of a channel error,
121 // but another reason. So fail now.
122 LOG(ERROR) << "Failed to create channel.";
123 FinishOnIO();
124 return;
126 reused_gpu_process_ = true;
129 host->EstablishGpuChannel(
130 gpu_client_id_,
131 true,
132 true,
133 base::Bind(
134 &BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO,
135 this));
138 void BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO(
139 const IPC::ChannelHandle& channel_handle,
140 const gpu::GPUInfo& gpu_info) {
141 if (channel_handle.name.empty() && reused_gpu_process_) {
142 // We failed after re-using the GPU process, but it may have died in the
143 // mean time. Retry to have a chance to create a fresh GPU process.
144 DVLOG(1) << "Failed to create channel on existing GPU process. Trying to "
145 "restart GPU process.";
146 EstablishOnIO();
147 } else {
148 channel_handle_ = channel_handle;
149 gpu_info_ = gpu_info;
150 FinishOnIO();
154 void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnIO() {
155 event_.Signal();
156 main_loop_->PostTask(
157 FROM_HERE,
158 base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain,
159 this));
162 void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain() {
163 if (!finished_) {
164 BrowserGpuChannelHostFactory* factory =
165 BrowserGpuChannelHostFactory::instance();
166 factory->GpuChannelEstablished();
167 finished_ = true;
171 void BrowserGpuChannelHostFactory::EstablishRequest::Wait() {
172 DCHECK(main_loop_->BelongsToCurrentThread());
174 // We're blocking the UI thread, which is generally undesirable.
175 // In this case we need to wait for this before we can show any UI
176 // /anyway/, so it won't cause additional jank.
177 // TODO(piman): Make this asynchronous (http://crbug.com/125248).
178 TRACE_EVENT0("browser",
179 "BrowserGpuChannelHostFactory::EstablishGpuChannelSync");
180 base::ThreadRestrictions::ScopedAllowWait allow_wait;
181 event_.Wait();
183 FinishOnMain();
186 void BrowserGpuChannelHostFactory::EstablishRequest::Cancel() {
187 DCHECK(main_loop_->BelongsToCurrentThread());
188 finished_ = true;
191 bool BrowserGpuChannelHostFactory::CanUseForTesting() {
192 return GpuDataManager::GetInstance()->GpuAccessAllowed(NULL);
195 void BrowserGpuChannelHostFactory::Initialize(bool establish_gpu_channel) {
196 DCHECK(!instance_);
197 instance_ = new BrowserGpuChannelHostFactory();
198 if (establish_gpu_channel) {
199 instance_->EstablishGpuChannel(CAUSE_FOR_GPU_LAUNCH_BROWSER_STARTUP,
200 base::Closure());
204 void BrowserGpuChannelHostFactory::Terminate() {
205 DCHECK(instance_);
206 delete instance_;
207 instance_ = NULL;
210 BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory()
211 : gpu_client_id_(ChildProcessHostImpl::GenerateChildProcessUniqueId()),
212 shutdown_event_(new base::WaitableEvent(true, false)),
213 gpu_host_id_(0),
214 next_create_gpu_memory_buffer_request_id_(0) {
217 BrowserGpuChannelHostFactory::~BrowserGpuChannelHostFactory() {
218 DCHECK(IsMainThread());
219 if (pending_request_.get())
220 pending_request_->Cancel();
221 for (size_t n = 0; n < established_callbacks_.size(); n++)
222 established_callbacks_[n].Run();
223 shutdown_event_->Signal();
226 bool BrowserGpuChannelHostFactory::IsMainThread() {
227 return BrowserThread::CurrentlyOn(BrowserThread::UI);
230 base::MessageLoop* BrowserGpuChannelHostFactory::GetMainLoop() {
231 return BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::UI);
234 scoped_refptr<base::MessageLoopProxy>
235 BrowserGpuChannelHostFactory::GetIOLoopProxy() {
236 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
239 scoped_ptr<base::SharedMemory>
240 BrowserGpuChannelHostFactory::AllocateSharedMemory(size_t size) {
241 scoped_ptr<base::SharedMemory> shm(new base::SharedMemory());
242 if (!shm->CreateAnonymous(size))
243 return scoped_ptr<base::SharedMemory>();
244 return shm.Pass();
247 void BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO(
248 CreateRequest* request,
249 int32 surface_id,
250 const GPUCreateCommandBufferConfig& init_params) {
251 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
252 if (!host) {
253 request->event.Signal();
254 return;
257 gfx::GLSurfaceHandle surface =
258 GpuSurfaceTracker::Get()->GetSurfaceHandle(surface_id);
260 host->CreateViewCommandBuffer(
261 surface,
262 surface_id,
263 gpu_client_id_,
264 init_params,
265 request->route_id,
266 base::Bind(&BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO,
267 request));
270 // static
271 void BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO(
272 CreateRequest* request, CreateCommandBufferResult result) {
273 request->result = result;
274 request->event.Signal();
277 CreateCommandBufferResult BrowserGpuChannelHostFactory::CreateViewCommandBuffer(
278 int32 surface_id,
279 const GPUCreateCommandBufferConfig& init_params,
280 int32 route_id) {
281 CreateRequest request;
282 request.route_id = route_id;
283 GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind(
284 &BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO,
285 base::Unretained(this),
286 &request,
287 surface_id,
288 init_params));
289 // We're blocking the UI thread, which is generally undesirable.
290 // In this case we need to wait for this before we can show any UI /anyway/,
291 // so it won't cause additional jank.
292 // TODO(piman): Make this asynchronous (http://crbug.com/125248).
293 TRACE_EVENT0("browser",
294 "BrowserGpuChannelHostFactory::CreateViewCommandBuffer");
295 base::ThreadRestrictions::ScopedAllowWait allow_wait;
296 request.event.Wait();
297 return request.result;
300 GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
301 CauseForGpuLaunch cause_for_gpu_launch) {
302 EstablishGpuChannel(cause_for_gpu_launch, base::Closure());
304 if (pending_request_.get())
305 pending_request_->Wait();
307 return gpu_channel_.get();
310 void BrowserGpuChannelHostFactory::EstablishGpuChannel(
311 CauseForGpuLaunch cause_for_gpu_launch,
312 const base::Closure& callback) {
313 if (gpu_channel_.get() && gpu_channel_->IsLost()) {
314 DCHECK(!pending_request_.get());
315 // Recreate the channel if it has been lost.
316 gpu_channel_ = NULL;
319 if (!gpu_channel_.get() && !pending_request_.get()) {
320 // We should only get here if the context was lost.
321 pending_request_ = EstablishRequest::Create(
322 cause_for_gpu_launch, gpu_client_id_, gpu_host_id_);
325 if (!callback.is_null()) {
326 if (gpu_channel_.get())
327 callback.Run();
328 else
329 established_callbacks_.push_back(callback);
333 GpuChannelHost* BrowserGpuChannelHostFactory::GetGpuChannel() {
334 if (gpu_channel_.get() && !gpu_channel_->IsLost())
335 return gpu_channel_.get();
337 return NULL;
340 void BrowserGpuChannelHostFactory::GpuChannelEstablished() {
341 DCHECK(IsMainThread());
342 DCHECK(pending_request_.get());
343 if (pending_request_->channel_handle().name.empty()) {
344 DCHECK(!gpu_channel_.get());
345 } else {
346 GetContentClient()->SetGpuInfo(pending_request_->gpu_info());
347 gpu_channel_ = GpuChannelHost::Create(this,
348 pending_request_->gpu_info(),
349 pending_request_->channel_handle(),
350 shutdown_event_.get());
352 gpu_host_id_ = pending_request_->gpu_host_id();
353 pending_request_ = NULL;
355 for (size_t n = 0; n < established_callbacks_.size(); n++)
356 established_callbacks_[n].Run();
358 established_callbacks_.clear();
361 scoped_ptr<gfx::GpuMemoryBuffer>
362 BrowserGpuChannelHostFactory::AllocateGpuMemoryBuffer(size_t width,
363 size_t height,
364 unsigned internalformat,
365 unsigned usage) {
366 if (!GpuMemoryBufferImpl::IsFormatValid(internalformat) ||
367 !GpuMemoryBufferImpl::IsUsageValid(usage))
368 return scoped_ptr<gfx::GpuMemoryBuffer>();
370 return GpuMemoryBufferImpl::Create(gfx::Size(width, height),
371 internalformat,
372 usage).PassAs<gfx::GpuMemoryBuffer>();
375 // static
376 void BrowserGpuChannelHostFactory::AddFilterOnIO(
377 int host_id,
378 scoped_refptr<IPC::MessageFilter> filter) {
379 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
381 GpuProcessHost* host = GpuProcessHost::FromID(host_id);
382 if (host)
383 host->AddFilter(filter.get());
386 void BrowserGpuChannelHostFactory::SetHandlerForControlMessages(
387 const uint32* message_ids,
388 size_t num_messages,
389 const base::Callback<void(const IPC::Message&)>& handler,
390 base::TaskRunner* target_task_runner) {
391 DCHECK(gpu_host_id_)
392 << "Do not call"
393 << " BrowserGpuChannelHostFactory::SetHandlerForControlMessages()"
394 << " until the GpuProcessHost has been set up.";
396 scoped_refptr<IPC::ForwardingMessageFilter> filter =
397 new IPC::ForwardingMessageFilter(message_ids,
398 num_messages,
399 target_task_runner);
400 filter->AddRoute(MSG_ROUTING_CONTROL, handler);
402 GetIOLoopProxy()->PostTask(
403 FROM_HERE,
404 base::Bind(&BrowserGpuChannelHostFactory::AddFilterOnIO,
405 gpu_host_id_,
406 filter));
409 void BrowserGpuChannelHostFactory::CreateGpuMemoryBuffer(
410 const gfx::GpuMemoryBufferHandle& handle,
411 const gfx::Size& size,
412 unsigned internalformat,
413 unsigned usage,
414 const CreateGpuMemoryBufferCallback& callback) {
415 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
416 uint32 request_id = next_create_gpu_memory_buffer_request_id_++;
417 create_gpu_memory_buffer_requests_[request_id] = callback;
418 GetIOLoopProxy()->PostTask(
419 FROM_HERE,
420 base::Bind(&BrowserGpuChannelHostFactory::CreateGpuMemoryBufferOnIO,
421 base::Unretained(this),
422 handle,
423 size,
424 internalformat,
425 usage,
426 request_id));
429 void BrowserGpuChannelHostFactory::DestroyGpuMemoryBuffer(
430 const gfx::GpuMemoryBufferHandle& handle,
431 int32 sync_point) {
432 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
433 GetIOLoopProxy()->PostTask(
434 FROM_HERE,
435 base::Bind(&BrowserGpuChannelHostFactory::DestroyGpuMemoryBufferOnIO,
436 base::Unretained(this),
437 handle,
438 sync_point));
441 void BrowserGpuChannelHostFactory::CreateGpuMemoryBufferOnIO(
442 const gfx::GpuMemoryBufferHandle& handle,
443 const gfx::Size& size,
444 unsigned internalformat,
445 unsigned usage,
446 uint32 request_id) {
447 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
448 if (!host) {
449 GpuMemoryBufferCreatedOnIO(request_id, gfx::GpuMemoryBufferHandle());
450 return;
453 host->CreateGpuMemoryBuffer(
454 handle,
455 size,
456 internalformat,
457 usage,
458 base::Bind(&BrowserGpuChannelHostFactory::GpuMemoryBufferCreatedOnIO,
459 base::Unretained(this),
460 request_id));
463 void BrowserGpuChannelHostFactory::GpuMemoryBufferCreatedOnIO(
464 uint32 request_id,
465 const gfx::GpuMemoryBufferHandle& handle) {
466 BrowserThread::PostTask(
467 BrowserThread::UI,
468 FROM_HERE,
469 base::Bind(&BrowserGpuChannelHostFactory::OnGpuMemoryBufferCreated,
470 base::Unretained(this),
471 request_id,
472 handle));
475 void BrowserGpuChannelHostFactory::OnGpuMemoryBufferCreated(
476 uint32 request_id,
477 const gfx::GpuMemoryBufferHandle& handle) {
478 CreateGpuMemoryBufferCallbackMap::iterator iter =
479 create_gpu_memory_buffer_requests_.find(request_id);
480 DCHECK(iter != create_gpu_memory_buffer_requests_.end());
481 iter->second.Run(handle);
482 create_gpu_memory_buffer_requests_.erase(iter);
485 void BrowserGpuChannelHostFactory::DestroyGpuMemoryBufferOnIO(
486 const gfx::GpuMemoryBufferHandle& handle,
487 int32 sync_point) {
488 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
489 if (!host)
490 return;
492 host->DestroyGpuMemoryBuffer(handle, sync_point);
495 } // namespace content