Add remoting and PPAPI tests to GN build
[chromium-blink-merge.git] / content / browser / gpu / browser_gpu_channel_host_factory.cc
blobfea661a4084ac07a158f20fe162574be2613ce8c
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 <set>
9 #include "base/bind.h"
10 #include "base/profiler/scoped_tracker.h"
11 #include "base/synchronization/waitable_event.h"
12 #include "base/threading/thread_restrictions.h"
13 #include "base/trace_event/trace_event.h"
14 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
15 #include "content/browser/gpu/gpu_data_manager_impl.h"
16 #include "content/browser/gpu/gpu_process_host.h"
17 #include "content/browser/gpu/gpu_surface_tracker.h"
18 #include "content/common/child_process_host_impl.h"
19 #include "content/common/gpu/gpu_memory_buffer_factory.h"
20 #include "content/common/gpu/gpu_messages.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/gpu_data_manager.h"
23 #include "content/public/common/content_client.h"
24 #include "gpu/GLES2/gl2extchromium.h"
25 #include "ipc/ipc_channel_handle.h"
26 #include "ipc/ipc_forwarding_message_filter.h"
27 #include "ipc/message_filter.h"
29 #if defined(OS_MACOSX)
30 #include "content/common/gpu/gpu_memory_buffer_factory_io_surface.h"
31 #endif
33 #if defined(OS_ANDROID)
34 #include "content/common/gpu/gpu_memory_buffer_factory_surface_texture.h"
35 #endif
37 #if defined(USE_OZONE)
38 #include "content/common/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h"
39 #endif
41 namespace content {
42 namespace {
44 base::LazyInstance<std::set<gfx::GpuMemoryBuffer::Usage>>
45 g_enabled_gpu_memory_buffer_usages;
48 BrowserGpuChannelHostFactory* BrowserGpuChannelHostFactory::instance_ = NULL;
50 struct BrowserGpuChannelHostFactory::CreateRequest {
51 CreateRequest(int32 route_id)
52 : event(true, false),
53 gpu_host_id(0),
54 route_id(route_id),
55 result(CREATE_COMMAND_BUFFER_FAILED) {}
56 ~CreateRequest() {}
57 base::WaitableEvent event;
58 int gpu_host_id;
59 int32 route_id;
60 CreateCommandBufferResult result;
63 class BrowserGpuChannelHostFactory::EstablishRequest
64 : public base::RefCountedThreadSafe<EstablishRequest> {
65 public:
66 static scoped_refptr<EstablishRequest> Create(CauseForGpuLaunch cause,
67 int gpu_client_id,
68 int gpu_host_id);
69 void Wait();
70 void Cancel();
72 int gpu_host_id() { return gpu_host_id_; }
73 IPC::ChannelHandle& channel_handle() { return channel_handle_; }
74 gpu::GPUInfo gpu_info() { return gpu_info_; }
76 private:
77 friend class base::RefCountedThreadSafe<EstablishRequest>;
78 explicit EstablishRequest(CauseForGpuLaunch cause,
79 int gpu_client_id,
80 int gpu_host_id);
81 ~EstablishRequest() {}
82 void EstablishOnIO();
83 void OnEstablishedOnIO(const IPC::ChannelHandle& channel_handle,
84 const gpu::GPUInfo& gpu_info);
85 void FinishOnIO();
86 void FinishOnMain();
88 base::WaitableEvent event_;
89 CauseForGpuLaunch cause_for_gpu_launch_;
90 const int gpu_client_id_;
91 int gpu_host_id_;
92 bool reused_gpu_process_;
93 IPC::ChannelHandle channel_handle_;
94 gpu::GPUInfo gpu_info_;
95 bool finished_;
96 scoped_refptr<base::MessageLoopProxy> main_loop_;
99 scoped_refptr<BrowserGpuChannelHostFactory::EstablishRequest>
100 BrowserGpuChannelHostFactory::EstablishRequest::Create(CauseForGpuLaunch cause,
101 int gpu_client_id,
102 int gpu_host_id) {
103 scoped_refptr<EstablishRequest> establish_request =
104 new EstablishRequest(cause, gpu_client_id, gpu_host_id);
105 scoped_refptr<base::MessageLoopProxy> loop =
106 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
107 // PostTask outside the constructor to ensure at least one reference exists.
108 loop->PostTask(
109 FROM_HERE,
110 base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO,
111 establish_request));
112 return establish_request;
115 BrowserGpuChannelHostFactory::EstablishRequest::EstablishRequest(
116 CauseForGpuLaunch cause,
117 int gpu_client_id,
118 int gpu_host_id)
119 : event_(false, false),
120 cause_for_gpu_launch_(cause),
121 gpu_client_id_(gpu_client_id),
122 gpu_host_id_(gpu_host_id),
123 reused_gpu_process_(false),
124 finished_(false),
125 main_loop_(base::MessageLoopProxy::current()) {
128 void BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO() {
129 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
130 if (!host) {
131 host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
132 cause_for_gpu_launch_);
133 if (!host) {
134 LOG(ERROR) << "Failed to launch GPU process.";
135 FinishOnIO();
136 return;
138 gpu_host_id_ = host->host_id();
139 reused_gpu_process_ = false;
140 } else {
141 if (reused_gpu_process_) {
142 // We come here if we retried to establish the channel because of a
143 // failure in ChannelEstablishedOnIO, but we ended up with the same
144 // process ID, meaning the failure was not because of a channel error,
145 // but another reason. So fail now.
146 LOG(ERROR) << "Failed to create channel.";
147 FinishOnIO();
148 return;
150 reused_gpu_process_ = true;
153 host->EstablishGpuChannel(
154 gpu_client_id_,
155 true,
156 true,
157 base::Bind(
158 &BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO,
159 this));
162 void BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO(
163 const IPC::ChannelHandle& channel_handle,
164 const gpu::GPUInfo& gpu_info) {
165 if (channel_handle.name.empty() && reused_gpu_process_) {
166 // We failed after re-using the GPU process, but it may have died in the
167 // mean time. Retry to have a chance to create a fresh GPU process.
168 DVLOG(1) << "Failed to create channel on existing GPU process. Trying to "
169 "restart GPU process.";
170 EstablishOnIO();
171 } else {
172 channel_handle_ = channel_handle;
173 gpu_info_ = gpu_info;
174 FinishOnIO();
178 void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnIO() {
179 event_.Signal();
180 main_loop_->PostTask(
181 FROM_HERE,
182 base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain,
183 this));
186 void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain() {
187 if (!finished_) {
188 BrowserGpuChannelHostFactory* factory =
189 BrowserGpuChannelHostFactory::instance();
190 factory->GpuChannelEstablished();
191 finished_ = true;
195 void BrowserGpuChannelHostFactory::EstablishRequest::Wait() {
196 DCHECK(main_loop_->BelongsToCurrentThread());
198 // TODO(vadimt): Remove ScopedTracker below once crbug.com/125248 is fixed.
199 tracked_objects::ScopedTracker tracking_profile(
200 FROM_HERE_WITH_EXPLICIT_FUNCTION(
201 "125248 BrowserGpuChannelHostFactory::EstablishRequest::Wait"));
203 // We're blocking the UI thread, which is generally undesirable.
204 // In this case we need to wait for this before we can show any UI
205 // /anyway/, so it won't cause additional jank.
206 // TODO(piman): Make this asynchronous (http://crbug.com/125248).
207 TRACE_EVENT0("browser",
208 "BrowserGpuChannelHostFactory::EstablishGpuChannelSync");
209 base::ThreadRestrictions::ScopedAllowWait allow_wait;
210 event_.Wait();
212 FinishOnMain();
215 void BrowserGpuChannelHostFactory::EstablishRequest::Cancel() {
216 DCHECK(main_loop_->BelongsToCurrentThread());
217 finished_ = true;
220 bool BrowserGpuChannelHostFactory::CanUseForTesting() {
221 return GpuDataManager::GetInstance()->GpuAccessAllowed(NULL);
224 void BrowserGpuChannelHostFactory::Initialize(bool establish_gpu_channel) {
225 DCHECK(!instance_);
226 instance_ = new BrowserGpuChannelHostFactory();
227 if (establish_gpu_channel) {
228 instance_->EstablishGpuChannel(CAUSE_FOR_GPU_LAUNCH_BROWSER_STARTUP,
229 base::Closure());
233 void BrowserGpuChannelHostFactory::Terminate() {
234 DCHECK(instance_);
235 delete instance_;
236 instance_ = NULL;
239 // static
240 void BrowserGpuChannelHostFactory::EnableGpuMemoryBufferFactoryUsage(
241 gfx::GpuMemoryBuffer::Usage usage) {
242 g_enabled_gpu_memory_buffer_usages.Get().insert(usage);
245 // static
246 bool BrowserGpuChannelHostFactory::IsGpuMemoryBufferFactoryUsageEnabled(
247 gfx::GpuMemoryBuffer::Usage usage) {
248 return g_enabled_gpu_memory_buffer_usages.Get().count(usage) != 0;
251 // static
252 uint32 BrowserGpuChannelHostFactory::GetImageTextureTarget() {
253 if (!IsGpuMemoryBufferFactoryUsageEnabled(gfx::GpuMemoryBuffer::MAP))
254 return GL_TEXTURE_2D;
256 std::vector<gfx::GpuMemoryBufferType> supported_types;
257 GpuMemoryBufferFactory::GetSupportedTypes(&supported_types);
258 DCHECK(!supported_types.empty());
260 // The GPU service will always use the preferred type.
261 gfx::GpuMemoryBufferType type = supported_types[0];
263 switch (type) {
264 case gfx::SURFACE_TEXTURE_BUFFER:
265 // Surface texture backed GPU memory buffers require
266 // TEXTURE_EXTERNAL_OES.
267 return GL_TEXTURE_EXTERNAL_OES;
268 case gfx::IO_SURFACE_BUFFER:
269 // IOSurface backed images require GL_TEXTURE_RECTANGLE_ARB.
270 return GL_TEXTURE_RECTANGLE_ARB;
271 default:
272 return GL_TEXTURE_2D;
276 BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory()
277 : gpu_client_id_(ChildProcessHostImpl::GenerateChildProcessUniqueId()),
278 shutdown_event_(new base::WaitableEvent(true, false)),
279 gpu_memory_buffer_manager_(
280 new BrowserGpuMemoryBufferManager(this, gpu_client_id_)),
281 gpu_host_id_(0),
282 next_create_gpu_memory_buffer_request_id_(0) {
285 BrowserGpuChannelHostFactory::~BrowserGpuChannelHostFactory() {
286 DCHECK(IsMainThread());
287 if (pending_request_.get())
288 pending_request_->Cancel();
289 for (size_t n = 0; n < established_callbacks_.size(); n++)
290 established_callbacks_[n].Run();
291 shutdown_event_->Signal();
294 bool BrowserGpuChannelHostFactory::IsMainThread() {
295 return BrowserThread::CurrentlyOn(BrowserThread::UI);
298 base::MessageLoop* BrowserGpuChannelHostFactory::GetMainLoop() {
299 return BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::UI);
302 scoped_refptr<base::MessageLoopProxy>
303 BrowserGpuChannelHostFactory::GetIOLoopProxy() {
304 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
307 scoped_ptr<base::SharedMemory>
308 BrowserGpuChannelHostFactory::AllocateSharedMemory(size_t size) {
309 scoped_ptr<base::SharedMemory> shm(new base::SharedMemory());
310 if (!shm->CreateAnonymous(size))
311 return scoped_ptr<base::SharedMemory>();
312 return shm.Pass();
315 void BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO(
316 CreateRequest* request,
317 int32 surface_id,
318 const GPUCreateCommandBufferConfig& init_params) {
319 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
320 if (!host) {
321 request->event.Signal();
322 return;
325 gfx::GLSurfaceHandle surface =
326 GpuSurfaceTracker::Get()->GetSurfaceHandle(surface_id);
328 host->CreateViewCommandBuffer(
329 surface,
330 surface_id,
331 gpu_client_id_,
332 init_params,
333 request->route_id,
334 base::Bind(&BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO,
335 request));
338 // static
339 void BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO(
340 CreateRequest* request, CreateCommandBufferResult result) {
341 request->result = result;
342 request->event.Signal();
345 CreateCommandBufferResult BrowserGpuChannelHostFactory::CreateViewCommandBuffer(
346 int32 surface_id,
347 const GPUCreateCommandBufferConfig& init_params,
348 int32 route_id) {
349 CreateRequest request(route_id);
350 GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind(
351 &BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO,
352 base::Unretained(this),
353 &request,
354 surface_id,
355 init_params));
356 // TODO(vadimt): Remove ScopedTracker below once crbug.com/125248 is fixed.
357 tracked_objects::ScopedTracker tracking_profile(
358 FROM_HERE_WITH_EXPLICIT_FUNCTION(
359 "125248 BrowserGpuChannelHostFactory::CreateViewCommandBuffer"));
361 // We're blocking the UI thread, which is generally undesirable.
362 // In this case we need to wait for this before we can show any UI /anyway/,
363 // so it won't cause additional jank.
364 // TODO(piman): Make this asynchronous (http://crbug.com/125248).
365 TRACE_EVENT0("browser",
366 "BrowserGpuChannelHostFactory::CreateViewCommandBuffer");
367 base::ThreadRestrictions::ScopedAllowWait allow_wait;
368 request.event.Wait();
369 return request.result;
372 // Blocking the UI thread to open a GPU channel is not supported on Android.
373 // (Opening the initial channel to a child process involves handling a reply
374 // task on the UI thread first, so we cannot block here.)
375 #if !defined(OS_ANDROID)
376 GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
377 CauseForGpuLaunch cause_for_gpu_launch) {
378 EstablishGpuChannel(cause_for_gpu_launch, base::Closure());
380 if (pending_request_.get())
381 pending_request_->Wait();
383 return gpu_channel_.get();
385 #endif
387 void BrowserGpuChannelHostFactory::EstablishGpuChannel(
388 CauseForGpuLaunch cause_for_gpu_launch,
389 const base::Closure& callback) {
390 if (gpu_channel_.get() && gpu_channel_->IsLost()) {
391 DCHECK(!pending_request_.get());
392 // Recreate the channel if it has been lost.
393 gpu_channel_ = NULL;
396 if (!gpu_channel_.get() && !pending_request_.get()) {
397 // We should only get here if the context was lost.
398 pending_request_ = EstablishRequest::Create(
399 cause_for_gpu_launch, gpu_client_id_, gpu_host_id_);
402 if (!callback.is_null()) {
403 if (gpu_channel_.get())
404 callback.Run();
405 else
406 established_callbacks_.push_back(callback);
410 GpuChannelHost* BrowserGpuChannelHostFactory::GetGpuChannel() {
411 if (gpu_channel_.get() && !gpu_channel_->IsLost())
412 return gpu_channel_.get();
414 return NULL;
417 void BrowserGpuChannelHostFactory::GpuChannelEstablished() {
418 DCHECK(IsMainThread());
419 DCHECK(pending_request_.get());
420 if (pending_request_->channel_handle().name.empty()) {
421 DCHECK(!gpu_channel_.get());
422 } else {
423 GetContentClient()->SetGpuInfo(pending_request_->gpu_info());
424 gpu_channel_ =
425 GpuChannelHost::Create(this,
426 pending_request_->gpu_info(),
427 pending_request_->channel_handle(),
428 shutdown_event_.get(),
429 BrowserGpuMemoryBufferManager::current());
431 gpu_host_id_ = pending_request_->gpu_host_id();
432 pending_request_ = NULL;
434 for (size_t n = 0; n < established_callbacks_.size(); n++)
435 established_callbacks_[n].Run();
437 established_callbacks_.clear();
440 // static
441 void BrowserGpuChannelHostFactory::AddFilterOnIO(
442 int host_id,
443 scoped_refptr<IPC::MessageFilter> filter) {
444 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
446 GpuProcessHost* host = GpuProcessHost::FromID(host_id);
447 if (host)
448 host->AddFilter(filter.get());
451 bool BrowserGpuChannelHostFactory::IsGpuMemoryBufferConfigurationSupported(
452 gfx::GpuMemoryBuffer::Format format,
453 gfx::GpuMemoryBuffer::Usage usage) {
454 // Return early if usage is not enabled.
455 if (!IsGpuMemoryBufferFactoryUsageEnabled(usage))
456 return false;
458 // Preferred type is always used by factory.
459 std::vector<gfx::GpuMemoryBufferType> supported_types;
460 GpuMemoryBufferFactory::GetSupportedTypes(&supported_types);
461 DCHECK(!supported_types.empty());
462 switch (supported_types[0]) {
463 case gfx::SHARED_MEMORY_BUFFER:
464 // Shared memory buffers must be created in-process.
465 return false;
466 #if defined(OS_MACOSX)
467 case gfx::IO_SURFACE_BUFFER:
468 return GpuMemoryBufferFactoryIOSurface::
469 IsGpuMemoryBufferConfigurationSupported(format, usage);
470 #endif
471 #if defined(OS_ANDROID)
472 case gfx::SURFACE_TEXTURE_BUFFER:
473 return GpuMemoryBufferFactorySurfaceTexture::
474 IsGpuMemoryBufferConfigurationSupported(format, usage);
475 #endif
476 #if defined(USE_OZONE)
477 case gfx::OZONE_NATIVE_BUFFER:
478 return GpuMemoryBufferFactoryOzoneNativeBuffer::
479 IsGpuMemoryBufferConfigurationSupported(format, usage);
480 #endif
481 default:
482 NOTREACHED();
483 return false;
487 void BrowserGpuChannelHostFactory::CreateGpuMemoryBuffer(
488 gfx::GpuMemoryBufferId id,
489 const gfx::Size& size,
490 gfx::GpuMemoryBuffer::Format format,
491 gfx::GpuMemoryBuffer::Usage usage,
492 int client_id,
493 int32 surface_id,
494 const CreateGpuMemoryBufferCallback& callback) {
495 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
497 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
498 if (!host) {
499 callback.Run(gfx::GpuMemoryBufferHandle());
500 return;
503 uint32 request_id = next_create_gpu_memory_buffer_request_id_++;
504 create_gpu_memory_buffer_requests_[request_id] = callback;
506 host->CreateGpuMemoryBuffer(
507 id, size, format, usage, client_id, surface_id,
508 base::Bind(&BrowserGpuChannelHostFactory::OnGpuMemoryBufferCreated,
509 base::Unretained(this), request_id));
512 void BrowserGpuChannelHostFactory::DestroyGpuMemoryBuffer(
513 gfx::GpuMemoryBufferId id,
514 int client_id,
515 int32 sync_point) {
516 BrowserThread::PostTask(
517 BrowserThread::IO,
518 FROM_HERE,
519 base::Bind(&BrowserGpuChannelHostFactory::DestroyGpuMemoryBufferOnIO,
520 base::Unretained(this),
522 client_id,
523 sync_point));
526 void BrowserGpuChannelHostFactory::DestroyGpuMemoryBufferOnIO(
527 gfx::GpuMemoryBufferId id,
528 int client_id,
529 int32 sync_point) {
530 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
532 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
533 if (!host)
534 return;
536 host->DestroyGpuMemoryBuffer(id, client_id, sync_point);
539 void BrowserGpuChannelHostFactory::OnGpuMemoryBufferCreated(
540 uint32 request_id,
541 const gfx::GpuMemoryBufferHandle& handle) {
542 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
544 CreateGpuMemoryBufferCallbackMap::iterator iter =
545 create_gpu_memory_buffer_requests_.find(request_id);
546 DCHECK(iter != create_gpu_memory_buffer_requests_.end());
547 iter->second.Run(handle);
548 create_gpu_memory_buffer_requests_.erase(iter);
551 } // namespace content