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/gpu_process_host_ui_shim.h"
10 #include "base/command_line.h"
11 #include "base/debug/trace_event.h"
12 #include "base/id_map.h"
13 #include "base/lazy_instance.h"
14 #include "base/strings/string_number_conversions.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/common/gpu/gpu_messages.h"
21 #include "content/port/browser/render_widget_host_view_port.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "ui/gl/gl_switches.h"
26 #ifndef GL_MAILBOX_SIZE_CHROMIUM
27 #define GL_MAILBOX_SIZE_CHROMIUM 64
34 // One of the linux specific headers defines this as a macro.
39 base::LazyInstance
<IDMap
<GpuProcessHostUIShim
> > g_hosts_by_id
=
40 LAZY_INSTANCE_INITIALIZER
;
42 void SendOnIOThreadTask(int host_id
, IPC::Message
* msg
) {
43 GpuProcessHost
* host
= GpuProcessHost::FromID(host_id
);
50 class ScopedSendOnIOThread
{
52 ScopedSendOnIOThread(int host_id
, IPC::Message
* msg
)
58 ~ScopedSendOnIOThread() {
60 BrowserThread::PostTask(BrowserThread::IO
,
62 base::Bind(&SendOnIOThreadTask
,
68 void Cancel() { cancelled_
= true; }
72 scoped_ptr
<IPC::Message
> msg_
;
76 RenderWidgetHostViewPort
* GetRenderWidgetHostViewFromSurfaceID(
78 int render_process_id
= 0;
79 int render_widget_id
= 0;
80 if (!GpuSurfaceTracker::Get()->GetRenderWidgetIDForSurface(
81 surface_id
, &render_process_id
, &render_widget_id
))
84 RenderWidgetHost
* host
=
85 RenderWidgetHost::FromID(render_process_id
, render_widget_id
);
86 return host
? RenderWidgetHostViewPort::FromRWHV(host
->GetView()) : NULL
;
91 void RouteToGpuProcessHostUIShimTask(int host_id
, const IPC::Message
& msg
) {
92 GpuProcessHostUIShim
* ui_shim
= GpuProcessHostUIShim::FromID(host_id
);
94 ui_shim
->OnMessageReceived(msg
);
97 GpuProcessHostUIShim::GpuProcessHostUIShim(int host_id
)
99 g_hosts_by_id
.Pointer()->AddWithID(this, host_id_
);
103 GpuProcessHostUIShim
* GpuProcessHostUIShim::Create(int host_id
) {
104 DCHECK(!FromID(host_id
));
105 return new GpuProcessHostUIShim(host_id
);
109 void GpuProcessHostUIShim::Destroy(int host_id
, const std::string
& message
) {
110 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
112 GpuDataManagerImpl::GetInstance()->AddLogMessage(
113 logging::LOG_ERROR
, "GpuProcessHostUIShim",
116 delete FromID(host_id
);
120 void GpuProcessHostUIShim::DestroyAll() {
121 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
122 while (!g_hosts_by_id
.Pointer()->IsEmpty()) {
123 IDMap
<GpuProcessHostUIShim
>::iterator
it(g_hosts_by_id
.Pointer());
124 delete it
.GetCurrentValue();
129 GpuProcessHostUIShim
* GpuProcessHostUIShim::FromID(int host_id
) {
130 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
131 return g_hosts_by_id
.Pointer()->Lookup(host_id
);
135 GpuProcessHostUIShim
* GpuProcessHostUIShim::GetOneInstance() {
136 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
137 if (g_hosts_by_id
.Pointer()->IsEmpty())
139 IDMap
<GpuProcessHostUIShim
>::iterator
it(g_hosts_by_id
.Pointer());
140 return it
.GetCurrentValue();
143 bool GpuProcessHostUIShim::Send(IPC::Message
* msg
) {
144 DCHECK(CalledOnValidThread());
145 return BrowserThread::PostTask(BrowserThread::IO
,
147 base::Bind(&SendOnIOThreadTask
,
152 bool GpuProcessHostUIShim::OnMessageReceived(const IPC::Message
& message
) {
153 DCHECK(CalledOnValidThread());
155 if (message
.routing_id() != MSG_ROUTING_CONTROL
)
158 return OnControlMessageReceived(message
);
161 void GpuProcessHostUIShim::SimulateRemoveAllContext() {
162 Send(new GpuMsg_Clean());
165 void GpuProcessHostUIShim::SimulateCrash() {
166 Send(new GpuMsg_Crash());
169 void GpuProcessHostUIShim::SimulateHang() {
170 Send(new GpuMsg_Hang());
173 GpuProcessHostUIShim::~GpuProcessHostUIShim() {
174 DCHECK(CalledOnValidThread());
175 g_hosts_by_id
.Pointer()->Remove(host_id_
);
178 bool GpuProcessHostUIShim::OnControlMessageReceived(
179 const IPC::Message
& message
) {
180 DCHECK(CalledOnValidThread());
182 IPC_BEGIN_MESSAGE_MAP(GpuProcessHostUIShim
, message
)
183 IPC_MESSAGE_HANDLER(GpuHostMsg_OnLogMessage
,
186 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceInitialized
,
187 OnAcceleratedSurfaceInitialized
)
188 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped
,
189 OnAcceleratedSurfaceBuffersSwapped
)
190 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfacePostSubBuffer
,
191 OnAcceleratedSurfacePostSubBuffer
)
192 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceSuspend
,
193 OnAcceleratedSurfaceSuspend
)
194 IPC_MESSAGE_HANDLER(GpuHostMsg_GraphicsInfoCollected
,
195 OnGraphicsInfoCollected
)
196 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceRelease
,
197 OnAcceleratedSurfaceRelease
)
198 IPC_MESSAGE_HANDLER(GpuHostMsg_VideoMemoryUsageStats
,
199 OnVideoMemoryUsageStatsReceived
);
200 IPC_MESSAGE_HANDLER(GpuHostMsg_UpdateVSyncParameters
,
201 OnUpdateVSyncParameters
)
202 IPC_MESSAGE_HANDLER(GpuHostMsg_FrameDrawn
, OnFrameDrawn
)
204 IPC_MESSAGE_HANDLER(GpuHostMsg_ResizeView
, OnResizeView
)
206 IPC_MESSAGE_UNHANDLED_ERROR()
207 IPC_END_MESSAGE_MAP()
212 void GpuProcessHostUIShim::OnUpdateVSyncParameters(int surface_id
,
213 base::TimeTicks timebase
,
214 base::TimeDelta interval
) {
216 int render_process_id
= 0;
217 int render_widget_id
= 0;
218 if (!GpuSurfaceTracker::Get()->GetRenderWidgetIDForSurface(
219 surface_id
, &render_process_id
, &render_widget_id
)) {
222 RenderWidgetHost
* rwh
=
223 RenderWidgetHost::FromID(render_process_id
, render_widget_id
);
226 RenderWidgetHostImpl::From(rwh
)->UpdateVSyncParameters(timebase
, interval
);
229 void GpuProcessHostUIShim::OnLogMessage(
231 const std::string
& header
,
232 const std::string
& message
) {
233 GpuDataManagerImpl::GetInstance()->AddLogMessage(
234 level
, header
, message
);
237 void GpuProcessHostUIShim::OnGraphicsInfoCollected(
238 const gpu::GPUInfo
& gpu_info
) {
239 // OnGraphicsInfoCollected is sent back after the GPU process successfully
241 TRACE_EVENT0("test_gpu", "OnGraphicsInfoCollected");
243 GpuDataManagerImpl::GetInstance()->UpdateGpuInfo(gpu_info
);
246 void GpuProcessHostUIShim::OnResizeView(int32 surface_id
,
249 // Always respond even if the window no longer exists. The GPU process cannot
250 // make progress on the resizing command buffer until it receives the
252 ScopedSendOnIOThread
delayed_send(
254 new AcceleratedSurfaceMsg_ResizeViewACK(route_id
));
256 RenderWidgetHostViewPort
* view
=
257 GetRenderWidgetHostViewFromSurfaceID(surface_id
);
261 view
->ResizeCompositingSurface(size
);
264 static base::TimeDelta
GetSwapDelay() {
265 CommandLine
* cmd_line
= CommandLine::ForCurrentProcess();
267 if (cmd_line
->HasSwitch(switches::kGpuSwapDelay
)) {
268 base::StringToInt(cmd_line
->GetSwitchValueNative(
269 switches::kGpuSwapDelay
).c_str(), &delay
);
271 return base::TimeDelta::FromMilliseconds(delay
);
274 void GpuProcessHostUIShim::OnAcceleratedSurfaceInitialized(int32 surface_id
,
276 RenderWidgetHostViewPort
* view
=
277 GetRenderWidgetHostViewFromSurfaceID(surface_id
);
280 view
->AcceleratedSurfaceInitialized(host_id_
, route_id
);
283 void GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped(
284 const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params
& params
) {
285 TRACE_EVENT0("renderer",
286 "GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped");
287 AcceleratedSurfaceMsg_BufferPresented_Params ack_params
;
288 ack_params
.mailbox_name
= params
.mailbox_name
;
289 ack_params
.sync_point
= 0;
290 ScopedSendOnIOThread
delayed_send(
292 new AcceleratedSurfaceMsg_BufferPresented(params
.route_id
,
295 if (!params
.mailbox_name
.empty() &&
296 params
.mailbox_name
.length() != GL_MAILBOX_SIZE_CHROMIUM
)
299 RenderWidgetHostViewPort
* view
= GetRenderWidgetHostViewFromSurfaceID(
304 delayed_send
.Cancel();
306 static const base::TimeDelta swap_delay
= GetSwapDelay();
307 if (swap_delay
.ToInternalValue())
308 base::PlatformThread::Sleep(swap_delay
);
310 // View must send ACK message after next composite.
311 view
->AcceleratedSurfaceBuffersSwapped(params
, host_id_
);
312 view
->DidReceiveRendererFrame();
315 void GpuProcessHostUIShim::OnFrameDrawn(const ui::LatencyInfo
& latency_info
) {
316 RenderWidgetHostImpl::CompositorFrameDrawn(latency_info
);
319 void GpuProcessHostUIShim::OnAcceleratedSurfacePostSubBuffer(
320 const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params
& params
) {
321 TRACE_EVENT0("renderer",
322 "GpuProcessHostUIShim::OnAcceleratedSurfacePostSubBuffer");
324 AcceleratedSurfaceMsg_BufferPresented_Params ack_params
;
325 ack_params
.mailbox_name
= params
.mailbox_name
;
326 ack_params
.sync_point
= 0;
327 ScopedSendOnIOThread
delayed_send(
329 new AcceleratedSurfaceMsg_BufferPresented(params
.route_id
,
332 if (!params
.mailbox_name
.empty() &&
333 params
.mailbox_name
.length() != GL_MAILBOX_SIZE_CHROMIUM
)
336 RenderWidgetHostViewPort
* view
=
337 GetRenderWidgetHostViewFromSurfaceID(params
.surface_id
);
341 delayed_send
.Cancel();
343 // View must send ACK message after next composite.
344 view
->AcceleratedSurfacePostSubBuffer(params
, host_id_
);
345 view
->DidReceiveRendererFrame();
348 void GpuProcessHostUIShim::OnAcceleratedSurfaceSuspend(int32 surface_id
) {
349 TRACE_EVENT0("renderer",
350 "GpuProcessHostUIShim::OnAcceleratedSurfaceSuspend");
352 RenderWidgetHostViewPort
* view
=
353 GetRenderWidgetHostViewFromSurfaceID(surface_id
);
357 view
->AcceleratedSurfaceSuspend();
360 void GpuProcessHostUIShim::OnAcceleratedSurfaceRelease(
361 const GpuHostMsg_AcceleratedSurfaceRelease_Params
& params
) {
362 RenderWidgetHostViewPort
* view
= GetRenderWidgetHostViewFromSurfaceID(
366 view
->AcceleratedSurfaceRelease();
369 void GpuProcessHostUIShim::OnVideoMemoryUsageStatsReceived(
370 const GPUVideoMemoryUsageStats
& video_memory_usage_stats
) {
371 GpuDataManagerImpl::GetInstance()->UpdateVideoMemoryUsageStats(
372 video_memory_usage_stats
);
375 } // namespace content