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/threading/thread_restrictions.h"
9 #include "content/browser/gpu/gpu_data_manager_impl.h"
10 #include "content/browser/gpu/gpu_process_host.h"
11 #include "content/browser/gpu/gpu_surface_tracker.h"
12 #include "content/common/gpu/gpu_messages.h"
13 #include "content/common/child_process_host_impl.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/common/content_client.h"
16 #include "ipc/ipc_forwarding_message_filter.h"
20 BrowserGpuChannelHostFactory
* BrowserGpuChannelHostFactory::instance_
= NULL
;
22 BrowserGpuChannelHostFactory::CreateRequest::CreateRequest()
23 : event(false, false),
25 route_id(MSG_ROUTING_NONE
) {
28 BrowserGpuChannelHostFactory::CreateRequest::~CreateRequest() {
31 BrowserGpuChannelHostFactory::EstablishRequest::EstablishRequest(
32 CauseForGpuLaunch cause
)
33 : event(false, false),
34 cause_for_gpu_launch(cause
),
36 reused_gpu_process(true) {
39 BrowserGpuChannelHostFactory::EstablishRequest::~EstablishRequest() {
42 void BrowserGpuChannelHostFactory::Initialize() {
43 instance_
= new BrowserGpuChannelHostFactory();
46 void BrowserGpuChannelHostFactory::Terminate() {
51 BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory()
52 : gpu_client_id_(ChildProcessHostImpl::GenerateChildProcessUniqueId()),
53 shutdown_event_(new base::WaitableEvent(true, false)),
57 BrowserGpuChannelHostFactory::~BrowserGpuChannelHostFactory() {
58 shutdown_event_
->Signal();
61 bool BrowserGpuChannelHostFactory::IsMainThread() {
62 return BrowserThread::CurrentlyOn(BrowserThread::UI
);
65 base::MessageLoop
* BrowserGpuChannelHostFactory::GetMainLoop() {
66 return BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::UI
);
69 scoped_refptr
<base::MessageLoopProxy
>
70 BrowserGpuChannelHostFactory::GetIOLoopProxy() {
71 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO
);
74 base::WaitableEvent
* BrowserGpuChannelHostFactory::GetShutDownEvent() {
75 return shutdown_event_
.get();
78 scoped_ptr
<base::SharedMemory
>
79 BrowserGpuChannelHostFactory::AllocateSharedMemory(size_t size
) {
80 scoped_ptr
<base::SharedMemory
> shm(new base::SharedMemory());
81 if (!shm
->CreateAnonymous(size
))
82 return scoped_ptr
<base::SharedMemory
>();
86 void BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO(
87 CreateRequest
* request
,
89 const GPUCreateCommandBufferConfig
& init_params
) {
90 GpuProcessHost
* host
= GpuProcessHost::FromID(gpu_host_id_
);
92 request
->event
.Signal();
96 gfx::GLSurfaceHandle surface
=
97 GpuSurfaceTracker::Get()->GetSurfaceHandle(surface_id
);
99 host
->CreateViewCommandBuffer(
104 base::Bind(&BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO
,
109 void BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO(
110 CreateRequest
* request
, int32 route_id
) {
111 request
->route_id
= route_id
;
112 request
->event
.Signal();
115 int32
BrowserGpuChannelHostFactory::CreateViewCommandBuffer(
117 const GPUCreateCommandBufferConfig
& init_params
) {
118 CreateRequest request
;
119 GetIOLoopProxy()->PostTask(FROM_HERE
, base::Bind(
120 &BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO
,
121 base::Unretained(this),
125 // We're blocking the UI thread, which is generally undesirable.
126 // In this case we need to wait for this before we can show any UI /anyway/,
127 // so it won't cause additional jank.
128 // TODO(piman): Make this asynchronous (http://crbug.com/125248).
129 base::ThreadRestrictions::ScopedAllowWait allow_wait
;
130 request
.event
.Wait();
131 return request
.route_id
;
134 void BrowserGpuChannelHostFactory::CreateImageOnIO(
135 gfx::PluginWindowHandle window
,
137 const CreateImageCallback
& callback
) {
138 GpuProcessHost
* host
= GpuProcessHost::FromID(gpu_host_id_
);
140 ImageCreatedOnIO(callback
, gfx::Size());
148 base::Bind(&BrowserGpuChannelHostFactory::ImageCreatedOnIO
, callback
));
152 void BrowserGpuChannelHostFactory::ImageCreatedOnIO(
153 const CreateImageCallback
& callback
, const gfx::Size size
) {
154 BrowserThread::PostTask(
157 base::Bind(&BrowserGpuChannelHostFactory::OnImageCreated
,
162 void BrowserGpuChannelHostFactory::OnImageCreated(
163 const CreateImageCallback
& callback
, const gfx::Size size
) {
167 void BrowserGpuChannelHostFactory::CreateImage(
168 gfx::PluginWindowHandle window
,
170 const CreateImageCallback
& callback
) {
171 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
172 GetIOLoopProxy()->PostTask(FROM_HERE
, base::Bind(
173 &BrowserGpuChannelHostFactory::CreateImageOnIO
,
174 base::Unretained(this),
180 void BrowserGpuChannelHostFactory::DeleteImageOnIO(
181 int32 image_id
, int32 sync_point
) {
182 GpuProcessHost
* host
= GpuProcessHost::FromID(gpu_host_id_
);
187 host
->DeleteImage(gpu_client_id_
, image_id
, sync_point
);
190 void BrowserGpuChannelHostFactory::DeleteImage(
191 int32 image_id
, int32 sync_point
) {
192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
193 GetIOLoopProxy()->PostTask(FROM_HERE
, base::Bind(
194 &BrowserGpuChannelHostFactory::DeleteImageOnIO
,
195 base::Unretained(this),
200 void BrowserGpuChannelHostFactory::EstablishGpuChannelOnIO(
201 EstablishRequest
* request
) {
202 GpuProcessHost
* host
= GpuProcessHost::FromID(gpu_host_id_
);
204 host
= GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED
,
205 request
->cause_for_gpu_launch
);
207 request
->event
.Signal();
210 gpu_host_id_
= host
->host_id();
211 request
->reused_gpu_process
= false;
213 if (host
->host_id() == request
->gpu_host_id
) {
214 // We come here if we retried to establish the channel because of a
215 // failure in GpuChannelEstablishedOnIO, but we ended up with the same
216 // process ID, meaning the failure was not because of a channel error, but
217 // another reason. So fail now.
218 request
->event
.Signal();
221 request
->reused_gpu_process
= true;
223 request
->gpu_host_id
= gpu_host_id_
;
225 host
->EstablishGpuChannel(
228 base::Bind(&BrowserGpuChannelHostFactory::GpuChannelEstablishedOnIO
,
229 base::Unretained(this),
233 void BrowserGpuChannelHostFactory::GpuChannelEstablishedOnIO(
234 EstablishRequest
* request
,
235 const IPC::ChannelHandle
& channel_handle
,
236 const gpu::GPUInfo
& gpu_info
) {
237 if (channel_handle
.name
.empty() && request
->reused_gpu_process
) {
238 // We failed after re-using the GPU process, but it may have died in the
239 // mean time. Retry to have a chance to create a fresh GPU process.
240 EstablishGpuChannelOnIO(request
);
242 request
->channel_handle
= channel_handle
;
243 request
->gpu_info
= gpu_info
;
244 request
->event
.Signal();
248 GpuChannelHost
* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
249 CauseForGpuLaunch cause_for_gpu_launch
) {
250 if (gpu_channel_
.get()) {
251 // Recreate the channel if it has been lost.
252 if (gpu_channel_
->IsLost())
255 return gpu_channel_
.get();
257 // Ensure initialization on the main thread.
258 GpuDataManagerImpl::GetInstance();
260 EstablishRequest
request(cause_for_gpu_launch
);
261 GetIOLoopProxy()->PostTask(
264 &BrowserGpuChannelHostFactory::EstablishGpuChannelOnIO
,
265 base::Unretained(this),
269 // We're blocking the UI thread, which is generally undesirable.
270 // In this case we need to wait for this before we can show any UI /anyway/,
271 // so it won't cause additional jank.
272 // TODO(piman): Make this asynchronous (http://crbug.com/125248).
273 base::ThreadRestrictions::ScopedAllowWait allow_wait
;
274 request
.event
.Wait();
277 if (request
.channel_handle
.name
.empty())
280 GetContentClient()->SetGpuInfo(request
.gpu_info
);
281 gpu_channel_
= GpuChannelHost::Create(
282 this, request
.gpu_host_id
, gpu_client_id_
,
283 request
.gpu_info
, request
.channel_handle
);
284 return gpu_channel_
.get();
288 void BrowserGpuChannelHostFactory::AddFilterOnIO(
290 scoped_refptr
<IPC::ChannelProxy::MessageFilter
> filter
) {
291 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
292 GpuProcessHost
* host
= GpuProcessHost::FromID(host_id
);
294 host
->AddFilter(filter
.get());
297 void BrowserGpuChannelHostFactory::SetHandlerForControlMessages(
298 const uint32
* message_ids
,
300 const base::Callback
<void(const IPC::Message
&)>& handler
,
301 base::TaskRunner
* target_task_runner
) {
302 scoped_refptr
<IPC::ForwardingMessageFilter
> filter
=
303 new IPC::ForwardingMessageFilter(message_ids
,
306 filter
->AddRoute(MSG_ROUTING_CONTROL
, handler
);
308 GetIOLoopProxy()->PostTask(
310 base::Bind(&BrowserGpuChannelHostFactory::AddFilterOnIO
,
315 } // namespace content