Save errno for logging before potentially overwriting it.
[chromium-blink-merge.git] / content / browser / gpu / browser_gpu_channel_host_factory.cc
blob05159d2d30cef111ed373c8bf071f4416ad6c994
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/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"
18 namespace content {
20 BrowserGpuChannelHostFactory* BrowserGpuChannelHostFactory::instance_ = NULL;
22 BrowserGpuChannelHostFactory::CreateRequest::CreateRequest()
23 : event(false, false),
24 gpu_host_id(0),
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),
35 gpu_host_id(0),
36 reused_gpu_process(true) {
39 BrowserGpuChannelHostFactory::EstablishRequest::~EstablishRequest() {
42 void BrowserGpuChannelHostFactory::Initialize() {
43 instance_ = new BrowserGpuChannelHostFactory();
46 void BrowserGpuChannelHostFactory::Terminate() {
47 delete instance_;
48 instance_ = NULL;
51 BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory()
52 : gpu_client_id_(ChildProcessHostImpl::GenerateChildProcessUniqueId()),
53 shutdown_event_(new base::WaitableEvent(true, false)),
54 gpu_host_id_(0) {
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>();
83 return shm.Pass();
86 void BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO(
87 CreateRequest* request,
88 int32 surface_id,
89 const GPUCreateCommandBufferConfig& init_params) {
90 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
91 if (!host) {
92 request->event.Signal();
93 return;
96 gfx::GLSurfaceHandle surface =
97 GpuSurfaceTracker::Get()->GetSurfaceHandle(surface_id);
99 host->CreateViewCommandBuffer(
100 surface,
101 surface_id,
102 gpu_client_id_,
103 init_params,
104 base::Bind(&BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO,
105 request));
108 // static
109 void BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO(
110 CreateRequest* request, int32 route_id) {
111 request->route_id = route_id;
112 request->event.Signal();
115 int32 BrowserGpuChannelHostFactory::CreateViewCommandBuffer(
116 int32 surface_id,
117 const GPUCreateCommandBufferConfig& init_params) {
118 CreateRequest request;
119 GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind(
120 &BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO,
121 base::Unretained(this),
122 &request,
123 surface_id,
124 init_params));
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,
136 int32 image_id,
137 const CreateImageCallback& callback) {
138 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
139 if (!host) {
140 ImageCreatedOnIO(callback, gfx::Size());
141 return;
144 host->CreateImage(
145 window,
146 gpu_client_id_,
147 image_id,
148 base::Bind(&BrowserGpuChannelHostFactory::ImageCreatedOnIO, callback));
151 // static
152 void BrowserGpuChannelHostFactory::ImageCreatedOnIO(
153 const CreateImageCallback& callback, const gfx::Size size) {
154 BrowserThread::PostTask(
155 BrowserThread::UI,
156 FROM_HERE,
157 base::Bind(&BrowserGpuChannelHostFactory::OnImageCreated,
158 callback, size));
161 // static
162 void BrowserGpuChannelHostFactory::OnImageCreated(
163 const CreateImageCallback& callback, const gfx::Size size) {
164 callback.Run(size);
167 void BrowserGpuChannelHostFactory::CreateImage(
168 gfx::PluginWindowHandle window,
169 int32 image_id,
170 const CreateImageCallback& callback) {
171 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
172 GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind(
173 &BrowserGpuChannelHostFactory::CreateImageOnIO,
174 base::Unretained(this),
175 window,
176 image_id,
177 callback));
180 void BrowserGpuChannelHostFactory::DeleteImageOnIO(
181 int32 image_id, int32 sync_point) {
182 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
183 if (!host) {
184 return;
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),
196 image_id,
197 sync_point));
200 void BrowserGpuChannelHostFactory::EstablishGpuChannelOnIO(
201 EstablishRequest* request) {
202 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
203 if (!host) {
204 host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
205 request->cause_for_gpu_launch);
206 if (!host) {
207 request->event.Signal();
208 return;
210 gpu_host_id_ = host->host_id();
211 request->reused_gpu_process = false;
212 } else {
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();
219 return;
221 request->reused_gpu_process = true;
223 request->gpu_host_id = gpu_host_id_;
225 host->EstablishGpuChannel(
226 gpu_client_id_,
227 true,
228 base::Bind(&BrowserGpuChannelHostFactory::GpuChannelEstablishedOnIO,
229 base::Unretained(this),
230 request));
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);
241 } else {
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())
253 gpu_channel_ = NULL;
254 else
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(
262 FROM_HERE,
263 base::Bind(
264 &BrowserGpuChannelHostFactory::EstablishGpuChannelOnIO,
265 base::Unretained(this),
266 &request));
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())
278 return NULL;
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();
287 // static
288 void BrowserGpuChannelHostFactory::AddFilterOnIO(
289 int host_id,
290 scoped_refptr<IPC::ChannelProxy::MessageFilter> filter) {
291 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
292 GpuProcessHost* host = GpuProcessHost::FromID(host_id);
293 if (host)
294 host->AddFilter(filter.get());
297 void BrowserGpuChannelHostFactory::SetHandlerForControlMessages(
298 const uint32* message_ids,
299 size_t num_messages,
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,
304 num_messages,
305 target_task_runner);
306 filter->AddRoute(MSG_ROUTING_CONTROL, handler);
308 GetIOLoopProxy()->PostTask(
309 FROM_HERE,
310 base::Bind(&BrowserGpuChannelHostFactory::AddFilterOnIO,
311 gpu_host_id_,
312 filter));
315 } // namespace content