Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(355)

Side by Side Diff: content/browser/gpu/gpu_message_hub.cc

Issue 7054005: Fix gpu acceleration with --in-process-gpu (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: cleanup Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 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.
4
5 #include "content/browser/gpu/gpu_message_hub.h"
6
7 #include "base/command_line.h"
8 #include "content/browser/browser_thread.h"
9 #include "content/browser/gpu/gpu_data_manager.h"
10 #include "content/browser/gpu/gpu_process_host.h"
11 #include "content/browser/gpu/gpu_process_host_ui_shim.h"
12 #include "content/browser/gpu/gpu_thread_host.h"
13 #include "content/common/content_switches.h"
14 #include "content/common/gpu/gpu_info.h"
15 #include "content/common/gpu/gpu_messages.h"
16 #include "ipc/ipc_channel_handle.h"
17 #include "ipc/ipc_message.h"
18 #include "ipc/ipc_message_macros.h"
19
20 #if defined(OS_LINUX)
21 #include "ui/gfx/gtk_native_view_id_manager.h"
22
23 class ReleasePermanentXIDDispatcher: public Task {
24 public:
25 explicit ReleasePermanentXIDDispatcher(gfx::PluginWindowHandle surface);
26 void Run();
27 private:
28 gfx::PluginWindowHandle surface_;
29 };
30
31 ReleasePermanentXIDDispatcher::ReleasePermanentXIDDispatcher(
32 gfx::PluginWindowHandle surface)
33 : surface_(surface) {
34 }
35
36 void ReleasePermanentXIDDispatcher::Run() {
37 GtkNativeViewManager* manager = GtkNativeViewManager::GetInstance();
38 manager->ReleasePermanentXID(surface_);
39 }
40
41 // Used to put a lock on surfaces so that the window to which the GPU
42 // process is drawing to doesn't disappear while it is drawing when
43 // a tab is closed.
44 class GpuMessageHub::SurfaceRef {
45 public:
46 explicit SurfaceRef(gfx::PluginWindowHandle surface);
47 ~SurfaceRef();
48 private:
49 gfx::PluginWindowHandle surface_;
50 };
51
52 GpuMessageHub::SurfaceRef::SurfaceRef(gfx::PluginWindowHandle surface)
53 : surface_(surface) {
54 GtkNativeViewManager* manager = GtkNativeViewManager::GetInstance();
55 if (!manager->AddRefPermanentXID(surface_)) {
56 LOG(ERROR) << "Surface " << surface << " cannot be referenced.";
57 }
58 }
59
60 GpuMessageHub::SurfaceRef::~SurfaceRef() {
61 BrowserThread::PostTask(BrowserThread::UI,
62 FROM_HERE,
63 new ReleasePermanentXIDDispatcher(surface_));
64 }
65 #endif // defined(OS_LINUX
66
67
68 // A task that will forward an IPC message to the UI shim.
69 class RouteToGpuProcessHostUIShimTask : public Task {
70 public:
71 RouteToGpuProcessHostUIShimTask(int host_id, IPC::Message* msg)
72 : host_id_(host_id),
73 msg_(*msg) {
74 }
75
76 private:
77 virtual void Run() {
78 GpuProcessHostUIShim* ui_shim = GpuProcessHostUIShim::FromID(host_id_);
79 if (ui_shim)
80 ui_shim->OnMessageReceived(msg_);
81 }
82
83 int host_id_;
84 IPC::Message msg_;
85 };
86
87
88 // A task that will forward an IPC message to a GpuProcessHost instance.
89 class SendToGpuProcessHostTask : public Task {
90 public:
91 SendToGpuProcessHostTask(int host_id, IPC::Message* msg)
92 : host_id_(host_id),
93 msg_(msg) {
94 }
95
96 private:
97 void Run() {
98 GpuProcessHost* host = GpuProcessHost::FromID(host_id_);
99 if (host)
100 host->Send(msg_.release());
101 }
102
103 int host_id_;
104 scoped_ptr<IPC::Message> msg_;
105 };
106
107 // static
108 bool GpuMessageHub::SendToGPU(int host_id, IPC::Message* msg) {
109 bool success;
110
111 if (host_id == 0) {
112 GpuThreadHost* host = GpuThreadHost::GetInstance();
113 success = host->Send(msg);
114 } else {
115 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
116 success = BrowserThread::PostTask(
117 BrowserThread::IO,
118 FROM_HERE,
119 new SendToGpuProcessHostTask(host_id, msg));
120 } else {
121 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
122 GpuProcessHost* host = GpuProcessHost::FromID(host_id);
123 success = host->Send(msg);
124 }
125 }
126
127 return success;
128 }
129
130 // static
131 bool GpuMessageHub::EstablishGpuChannel(int renderer_id,
132 content::CauseForGpuLaunch cause,
133 EstablishChannelCallback* callback,
134 int& host_id) {
135 linked_ptr<EstablishChannelCallback> wrapped_callback(callback);
136
137 // If GPU features are already blacklisted, no need to establish the channel.
138 if (!GpuDataManager::GetInstance()->GpuAccessAllowed()) {
139 EstablishChannelError(callback);
140 return false;
141 }
142
143 IPC::Message::Sender* sender;
144 GpuMessageHub* hub;
145
146 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) ||
147 CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessGPU)) {
148 GpuThreadHost* host = GpuThreadHost::GetInstance();
149 if (host) {
150 host_id = 0;
151 hub = host->GetMessageHub();
152 sender = host;
153 } else {
154 EstablishChannelError(callback);
155 return false;
156 }
157 } else {
158 GpuProcessHost* host = GpuProcessHost::GetForRenderer(renderer_id,
159 cause);
160 if (host) {
161 host_id = host->host_id();
162 hub = host->GetMessageHub();
163 sender = host;
164 } else {
165 EstablishChannelError(callback);
166 return false;
167 }
168 }
169
170 DCHECK(hub);
171
172 if (!sender->Send(new GpuMsg_EstablishChannel(renderer_id))) {
173 EstablishChannelError(callback);
174 return false;
175 }
176
177 hub->ExpectChannelEstablished(wrapped_callback);
178 return true;
179 }
180
181 // static
182 void GpuMessageHub::Synchronize(int host_id, SynchronizeCallback* callback) {
183 linked_ptr<SynchronizeCallback> wrapped_callback(callback);
184
185 IPC::Message::Sender* sender;
186 GpuMessageHub* hub;
187
188 if (!FromID(host_id, sender, hub)) {
189 SynchronizeError(callback);
190 return;
191 }
192
193 if (sender->Send(new GpuMsg_Synchronize()))
194 hub->ExpectSynchronizeReply(wrapped_callback);
195 else
196 SynchronizeError(callback);
197 }
198
199 // static
200 void GpuMessageHub::CreateViewCommandBuffer(
201 int host_id,
202 gfx::PluginWindowHandle compositing_surface,
203 int32 render_view_id,
204 int32 renderer_id,
205 const GPUCreateCommandBufferConfig& init_params,
206 CreateCommandBufferCallback* callback) {
207 linked_ptr<CreateCommandBufferCallback> wrapped_callback(callback);
208
209 IPC::Message::Sender* sender;
210 GpuMessageHub* hub;
211
212 if (!FromID(host_id, sender, hub)) {
213 CreateCommandBufferError(callback);
214 return;
215 }
216
217 if (sender->Send(new GpuMsg_CreateViewCommandBuffer(
218 compositing_surface, render_view_id, renderer_id, init_params)))
219 hub->ExpectCommandBufferCreated(compositing_surface,
220 render_view_id,
221 renderer_id,
222 wrapped_callback);
223 else
224 CreateCommandBufferError(callback);
225 }
226
227 // static
228 void GpuMessageHub::EstablishChannelError(EstablishChannelCallback* callback) {
229 callback->Run(IPC::ChannelHandle(),
230 base::kNullProcessHandle,
231 GPUInfo());
232 }
233
234 // static
235 void GpuMessageHub::CreateCommandBufferError(
236 CreateCommandBufferCallback* callback) {
237 callback->Run(MSG_ROUTING_NONE);
238 }
239
240 // static
241 void GpuMessageHub::SynchronizeError(SynchronizeCallback* callback) {
242 callback->Run();
243 }
244
245 // static
246 bool GpuMessageHub::FromID(
247 int host_id,
248 IPC::Message::Sender*& host,
249 GpuMessageHub*& hub) {
250
251 if (host_id == 0) {
252 GpuThreadHost* thread_host = GpuThreadHost::GetInstance();
253
254 if (!thread_host)
255 return false;
256
257 hub = thread_host->GetMessageHub();
258 host = thread_host;
259 } else {
260 GpuProcessHost* process_host = GpuProcessHost::FromID(host_id);
261
262 if (!process_host)
263 return false;
264
265 hub = process_host->GetMessageHub();
266 host = process_host;
267 }
268
269 DCHECK(hub);
270 return true;
271 }
272
273 GpuMessageHub::GpuMessageHub(int host_id)
274 : host_id_(host_id),
275 gpu_process_(base::kNullProcessHandle) {
276 // Post a task to create the corresponding GpuProcessHostUIShim. The
277 // GpuProcessHostUIShim will be destroyed if either the browser exits,
278 // in which case it calls GpuProcessHostUIShim::DestroyAll, or the
279 // GpuProcessHost is destroyed, which happens when the corresponding GPU
280 // process terminates or fails to launch.
281 BrowserThread::PostTask(
282 BrowserThread::UI,
283 FROM_HERE,
284 NewRunnableFunction(&GpuProcessHostUIShim::Create, host_id));
285 }
286
287
288 GpuMessageHub::~GpuMessageHub() {
289 BrowserThread::PostTask(BrowserThread::UI,
290 FROM_HERE,
291 NewRunnableFunction(GpuProcessHostUIShim::Destroy,
292 host_id_));
293 }
294
295 void GpuMessageHub::SetGPUProcess(base::ProcessHandle gpu_process) {
296 gpu_process_ = gpu_process;
297 }
298
299 bool GpuMessageHub::RouteToUIThread(IPC::Message* message) {
300 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
301 // The GPU process must never send a synchronous IPC message to the browser
302 // process. This could result in deadlock. Unfortunately linux does this for
303 // GpuHostMsg_ResizeXID. TODO(apatrick): fix this before issuing any GL calls
304 // on the browser process' GPU thread.
305 #if !defined(OS_LINUX)
306 DCHECK(!message->is_sync());
307 #endif
308
309 return BrowserThread::PostTask(
310 BrowserThread::UI,
311 FROM_HERE,
312 new RouteToGpuProcessHostUIShimTask(host_id_, message));
313 }
314
315 bool GpuMessageHub::OnMessageReceived(const IPC::Message& message) {
316 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
317 IPC_BEGIN_MESSAGE_MAP(GpuMessageHub, message)
318 IPC_MESSAGE_HANDLER(GpuHostMsg_ChannelEstablished, OnChannelEstablished)
319 IPC_MESSAGE_HANDLER(GpuHostMsg_SynchronizeReply, OnSynchronizeReply)
320 IPC_MESSAGE_HANDLER(GpuHostMsg_CommandBufferCreated, OnCommandBufferCreated)
321 IPC_MESSAGE_HANDLER(GpuHostMsg_DestroyCommandBuffer, OnDestroyCommandBuffer)
322 IPC_MESSAGE_HANDLER(GpuHostMsg_GraphicsInfoCollected,
323 OnGraphicsInfoCollected)
324 IPC_MESSAGE_UNHANDLED(RouteToUIThread(new IPC::Message(message)))
325 IPC_END_MESSAGE_MAP()
326
327 return true;
328 }
329
330 void GpuMessageHub::ExpectChannelEstablished(
331 linked_ptr<EstablishChannelCallback>& callback) {
332 DCHECK(CalledOnValidThread());
333 channel_requests_.push(callback);
334 }
335
336 void GpuMessageHub::ExpectSynchronizeReply(
337 linked_ptr<SynchronizeCallback>& callback) {
338 DCHECK(CalledOnValidThread());
339 synchronize_requests_.push(callback);
340 }
341
342 void GpuMessageHub::ExpectCommandBufferCreated(
343 gfx::PluginWindowHandle compositing_surface,
344 int32 render_view_id,
345 int32 renderer_id,
346 linked_ptr<CreateCommandBufferCallback>& callback) {
347 DCHECK(CalledOnValidThread());
348 create_command_buffer_requests_.push(callback);
349
350 #if defined(OS_LINUX)
351 ViewID view_id(renderer_id, render_view_id);
352
353 // There should only be one such command buffer (for the compositor). In
354 // practice, if the GPU process lost a context, GraphicsContext3D with
355 // associated command buffer and view surface will not be gone until new
356 // one is in place and all layers are reattached.
357 linked_ptr<SurfaceRef> surface_ref;
358 SurfaceRefMap::iterator it = surface_refs_.find(view_id);
359 if (it != surface_refs_.end())
360 surface_ref = (*it).second;
361 else
362 surface_ref.reset(new SurfaceRef(compositing_surface));
363
364 surface_refs_.insert(std::pair<ViewID, linked_ptr<SurfaceRef> >(
365 view_id, surface_ref));
366 #endif // defined(OS_LINUX)
367 }
368
369 void GpuMessageHub::SendOutstandingReplies() {
370 DCHECK(CalledOnValidThread());
371 // First send empty channel handles for all EstablishChannel requests.
372 while (!channel_requests_.empty()) {
373 linked_ptr<EstablishChannelCallback> callback = channel_requests_.front();
374 channel_requests_.pop();
375 EstablishChannelError(callback.release());
376 }
377 }
378
379 IPC::Message::Sender* GpuMessageHub::FromID(int host_id) {
380 if (host_id == 0)
381 return GpuThreadHost::GetInstance();
382 else
383 return GpuProcessHost::FromID(host_id);
384 }
385
386 void GpuMessageHub::OnChannelEstablished(
387 const IPC::ChannelHandle& channel_handle) {
388 DCHECK(CalledOnValidThread());
389 // The GPU process should have launched at this point and this object should
390 // have been notified of its process handle.
391 DCHECK(gpu_process_ != base::kNullProcessHandle && channel_requests_.size());
392
393 linked_ptr<EstablishChannelCallback> callback = channel_requests_.front();
394 channel_requests_.pop();
395
396 // Currently if any of the GPU features are blacklisted, we don't establish a
397 // GPU channel.
398 if (!channel_handle.name.empty() &&
399 !GpuDataManager::GetInstance()->GpuAccessAllowed()) {
400 IPC::Message::Sender* sender = FromID(host_id_);
401 if (sender)
402 sender->Send(new GpuMsg_CloseChannel(channel_handle));
403 EstablishChannelError(callback.release());
404 RouteToUIThread(new GpuHostMsg_OnLogMessage(
405 logging::LOG_WARNING,
406 "WARNING",
407 "Hardware acceleration is unavailable."));
408 return;
409 }
410
411 callback->Run(
412 channel_handle, gpu_process_, GpuDataManager::GetInstance()->gpu_info());
413 }
414
415 void GpuMessageHub::OnSynchronizeReply() {
416 DCHECK(CalledOnValidThread());
417 // Guard against race conditions in abrupt GPU process termination.
418 if (!synchronize_requests_.empty()) {
419 linked_ptr<SynchronizeCallback> callback(synchronize_requests_.front());
420 synchronize_requests_.pop();
421 callback->Run();
422 }
423 }
424
425 void GpuMessageHub::OnCommandBufferCreated(const int32 route_id) {
426 DCHECK(CalledOnValidThread());
427 if (!create_command_buffer_requests_.empty()) {
428 linked_ptr<CreateCommandBufferCallback> callback =
429 create_command_buffer_requests_.front();
430 create_command_buffer_requests_.pop();
431 if (route_id == MSG_ROUTING_NONE)
432 CreateCommandBufferError(callback.release());
433 else
434 callback->Run(route_id);
435 }
436 }
437
438 void GpuMessageHub::OnDestroyCommandBuffer(gfx::PluginWindowHandle window,
439 int32 renderer_id,
440 int32 render_view_id) {
441 DCHECK(CalledOnValidThread());
442 #if defined(OS_LINUX)
443 ViewID view_id(renderer_id, render_view_id);
444 SurfaceRefMap::iterator it = surface_refs_.find(view_id);
445 if (it != surface_refs_.end())
446 surface_refs_.erase(it);
447 #endif // defined(OS_LINUX)
448 }
449
450 void GpuMessageHub::OnGraphicsInfoCollected(const GPUInfo& gpu_info) {
451 GpuDataManager::GetInstance()->UpdateGpuInfo(gpu_info);
452 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698