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"
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"
33 #if defined(OS_ANDROID)
34 #include "content/common/gpu/gpu_memory_buffer_factory_surface_texture.h"
37 #if defined(USE_OZONE)
38 #include "content/common/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h"
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
)
55 result(CREATE_COMMAND_BUFFER_FAILED
) {}
57 base::WaitableEvent event
;
60 CreateCommandBufferResult result
;
63 class BrowserGpuChannelHostFactory::EstablishRequest
64 : public base::RefCountedThreadSafe
<EstablishRequest
> {
66 static scoped_refptr
<EstablishRequest
> Create(CauseForGpuLaunch cause
,
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_
; }
77 friend class base::RefCountedThreadSafe
<EstablishRequest
>;
78 explicit EstablishRequest(CauseForGpuLaunch cause
,
81 ~EstablishRequest() {}
83 void OnEstablishedOnIO(const IPC::ChannelHandle
& channel_handle
,
84 const gpu::GPUInfo
& gpu_info
);
88 base::WaitableEvent event_
;
89 CauseForGpuLaunch cause_for_gpu_launch_
;
90 const int gpu_client_id_
;
92 bool reused_gpu_process_
;
93 IPC::ChannelHandle channel_handle_
;
94 gpu::GPUInfo gpu_info_
;
96 scoped_refptr
<base::MessageLoopProxy
> main_loop_
;
99 scoped_refptr
<BrowserGpuChannelHostFactory::EstablishRequest
>
100 BrowserGpuChannelHostFactory::EstablishRequest::Create(CauseForGpuLaunch cause
,
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.
110 base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO
,
112 return establish_request
;
115 BrowserGpuChannelHostFactory::EstablishRequest::EstablishRequest(
116 CauseForGpuLaunch cause
,
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),
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(
133 "BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO"));
134 GpuProcessHost
* host
= GpuProcessHost::FromID(gpu_host_id_
);
136 host
= GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED
,
137 cause_for_gpu_launch_
);
139 LOG(ERROR
) << "Failed to launch GPU process.";
143 gpu_host_id_
= host
->host_id();
144 reused_gpu_process_
= false;
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.";
155 reused_gpu_process_
= true;
158 host
->EstablishGpuChannel(
163 &BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO
,
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.";
177 channel_handle_
= channel_handle
;
178 gpu_info_
= gpu_info
;
183 void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnIO() {
185 main_loop_
->PostTask(
187 base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain
,
191 void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain() {
193 BrowserGpuChannelHostFactory
* factory
=
194 BrowserGpuChannelHostFactory::instance();
195 factory
->GpuChannelEstablished();
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
;
220 void BrowserGpuChannelHostFactory::EstablishRequest::Cancel() {
221 DCHECK(main_loop_
->BelongsToCurrentThread());
225 bool BrowserGpuChannelHostFactory::CanUseForTesting() {
226 return GpuDataManager::GetInstance()->GpuAccessAllowed(NULL
);
229 void BrowserGpuChannelHostFactory::Initialize(bool establish_gpu_channel
) {
231 instance_
= new BrowserGpuChannelHostFactory();
232 if (establish_gpu_channel
) {
233 instance_
->EstablishGpuChannel(CAUSE_FOR_GPU_LAUNCH_BROWSER_STARTUP
,
238 void BrowserGpuChannelHostFactory::Terminate() {
245 void BrowserGpuChannelHostFactory::EnableGpuMemoryBufferFactoryUsage(
246 gfx::GpuMemoryBuffer::Usage usage
) {
247 g_enabled_gpu_memory_buffer_usages
.Get().insert(usage
);
251 bool BrowserGpuChannelHostFactory::IsGpuMemoryBufferFactoryUsageEnabled(
252 gfx::GpuMemoryBuffer::Usage usage
) {
253 return g_enabled_gpu_memory_buffer_usages
.Get().count(usage
) != 0;
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];
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
;
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_
)),
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
>();
321 void BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO(
322 CreateRequest
* request
,
324 const GPUCreateCommandBufferConfig
& init_params
) {
325 GpuProcessHost
* host
= GpuProcessHost::FromID(gpu_host_id_
);
327 request
->event
.Signal();
331 gfx::GLSurfaceHandle surface
=
332 GpuSurfaceTracker::Get()->GetSurfaceHandle(surface_id
);
334 host
->CreateViewCommandBuffer(
340 base::Bind(&BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO
,
345 void BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO(
346 CreateRequest
* request
, CreateCommandBufferResult result
) {
347 request
->result
= result
;
348 request
->event
.Signal();
351 CreateCommandBufferResult
BrowserGpuChannelHostFactory::CreateViewCommandBuffer(
353 const GPUCreateCommandBufferConfig
& init_params
,
355 CreateRequest
request(route_id
);
356 GetIOLoopProxy()->PostTask(FROM_HERE
, base::Bind(
357 &BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO
,
358 base::Unretained(this),
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();
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.
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())
412 established_callbacks_
.push_back(callback
);
416 GpuChannelHost
* BrowserGpuChannelHostFactory::GetGpuChannel() {
417 if (gpu_channel_
.get() && !gpu_channel_
->IsLost())
418 return gpu_channel_
.get();
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());
429 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/466866
431 tracked_objects::ScopedTracker
tracking_profile1(
432 FROM_HERE_WITH_EXPLICIT_FUNCTION(
433 "466866 BrowserGpuChannelHostFactory::GpuChannelEstablished1"));
434 GetContentClient()->SetGpuInfo(pending_request_
->gpu_info());
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
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();
458 void BrowserGpuChannelHostFactory::AddFilterOnIO(
460 scoped_refptr
<IPC::MessageFilter
> filter
) {
461 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
463 GpuProcessHost
* host
= GpuProcessHost::FromID(host_id
);
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
))
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.
483 #if defined(OS_MACOSX)
484 case gfx::IO_SURFACE_BUFFER
:
485 return GpuMemoryBufferFactoryIOSurface::
486 IsGpuMemoryBufferConfigurationSupported(format
, usage
);
488 #if defined(OS_ANDROID)
489 case gfx::SURFACE_TEXTURE_BUFFER
:
490 return GpuMemoryBufferFactorySurfaceTexture::
491 IsGpuMemoryBufferConfigurationSupported(format
, usage
);
493 #if defined(USE_OZONE)
494 case gfx::OZONE_NATIVE_BUFFER
:
495 return GpuMemoryBufferFactoryOzoneNativeBuffer::
496 IsGpuMemoryBufferConfigurationSupported(format
, usage
);
504 void BrowserGpuChannelHostFactory::CreateGpuMemoryBuffer(
505 gfx::GpuMemoryBufferId id
,
506 const gfx::Size
& size
,
507 gfx::GpuMemoryBuffer::Format format
,
508 gfx::GpuMemoryBuffer::Usage usage
,
511 const CreateGpuMemoryBufferCallback
& callback
) {
512 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
514 GpuProcessHost
* host
= GpuProcessHost::FromID(gpu_host_id_
);
516 callback
.Run(gfx::GpuMemoryBufferHandle());
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
,
533 BrowserThread::PostTask(
536 base::Bind(&BrowserGpuChannelHostFactory::DestroyGpuMemoryBufferOnIO
,
537 base::Unretained(this),
543 void BrowserGpuChannelHostFactory::DestroyGpuMemoryBufferOnIO(
544 gfx::GpuMemoryBufferId id
,
547 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
549 GpuProcessHost
* host
= GpuProcessHost::FromID(gpu_host_id_
);
553 host
->DestroyGpuMemoryBuffer(id
, client_id
, sync_point
);
556 void BrowserGpuChannelHostFactory::OnGpuMemoryBufferCreated(
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