Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / content / browser / gpu / browser_gpu_channel_host_factory.cc
blob9edb9677c56abc2b4801d5aa62193d362236b95c
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 // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
130 tracked_objects::ScopedTracker tracking_profile(
131 FROM_HERE_WITH_EXPLICIT_FUNCTION(
132 "477117 "
133 "BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO"));
134 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
135 if (!host) {
136 host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
137 cause_for_gpu_launch_);
138 if (!host) {
139 LOG(ERROR) << "Failed to launch GPU process.";
140 FinishOnIO();
141 return;
143 gpu_host_id_ = host->host_id();
144 reused_gpu_process_ = false;
145 } else {
146 if (reused_gpu_process_) {
147 // We come here if we retried to establish the channel because of a
148 // failure in ChannelEstablishedOnIO, but we ended up with the same
149 // process ID, meaning the failure was not because of a channel error,
150 // but another reason. So fail now.
151 LOG(ERROR) << "Failed to create channel.";
152 FinishOnIO();
153 return;
155 reused_gpu_process_ = true;
158 host->EstablishGpuChannel(
159 gpu_client_id_,
160 true,
161 true,
162 base::Bind(
163 &BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO,
164 this));
167 void BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO(
168 const IPC::ChannelHandle& channel_handle,
169 const gpu::GPUInfo& gpu_info) {
170 if (channel_handle.name.empty() && reused_gpu_process_) {
171 // We failed after re-using the GPU process, but it may have died in the
172 // mean time. Retry to have a chance to create a fresh GPU process.
173 DVLOG(1) << "Failed to create channel on existing GPU process. Trying to "
174 "restart GPU process.";
175 EstablishOnIO();
176 } else {
177 channel_handle_ = channel_handle;
178 gpu_info_ = gpu_info;
179 FinishOnIO();
183 void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnIO() {
184 event_.Signal();
185 main_loop_->PostTask(
186 FROM_HERE,
187 base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain,
188 this));
191 void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain() {
192 if (!finished_) {
193 BrowserGpuChannelHostFactory* factory =
194 BrowserGpuChannelHostFactory::instance();
195 factory->GpuChannelEstablished();
196 finished_ = true;
200 void BrowserGpuChannelHostFactory::EstablishRequest::Wait() {
201 DCHECK(main_loop_->BelongsToCurrentThread());
203 // TODO(vadimt): Remove ScopedTracker below once crbug.com/125248 is fixed.
204 tracked_objects::ScopedTracker tracking_profile(
205 FROM_HERE_WITH_EXPLICIT_FUNCTION(
206 "125248 BrowserGpuChannelHostFactory::EstablishRequest::Wait"));
208 // We're blocking the UI thread, which is generally undesirable.
209 // In this case we need to wait for this before we can show any UI
210 // /anyway/, so it won't cause additional jank.
211 // TODO(piman): Make this asynchronous (http://crbug.com/125248).
212 TRACE_EVENT0("browser",
213 "BrowserGpuChannelHostFactory::EstablishGpuChannelSync");
214 base::ThreadRestrictions::ScopedAllowWait allow_wait;
215 event_.Wait();
217 FinishOnMain();
220 void BrowserGpuChannelHostFactory::EstablishRequest::Cancel() {
221 DCHECK(main_loop_->BelongsToCurrentThread());
222 finished_ = true;
225 bool BrowserGpuChannelHostFactory::CanUseForTesting() {
226 return GpuDataManager::GetInstance()->GpuAccessAllowed(NULL);
229 void BrowserGpuChannelHostFactory::Initialize(bool establish_gpu_channel) {
230 DCHECK(!instance_);
231 instance_ = new BrowserGpuChannelHostFactory();
232 if (establish_gpu_channel) {
233 instance_->EstablishGpuChannel(CAUSE_FOR_GPU_LAUNCH_BROWSER_STARTUP,
234 base::Closure());
238 void BrowserGpuChannelHostFactory::Terminate() {
239 DCHECK(instance_);
240 delete instance_;
241 instance_ = NULL;
244 // static
245 void BrowserGpuChannelHostFactory::EnableGpuMemoryBufferFactoryUsage(
246 gfx::GpuMemoryBuffer::Usage usage) {
247 g_enabled_gpu_memory_buffer_usages.Get().insert(usage);
250 // static
251 bool BrowserGpuChannelHostFactory::IsGpuMemoryBufferFactoryUsageEnabled(
252 gfx::GpuMemoryBuffer::Usage usage) {
253 return g_enabled_gpu_memory_buffer_usages.Get().count(usage) != 0;
256 // static
257 uint32 BrowserGpuChannelHostFactory::GetImageTextureTarget() {
258 if (!IsGpuMemoryBufferFactoryUsageEnabled(gfx::GpuMemoryBuffer::MAP))
259 return GL_TEXTURE_2D;
261 std::vector<gfx::GpuMemoryBufferType> supported_types;
262 GpuMemoryBufferFactory::GetSupportedTypes(&supported_types);
263 DCHECK(!supported_types.empty());
265 // The GPU service will always use the preferred type.
266 gfx::GpuMemoryBufferType type = supported_types[0];
268 switch (type) {
269 case gfx::SURFACE_TEXTURE_BUFFER:
270 case gfx::OZONE_NATIVE_BUFFER:
271 // GPU memory buffers that are shared with the GL using EGLImages require
272 // TEXTURE_EXTERNAL_OES.
273 return GL_TEXTURE_EXTERNAL_OES;
274 case gfx::IO_SURFACE_BUFFER:
275 // IOSurface backed images require GL_TEXTURE_RECTANGLE_ARB.
276 return GL_TEXTURE_RECTANGLE_ARB;
277 default:
278 return GL_TEXTURE_2D;
282 BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory()
283 : gpu_client_id_(ChildProcessHostImpl::GenerateChildProcessUniqueId()),
284 shutdown_event_(new base::WaitableEvent(true, false)),
285 gpu_memory_buffer_manager_(
286 new BrowserGpuMemoryBufferManager(this, gpu_client_id_)),
287 gpu_host_id_(0),
288 next_create_gpu_memory_buffer_request_id_(0) {
291 BrowserGpuChannelHostFactory::~BrowserGpuChannelHostFactory() {
292 DCHECK(IsMainThread());
293 if (pending_request_.get())
294 pending_request_->Cancel();
295 for (size_t n = 0; n < established_callbacks_.size(); n++)
296 established_callbacks_[n].Run();
297 shutdown_event_->Signal();
300 bool BrowserGpuChannelHostFactory::IsMainThread() {
301 return BrowserThread::CurrentlyOn(BrowserThread::UI);
304 base::MessageLoop* BrowserGpuChannelHostFactory::GetMainLoop() {
305 return BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::UI);
308 scoped_refptr<base::MessageLoopProxy>
309 BrowserGpuChannelHostFactory::GetIOLoopProxy() {
310 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
313 scoped_ptr<base::SharedMemory>
314 BrowserGpuChannelHostFactory::AllocateSharedMemory(size_t size) {
315 scoped_ptr<base::SharedMemory> shm(new base::SharedMemory());
316 if (!shm->CreateAnonymous(size))
317 return scoped_ptr<base::SharedMemory>();
318 return shm.Pass();
321 void BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO(
322 CreateRequest* request,
323 int32 surface_id,
324 const GPUCreateCommandBufferConfig& init_params) {
325 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
326 if (!host) {
327 request->event.Signal();
328 return;
331 gfx::GLSurfaceHandle surface =
332 GpuSurfaceTracker::Get()->GetSurfaceHandle(surface_id);
334 host->CreateViewCommandBuffer(
335 surface,
336 surface_id,
337 gpu_client_id_,
338 init_params,
339 request->route_id,
340 base::Bind(&BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO,
341 request));
344 // static
345 void BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO(
346 CreateRequest* request, CreateCommandBufferResult result) {
347 request->result = result;
348 request->event.Signal();
351 CreateCommandBufferResult BrowserGpuChannelHostFactory::CreateViewCommandBuffer(
352 int32 surface_id,
353 const GPUCreateCommandBufferConfig& init_params,
354 int32 route_id) {
355 CreateRequest request(route_id);
356 GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind(
357 &BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO,
358 base::Unretained(this),
359 &request,
360 surface_id,
361 init_params));
362 // TODO(vadimt): Remove ScopedTracker below once crbug.com/125248 is fixed.
363 tracked_objects::ScopedTracker tracking_profile(
364 FROM_HERE_WITH_EXPLICIT_FUNCTION(
365 "125248 BrowserGpuChannelHostFactory::CreateViewCommandBuffer"));
367 // We're blocking the UI thread, which is generally undesirable.
368 // In this case we need to wait for this before we can show any UI /anyway/,
369 // so it won't cause additional jank.
370 // TODO(piman): Make this asynchronous (http://crbug.com/125248).
371 TRACE_EVENT0("browser",
372 "BrowserGpuChannelHostFactory::CreateViewCommandBuffer");
373 base::ThreadRestrictions::ScopedAllowWait allow_wait;
374 request.event.Wait();
375 return request.result;
378 // Blocking the UI thread to open a GPU channel is not supported on Android.
379 // (Opening the initial channel to a child process involves handling a reply
380 // task on the UI thread first, so we cannot block here.)
381 #if !defined(OS_ANDROID)
382 GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
383 CauseForGpuLaunch cause_for_gpu_launch) {
384 EstablishGpuChannel(cause_for_gpu_launch, base::Closure());
386 if (pending_request_.get())
387 pending_request_->Wait();
389 return gpu_channel_.get();
391 #endif
393 void BrowserGpuChannelHostFactory::EstablishGpuChannel(
394 CauseForGpuLaunch cause_for_gpu_launch,
395 const base::Closure& callback) {
396 if (gpu_channel_.get() && gpu_channel_->IsLost()) {
397 DCHECK(!pending_request_.get());
398 // Recreate the channel if it has been lost.
399 gpu_channel_ = NULL;
402 if (!gpu_channel_.get() && !pending_request_.get()) {
403 // We should only get here if the context was lost.
404 pending_request_ = EstablishRequest::Create(
405 cause_for_gpu_launch, gpu_client_id_, gpu_host_id_);
408 if (!callback.is_null()) {
409 if (gpu_channel_.get())
410 callback.Run();
411 else
412 established_callbacks_.push_back(callback);
416 GpuChannelHost* BrowserGpuChannelHostFactory::GetGpuChannel() {
417 if (gpu_channel_.get() && !gpu_channel_->IsLost())
418 return gpu_channel_.get();
420 return NULL;
423 void BrowserGpuChannelHostFactory::GpuChannelEstablished() {
424 DCHECK(IsMainThread());
425 DCHECK(pending_request_.get());
426 if (pending_request_->channel_handle().name.empty()) {
427 DCHECK(!gpu_channel_.get());
428 } else {
429 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/466866
430 // is fixed.
431 tracked_objects::ScopedTracker tracking_profile1(
432 FROM_HERE_WITH_EXPLICIT_FUNCTION(
433 "466866 BrowserGpuChannelHostFactory::GpuChannelEstablished1"));
434 GetContentClient()->SetGpuInfo(pending_request_->gpu_info());
435 gpu_channel_ =
436 GpuChannelHost::Create(this,
437 pending_request_->gpu_info(),
438 pending_request_->channel_handle(),
439 shutdown_event_.get(),
440 BrowserGpuMemoryBufferManager::current());
442 gpu_host_id_ = pending_request_->gpu_host_id();
443 pending_request_ = NULL;
445 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/466866 is
446 // fixed.
447 tracked_objects::ScopedTracker tracking_profile2(
448 FROM_HERE_WITH_EXPLICIT_FUNCTION(
449 "466866 BrowserGpuChannelHostFactory::GpuChannelEstablished2"));
451 for (size_t n = 0; n < established_callbacks_.size(); n++)
452 established_callbacks_[n].Run();
454 established_callbacks_.clear();
457 // static
458 void BrowserGpuChannelHostFactory::AddFilterOnIO(
459 int host_id,
460 scoped_refptr<IPC::MessageFilter> filter) {
461 DCHECK_CURRENTLY_ON(BrowserThread::IO);
463 GpuProcessHost* host = GpuProcessHost::FromID(host_id);
464 if (host)
465 host->AddFilter(filter.get());
468 bool BrowserGpuChannelHostFactory::IsGpuMemoryBufferConfigurationSupported(
469 gfx::GpuMemoryBuffer::Format format,
470 gfx::GpuMemoryBuffer::Usage usage) {
471 // Return early if usage is not enabled.
472 if (!IsGpuMemoryBufferFactoryUsageEnabled(usage))
473 return false;
475 // Preferred type is always used by factory.
476 std::vector<gfx::GpuMemoryBufferType> supported_types;
477 GpuMemoryBufferFactory::GetSupportedTypes(&supported_types);
478 DCHECK(!supported_types.empty());
479 switch (supported_types[0]) {
480 case gfx::SHARED_MEMORY_BUFFER:
481 // Shared memory buffers must be created in-process.
482 return false;
483 #if defined(OS_MACOSX)
484 case gfx::IO_SURFACE_BUFFER:
485 return GpuMemoryBufferFactoryIOSurface::
486 IsGpuMemoryBufferConfigurationSupported(format, usage);
487 #endif
488 #if defined(OS_ANDROID)
489 case gfx::SURFACE_TEXTURE_BUFFER:
490 return GpuMemoryBufferFactorySurfaceTexture::
491 IsGpuMemoryBufferConfigurationSupported(format, usage);
492 #endif
493 #if defined(USE_OZONE)
494 case gfx::OZONE_NATIVE_BUFFER:
495 return GpuMemoryBufferFactoryOzoneNativeBuffer::
496 IsGpuMemoryBufferConfigurationSupported(format, usage);
497 #endif
498 default:
499 NOTREACHED();
500 return false;
504 void BrowserGpuChannelHostFactory::CreateGpuMemoryBuffer(
505 gfx::GpuMemoryBufferId id,
506 const gfx::Size& size,
507 gfx::GpuMemoryBuffer::Format format,
508 gfx::GpuMemoryBuffer::Usage usage,
509 int client_id,
510 int32 surface_id,
511 const CreateGpuMemoryBufferCallback& callback) {
512 DCHECK_CURRENTLY_ON(BrowserThread::IO);
514 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
515 if (!host) {
516 callback.Run(gfx::GpuMemoryBufferHandle());
517 return;
520 uint32 request_id = next_create_gpu_memory_buffer_request_id_++;
521 create_gpu_memory_buffer_requests_[request_id] = callback;
523 host->CreateGpuMemoryBuffer(
524 id, size, format, usage, client_id, surface_id,
525 base::Bind(&BrowserGpuChannelHostFactory::OnGpuMemoryBufferCreated,
526 base::Unretained(this), request_id));
529 void BrowserGpuChannelHostFactory::DestroyGpuMemoryBuffer(
530 gfx::GpuMemoryBufferId id,
531 int client_id,
532 int32 sync_point) {
533 BrowserThread::PostTask(
534 BrowserThread::IO,
535 FROM_HERE,
536 base::Bind(&BrowserGpuChannelHostFactory::DestroyGpuMemoryBufferOnIO,
537 base::Unretained(this),
539 client_id,
540 sync_point));
543 void BrowserGpuChannelHostFactory::DestroyGpuMemoryBufferOnIO(
544 gfx::GpuMemoryBufferId id,
545 int client_id,
546 int32 sync_point) {
547 DCHECK_CURRENTLY_ON(BrowserThread::IO);
549 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
550 if (!host)
551 return;
553 host->DestroyGpuMemoryBuffer(id, client_id, sync_point);
556 void BrowserGpuChannelHostFactory::OnGpuMemoryBufferCreated(
557 uint32 request_id,
558 const gfx::GpuMemoryBufferHandle& handle) {
559 DCHECK_CURRENTLY_ON(BrowserThread::IO);
561 CreateGpuMemoryBufferCallbackMap::iterator iter =
562 create_gpu_memory_buffer_requests_.find(request_id);
563 DCHECK(iter != create_gpu_memory_buffer_requests_.end());
564 iter->second.Run(handle);
565 create_gpu_memory_buffer_requests_.erase(iter);
568 } // namespace content