Add ICU message format support
[chromium-blink-merge.git] / content / browser / gpu / browser_gpu_channel_host_factory.cc
blobe45b4061743ae24ee5f28a615f366a1281ed4b0a
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/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"
28 namespace content {
30 BrowserGpuChannelHostFactory* BrowserGpuChannelHostFactory::instance_ = NULL;
32 struct BrowserGpuChannelHostFactory::CreateRequest {
33 CreateRequest(int32 route_id)
34 : event(true, false),
35 gpu_host_id(0),
36 route_id(route_id),
37 result(CREATE_COMMAND_BUFFER_FAILED) {}
38 ~CreateRequest() {}
39 base::WaitableEvent event;
40 int gpu_host_id;
41 int32 route_id;
42 CreateCommandBufferResult result;
45 class BrowserGpuChannelHostFactory::EstablishRequest
46 : public base::RefCountedThreadSafe<EstablishRequest> {
47 public:
48 static scoped_refptr<EstablishRequest> Create(CauseForGpuLaunch cause,
49 int gpu_client_id,
50 uint64_t gpu_client_tracing_id,
51 int gpu_host_id);
52 void Wait();
53 void Cancel();
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_; }
59 private:
60 friend class base::RefCountedThreadSafe<EstablishRequest>;
61 explicit EstablishRequest(CauseForGpuLaunch cause,
62 int gpu_client_id,
63 uint64_t gpu_client_tracing_id,
64 int gpu_host_id);
65 ~EstablishRequest() {}
66 void EstablishOnIO();
67 void OnEstablishedOnIO(const IPC::ChannelHandle& channel_handle,
68 const gpu::GPUInfo& gpu_info);
69 void FinishOnIO();
70 void FinishOnMain();
72 base::WaitableEvent event_;
73 CauseForGpuLaunch cause_for_gpu_launch_;
74 const int gpu_client_id_;
75 const uint64_t gpu_client_tracing_id_;
76 int gpu_host_id_;
77 bool reused_gpu_process_;
78 IPC::ChannelHandle channel_handle_;
79 gpu::GPUInfo gpu_info_;
80 bool finished_;
81 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
84 scoped_refptr<BrowserGpuChannelHostFactory::EstablishRequest>
85 BrowserGpuChannelHostFactory::EstablishRequest::Create(
86 CauseForGpuLaunch cause,
87 int gpu_client_id,
88 uint64_t gpu_client_tracing_id,
89 int gpu_host_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(
96 FROM_HERE,
97 base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO,
98 establish_request));
99 return establish_request;
102 BrowserGpuChannelHostFactory::EstablishRequest::EstablishRequest(
103 CauseForGpuLaunch cause,
104 int gpu_client_id,
105 uint64_t gpu_client_tracing_id,
106 int gpu_host_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),
113 finished_(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(
121 "477117 "
122 "BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO"));
123 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
124 if (!host) {
125 host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
126 cause_for_gpu_launch_);
127 if (!host) {
128 LOG(ERROR) << "Failed to launch GPU process.";
129 FinishOnIO();
130 return;
132 gpu_host_id_ = host->host_id();
133 reused_gpu_process_ = false;
134 } else {
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.";
141 FinishOnIO();
142 return;
144 reused_gpu_process_ = true;
147 host->EstablishGpuChannel(
148 gpu_client_id_,
149 gpu_client_tracing_id_,
150 true,
151 true,
152 base::Bind(
153 &BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO,
154 this));
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.";
165 EstablishOnIO();
166 } else {
167 channel_handle_ = channel_handle;
168 gpu_info_ = gpu_info;
169 FinishOnIO();
173 void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnIO() {
174 event_.Signal();
175 main_task_runner_->PostTask(
176 FROM_HERE,
177 base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain,
178 this));
181 void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain() {
182 if (!finished_) {
183 BrowserGpuChannelHostFactory* factory =
184 BrowserGpuChannelHostFactory::instance();
185 factory->GpuChannelEstablished();
186 finished_ = true;
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;
205 event_.Wait();
207 FinishOnMain();
210 void BrowserGpuChannelHostFactory::EstablishRequest::Cancel() {
211 DCHECK(main_task_runner_->BelongsToCurrentThread());
212 finished_ = true;
215 bool BrowserGpuChannelHostFactory::CanUseForTesting() {
216 return GpuDataManager::GetInstance()->GpuAccessAllowed(NULL);
219 void BrowserGpuChannelHostFactory::Initialize(bool establish_gpu_channel) {
220 DCHECK(!instance_);
221 instance_ = new BrowserGpuChannelHostFactory();
222 if (establish_gpu_channel) {
223 instance_->EstablishGpuChannel(CAUSE_FOR_GPU_LAUNCH_BROWSER_STARTUP,
224 base::Closure());
228 void BrowserGpuChannelHostFactory::Terminate() {
229 DCHECK(instance_);
230 delete instance_;
231 instance_ = NULL;
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_,
240 gpu_client_tracing_id_)),
241 gpu_host_id_(0) {}
243 BrowserGpuChannelHostFactory::~BrowserGpuChannelHostFactory() {
244 DCHECK(IsMainThread());
245 if (pending_request_.get())
246 pending_request_->Cancel();
247 for (size_t n = 0; n < established_callbacks_.size(); n++)
248 established_callbacks_[n].Run();
249 shutdown_event_->Signal();
250 if (gpu_channel_) {
251 gpu_channel_->DestroyChannel();
252 gpu_channel_ = NULL;
256 bool BrowserGpuChannelHostFactory::IsMainThread() {
257 return BrowserThread::CurrentlyOn(BrowserThread::UI);
260 scoped_refptr<base::SingleThreadTaskRunner>
261 BrowserGpuChannelHostFactory::GetIOThreadTaskRunner() {
262 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
265 scoped_ptr<base::SharedMemory>
266 BrowserGpuChannelHostFactory::AllocateSharedMemory(size_t size) {
267 scoped_ptr<base::SharedMemory> shm(new base::SharedMemory());
268 if (!shm->CreateAnonymous(size))
269 return scoped_ptr<base::SharedMemory>();
270 return shm.Pass();
273 void BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO(
274 CreateRequest* request,
275 int32 surface_id,
276 const GPUCreateCommandBufferConfig& init_params) {
277 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
278 if (!host) {
279 request->event.Signal();
280 return;
283 gfx::GLSurfaceHandle surface =
284 GpuSurfaceTracker::Get()->GetSurfaceHandle(surface_id);
286 host->CreateViewCommandBuffer(
287 surface,
288 surface_id,
289 gpu_client_id_,
290 init_params,
291 request->route_id,
292 base::Bind(&BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO,
293 request));
296 IPC::AttachmentBroker* BrowserGpuChannelHostFactory::GetAttachmentBroker() {
297 return content::ChildProcessHost::GetAttachmentBroker();
300 // static
301 void BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO(
302 CreateRequest* request, CreateCommandBufferResult result) {
303 request->result = result;
304 request->event.Signal();
307 CreateCommandBufferResult BrowserGpuChannelHostFactory::CreateViewCommandBuffer(
308 int32 surface_id,
309 const GPUCreateCommandBufferConfig& init_params,
310 int32 route_id) {
311 CreateRequest request(route_id);
312 GetIOThreadTaskRunner()->PostTask(
313 FROM_HERE,
314 base::Bind(&BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO,
315 base::Unretained(this), &request, surface_id, init_params));
316 // TODO(vadimt): Remove ScopedTracker below once crbug.com/125248 is fixed.
317 tracked_objects::ScopedTracker tracking_profile(
318 FROM_HERE_WITH_EXPLICIT_FUNCTION(
319 "125248 BrowserGpuChannelHostFactory::CreateViewCommandBuffer"));
321 // We're blocking the UI thread, which is generally undesirable.
322 // In this case we need to wait for this before we can show any UI /anyway/,
323 // so it won't cause additional jank.
324 // TODO(piman): Make this asynchronous (http://crbug.com/125248).
325 TRACE_EVENT0("browser",
326 "BrowserGpuChannelHostFactory::CreateViewCommandBuffer");
327 base::ThreadRestrictions::ScopedAllowWait allow_wait;
328 request.event.Wait();
329 return request.result;
332 // Blocking the UI thread to open a GPU channel is not supported on Android.
333 // (Opening the initial channel to a child process involves handling a reply
334 // task on the UI thread first, so we cannot block here.)
335 #if !defined(OS_ANDROID)
336 GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
337 CauseForGpuLaunch cause_for_gpu_launch) {
338 EstablishGpuChannel(cause_for_gpu_launch, base::Closure());
340 if (pending_request_.get())
341 pending_request_->Wait();
343 return gpu_channel_.get();
345 #endif
347 void BrowserGpuChannelHostFactory::EstablishGpuChannel(
348 CauseForGpuLaunch cause_for_gpu_launch,
349 const base::Closure& callback) {
350 if (gpu_channel_.get() && gpu_channel_->IsLost()) {
351 DCHECK(!pending_request_.get());
352 // Recreate the channel if it has been lost.
353 gpu_channel_->DestroyChannel();
354 gpu_channel_ = NULL;
357 if (!gpu_channel_.get() && !pending_request_.get()) {
358 // We should only get here if the context was lost.
359 pending_request_ = EstablishRequest::Create(
360 cause_for_gpu_launch, gpu_client_id_,
361 gpu_client_tracing_id_,
362 gpu_host_id_);
365 if (!callback.is_null()) {
366 if (gpu_channel_.get())
367 callback.Run();
368 else
369 established_callbacks_.push_back(callback);
373 GpuChannelHost* BrowserGpuChannelHostFactory::GetGpuChannel() {
374 if (gpu_channel_.get() && !gpu_channel_->IsLost())
375 return gpu_channel_.get();
377 return NULL;
380 void BrowserGpuChannelHostFactory::GpuChannelEstablished() {
381 DCHECK(IsMainThread());
382 DCHECK(pending_request_.get());
383 if (pending_request_->channel_handle().name.empty()) {
384 DCHECK(!gpu_channel_.get());
385 } else {
386 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/466866
387 // is fixed.
388 tracked_objects::ScopedTracker tracking_profile1(
389 FROM_HERE_WITH_EXPLICIT_FUNCTION(
390 "466866 BrowserGpuChannelHostFactory::GpuChannelEstablished1"));
391 GetContentClient()->SetGpuInfo(pending_request_->gpu_info());
392 gpu_channel_ = GpuChannelHost::Create(
393 this, pending_request_->gpu_info(), pending_request_->channel_handle(),
394 shutdown_event_.get(), gpu_memory_buffer_manager_.get());
396 gpu_host_id_ = pending_request_->gpu_host_id();
397 pending_request_ = NULL;
399 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/466866 is
400 // fixed.
401 tracked_objects::ScopedTracker tracking_profile2(
402 FROM_HERE_WITH_EXPLICIT_FUNCTION(
403 "466866 BrowserGpuChannelHostFactory::GpuChannelEstablished2"));
405 for (size_t n = 0; n < established_callbacks_.size(); n++)
406 established_callbacks_[n].Run();
408 established_callbacks_.clear();
411 // static
412 void BrowserGpuChannelHostFactory::AddFilterOnIO(
413 int host_id,
414 scoped_refptr<IPC::MessageFilter> filter) {
415 DCHECK_CURRENTLY_ON(BrowserThread::IO);
417 GpuProcessHost* host = GpuProcessHost::FromID(host_id);
418 if (host)
419 host->AddFilter(filter.get());
422 } // namespace content