[refactor] More post-NSS WebCrypto cleanups (utility functions).
[chromium-blink-merge.git] / content / browser / gpu / browser_gpu_channel_host_factory.cc
blob3dda55152db9b6f73e976baeda86ca43d34816db
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 "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/location.h"
10 #include "base/profiler/scoped_tracker.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/threading/thread_restrictions.h"
15 #include "base/trace_event/memory_dump_manager.h"
16 #include "base/trace_event/trace_event.h"
17 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
18 #include "content/browser/gpu/gpu_data_manager_impl.h"
19 #include "content/browser/gpu/gpu_process_host.h"
20 #include "content/browser/gpu/gpu_surface_tracker.h"
21 #include "content/browser/gpu/shader_disk_cache.h"
22 #include "content/common/child_process_host_impl.h"
23 #include "content/common/gpu/gpu_messages.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "content/public/browser/content_browser_client.h"
26 #include "content/public/browser/gpu_data_manager.h"
27 #include "content/public/common/content_client.h"
28 #include "gpu/command_buffer/service/gpu_switches.h"
29 #include "ipc/ipc_channel_handle.h"
30 #include "ipc/message_filter.h"
32 namespace content {
34 BrowserGpuChannelHostFactory* BrowserGpuChannelHostFactory::instance_ = NULL;
36 struct BrowserGpuChannelHostFactory::CreateRequest {
37 CreateRequest(int32 route_id)
38 : event(true, false),
39 gpu_host_id(0),
40 route_id(route_id),
41 result(CREATE_COMMAND_BUFFER_FAILED) {}
42 ~CreateRequest() {}
43 base::WaitableEvent event;
44 int gpu_host_id;
45 int32 route_id;
46 CreateCommandBufferResult result;
49 class BrowserGpuChannelHostFactory::EstablishRequest
50 : public base::RefCountedThreadSafe<EstablishRequest> {
51 public:
52 static scoped_refptr<EstablishRequest> Create(CauseForGpuLaunch cause,
53 int gpu_client_id,
54 uint64_t gpu_client_tracing_id,
55 int gpu_host_id);
56 void Wait();
57 void Cancel();
59 int gpu_host_id() { return gpu_host_id_; }
60 IPC::ChannelHandle& channel_handle() { return channel_handle_; }
61 gpu::GPUInfo gpu_info() { return gpu_info_; }
63 private:
64 friend class base::RefCountedThreadSafe<EstablishRequest>;
65 explicit EstablishRequest(CauseForGpuLaunch cause,
66 int gpu_client_id,
67 uint64_t gpu_client_tracing_id,
68 int gpu_host_id);
69 ~EstablishRequest() {}
70 void EstablishOnIO();
71 void OnEstablishedOnIO(const IPC::ChannelHandle& channel_handle,
72 const gpu::GPUInfo& gpu_info);
73 void FinishOnIO();
74 void FinishOnMain();
76 base::WaitableEvent event_;
77 CauseForGpuLaunch cause_for_gpu_launch_;
78 const int gpu_client_id_;
79 const uint64_t gpu_client_tracing_id_;
80 int gpu_host_id_;
81 bool reused_gpu_process_;
82 IPC::ChannelHandle channel_handle_;
83 gpu::GPUInfo gpu_info_;
84 bool finished_;
85 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
88 scoped_refptr<BrowserGpuChannelHostFactory::EstablishRequest>
89 BrowserGpuChannelHostFactory::EstablishRequest::Create(
90 CauseForGpuLaunch cause,
91 int gpu_client_id,
92 uint64_t gpu_client_tracing_id,
93 int gpu_host_id) {
94 scoped_refptr<EstablishRequest> establish_request = new EstablishRequest(
95 cause, gpu_client_id, gpu_client_tracing_id, gpu_host_id);
96 scoped_refptr<base::SingleThreadTaskRunner> task_runner =
97 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
98 // PostTask outside the constructor to ensure at least one reference exists.
99 task_runner->PostTask(
100 FROM_HERE,
101 base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO,
102 establish_request));
103 return establish_request;
106 BrowserGpuChannelHostFactory::EstablishRequest::EstablishRequest(
107 CauseForGpuLaunch cause,
108 int gpu_client_id,
109 uint64_t gpu_client_tracing_id,
110 int gpu_host_id)
111 : event_(false, false),
112 cause_for_gpu_launch_(cause),
113 gpu_client_id_(gpu_client_id),
114 gpu_client_tracing_id_(gpu_client_tracing_id),
115 gpu_host_id_(gpu_host_id),
116 reused_gpu_process_(false),
117 finished_(false),
118 main_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
121 void BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO() {
122 // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
123 tracked_objects::ScopedTracker tracking_profile(
124 FROM_HERE_WITH_EXPLICIT_FUNCTION(
125 "477117 "
126 "BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO"));
127 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
128 if (!host) {
129 host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
130 cause_for_gpu_launch_);
131 if (!host) {
132 LOG(ERROR) << "Failed to launch GPU process.";
133 FinishOnIO();
134 return;
136 gpu_host_id_ = host->host_id();
137 reused_gpu_process_ = false;
138 } else {
139 if (reused_gpu_process_) {
140 // We come here if we retried to establish the channel because of a
141 // failure in ChannelEstablishedOnIO, but we ended up with the same
142 // process ID, meaning the failure was not because of a channel error,
143 // but another reason. So fail now.
144 LOG(ERROR) << "Failed to create channel.";
145 FinishOnIO();
146 return;
148 reused_gpu_process_ = true;
151 host->EstablishGpuChannel(
152 gpu_client_id_, gpu_client_tracing_id_, true, true, true,
153 base::Bind(
154 &BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO,
155 this));
158 void BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO(
159 const IPC::ChannelHandle& channel_handle,
160 const gpu::GPUInfo& gpu_info) {
161 if (channel_handle.name.empty() && reused_gpu_process_) {
162 // We failed after re-using the GPU process, but it may have died in the
163 // mean time. Retry to have a chance to create a fresh GPU process.
164 DVLOG(1) << "Failed to create channel on existing GPU process. Trying to "
165 "restart GPU process.";
166 EstablishOnIO();
167 } else {
168 channel_handle_ = channel_handle;
169 gpu_info_ = gpu_info;
170 FinishOnIO();
174 void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnIO() {
175 event_.Signal();
176 main_task_runner_->PostTask(
177 FROM_HERE,
178 base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain,
179 this));
182 void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain() {
183 if (!finished_) {
184 BrowserGpuChannelHostFactory* factory =
185 BrowserGpuChannelHostFactory::instance();
186 factory->GpuChannelEstablished();
187 finished_ = true;
191 void BrowserGpuChannelHostFactory::EstablishRequest::Wait() {
192 DCHECK(main_task_runner_->BelongsToCurrentThread());
194 // TODO(vadimt): Remove ScopedTracker below once crbug.com/125248 is fixed.
195 tracked_objects::ScopedTracker tracking_profile(
196 FROM_HERE_WITH_EXPLICIT_FUNCTION(
197 "125248 BrowserGpuChannelHostFactory::EstablishRequest::Wait"));
199 // We're blocking the UI thread, which is generally undesirable.
200 // In this case we need to wait for this before we can show any UI
201 // /anyway/, so it won't cause additional jank.
202 // TODO(piman): Make this asynchronous (http://crbug.com/125248).
203 TRACE_EVENT0("browser",
204 "BrowserGpuChannelHostFactory::EstablishGpuChannelSync");
205 base::ThreadRestrictions::ScopedAllowWait allow_wait;
206 event_.Wait();
208 FinishOnMain();
211 void BrowserGpuChannelHostFactory::EstablishRequest::Cancel() {
212 DCHECK(main_task_runner_->BelongsToCurrentThread());
213 finished_ = true;
216 bool BrowserGpuChannelHostFactory::CanUseForTesting() {
217 return GpuDataManager::GetInstance()->GpuAccessAllowed(NULL);
220 void BrowserGpuChannelHostFactory::Initialize(bool establish_gpu_channel) {
221 DCHECK(!instance_);
222 instance_ = new BrowserGpuChannelHostFactory();
223 if (establish_gpu_channel) {
224 instance_->EstablishGpuChannel(CAUSE_FOR_GPU_LAUNCH_BROWSER_STARTUP,
225 base::Closure());
229 void BrowserGpuChannelHostFactory::Terminate() {
230 DCHECK(instance_);
231 delete instance_;
232 instance_ = NULL;
235 BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory()
236 : gpu_client_id_(ChildProcessHostImpl::GenerateChildProcessUniqueId()),
237 gpu_client_tracing_id_(ChildProcessHost::kBrowserTracingProcessId),
238 shutdown_event_(new base::WaitableEvent(true, false)),
239 gpu_memory_buffer_manager_(
240 new BrowserGpuMemoryBufferManager(gpu_client_id_,
241 gpu_client_tracing_id_)),
242 gpu_host_id_(0) {
243 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
244 switches::kDisableGpuShaderDiskCache)) {
245 DCHECK(GetContentClient());
246 base::FilePath cache_dir =
247 GetContentClient()->browser()->GetShaderDiskCacheDirectory();
248 if (!cache_dir.empty()) {
249 GetIOThreadTaskRunner()->PostTask(
250 FROM_HERE,
251 base::Bind(
252 &BrowserGpuChannelHostFactory::InitializeShaderDiskCacheOnIO,
253 gpu_client_id_, cache_dir));
258 BrowserGpuChannelHostFactory::~BrowserGpuChannelHostFactory() {
259 DCHECK(IsMainThread());
260 if (pending_request_.get())
261 pending_request_->Cancel();
262 for (size_t n = 0; n < established_callbacks_.size(); n++)
263 established_callbacks_[n].Run();
264 shutdown_event_->Signal();
265 if (gpu_channel_) {
266 gpu_channel_->DestroyChannel();
267 gpu_channel_ = NULL;
271 bool BrowserGpuChannelHostFactory::IsMainThread() {
272 return BrowserThread::CurrentlyOn(BrowserThread::UI);
275 scoped_refptr<base::SingleThreadTaskRunner>
276 BrowserGpuChannelHostFactory::GetIOThreadTaskRunner() {
277 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
280 scoped_ptr<base::SharedMemory>
281 BrowserGpuChannelHostFactory::AllocateSharedMemory(size_t size) {
282 scoped_ptr<base::SharedMemory> shm(new base::SharedMemory());
283 if (!shm->CreateAnonymous(size))
284 return scoped_ptr<base::SharedMemory>();
285 return shm.Pass();
288 void BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO(
289 CreateRequest* request,
290 int32 surface_id,
291 const GPUCreateCommandBufferConfig& init_params) {
292 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
293 if (!host) {
294 request->event.Signal();
295 return;
298 gfx::GLSurfaceHandle surface =
299 GpuSurfaceTracker::Get()->GetSurfaceHandle(surface_id);
301 host->CreateViewCommandBuffer(
302 surface,
303 surface_id,
304 gpu_client_id_,
305 init_params,
306 request->route_id,
307 base::Bind(&BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO,
308 request));
311 // static
312 void BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO(
313 CreateRequest* request, CreateCommandBufferResult result) {
314 request->result = result;
315 request->event.Signal();
318 CreateCommandBufferResult BrowserGpuChannelHostFactory::CreateViewCommandBuffer(
319 int32 surface_id,
320 const GPUCreateCommandBufferConfig& init_params,
321 int32 route_id) {
322 CreateRequest request(route_id);
323 GetIOThreadTaskRunner()->PostTask(
324 FROM_HERE,
325 base::Bind(&BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO,
326 base::Unretained(this), &request, surface_id, init_params));
327 // TODO(vadimt): Remove ScopedTracker below once crbug.com/125248 is fixed.
328 tracked_objects::ScopedTracker tracking_profile(
329 FROM_HERE_WITH_EXPLICIT_FUNCTION(
330 "125248 BrowserGpuChannelHostFactory::CreateViewCommandBuffer"));
332 // We're blocking the UI thread, which is generally undesirable.
333 // In this case we need to wait for this before we can show any UI /anyway/,
334 // so it won't cause additional jank.
335 // TODO(piman): Make this asynchronous (http://crbug.com/125248).
336 TRACE_EVENT0("browser",
337 "BrowserGpuChannelHostFactory::CreateViewCommandBuffer");
338 base::ThreadRestrictions::ScopedAllowWait allow_wait;
339 request.event.Wait();
340 return request.result;
343 // Blocking the UI thread to open a GPU channel is not supported on Android.
344 // (Opening the initial channel to a child process involves handling a reply
345 // task on the UI thread first, so we cannot block here.)
346 #if !defined(OS_ANDROID)
347 GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
348 CauseForGpuLaunch cause_for_gpu_launch) {
349 EstablishGpuChannel(cause_for_gpu_launch, base::Closure());
351 if (pending_request_.get())
352 pending_request_->Wait();
354 return gpu_channel_.get();
356 #endif
358 void BrowserGpuChannelHostFactory::EstablishGpuChannel(
359 CauseForGpuLaunch cause_for_gpu_launch,
360 const base::Closure& callback) {
361 if (gpu_channel_.get() && gpu_channel_->IsLost()) {
362 DCHECK(!pending_request_.get());
363 // Recreate the channel if it has been lost.
364 gpu_channel_->DestroyChannel();
365 gpu_channel_ = NULL;
368 if (!gpu_channel_.get() && !pending_request_.get()) {
369 // We should only get here if the context was lost.
370 pending_request_ = EstablishRequest::Create(
371 cause_for_gpu_launch, gpu_client_id_,
372 gpu_client_tracing_id_,
373 gpu_host_id_);
376 if (!callback.is_null()) {
377 if (gpu_channel_.get())
378 callback.Run();
379 else
380 established_callbacks_.push_back(callback);
384 GpuChannelHost* BrowserGpuChannelHostFactory::GetGpuChannel() {
385 if (gpu_channel_.get() && !gpu_channel_->IsLost())
386 return gpu_channel_.get();
388 return NULL;
391 void BrowserGpuChannelHostFactory::GpuChannelEstablished() {
392 DCHECK(IsMainThread());
393 DCHECK(pending_request_.get());
394 if (pending_request_->channel_handle().name.empty()) {
395 DCHECK(!gpu_channel_.get());
396 } else {
397 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/466866
398 // is fixed.
399 tracked_objects::ScopedTracker tracking_profile1(
400 FROM_HERE_WITH_EXPLICIT_FUNCTION(
401 "466866 BrowserGpuChannelHostFactory::GpuChannelEstablished1"));
402 GetContentClient()->SetGpuInfo(pending_request_->gpu_info());
403 gpu_channel_ = GpuChannelHost::Create(
404 this, gpu_client_id_, pending_request_->gpu_info(),
405 pending_request_->channel_handle(), shutdown_event_.get(),
406 gpu_memory_buffer_manager_.get());
408 gpu_host_id_ = pending_request_->gpu_host_id();
409 pending_request_ = NULL;
411 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/466866 is
412 // fixed.
413 tracked_objects::ScopedTracker tracking_profile2(
414 FROM_HERE_WITH_EXPLICIT_FUNCTION(
415 "466866 BrowserGpuChannelHostFactory::GpuChannelEstablished2"));
417 for (size_t n = 0; n < established_callbacks_.size(); n++)
418 established_callbacks_[n].Run();
420 established_callbacks_.clear();
423 // static
424 void BrowserGpuChannelHostFactory::AddFilterOnIO(
425 int host_id,
426 scoped_refptr<IPC::MessageFilter> filter) {
427 DCHECK_CURRENTLY_ON(BrowserThread::IO);
429 GpuProcessHost* host = GpuProcessHost::FromID(host_id);
430 if (host)
431 host->AddFilter(filter.get());
434 // static
435 void BrowserGpuChannelHostFactory::InitializeShaderDiskCacheOnIO(
436 int gpu_client_id,
437 const base::FilePath& cache_dir) {
438 ShaderCacheFactory::GetInstance()->SetCacheInfo(gpu_client_id, cache_dir);
441 } // namespace content