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/debug/trace_event.h"
11 #include "base/synchronization/waitable_event.h"
12 #include "base/threading/thread_restrictions.h"
13 #include "base/tracked_objects.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 "ipc/ipc_channel_handle.h"
25 #include "ipc/ipc_forwarding_message_filter.h"
26 #include "ipc/message_filter.h"
28 #if defined(OS_MACOSX)
29 #include "content/common/gpu/gpu_memory_buffer_factory_io_surface.h"
32 #if defined(OS_ANDROID)
33 #include "content/common/gpu/gpu_memory_buffer_factory_surface_texture.h"
36 #if defined(USE_OZONE)
37 #include "content/common/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h"
43 base::LazyInstance
<std::set
<gfx::GpuMemoryBuffer::Usage
>>
44 g_enabled_gpu_memory_buffer_usages
;
47 BrowserGpuChannelHostFactory
* BrowserGpuChannelHostFactory::instance_
= NULL
;
49 struct BrowserGpuChannelHostFactory::CreateRequest
{
50 CreateRequest(int32 route_id
)
54 result(CREATE_COMMAND_BUFFER_FAILED
) {}
56 base::WaitableEvent event
;
59 CreateCommandBufferResult result
;
62 class BrowserGpuChannelHostFactory::EstablishRequest
63 : public base::RefCountedThreadSafe
<EstablishRequest
> {
65 static scoped_refptr
<EstablishRequest
> Create(CauseForGpuLaunch cause
,
71 int gpu_host_id() { return gpu_host_id_
; }
72 IPC::ChannelHandle
& channel_handle() { return channel_handle_
; }
73 gpu::GPUInfo
gpu_info() { return gpu_info_
; }
76 friend class base::RefCountedThreadSafe
<EstablishRequest
>;
77 explicit EstablishRequest(CauseForGpuLaunch cause
,
80 ~EstablishRequest() {}
82 void OnEstablishedOnIO(const IPC::ChannelHandle
& channel_handle
,
83 const gpu::GPUInfo
& gpu_info
);
87 base::WaitableEvent event_
;
88 CauseForGpuLaunch cause_for_gpu_launch_
;
89 const int gpu_client_id_
;
91 bool reused_gpu_process_
;
92 IPC::ChannelHandle channel_handle_
;
93 gpu::GPUInfo gpu_info_
;
95 scoped_refptr
<base::MessageLoopProxy
> main_loop_
;
98 scoped_refptr
<BrowserGpuChannelHostFactory::EstablishRequest
>
99 BrowserGpuChannelHostFactory::EstablishRequest::Create(CauseForGpuLaunch cause
,
102 scoped_refptr
<EstablishRequest
> establish_request
=
103 new EstablishRequest(cause
, gpu_client_id
, gpu_host_id
);
104 scoped_refptr
<base::MessageLoopProxy
> loop
=
105 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO
);
106 // PostTask outside the constructor to ensure at least one reference exists.
109 base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO
,
111 return establish_request
;
114 BrowserGpuChannelHostFactory::EstablishRequest::EstablishRequest(
115 CauseForGpuLaunch cause
,
118 : event_(false, false),
119 cause_for_gpu_launch_(cause
),
120 gpu_client_id_(gpu_client_id
),
121 gpu_host_id_(gpu_host_id
),
122 reused_gpu_process_(false),
124 main_loop_(base::MessageLoopProxy::current()) {
127 void BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO() {
128 GpuProcessHost
* host
= GpuProcessHost::FromID(gpu_host_id_
);
130 host
= GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED
,
131 cause_for_gpu_launch_
);
133 LOG(ERROR
) << "Failed to launch GPU process.";
137 gpu_host_id_
= host
->host_id();
138 reused_gpu_process_
= false;
140 if (reused_gpu_process_
) {
141 // We come here if we retried to establish the channel because of a
142 // failure in ChannelEstablishedOnIO, but we ended up with the same
143 // process ID, meaning the failure was not because of a channel error,
144 // but another reason. So fail now.
145 LOG(ERROR
) << "Failed to create channel.";
149 reused_gpu_process_
= true;
152 host
->EstablishGpuChannel(
157 &BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO
,
161 void BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO(
162 const IPC::ChannelHandle
& channel_handle
,
163 const gpu::GPUInfo
& gpu_info
) {
164 if (channel_handle
.name
.empty() && reused_gpu_process_
) {
165 // We failed after re-using the GPU process, but it may have died in the
166 // mean time. Retry to have a chance to create a fresh GPU process.
167 DVLOG(1) << "Failed to create channel on existing GPU process. Trying to "
168 "restart GPU process.";
171 channel_handle_
= channel_handle
;
172 gpu_info_
= gpu_info
;
177 void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnIO() {
179 main_loop_
->PostTask(
181 base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain
,
185 void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain() {
187 BrowserGpuChannelHostFactory
* factory
=
188 BrowserGpuChannelHostFactory::instance();
189 factory
->GpuChannelEstablished();
194 void BrowserGpuChannelHostFactory::EstablishRequest::Wait() {
195 DCHECK(main_loop_
->BelongsToCurrentThread());
197 // Since the current task synchronously waits for establishing a GPU
198 // channel, it shouldn't be tallied because its execution time has nothing
199 // to do with its efficiency. Using task stopwatch to exclude the waiting
200 // time from the current task run time.
201 tracked_objects::TaskStopwatch stopwatch
;
204 // We're blocking the UI thread, which is generally undesirable.
205 // In this case we need to wait for this before we can show any UI
206 // /anyway/, so it won't cause additional jank.
207 // TODO(piman): Make this asynchronous (http://crbug.com/125248).
208 TRACE_EVENT0("browser",
209 "BrowserGpuChannelHostFactory::EstablishGpuChannelSync");
210 base::ThreadRestrictions::ScopedAllowWait allow_wait
;
218 void BrowserGpuChannelHostFactory::EstablishRequest::Cancel() {
219 DCHECK(main_loop_
->BelongsToCurrentThread());
223 bool BrowserGpuChannelHostFactory::CanUseForTesting() {
224 return GpuDataManager::GetInstance()->GpuAccessAllowed(NULL
);
227 void BrowserGpuChannelHostFactory::Initialize(bool establish_gpu_channel
) {
229 instance_
= new BrowserGpuChannelHostFactory();
230 if (establish_gpu_channel
) {
231 instance_
->EstablishGpuChannel(CAUSE_FOR_GPU_LAUNCH_BROWSER_STARTUP
,
236 void BrowserGpuChannelHostFactory::Terminate() {
243 void BrowserGpuChannelHostFactory::EnableGpuMemoryBufferFactoryUsage(
244 gfx::GpuMemoryBuffer::Usage usage
) {
245 g_enabled_gpu_memory_buffer_usages
.Get().insert(usage
);
249 bool BrowserGpuChannelHostFactory::IsGpuMemoryBufferFactoryUsageEnabled(
250 gfx::GpuMemoryBuffer::Usage usage
) {
251 return g_enabled_gpu_memory_buffer_usages
.Get().count(usage
) != 0;
254 BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory()
255 : gpu_client_id_(ChildProcessHostImpl::GenerateChildProcessUniqueId()),
256 shutdown_event_(new base::WaitableEvent(true, false)),
257 gpu_memory_buffer_manager_(
258 new BrowserGpuMemoryBufferManager(this, gpu_client_id_
)),
260 next_create_gpu_memory_buffer_request_id_(0) {
263 BrowserGpuChannelHostFactory::~BrowserGpuChannelHostFactory() {
264 DCHECK(IsMainThread());
265 if (pending_request_
.get())
266 pending_request_
->Cancel();
267 for (size_t n
= 0; n
< established_callbacks_
.size(); n
++)
268 established_callbacks_
[n
].Run();
269 shutdown_event_
->Signal();
272 bool BrowserGpuChannelHostFactory::IsMainThread() {
273 return BrowserThread::CurrentlyOn(BrowserThread::UI
);
276 base::MessageLoop
* BrowserGpuChannelHostFactory::GetMainLoop() {
277 return BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::UI
);
280 scoped_refptr
<base::MessageLoopProxy
>
281 BrowserGpuChannelHostFactory::GetIOLoopProxy() {
282 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO
);
285 scoped_ptr
<base::SharedMemory
>
286 BrowserGpuChannelHostFactory::AllocateSharedMemory(size_t size
) {
287 scoped_ptr
<base::SharedMemory
> shm(new base::SharedMemory());
288 if (!shm
->CreateAnonymous(size
))
289 return scoped_ptr
<base::SharedMemory
>();
293 void BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO(
294 CreateRequest
* request
,
296 const GPUCreateCommandBufferConfig
& init_params
) {
297 GpuProcessHost
* host
= GpuProcessHost::FromID(gpu_host_id_
);
299 request
->event
.Signal();
303 gfx::GLSurfaceHandle surface
=
304 GpuSurfaceTracker::Get()->GetSurfaceHandle(surface_id
);
306 host
->CreateViewCommandBuffer(
312 base::Bind(&BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO
,
317 void BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO(
318 CreateRequest
* request
, CreateCommandBufferResult result
) {
319 request
->result
= result
;
320 request
->event
.Signal();
323 CreateCommandBufferResult
BrowserGpuChannelHostFactory::CreateViewCommandBuffer(
325 const GPUCreateCommandBufferConfig
& init_params
,
327 CreateRequest
request(route_id
);
328 GetIOLoopProxy()->PostTask(FROM_HERE
, base::Bind(
329 &BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO
,
330 base::Unretained(this),
334 // We're blocking the UI thread, which is generally undesirable.
335 // In this case we need to wait for this before we can show any UI /anyway/,
336 // so it won't cause additional jank.
337 // TODO(piman): Make this asynchronous (http://crbug.com/125248).
338 TRACE_EVENT0("browser",
339 "BrowserGpuChannelHostFactory::CreateViewCommandBuffer");
340 base::ThreadRestrictions::ScopedAllowWait allow_wait
;
341 request
.event
.Wait();
342 return request
.result
;
345 // Blocking the UI thread to open a GPU channel is not supported on Android.
346 // (Opening the initial channel to a child process involves handling a reply
347 // task on the UI thread first, so we cannot block here.)
348 #if !defined(OS_ANDROID)
349 GpuChannelHost
* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
350 CauseForGpuLaunch cause_for_gpu_launch
) {
351 EstablishGpuChannel(cause_for_gpu_launch
, base::Closure());
353 if (pending_request_
.get())
354 pending_request_
->Wait();
356 return gpu_channel_
.get();
360 void BrowserGpuChannelHostFactory::EstablishGpuChannel(
361 CauseForGpuLaunch cause_for_gpu_launch
,
362 const base::Closure
& callback
) {
363 if (gpu_channel_
.get() && gpu_channel_
->IsLost()) {
364 DCHECK(!pending_request_
.get());
365 // Recreate the channel if it has been lost.
369 if (!gpu_channel_
.get() && !pending_request_
.get()) {
370 // We should only get here if the context was lost.
371 pending_request_
= EstablishRequest::Create(
372 cause_for_gpu_launch
, gpu_client_id_
, gpu_host_id_
);
375 if (!callback
.is_null()) {
376 if (gpu_channel_
.get())
379 established_callbacks_
.push_back(callback
);
383 GpuChannelHost
* BrowserGpuChannelHostFactory::GetGpuChannel() {
384 if (gpu_channel_
.get() && !gpu_channel_
->IsLost())
385 return gpu_channel_
.get();
390 void BrowserGpuChannelHostFactory::GpuChannelEstablished() {
391 DCHECK(IsMainThread());
392 DCHECK(pending_request_
.get());
393 if (pending_request_
->channel_handle().name
.empty()) {
394 DCHECK(!gpu_channel_
.get());
396 GetContentClient()->SetGpuInfo(pending_request_
->gpu_info());
398 GpuChannelHost::Create(this,
399 pending_request_
->gpu_info(),
400 pending_request_
->channel_handle(),
401 shutdown_event_
.get(),
402 BrowserGpuMemoryBufferManager::current());
404 gpu_host_id_
= pending_request_
->gpu_host_id();
405 pending_request_
= NULL
;
407 for (size_t n
= 0; n
< established_callbacks_
.size(); n
++)
408 established_callbacks_
[n
].Run();
410 established_callbacks_
.clear();
414 void BrowserGpuChannelHostFactory::AddFilterOnIO(
416 scoped_refptr
<IPC::MessageFilter
> filter
) {
417 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
419 GpuProcessHost
* host
= GpuProcessHost::FromID(host_id
);
421 host
->AddFilter(filter
.get());
424 void BrowserGpuChannelHostFactory::SetHandlerForControlMessages(
425 const uint32
* message_ids
,
427 const base::Callback
<void(const IPC::Message
&)>& handler
,
428 base::TaskRunner
* target_task_runner
) {
431 << " BrowserGpuChannelHostFactory::SetHandlerForControlMessages()"
432 << " until the GpuProcessHost has been set up.";
434 scoped_refptr
<IPC::ForwardingMessageFilter
> filter
=
435 new IPC::ForwardingMessageFilter(message_ids
,
438 filter
->AddRoute(MSG_ROUTING_CONTROL
, handler
);
440 GetIOLoopProxy()->PostTask(
442 base::Bind(&BrowserGpuChannelHostFactory::AddFilterOnIO
,
447 bool BrowserGpuChannelHostFactory::IsGpuMemoryBufferConfigurationSupported(
448 gfx::GpuMemoryBuffer::Format format
,
449 gfx::GpuMemoryBuffer::Usage usage
) {
450 // Return early if usage is not enabled.
451 if (!IsGpuMemoryBufferFactoryUsageEnabled(usage
))
454 // Preferred type is always used by factory.
455 std::vector
<gfx::GpuMemoryBufferType
> supported_types
;
456 GpuMemoryBufferFactory::GetSupportedTypes(&supported_types
);
457 DCHECK(!supported_types
.empty());
458 switch (supported_types
[0]) {
459 case gfx::SHARED_MEMORY_BUFFER
:
460 // Shared memory buffers must be created in-process.
462 #if defined(OS_MACOSX)
463 case gfx::IO_SURFACE_BUFFER
:
464 return GpuMemoryBufferFactoryIOSurface::
465 IsGpuMemoryBufferConfigurationSupported(format
, usage
);
467 #if defined(OS_ANDROID)
468 case gfx::SURFACE_TEXTURE_BUFFER
:
469 return GpuMemoryBufferFactorySurfaceTexture::
470 IsGpuMemoryBufferConfigurationSupported(format
, usage
);
472 #if defined(USE_OZONE)
473 case gfx::OZONE_NATIVE_BUFFER
:
474 return GpuMemoryBufferFactoryOzoneNativeBuffer::
475 IsGpuMemoryBufferConfigurationSupported(format
, usage
);
483 void BrowserGpuChannelHostFactory::CreateGpuMemoryBuffer(
484 gfx::GpuMemoryBufferId id
,
485 const gfx::Size
& size
,
486 gfx::GpuMemoryBuffer::Format format
,
487 gfx::GpuMemoryBuffer::Usage usage
,
490 const CreateGpuMemoryBufferCallback
& callback
) {
491 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
493 GpuProcessHost
* host
= GpuProcessHost::FromID(gpu_host_id_
);
495 callback
.Run(gfx::GpuMemoryBufferHandle());
499 uint32 request_id
= next_create_gpu_memory_buffer_request_id_
++;
500 create_gpu_memory_buffer_requests_
[request_id
] = callback
;
502 host
->CreateGpuMemoryBuffer(
503 id
, size
, format
, usage
, client_id
, surface_id
,
504 base::Bind(&BrowserGpuChannelHostFactory::OnGpuMemoryBufferCreated
,
505 base::Unretained(this), request_id
));
508 void BrowserGpuChannelHostFactory::DestroyGpuMemoryBuffer(
509 gfx::GpuMemoryBufferId id
,
512 BrowserThread::PostTask(
515 base::Bind(&BrowserGpuChannelHostFactory::DestroyGpuMemoryBufferOnIO
,
516 base::Unretained(this),
522 void BrowserGpuChannelHostFactory::DestroyGpuMemoryBufferOnIO(
523 gfx::GpuMemoryBufferId id
,
526 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
528 GpuProcessHost
* host
= GpuProcessHost::FromID(gpu_host_id_
);
532 host
->DestroyGpuMemoryBuffer(id
, client_id
, sync_point
);
535 void BrowserGpuChannelHostFactory::OnGpuMemoryBufferCreated(
537 const gfx::GpuMemoryBufferHandle
& handle
) {
538 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
540 CreateGpuMemoryBufferCallbackMap::iterator iter
=
541 create_gpu_memory_buffer_requests_
.find(request_id
);
542 DCHECK(iter
!= create_gpu_memory_buffer_requests_
.end());
543 iter
->second
.Run(handle
);
544 create_gpu_memory_buffer_requests_
.erase(iter
);
547 } // namespace content