DevTools: cut host and port from webSocketDebuggerUrl in addition to ws:// prefix
[chromium-blink-merge.git] / content / browser / gpu / browser_gpu_channel_host_factory.cc
blob3de76c0b298191048f40635bbb47f63167028bab
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/trace_event.h"
15 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
16 #include "content/browser/gpu/gpu_data_manager_impl.h"
17 #include "content/browser/gpu/gpu_process_host.h"
18 #include "content/browser/gpu/gpu_surface_tracker.h"
19 #include "content/common/child_process_host_impl.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 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 int gpu_host_id);
51 void Wait();
52 void Cancel();
54 int gpu_host_id() { return gpu_host_id_; }
55 IPC::ChannelHandle& channel_handle() { return channel_handle_; }
56 gpu::GPUInfo gpu_info() { return gpu_info_; }
58 private:
59 friend class base::RefCountedThreadSafe<EstablishRequest>;
60 explicit EstablishRequest(CauseForGpuLaunch cause,
61 int gpu_client_id,
62 int gpu_host_id);
63 ~EstablishRequest() {}
64 void EstablishOnIO();
65 void OnEstablishedOnIO(const IPC::ChannelHandle& channel_handle,
66 const gpu::GPUInfo& gpu_info);
67 void FinishOnIO();
68 void FinishOnMain();
70 base::WaitableEvent event_;
71 CauseForGpuLaunch cause_for_gpu_launch_;
72 const int gpu_client_id_;
73 int gpu_host_id_;
74 bool reused_gpu_process_;
75 IPC::ChannelHandle channel_handle_;
76 gpu::GPUInfo gpu_info_;
77 bool finished_;
78 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
81 scoped_refptr<BrowserGpuChannelHostFactory::EstablishRequest>
82 BrowserGpuChannelHostFactory::EstablishRequest::Create(CauseForGpuLaunch cause,
83 int gpu_client_id,
84 int gpu_host_id) {
85 scoped_refptr<EstablishRequest> establish_request =
86 new EstablishRequest(cause, gpu_client_id, gpu_host_id);
87 scoped_refptr<base::SingleThreadTaskRunner> task_runner =
88 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
89 // PostTask outside the constructor to ensure at least one reference exists.
90 task_runner->PostTask(
91 FROM_HERE,
92 base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO,
93 establish_request));
94 return establish_request;
97 BrowserGpuChannelHostFactory::EstablishRequest::EstablishRequest(
98 CauseForGpuLaunch cause,
99 int gpu_client_id,
100 int gpu_host_id)
101 : event_(false, false),
102 cause_for_gpu_launch_(cause),
103 gpu_client_id_(gpu_client_id),
104 gpu_host_id_(gpu_host_id),
105 reused_gpu_process_(false),
106 finished_(false),
107 main_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
110 void BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO() {
111 // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
112 tracked_objects::ScopedTracker tracking_profile(
113 FROM_HERE_WITH_EXPLICIT_FUNCTION(
114 "477117 "
115 "BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO"));
116 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
117 if (!host) {
118 host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
119 cause_for_gpu_launch_);
120 if (!host) {
121 LOG(ERROR) << "Failed to launch GPU process.";
122 FinishOnIO();
123 return;
125 gpu_host_id_ = host->host_id();
126 reused_gpu_process_ = false;
127 } else {
128 if (reused_gpu_process_) {
129 // We come here if we retried to establish the channel because of a
130 // failure in ChannelEstablishedOnIO, but we ended up with the same
131 // process ID, meaning the failure was not because of a channel error,
132 // but another reason. So fail now.
133 LOG(ERROR) << "Failed to create channel.";
134 FinishOnIO();
135 return;
137 reused_gpu_process_ = true;
140 host->EstablishGpuChannel(
141 gpu_client_id_,
142 true,
143 true,
144 base::Bind(
145 &BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO,
146 this));
149 void BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO(
150 const IPC::ChannelHandle& channel_handle,
151 const gpu::GPUInfo& gpu_info) {
152 if (channel_handle.name.empty() && reused_gpu_process_) {
153 // We failed after re-using the GPU process, but it may have died in the
154 // mean time. Retry to have a chance to create a fresh GPU process.
155 DVLOG(1) << "Failed to create channel on existing GPU process. Trying to "
156 "restart GPU process.";
157 EstablishOnIO();
158 } else {
159 channel_handle_ = channel_handle;
160 gpu_info_ = gpu_info;
161 FinishOnIO();
165 void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnIO() {
166 event_.Signal();
167 main_task_runner_->PostTask(
168 FROM_HERE,
169 base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain,
170 this));
173 void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain() {
174 if (!finished_) {
175 BrowserGpuChannelHostFactory* factory =
176 BrowserGpuChannelHostFactory::instance();
177 factory->GpuChannelEstablished();
178 finished_ = true;
182 void BrowserGpuChannelHostFactory::EstablishRequest::Wait() {
183 DCHECK(main_task_runner_->BelongsToCurrentThread());
185 // TODO(vadimt): Remove ScopedTracker below once crbug.com/125248 is fixed.
186 tracked_objects::ScopedTracker tracking_profile(
187 FROM_HERE_WITH_EXPLICIT_FUNCTION(
188 "125248 BrowserGpuChannelHostFactory::EstablishRequest::Wait"));
190 // We're blocking the UI thread, which is generally undesirable.
191 // In this case we need to wait for this before we can show any UI
192 // /anyway/, so it won't cause additional jank.
193 // TODO(piman): Make this asynchronous (http://crbug.com/125248).
194 TRACE_EVENT0("browser",
195 "BrowserGpuChannelHostFactory::EstablishGpuChannelSync");
196 base::ThreadRestrictions::ScopedAllowWait allow_wait;
197 event_.Wait();
199 FinishOnMain();
202 void BrowserGpuChannelHostFactory::EstablishRequest::Cancel() {
203 DCHECK(main_task_runner_->BelongsToCurrentThread());
204 finished_ = true;
207 bool BrowserGpuChannelHostFactory::CanUseForTesting() {
208 return GpuDataManager::GetInstance()->GpuAccessAllowed(NULL);
211 void BrowserGpuChannelHostFactory::Initialize(bool establish_gpu_channel) {
212 DCHECK(!instance_);
213 instance_ = new BrowserGpuChannelHostFactory();
214 if (establish_gpu_channel) {
215 instance_->EstablishGpuChannel(CAUSE_FOR_GPU_LAUNCH_BROWSER_STARTUP,
216 base::Closure());
220 void BrowserGpuChannelHostFactory::Terminate() {
221 DCHECK(instance_);
222 delete instance_;
223 instance_ = NULL;
226 BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory()
227 : gpu_client_id_(ChildProcessHostImpl::GenerateChildProcessUniqueId()),
228 shutdown_event_(new base::WaitableEvent(true, false)),
229 gpu_memory_buffer_manager_(
230 new BrowserGpuMemoryBufferManager(gpu_client_id_)),
231 gpu_host_id_(0) {
234 BrowserGpuChannelHostFactory::~BrowserGpuChannelHostFactory() {
235 DCHECK(IsMainThread());
236 if (pending_request_.get())
237 pending_request_->Cancel();
238 for (size_t n = 0; n < established_callbacks_.size(); n++)
239 established_callbacks_[n].Run();
240 shutdown_event_->Signal();
241 if (gpu_channel_) {
242 gpu_channel_->DestroyChannel();
243 gpu_channel_ = NULL;
247 bool BrowserGpuChannelHostFactory::IsMainThread() {
248 return BrowserThread::CurrentlyOn(BrowserThread::UI);
251 scoped_refptr<base::SingleThreadTaskRunner>
252 BrowserGpuChannelHostFactory::GetIOThreadTaskRunner() {
253 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
256 scoped_ptr<base::SharedMemory>
257 BrowserGpuChannelHostFactory::AllocateSharedMemory(size_t size) {
258 scoped_ptr<base::SharedMemory> shm(new base::SharedMemory());
259 if (!shm->CreateAnonymous(size))
260 return scoped_ptr<base::SharedMemory>();
261 return shm.Pass();
264 void BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO(
265 CreateRequest* request,
266 int32 surface_id,
267 const GPUCreateCommandBufferConfig& init_params) {
268 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
269 if (!host) {
270 request->event.Signal();
271 return;
274 gfx::GLSurfaceHandle surface =
275 GpuSurfaceTracker::Get()->GetSurfaceHandle(surface_id);
277 host->CreateViewCommandBuffer(
278 surface,
279 surface_id,
280 gpu_client_id_,
281 init_params,
282 request->route_id,
283 base::Bind(&BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO,
284 request));
287 IPC::AttachmentBroker* BrowserGpuChannelHostFactory::GetAttachmentBroker() {
288 return content::ChildProcessHost::GetAttachmentBroker();
291 // static
292 void BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO(
293 CreateRequest* request, CreateCommandBufferResult result) {
294 request->result = result;
295 request->event.Signal();
298 CreateCommandBufferResult BrowserGpuChannelHostFactory::CreateViewCommandBuffer(
299 int32 surface_id,
300 const GPUCreateCommandBufferConfig& init_params,
301 int32 route_id) {
302 CreateRequest request(route_id);
303 GetIOThreadTaskRunner()->PostTask(
304 FROM_HERE,
305 base::Bind(&BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO,
306 base::Unretained(this), &request, surface_id, init_params));
307 // TODO(vadimt): Remove ScopedTracker below once crbug.com/125248 is fixed.
308 tracked_objects::ScopedTracker tracking_profile(
309 FROM_HERE_WITH_EXPLICIT_FUNCTION(
310 "125248 BrowserGpuChannelHostFactory::CreateViewCommandBuffer"));
312 // We're blocking the UI thread, which is generally undesirable.
313 // In this case we need to wait for this before we can show any UI /anyway/,
314 // so it won't cause additional jank.
315 // TODO(piman): Make this asynchronous (http://crbug.com/125248).
316 TRACE_EVENT0("browser",
317 "BrowserGpuChannelHostFactory::CreateViewCommandBuffer");
318 base::ThreadRestrictions::ScopedAllowWait allow_wait;
319 request.event.Wait();
320 return request.result;
323 // Blocking the UI thread to open a GPU channel is not supported on Android.
324 // (Opening the initial channel to a child process involves handling a reply
325 // task on the UI thread first, so we cannot block here.)
326 #if !defined(OS_ANDROID)
327 GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
328 CauseForGpuLaunch cause_for_gpu_launch) {
329 EstablishGpuChannel(cause_for_gpu_launch, base::Closure());
331 if (pending_request_.get())
332 pending_request_->Wait();
334 return gpu_channel_.get();
336 #endif
338 void BrowserGpuChannelHostFactory::EstablishGpuChannel(
339 CauseForGpuLaunch cause_for_gpu_launch,
340 const base::Closure& callback) {
341 if (gpu_channel_.get() && gpu_channel_->IsLost()) {
342 DCHECK(!pending_request_.get());
343 // Recreate the channel if it has been lost.
344 gpu_channel_->DestroyChannel();
345 gpu_channel_ = NULL;
348 if (!gpu_channel_.get() && !pending_request_.get()) {
349 // We should only get here if the context was lost.
350 pending_request_ = EstablishRequest::Create(
351 cause_for_gpu_launch, gpu_client_id_, gpu_host_id_);
354 if (!callback.is_null()) {
355 if (gpu_channel_.get())
356 callback.Run();
357 else
358 established_callbacks_.push_back(callback);
362 GpuChannelHost* BrowserGpuChannelHostFactory::GetGpuChannel() {
363 if (gpu_channel_.get() && !gpu_channel_->IsLost())
364 return gpu_channel_.get();
366 return NULL;
369 void BrowserGpuChannelHostFactory::GpuChannelEstablished() {
370 DCHECK(IsMainThread());
371 DCHECK(pending_request_.get());
372 if (pending_request_->channel_handle().name.empty()) {
373 DCHECK(!gpu_channel_.get());
374 } else {
375 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/466866
376 // is fixed.
377 tracked_objects::ScopedTracker tracking_profile1(
378 FROM_HERE_WITH_EXPLICIT_FUNCTION(
379 "466866 BrowserGpuChannelHostFactory::GpuChannelEstablished1"));
380 GetContentClient()->SetGpuInfo(pending_request_->gpu_info());
381 gpu_channel_ = GpuChannelHost::Create(
382 this, pending_request_->gpu_info(), pending_request_->channel_handle(),
383 shutdown_event_.get(), gpu_memory_buffer_manager_.get());
385 gpu_host_id_ = pending_request_->gpu_host_id();
386 pending_request_ = NULL;
388 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/466866 is
389 // fixed.
390 tracked_objects::ScopedTracker tracking_profile2(
391 FROM_HERE_WITH_EXPLICIT_FUNCTION(
392 "466866 BrowserGpuChannelHostFactory::GpuChannelEstablished2"));
394 for (size_t n = 0; n < established_callbacks_.size(); n++)
395 established_callbacks_[n].Run();
397 established_callbacks_.clear();
400 // static
401 void BrowserGpuChannelHostFactory::AddFilterOnIO(
402 int host_id,
403 scoped_refptr<IPC::MessageFilter> filter) {
404 DCHECK_CURRENTLY_ON(BrowserThread::IO);
406 GpuProcessHost* host = GpuProcessHost::FromID(host_id);
407 if (host)
408 host->AddFilter(filter.get());
411 } // namespace content