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/debug/trace_event.h"
9 #include "base/threading/thread_restrictions.h"
10 #include "content/browser/gpu/gpu_data_manager_impl.h"
11 #include "content/browser/gpu/gpu_process_host.h"
12 #include "content/browser/gpu/gpu_surface_tracker.h"
13 #include "content/common/child_process_host_impl.h"
14 #include "content/common/gpu/client/gpu_memory_buffer_impl.h"
15 #include "content/common/gpu/gpu_messages.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/common/content_client.h"
18 #include "ipc/ipc_forwarding_message_filter.h"
22 BrowserGpuChannelHostFactory* BrowserGpuChannelHostFactory::instance_ = NULL;
24 BrowserGpuChannelHostFactory::CreateRequest::CreateRequest()
27 route_id(MSG_ROUTING_NONE) {
30 BrowserGpuChannelHostFactory::CreateRequest::~CreateRequest() {
33 BrowserGpuChannelHostFactory::EstablishRequest::EstablishRequest(
34 CauseForGpuLaunch cause,
37 : event_(false, false),
38 cause_for_gpu_launch_(cause),
39 gpu_client_id_(gpu_client_id),
40 gpu_host_id_(gpu_host_id),
41 reused_gpu_process_(false),
43 main_loop_(base::MessageLoopProxy::current()) {
44 scoped_refptr<base::MessageLoopProxy> loop =
45 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
48 base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO,
52 BrowserGpuChannelHostFactory::EstablishRequest::~EstablishRequest() {
55 void BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO() {
56 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
58 host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
59 cause_for_gpu_launch_);
64 gpu_host_id_ = host->host_id();
65 reused_gpu_process_ = false;
67 if (reused_gpu_process_) {
68 // We come here if we retried to establish the channel because of a
69 // failure in ChannelEstablishedOnIO, but we ended up with the same
70 // process ID, meaning the failure was not because of a channel error,
71 // but another reason. So fail now.
75 reused_gpu_process_ = true;
78 host->EstablishGpuChannel(
82 &BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO,
86 void BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO(
87 const IPC::ChannelHandle& channel_handle,
88 const gpu::GPUInfo& gpu_info) {
89 if (channel_handle.name.empty() && reused_gpu_process_) {
90 // We failed after re-using the GPU process, but it may have died in the
91 // mean time. Retry to have a chance to create a fresh GPU process.
94 channel_handle_ = channel_handle;
100 void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnIO() {
102 main_loop_->PostTask(
104 base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain,
108 void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain() {
110 BrowserGpuChannelHostFactory* factory =
111 BrowserGpuChannelHostFactory::instance();
112 factory->GpuChannelEstablished();
117 void BrowserGpuChannelHostFactory::EstablishRequest::Wait() {
118 DCHECK(main_loop_->BelongsToCurrentThread());
120 // We're blocking the UI thread, which is generally undesirable.
121 // In this case we need to wait for this before we can show any UI
122 // /anyway/, so it won't cause additional jank.
123 // TODO(piman): Make this asynchronous (http://crbug.com/125248).
124 TRACE_EVENT0("browser",
125 "BrowserGpuChannelHostFactory::EstablishGpuChannelSync");
126 base::ThreadRestrictions::ScopedAllowWait allow_wait;
132 void BrowserGpuChannelHostFactory::EstablishRequest::Cancel() {
133 DCHECK(main_loop_->BelongsToCurrentThread());
137 void BrowserGpuChannelHostFactory::Initialize(bool establish_gpu_channel) {
139 instance_ = new BrowserGpuChannelHostFactory(establish_gpu_channel);
142 void BrowserGpuChannelHostFactory::Terminate() {
148 BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory(
149 bool establish_gpu_channel)
150 : gpu_client_id_(ChildProcessHostImpl::GenerateChildProcessUniqueId()),
151 shutdown_event_(new base::WaitableEvent(true, false)),
153 if (establish_gpu_channel) {
154 pending_request_ = new EstablishRequest(
155 CAUSE_FOR_GPU_LAUNCH_BROWSER_STARTUP, gpu_client_id_, gpu_host_id_);
159 BrowserGpuChannelHostFactory::~BrowserGpuChannelHostFactory() {
160 DCHECK(IsMainThread());
161 if (pending_request_)
162 pending_request_->Cancel();
163 for (size_t n = 0; n < established_callbacks_.size(); n++)
164 established_callbacks_[n].Run();
165 shutdown_event_->Signal();
168 bool BrowserGpuChannelHostFactory::IsMainThread() {
169 return BrowserThread::CurrentlyOn(BrowserThread::UI);
172 base::MessageLoop* BrowserGpuChannelHostFactory::GetMainLoop() {
173 return BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::UI);
176 scoped_refptr<base::MessageLoopProxy>
177 BrowserGpuChannelHostFactory::GetIOLoopProxy() {
178 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
181 base::WaitableEvent* BrowserGpuChannelHostFactory::GetShutDownEvent() {
182 return shutdown_event_.get();
185 scoped_ptr<base::SharedMemory>
186 BrowserGpuChannelHostFactory::AllocateSharedMemory(size_t size) {
187 scoped_ptr<base::SharedMemory> shm(new base::SharedMemory());
188 if (!shm->CreateAnonymous(size))
189 return scoped_ptr<base::SharedMemory>();
193 void BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO(
194 CreateRequest* request,
196 const GPUCreateCommandBufferConfig& init_params) {
197 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
199 request->event.Signal();
203 gfx::GLSurfaceHandle surface =
204 GpuSurfaceTracker::Get()->GetSurfaceHandle(surface_id);
206 host->CreateViewCommandBuffer(
211 base::Bind(&BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO,
216 void BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO(
217 CreateRequest* request, int32 route_id) {
218 request->route_id = route_id;
219 request->event.Signal();
222 int32 BrowserGpuChannelHostFactory::CreateViewCommandBuffer(
224 const GPUCreateCommandBufferConfig& init_params) {
225 CreateRequest request;
226 GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind(
227 &BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO,
228 base::Unretained(this),
232 // We're blocking the UI thread, which is generally undesirable.
233 // In this case we need to wait for this before we can show any UI /anyway/,
234 // so it won't cause additional jank.
235 // TODO(piman): Make this asynchronous (http://crbug.com/125248).
236 TRACE_EVENT0("browser",
237 "BrowserGpuChannelHostFactory::CreateViewCommandBuffer");
238 base::ThreadRestrictions::ScopedAllowWait allow_wait;
239 request.event.Wait();
240 return request.route_id;
243 void BrowserGpuChannelHostFactory::CreateImageOnIO(
244 gfx::PluginWindowHandle window,
246 const CreateImageCallback& callback) {
247 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
249 ImageCreatedOnIO(callback, gfx::Size());
257 base::Bind(&BrowserGpuChannelHostFactory::ImageCreatedOnIO, callback));
261 void BrowserGpuChannelHostFactory::ImageCreatedOnIO(
262 const CreateImageCallback& callback, const gfx::Size size) {
263 BrowserThread::PostTask(
266 base::Bind(&BrowserGpuChannelHostFactory::OnImageCreated,
271 void BrowserGpuChannelHostFactory::OnImageCreated(
272 const CreateImageCallback& callback, const gfx::Size size) {
276 void BrowserGpuChannelHostFactory::CreateImage(
277 gfx::PluginWindowHandle window,
279 const CreateImageCallback& callback) {
280 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
281 GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind(
282 &BrowserGpuChannelHostFactory::CreateImageOnIO,
283 base::Unretained(this),
289 void BrowserGpuChannelHostFactory::DeleteImageOnIO(
290 int32 image_id, int32 sync_point) {
291 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
296 host->DeleteImage(gpu_client_id_, image_id, sync_point);
299 void BrowserGpuChannelHostFactory::DeleteImage(
300 int32 image_id, int32 sync_point) {
301 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
302 GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind(
303 &BrowserGpuChannelHostFactory::DeleteImageOnIO,
304 base::Unretained(this),
309 GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
310 CauseForGpuLaunch cause_for_gpu_launch) {
311 EstablishGpuChannel(cause_for_gpu_launch, base::Closure());
313 if (pending_request_)
314 pending_request_->Wait();
316 return gpu_channel_.get();
319 void BrowserGpuChannelHostFactory::EstablishGpuChannel(
320 CauseForGpuLaunch cause_for_gpu_launch,
321 const base::Closure& callback) {
322 if (gpu_channel_.get() && gpu_channel_->IsLost()) {
323 DCHECK(!pending_request_);
324 // Recreate the channel if it has been lost.
328 if (!gpu_channel_ && !pending_request_) {
329 // We should only get here if the context was lost.
330 pending_request_ = new EstablishRequest(
331 cause_for_gpu_launch, gpu_client_id_, gpu_host_id_);
334 if (!callback.is_null()) {
338 established_callbacks_.push_back(callback);
342 GpuChannelHost* BrowserGpuChannelHostFactory::GetGpuChannel() {
343 if (gpu_channel_ && !gpu_channel_->IsLost())
349 void BrowserGpuChannelHostFactory::GpuChannelEstablished() {
350 DCHECK(IsMainThread());
351 DCHECK(pending_request_);
352 if (pending_request_->channel_handle().name.empty())
355 GetContentClient()->SetGpuInfo(pending_request_->gpu_info());
356 gpu_channel_ = GpuChannelHost::Create(this,
357 pending_request_->gpu_host_id(),
359 pending_request_->gpu_info(),
360 pending_request_->channel_handle());
361 gpu_host_id_ = pending_request_->gpu_host_id();
362 pending_request_ = NULL;
364 for (size_t n = 0; n < established_callbacks_.size(); n++)
365 established_callbacks_[n].Run();
367 established_callbacks_.clear();
370 scoped_ptr<gfx::GpuMemoryBuffer>
371 BrowserGpuChannelHostFactory::AllocateGpuMemoryBuffer(
374 unsigned internalformat) {
375 if (!GpuMemoryBufferImpl::IsFormatValid(internalformat))
376 return scoped_ptr<gfx::GpuMemoryBuffer>();
378 size_t size = width * height *
379 GpuMemoryBufferImpl::BytesPerPixel(internalformat);
380 scoped_ptr<base::SharedMemory> shm(new base::SharedMemory());
381 if (!shm->CreateAnonymous(size))
382 return scoped_ptr<gfx::GpuMemoryBuffer>();
384 return make_scoped_ptr<gfx::GpuMemoryBuffer>(
385 new GpuMemoryBufferImpl(shm.Pass(),
392 void BrowserGpuChannelHostFactory::AddFilterOnIO(
394 scoped_refptr<IPC::ChannelProxy::MessageFilter> filter) {
395 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
397 GpuProcessHost* host = GpuProcessHost::FromID(host_id);
399 host->AddFilter(filter.get());
402 void BrowserGpuChannelHostFactory::SetHandlerForControlMessages(
403 const uint32* message_ids,
405 const base::Callback<void(const IPC::Message&)>& handler,
406 base::TaskRunner* target_task_runner) {
409 << " BrowserGpuChannelHostFactory::SetHandlerForControlMessages()"
410 << " until the GpuProcessHost has been set up.";
412 scoped_refptr<IPC::ForwardingMessageFilter> filter =
413 new IPC::ForwardingMessageFilter(message_ids,
416 filter->AddRoute(MSG_ROUTING_CONTROL, handler);
418 GetIOLoopProxy()->PostTask(
420 base::Bind(&BrowserGpuChannelHostFactory::AddFilterOnIO,
425 } // namespace content