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.
4
5 #include "content/browser/gpu/gpu_process_host_ui_shim.h"
6
7 #include <algorithm>
8
9 #include "base/bind.h"
10 #include "base/debug/trace_event.h"
11 #include "base/id_map.h"
12 #include "base/lazy_instance.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "content/browser/gpu/compositor_util.h"
15 #include "content/browser/gpu/gpu_data_manager_impl.h"
16 #include "content/browser/gpu/gpu_process_host.h"
17 #include "content/browser/gpu/gpu_surface_tracker.h"
18 #include "content/browser/renderer_host/render_process_host_impl.h"
19 #include "content/browser/renderer_host/render_view_host_impl.h"
20 #include "content/browser/renderer_host/render_widget_helper.h"
21 #include "content/browser/renderer_host/render_widget_host_view_base.h"
22 #include "content/common/gpu/gpu_messages.h"
23 #include "content/public/browser/browser_thread.h"
24
25 #if defined(OS_MACOSX)
26 #include "content/browser/compositor/browser_compositor_view_mac.h"
27 #endif
28
29 #if defined(USE_OZONE)
30 #include "ui/ozone/public/gpu_platform_support_host.h"
31 #include "ui/ozone/public/ozone_platform.h"
32 #endif
33
34 namespace content {
35
36 namespace {
37
38 // One of the linux specific headers defines this as a macro.
39 #ifdef DestroyAll
40 #undef DestroyAll
41 #endif
42
43 base::LazyInstance<IDMap<GpuProcessHostUIShim> > g_hosts_by_id =
44 LAZY_INSTANCE_INITIALIZER;
45
SendOnIOThreadTask(int host_id,IPC::Message * msg)46 void SendOnIOThreadTask(int host_id, IPC::Message* msg) {
47 GpuProcessHost* host = GpuProcessHost::FromID(host_id);
48 if (host)
49 host->Send(msg);
50 else
51 delete msg;
52 }
53
54 class ScopedSendOnIOThread {
55 public:
ScopedSendOnIOThread(int host_id,IPC::Message * msg)56 ScopedSendOnIOThread(int host_id, IPC::Message* msg)
57 : host_id_(host_id),
58 msg_(msg),
59 cancelled_(false) {
60 }
61
~ScopedSendOnIOThread()62 ~ScopedSendOnIOThread() {
63 if (!cancelled_) {
64 BrowserThread::PostTask(BrowserThread::IO,
65 FROM_HERE,
66 base::Bind(&SendOnIOThreadTask,
67 host_id_,
68 msg_.release()));
69 }
70 }
71
Cancel()72 void Cancel() { cancelled_ = true; }
73
74 private:
75 int host_id_;
76 scoped_ptr<IPC::Message> msg_;
77 bool cancelled_;
78 };
79
GetRenderWidgetHostViewFromSurfaceID(int surface_id)80 RenderWidgetHostViewBase* GetRenderWidgetHostViewFromSurfaceID(
81 int surface_id) {
82 int render_process_id = 0;
83 int render_widget_id = 0;
84 if (!GpuSurfaceTracker::Get()->GetRenderWidgetIDForSurface(
85 surface_id, &render_process_id, &render_widget_id))
86 return NULL;
87
88 RenderWidgetHost* host =
89 RenderWidgetHost::FromID(render_process_id, render_widget_id);
90 return host ? static_cast<RenderWidgetHostViewBase*>(host->GetView()) : NULL;
91 }
92
93 } // namespace
94
RouteToGpuProcessHostUIShimTask(int host_id,const IPC::Message & msg)95 void RouteToGpuProcessHostUIShimTask(int host_id, const IPC::Message& msg) {
96 GpuProcessHostUIShim* ui_shim = GpuProcessHostUIShim::FromID(host_id);
97 if (ui_shim)
98 ui_shim->OnMessageReceived(msg);
99 }
100
GpuProcessHostUIShim(int host_id)101 GpuProcessHostUIShim::GpuProcessHostUIShim(int host_id)
102 : host_id_(host_id) {
103 g_hosts_by_id.Pointer()->AddWithID(this, host_id_);
104 #if defined(USE_OZONE)
105 ui::OzonePlatform::GetInstance()
106 ->GetGpuPlatformSupportHost()
107 ->OnChannelEstablished(host_id, this);
108 #endif
109 }
110
111 // static
Create(int host_id)112 GpuProcessHostUIShim* GpuProcessHostUIShim::Create(int host_id) {
113 DCHECK(!FromID(host_id));
114 return new GpuProcessHostUIShim(host_id);
115 }
116
117 // static
Destroy(int host_id,const std::string & message)118 void GpuProcessHostUIShim::Destroy(int host_id, const std::string& message) {
119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
120
121 GpuDataManagerImpl::GetInstance()->AddLogMessage(
122 logging::LOG_ERROR, "GpuProcessHostUIShim",
123 message);
124
125 #if defined(USE_OZONE)
126 ui::OzonePlatform::GetInstance()
127 ->GetGpuPlatformSupportHost()
128 ->OnChannelDestroyed(host_id);
129 #endif
130
131 delete FromID(host_id);
132 }
133
134 // static
DestroyAll()135 void GpuProcessHostUIShim::DestroyAll() {
136 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
137 while (!g_hosts_by_id.Pointer()->IsEmpty()) {
138 IDMap<GpuProcessHostUIShim>::iterator it(g_hosts_by_id.Pointer());
139 delete it.GetCurrentValue();
140 }
141 }
142
143 // static
FromID(int host_id)144 GpuProcessHostUIShim* GpuProcessHostUIShim::FromID(int host_id) {
145 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
146 return g_hosts_by_id.Pointer()->Lookup(host_id);
147 }
148
149 // static
GetOneInstance()150 GpuProcessHostUIShim* GpuProcessHostUIShim::GetOneInstance() {
151 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
152 if (g_hosts_by_id.Pointer()->IsEmpty())
153 return NULL;
154 IDMap<GpuProcessHostUIShim>::iterator it(g_hosts_by_id.Pointer());
155 return it.GetCurrentValue();
156 }
157
Send(IPC::Message * msg)158 bool GpuProcessHostUIShim::Send(IPC::Message* msg) {
159 DCHECK(CalledOnValidThread());
160 return BrowserThread::PostTask(BrowserThread::IO,
161 FROM_HERE,
162 base::Bind(&SendOnIOThreadTask,
163 host_id_,
164 msg));
165 }
166
OnMessageReceived(const IPC::Message & message)167 bool GpuProcessHostUIShim::OnMessageReceived(const IPC::Message& message) {
168 DCHECK(CalledOnValidThread());
169
170 #if defined(USE_OZONE)
171 if (ui::OzonePlatform::GetInstance()
172 ->GetGpuPlatformSupportHost()
173 ->OnMessageReceived(message))
174 return true;
175 #endif
176
177 if (message.routing_id() != MSG_ROUTING_CONTROL)
178 return false;
179
180 return OnControlMessageReceived(message);
181 }
182
SimulateRemoveAllContext()183 void GpuProcessHostUIShim::SimulateRemoveAllContext() {
184 Send(new GpuMsg_Clean());
185 }
186
SimulateCrash()187 void GpuProcessHostUIShim::SimulateCrash() {
188 Send(new GpuMsg_Crash());
189 }
190
SimulateHang()191 void GpuProcessHostUIShim::SimulateHang() {
192 Send(new GpuMsg_Hang());
193 }
194
~GpuProcessHostUIShim()195 GpuProcessHostUIShim::~GpuProcessHostUIShim() {
196 DCHECK(CalledOnValidThread());
197 g_hosts_by_id.Pointer()->Remove(host_id_);
198 }
199
OnControlMessageReceived(const IPC::Message & message)200 bool GpuProcessHostUIShim::OnControlMessageReceived(
201 const IPC::Message& message) {
202 DCHECK(CalledOnValidThread());
203
204 IPC_BEGIN_MESSAGE_MAP(GpuProcessHostUIShim, message)
205 IPC_MESSAGE_HANDLER(GpuHostMsg_OnLogMessage,
206 OnLogMessage)
207
208 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceInitialized,
209 OnAcceleratedSurfaceInitialized)
210 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped,
211 OnAcceleratedSurfaceBuffersSwapped)
212 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfacePostSubBuffer,
213 OnAcceleratedSurfacePostSubBuffer)
214 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceSuspend,
215 OnAcceleratedSurfaceSuspend)
216 IPC_MESSAGE_HANDLER(GpuHostMsg_GraphicsInfoCollected,
217 OnGraphicsInfoCollected)
218 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceRelease,
219 OnAcceleratedSurfaceRelease)
220 IPC_MESSAGE_HANDLER(GpuHostMsg_VideoMemoryUsageStats,
221 OnVideoMemoryUsageStatsReceived);
222 IPC_MESSAGE_HANDLER(GpuHostMsg_FrameDrawn, OnFrameDrawn)
223
224 IPC_MESSAGE_UNHANDLED_ERROR()
225 IPC_END_MESSAGE_MAP()
226
227 return true;
228 }
229
OnLogMessage(int level,const std::string & header,const std::string & message)230 void GpuProcessHostUIShim::OnLogMessage(
231 int level,
232 const std::string& header,
233 const std::string& message) {
234 GpuDataManagerImpl::GetInstance()->AddLogMessage(
235 level, header, message);
236 }
237
OnGraphicsInfoCollected(const gpu::GPUInfo & gpu_info)238 void GpuProcessHostUIShim::OnGraphicsInfoCollected(
239 const gpu::GPUInfo& gpu_info) {
240 // OnGraphicsInfoCollected is sent back after the GPU process successfully
241 // initializes GL.
242 TRACE_EVENT0("test_gpu", "OnGraphicsInfoCollected");
243
244 GpuDataManagerImpl::GetInstance()->UpdateGpuInfo(gpu_info);
245 }
246
OnAcceleratedSurfaceInitialized(int32 surface_id,int32 route_id)247 void GpuProcessHostUIShim::OnAcceleratedSurfaceInitialized(int32 surface_id,
248 int32 route_id) {
249 RenderWidgetHostViewBase* view =
250 GetRenderWidgetHostViewFromSurfaceID(surface_id);
251 if (!view)
252 return;
253 view->AcceleratedSurfaceInitialized(host_id_, route_id);
254 }
255
OnAcceleratedSurfaceBuffersSwapped(const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params & params)256 void GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped(
257 const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params) {
258 TRACE_EVENT0("renderer",
259 "GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped");
260 if (!ui::LatencyInfo::Verify(params.latency_info,
261 "GpuHostMsg_AcceleratedSurfaceBuffersSwapped"))
262 return;
263
264 #if defined(OS_MACOSX)
265 // On Mac with delegated rendering, accelerated surfaces are not necessarily
266 // associated with a RenderWidgetHostViewBase.
267 if (IsDelegatedRendererEnabled()) {
268 gfx::AcceleratedWidget native_widget =
269 content::GpuSurfaceTracker::Get()->AcquireNativeWidget(
270 params.surface_id);
271 BrowserCompositorViewMac::GotAcceleratedFrame(
272 native_widget, params.surface_handle, params.surface_id,
273 params.latency_info, params.size, params.scale_factor,
274 host_id_, params.route_id);
275 return;
276 }
277 #endif
278
279 AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
280 ack_params.mailbox = params.mailbox;
281 ack_params.sync_point = 0;
282 ScopedSendOnIOThread delayed_send(
283 host_id_,
284 new AcceleratedSurfaceMsg_BufferPresented(params.route_id,
285 ack_params));
286
287 RenderWidgetHostViewBase* view = GetRenderWidgetHostViewFromSurfaceID(
288 params.surface_id);
289 if (!view)
290 return;
291
292 delayed_send.Cancel();
293
294 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params view_params = params;
295
296 RenderWidgetHostImpl* impl =
297 RenderWidgetHostImpl::From(view->GetRenderWidgetHost());
298 for (size_t i = 0; i < view_params.latency_info.size(); i++)
299 impl->AddLatencyInfoComponentIds(&view_params.latency_info[i]);
300
301 // View must send ACK message after next composite.
302 view->AcceleratedSurfaceBuffersSwapped(view_params, host_id_);
303 view->DidReceiveRendererFrame();
304 }
305
OnFrameDrawn(const std::vector<ui::LatencyInfo> & latency_info)306 void GpuProcessHostUIShim::OnFrameDrawn(
307 const std::vector<ui::LatencyInfo>& latency_info) {
308 if (!ui::LatencyInfo::Verify(latency_info,
309 "GpuProcessHostUIShim::OnFrameDrawn"))
310 return;
311 RenderWidgetHostImpl::CompositorFrameDrawn(latency_info);
312 }
313
OnAcceleratedSurfacePostSubBuffer(const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params & params)314 void GpuProcessHostUIShim::OnAcceleratedSurfacePostSubBuffer(
315 const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params) {
316 TRACE_EVENT0("renderer",
317 "GpuProcessHostUIShim::OnAcceleratedSurfacePostSubBuffer");
318 if (!ui::LatencyInfo::Verify(params.latency_info,
319 "GpuHostMsg_AcceleratedSurfacePostSubBuffer"))
320 return;
321 AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
322 ack_params.mailbox = params.mailbox;
323 ack_params.sync_point = 0;
324 ScopedSendOnIOThread delayed_send(
325 host_id_,
326 new AcceleratedSurfaceMsg_BufferPresented(params.route_id,
327 ack_params));
328
329 RenderWidgetHostViewBase* view =
330 GetRenderWidgetHostViewFromSurfaceID(params.surface_id);
331 if (!view)
332 return;
333
334 delayed_send.Cancel();
335
336 GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params view_params = params;
337
338 RenderWidgetHostImpl* impl =
339 RenderWidgetHostImpl::From(view->GetRenderWidgetHost());
340 for (size_t i = 0; i < view_params.latency_info.size(); i++)
341 impl->AddLatencyInfoComponentIds(&view_params.latency_info[i]);
342
343 // View must send ACK message after next composite.
344 view->AcceleratedSurfacePostSubBuffer(view_params, host_id_);
345 view->DidReceiveRendererFrame();
346 }
347
OnAcceleratedSurfaceSuspend(int32 surface_id)348 void GpuProcessHostUIShim::OnAcceleratedSurfaceSuspend(int32 surface_id) {
349 TRACE_EVENT0("renderer",
350 "GpuProcessHostUIShim::OnAcceleratedSurfaceSuspend");
351
352 RenderWidgetHostViewBase* view =
353 GetRenderWidgetHostViewFromSurfaceID(surface_id);
354 if (!view)
355 return;
356
357 view->AcceleratedSurfaceSuspend();
358 }
359
OnAcceleratedSurfaceRelease(const GpuHostMsg_AcceleratedSurfaceRelease_Params & params)360 void GpuProcessHostUIShim::OnAcceleratedSurfaceRelease(
361 const GpuHostMsg_AcceleratedSurfaceRelease_Params& params) {
362 RenderWidgetHostViewBase* view = GetRenderWidgetHostViewFromSurfaceID(
363 params.surface_id);
364 if (!view)
365 return;
366 view->AcceleratedSurfaceRelease();
367 }
368
OnVideoMemoryUsageStatsReceived(const GPUVideoMemoryUsageStats & video_memory_usage_stats)369 void GpuProcessHostUIShim::OnVideoMemoryUsageStatsReceived(
370 const GPUVideoMemoryUsageStats& video_memory_usage_stats) {
371 GpuDataManagerImpl::GetInstance()->UpdateVideoMemoryUsageStats(
372 video_memory_usage_stats);
373 }
374
375 } // namespace content
376