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"
8 #include "base/location.h"
9 #include "base/profiler/scoped_tracker.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/synchronization/waitable_event.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "base/threading/thread_restrictions.h"
14 #include "base/trace_event/memory_dump_manager.h"
15 #include "base/trace_event/trace_event.h"
16 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
17 #include "content/browser/gpu/gpu_data_manager_impl.h"
18 #include "content/browser/gpu/gpu_process_host.h"
19 #include "content/browser/gpu/gpu_surface_tracker.h"
20 #include "content/common/child_process_host_impl.h"
21 #include "content/common/gpu/gpu_messages.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/gpu_data_manager.h"
24 #include "content/public/common/content_client.h"
25 #include "ipc/ipc_channel_handle.h"
26 #include "ipc/message_filter.h"
30 BrowserGpuChannelHostFactory
* BrowserGpuChannelHostFactory::instance_
= NULL
;
32 struct BrowserGpuChannelHostFactory::CreateRequest
{
33 CreateRequest(int32 route_id
)
37 result(CREATE_COMMAND_BUFFER_FAILED
) {}
39 base::WaitableEvent event
;
42 CreateCommandBufferResult result
;
45 class BrowserGpuChannelHostFactory::EstablishRequest
46 : public base::RefCountedThreadSafe
<EstablishRequest
> {
48 static scoped_refptr
<EstablishRequest
> Create(CauseForGpuLaunch cause
,
50 uint64_t gpu_client_tracing_id
,
55 int gpu_host_id() { return gpu_host_id_
; }
56 IPC::ChannelHandle
& channel_handle() { return channel_handle_
; }
57 gpu::GPUInfo
gpu_info() { return gpu_info_
; }
60 friend class base::RefCountedThreadSafe
<EstablishRequest
>;
61 explicit EstablishRequest(CauseForGpuLaunch cause
,
63 uint64_t gpu_client_tracing_id
,
65 ~EstablishRequest() {}
67 void OnEstablishedOnIO(const IPC::ChannelHandle
& channel_handle
,
68 const gpu::GPUInfo
& gpu_info
);
72 base::WaitableEvent event_
;
73 CauseForGpuLaunch cause_for_gpu_launch_
;
74 const int gpu_client_id_
;
75 const uint64_t gpu_client_tracing_id_
;
77 bool reused_gpu_process_
;
78 IPC::ChannelHandle channel_handle_
;
79 gpu::GPUInfo gpu_info_
;
81 scoped_refptr
<base::SingleThreadTaskRunner
> main_task_runner_
;
84 scoped_refptr
<BrowserGpuChannelHostFactory::EstablishRequest
>
85 BrowserGpuChannelHostFactory::EstablishRequest::Create(
86 CauseForGpuLaunch cause
,
88 uint64_t gpu_client_tracing_id
,
90 scoped_refptr
<EstablishRequest
> establish_request
= new EstablishRequest(
91 cause
, gpu_client_id
, gpu_client_tracing_id
, gpu_host_id
);
92 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
=
93 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO
);
94 // PostTask outside the constructor to ensure at least one reference exists.
95 task_runner
->PostTask(
97 base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO
,
99 return establish_request
;
102 BrowserGpuChannelHostFactory::EstablishRequest::EstablishRequest(
103 CauseForGpuLaunch cause
,
105 uint64_t gpu_client_tracing_id
,
107 : event_(false, false),
108 cause_for_gpu_launch_(cause
),
109 gpu_client_id_(gpu_client_id
),
110 gpu_client_tracing_id_(gpu_client_tracing_id
),
111 gpu_host_id_(gpu_host_id
),
112 reused_gpu_process_(false),
114 main_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
117 void BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO() {
118 // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
119 tracked_objects::ScopedTracker
tracking_profile(
120 FROM_HERE_WITH_EXPLICIT_FUNCTION(
122 "BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO"));
123 GpuProcessHost
* host
= GpuProcessHost::FromID(gpu_host_id_
);
125 host
= GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED
,
126 cause_for_gpu_launch_
);
128 LOG(ERROR
) << "Failed to launch GPU process.";
132 gpu_host_id_
= host
->host_id();
133 reused_gpu_process_
= false;
135 if (reused_gpu_process_
) {
136 // We come here if we retried to establish the channel because of a
137 // failure in ChannelEstablishedOnIO, but we ended up with the same
138 // process ID, meaning the failure was not because of a channel error,
139 // but another reason. So fail now.
140 LOG(ERROR
) << "Failed to create channel.";
144 reused_gpu_process_
= true;
147 host
->EstablishGpuChannel(
149 gpu_client_tracing_id_
,
153 &BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO
,
157 void BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO(
158 const IPC::ChannelHandle
& channel_handle
,
159 const gpu::GPUInfo
& gpu_info
) {
160 if (channel_handle
.name
.empty() && reused_gpu_process_
) {
161 // We failed after re-using the GPU process, but it may have died in the
162 // mean time. Retry to have a chance to create a fresh GPU process.
163 DVLOG(1) << "Failed to create channel on existing GPU process. Trying to "
164 "restart GPU process.";
167 channel_handle_
= channel_handle
;
168 gpu_info_
= gpu_info
;
173 void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnIO() {
175 main_task_runner_
->PostTask(
177 base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain
,
181 void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain() {
183 BrowserGpuChannelHostFactory
* factory
=
184 BrowserGpuChannelHostFactory::instance();
185 factory
->GpuChannelEstablished();
190 void BrowserGpuChannelHostFactory::EstablishRequest::Wait() {
191 DCHECK(main_task_runner_
->BelongsToCurrentThread());
193 // TODO(vadimt): Remove ScopedTracker below once crbug.com/125248 is fixed.
194 tracked_objects::ScopedTracker
tracking_profile(
195 FROM_HERE_WITH_EXPLICIT_FUNCTION(
196 "125248 BrowserGpuChannelHostFactory::EstablishRequest::Wait"));
198 // We're blocking the UI thread, which is generally undesirable.
199 // In this case we need to wait for this before we can show any UI
200 // /anyway/, so it won't cause additional jank.
201 // TODO(piman): Make this asynchronous (http://crbug.com/125248).
202 TRACE_EVENT0("browser",
203 "BrowserGpuChannelHostFactory::EstablishGpuChannelSync");
204 base::ThreadRestrictions::ScopedAllowWait allow_wait
;
210 void BrowserGpuChannelHostFactory::EstablishRequest::Cancel() {
211 DCHECK(main_task_runner_
->BelongsToCurrentThread());
215 bool BrowserGpuChannelHostFactory::CanUseForTesting() {
216 return GpuDataManager::GetInstance()->GpuAccessAllowed(NULL
);
219 void BrowserGpuChannelHostFactory::Initialize(bool establish_gpu_channel
) {
221 instance_
= new BrowserGpuChannelHostFactory();
222 if (establish_gpu_channel
) {
223 instance_
->EstablishGpuChannel(CAUSE_FOR_GPU_LAUNCH_BROWSER_STARTUP
,
228 void BrowserGpuChannelHostFactory::Terminate() {
234 BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory()
235 : gpu_client_id_(ChildProcessHostImpl::GenerateChildProcessUniqueId()),
236 gpu_client_tracing_id_(ChildProcessHost::kBrowserTracingProcessId
),
237 shutdown_event_(new base::WaitableEvent(true, false)),
238 gpu_memory_buffer_manager_(
239 new BrowserGpuMemoryBufferManager(gpu_client_id_
)),
242 BrowserGpuChannelHostFactory::~BrowserGpuChannelHostFactory() {
243 DCHECK(IsMainThread());
244 if (pending_request_
.get())
245 pending_request_
->Cancel();
246 for (size_t n
= 0; n
< established_callbacks_
.size(); n
++)
247 established_callbacks_
[n
].Run();
248 shutdown_event_
->Signal();
250 gpu_channel_
->DestroyChannel();
255 bool BrowserGpuChannelHostFactory::IsMainThread() {
256 return BrowserThread::CurrentlyOn(BrowserThread::UI
);
259 scoped_refptr
<base::SingleThreadTaskRunner
>
260 BrowserGpuChannelHostFactory::GetIOThreadTaskRunner() {
261 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO
);
264 scoped_ptr
<base::SharedMemory
>
265 BrowserGpuChannelHostFactory::AllocateSharedMemory(size_t size
) {
266 scoped_ptr
<base::SharedMemory
> shm(new base::SharedMemory());
267 if (!shm
->CreateAnonymous(size
))
268 return scoped_ptr
<base::SharedMemory
>();
272 void BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO(
273 CreateRequest
* request
,
275 const GPUCreateCommandBufferConfig
& init_params
) {
276 GpuProcessHost
* host
= GpuProcessHost::FromID(gpu_host_id_
);
278 request
->event
.Signal();
282 gfx::GLSurfaceHandle surface
=
283 GpuSurfaceTracker::Get()->GetSurfaceHandle(surface_id
);
285 host
->CreateViewCommandBuffer(
291 base::Bind(&BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO
,
295 IPC::AttachmentBroker
* BrowserGpuChannelHostFactory::GetAttachmentBroker() {
296 return content::ChildProcessHost::GetAttachmentBroker();
300 void BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO(
301 CreateRequest
* request
, CreateCommandBufferResult result
) {
302 request
->result
= result
;
303 request
->event
.Signal();
306 CreateCommandBufferResult
BrowserGpuChannelHostFactory::CreateViewCommandBuffer(
308 const GPUCreateCommandBufferConfig
& init_params
,
310 CreateRequest
request(route_id
);
311 GetIOThreadTaskRunner()->PostTask(
313 base::Bind(&BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO
,
314 base::Unretained(this), &request
, surface_id
, init_params
));
315 // TODO(vadimt): Remove ScopedTracker below once crbug.com/125248 is fixed.
316 tracked_objects::ScopedTracker
tracking_profile(
317 FROM_HERE_WITH_EXPLICIT_FUNCTION(
318 "125248 BrowserGpuChannelHostFactory::CreateViewCommandBuffer"));
320 // We're blocking the UI thread, which is generally undesirable.
321 // In this case we need to wait for this before we can show any UI /anyway/,
322 // so it won't cause additional jank.
323 // TODO(piman): Make this asynchronous (http://crbug.com/125248).
324 TRACE_EVENT0("browser",
325 "BrowserGpuChannelHostFactory::CreateViewCommandBuffer");
326 base::ThreadRestrictions::ScopedAllowWait allow_wait
;
327 request
.event
.Wait();
328 return request
.result
;
331 // Blocking the UI thread to open a GPU channel is not supported on Android.
332 // (Opening the initial channel to a child process involves handling a reply
333 // task on the UI thread first, so we cannot block here.)
334 #if !defined(OS_ANDROID)
335 GpuChannelHost
* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
336 CauseForGpuLaunch cause_for_gpu_launch
) {
337 EstablishGpuChannel(cause_for_gpu_launch
, base::Closure());
339 if (pending_request_
.get())
340 pending_request_
->Wait();
342 return gpu_channel_
.get();
346 void BrowserGpuChannelHostFactory::EstablishGpuChannel(
347 CauseForGpuLaunch cause_for_gpu_launch
,
348 const base::Closure
& callback
) {
349 if (gpu_channel_
.get() && gpu_channel_
->IsLost()) {
350 DCHECK(!pending_request_
.get());
351 // Recreate the channel if it has been lost.
352 gpu_channel_
->DestroyChannel();
356 if (!gpu_channel_
.get() && !pending_request_
.get()) {
357 // We should only get here if the context was lost.
358 pending_request_
= EstablishRequest::Create(
359 cause_for_gpu_launch
, gpu_client_id_
,
360 gpu_client_tracing_id_
,
364 if (!callback
.is_null()) {
365 if (gpu_channel_
.get())
368 established_callbacks_
.push_back(callback
);
372 GpuChannelHost
* BrowserGpuChannelHostFactory::GetGpuChannel() {
373 if (gpu_channel_
.get() && !gpu_channel_
->IsLost())
374 return gpu_channel_
.get();
379 void BrowserGpuChannelHostFactory::GpuChannelEstablished() {
380 DCHECK(IsMainThread());
381 DCHECK(pending_request_
.get());
382 if (pending_request_
->channel_handle().name
.empty()) {
383 DCHECK(!gpu_channel_
.get());
385 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/466866
387 tracked_objects::ScopedTracker
tracking_profile1(
388 FROM_HERE_WITH_EXPLICIT_FUNCTION(
389 "466866 BrowserGpuChannelHostFactory::GpuChannelEstablished1"));
390 GetContentClient()->SetGpuInfo(pending_request_
->gpu_info());
391 gpu_channel_
= GpuChannelHost::Create(
392 this, pending_request_
->gpu_info(), pending_request_
->channel_handle(),
393 shutdown_event_
.get(), gpu_memory_buffer_manager_
.get());
395 gpu_host_id_
= pending_request_
->gpu_host_id();
396 pending_request_
= NULL
;
398 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/466866 is
400 tracked_objects::ScopedTracker
tracking_profile2(
401 FROM_HERE_WITH_EXPLICIT_FUNCTION(
402 "466866 BrowserGpuChannelHostFactory::GpuChannelEstablished2"));
404 for (size_t n
= 0; n
< established_callbacks_
.size(); n
++)
405 established_callbacks_
[n
].Run();
407 established_callbacks_
.clear();
411 void BrowserGpuChannelHostFactory::AddFilterOnIO(
413 scoped_refptr
<IPC::MessageFilter
> filter
) {
414 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
416 GpuProcessHost
* host
= GpuProcessHost::FromID(host_id
);
418 host
->AddFilter(filter
.get());
421 } // namespace content