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/callback_helpers.h"
11 #include "base/id_map.h"
12 #include "base/lazy_instance.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/trace_event/trace_event.h"
15 #include "content/browser/compositor/gpu_process_transport_factory.h"
16 #include "content/browser/gpu/compositor_util.h"
17 #include "content/browser/gpu/gpu_data_manager_impl.h"
18 #include "content/browser/gpu/gpu_process_host.h"
19 #include "content/browser/gpu/gpu_surface_tracker.h"
20 #include "content/browser/renderer_host/render_process_host_impl.h"
21 #include "content/browser/renderer_host/render_view_host_impl.h"
22 #include "content/browser/renderer_host/render_widget_helper.h"
23 #include "content/browser/renderer_host/render_widget_host_view_base.h"
24 #include "content/common/gpu/gpu_messages.h"
25 #include "content/public/browser/browser_thread.h"
27 #if defined(OS_MACOSX)
28 #include "ui/accelerated_widget_mac/accelerated_widget_mac.h"
31 #if defined(USE_OZONE)
32 #include "ui/ozone/public/gpu_platform_support_host.h"
33 #include "ui/ozone/public/ozone_platform.h"
40 // One of the linux specific headers defines this as a macro.
45 #if defined(OS_MACOSX)
46 void OnSurfaceDisplayedCallback(int output_surface_id
) {
47 content::ImageTransportFactory::GetInstance()->OnSurfaceDisplayed(
52 base::LazyInstance
<IDMap
<GpuProcessHostUIShim
> > g_hosts_by_id
=
53 LAZY_INSTANCE_INITIALIZER
;
55 void SendOnIOThreadTask(int host_id
, IPC::Message
* msg
) {
56 GpuProcessHost
* host
= GpuProcessHost::FromID(host_id
);
63 class ScopedSendOnIOThread
{
65 ScopedSendOnIOThread(int host_id
, IPC::Message
* msg
)
71 ~ScopedSendOnIOThread() {
73 BrowserThread::PostTask(BrowserThread::IO
,
75 base::Bind(&SendOnIOThreadTask
,
81 void Cancel() { cancelled_
= true; }
85 scoped_ptr
<IPC::Message
> msg_
;
89 RenderWidgetHostViewBase
* GetRenderWidgetHostViewFromSurfaceID(
91 int render_process_id
= 0;
92 int render_widget_id
= 0;
93 if (!GpuSurfaceTracker::Get()->GetRenderWidgetIDForSurface(
94 surface_id
, &render_process_id
, &render_widget_id
))
97 RenderWidgetHost
* host
=
98 RenderWidgetHost::FromID(render_process_id
, render_widget_id
);
99 return host
? static_cast<RenderWidgetHostViewBase
*>(host
->GetView()) : NULL
;
104 void RouteToGpuProcessHostUIShimTask(int host_id
, const IPC::Message
& msg
) {
105 GpuProcessHostUIShim
* ui_shim
= GpuProcessHostUIShim::FromID(host_id
);
107 ui_shim
->OnMessageReceived(msg
);
110 GpuProcessHostUIShim::GpuProcessHostUIShim(int host_id
)
111 : host_id_(host_id
) {
112 g_hosts_by_id
.Pointer()->AddWithID(this, host_id_
);
113 #if defined(USE_OZONE)
114 ui::OzonePlatform::GetInstance()
115 ->GetGpuPlatformSupportHost()
116 ->OnChannelEstablished(
118 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO
),
119 base::Bind(&SendOnIOThreadTask
, host_id_
));
124 GpuProcessHostUIShim
* GpuProcessHostUIShim::Create(int host_id
) {
125 DCHECK(!FromID(host_id
));
126 return new GpuProcessHostUIShim(host_id
);
130 void GpuProcessHostUIShim::Destroy(int host_id
, const std::string
& message
) {
131 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
133 GpuDataManagerImpl::GetInstance()->AddLogMessage(
134 logging::LOG_ERROR
, "GpuProcessHostUIShim",
137 #if defined(USE_OZONE)
138 ui::OzonePlatform::GetInstance()
139 ->GetGpuPlatformSupportHost()
140 ->OnChannelDestroyed(host_id
);
143 delete FromID(host_id
);
147 void GpuProcessHostUIShim::DestroyAll() {
148 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
149 while (!g_hosts_by_id
.Pointer()->IsEmpty()) {
150 IDMap
<GpuProcessHostUIShim
>::iterator
it(g_hosts_by_id
.Pointer());
151 delete it
.GetCurrentValue();
156 GpuProcessHostUIShim
* GpuProcessHostUIShim::FromID(int host_id
) {
157 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
158 return g_hosts_by_id
.Pointer()->Lookup(host_id
);
162 GpuProcessHostUIShim
* GpuProcessHostUIShim::GetOneInstance() {
163 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
164 if (g_hosts_by_id
.Pointer()->IsEmpty())
166 IDMap
<GpuProcessHostUIShim
>::iterator
it(g_hosts_by_id
.Pointer());
167 return it
.GetCurrentValue();
170 bool GpuProcessHostUIShim::Send(IPC::Message
* msg
) {
171 DCHECK(CalledOnValidThread());
172 return BrowserThread::PostTask(BrowserThread::IO
,
174 base::Bind(&SendOnIOThreadTask
,
179 bool GpuProcessHostUIShim::OnMessageReceived(const IPC::Message
& message
) {
180 DCHECK(CalledOnValidThread());
182 #if defined(USE_OZONE)
183 if (ui::OzonePlatform::GetInstance()
184 ->GetGpuPlatformSupportHost()
185 ->OnMessageReceived(message
))
189 if (message
.routing_id() != MSG_ROUTING_CONTROL
)
192 return OnControlMessageReceived(message
);
195 void GpuProcessHostUIShim::RelinquishGpuResources(
196 const base::Closure
& callback
) {
197 DCHECK(relinquish_callback_
.is_null());
198 relinquish_callback_
= callback
;
199 Send(new GpuMsg_RelinquishResources());
202 void GpuProcessHostUIShim::SimulateRemoveAllContext() {
203 Send(new GpuMsg_Clean());
206 void GpuProcessHostUIShim::SimulateCrash() {
207 Send(new GpuMsg_Crash());
210 void GpuProcessHostUIShim::SimulateHang() {
211 Send(new GpuMsg_Hang());
214 GpuProcessHostUIShim::~GpuProcessHostUIShim() {
215 DCHECK(CalledOnValidThread());
216 g_hosts_by_id
.Pointer()->Remove(host_id_
);
219 bool GpuProcessHostUIShim::OnControlMessageReceived(
220 const IPC::Message
& message
) {
221 DCHECK(CalledOnValidThread());
223 IPC_BEGIN_MESSAGE_MAP(GpuProcessHostUIShim
, message
)
224 IPC_MESSAGE_HANDLER(GpuHostMsg_OnLogMessage
,
226 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceInitialized
,
227 OnAcceleratedSurfaceInitialized
)
228 #if defined(OS_MACOSX)
229 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped
,
230 OnAcceleratedSurfaceBuffersSwapped
)
232 IPC_MESSAGE_HANDLER(GpuHostMsg_GraphicsInfoCollected
,
233 OnGraphicsInfoCollected
)
234 IPC_MESSAGE_HANDLER(GpuHostMsg_VideoMemoryUsageStats
,
235 OnVideoMemoryUsageStatsReceived
);
236 IPC_MESSAGE_HANDLER(GpuHostMsg_ResourcesRelinquished
,
237 OnResourcesRelinquished
)
238 IPC_MESSAGE_HANDLER(GpuHostMsg_AddSubscription
, OnAddSubscription
);
239 IPC_MESSAGE_HANDLER(GpuHostMsg_RemoveSubscription
, OnRemoveSubscription
);
241 IPC_MESSAGE_UNHANDLED_ERROR()
242 IPC_END_MESSAGE_MAP()
247 void GpuProcessHostUIShim::OnLogMessage(
249 const std::string
& header
,
250 const std::string
& message
) {
251 GpuDataManagerImpl::GetInstance()->AddLogMessage(
252 level
, header
, message
);
255 void GpuProcessHostUIShim::OnGraphicsInfoCollected(
256 const gpu::GPUInfo
& gpu_info
) {
257 // OnGraphicsInfoCollected is sent back after the GPU process successfully
259 TRACE_EVENT0("test_gpu", "OnGraphicsInfoCollected");
261 GpuDataManagerImpl::GetInstance()->UpdateGpuInfo(gpu_info
);
264 void GpuProcessHostUIShim::OnAcceleratedSurfaceInitialized(int32 surface_id
,
266 RenderWidgetHostViewBase
* view
=
267 GetRenderWidgetHostViewFromSurfaceID(surface_id
);
270 view
->AcceleratedSurfaceInitialized(route_id
);
273 #if defined(OS_MACOSX)
274 void GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped(
275 const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params
& params
) {
276 TRACE_EVENT0("renderer",
277 "GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped");
278 if (!ui::LatencyInfo::Verify(params
.latency_info
,
279 "GpuHostMsg_AcceleratedSurfaceBuffersSwapped")) {
283 // On Mac with delegated rendering, accelerated surfaces are not necessarily
284 // associated with a RenderWidgetHostViewBase.
285 AcceleratedSurfaceMsg_BufferPresented_Params ack_params
;
286 DCHECK(IsDelegatedRendererEnabled());
288 // If the frame was intended for an NSView that the gfx::AcceleratedWidget is
289 // no longer attached to, do not pass the frame along to the widget. Just ack
290 // it to the GPU process immediately, so we can proceed to the next frame.
291 bool should_not_show_frame
=
292 content::ImageTransportFactory::GetInstance()
293 ->SurfaceShouldNotShowFramesAfterSuspendForRecycle(params
.surface_id
);
294 if (should_not_show_frame
) {
295 OnSurfaceDisplayedCallback(params
.surface_id
);
297 gfx::AcceleratedWidget native_widget
=
298 content::GpuSurfaceTracker::Get()->AcquireNativeWidget(
300 ui::AcceleratedWidgetMacGotAcceleratedFrame(
301 native_widget
, params
.surface_handle
, params
.latency_info
, params
.size
,
304 base::Bind(&OnSurfaceDisplayedCallback
, params
.surface_id
),
305 &ack_params
.disable_throttling
, &ack_params
.renderer_id
);
307 Send(new AcceleratedSurfaceMsg_BufferPresented(params
.route_id
, ack_params
));
311 void GpuProcessHostUIShim::OnVideoMemoryUsageStatsReceived(
312 const GPUVideoMemoryUsageStats
& video_memory_usage_stats
) {
313 GpuDataManagerImpl::GetInstance()->UpdateVideoMemoryUsageStats(
314 video_memory_usage_stats
);
317 void GpuProcessHostUIShim::OnResourcesRelinquished() {
318 if (!relinquish_callback_
.is_null()) {
319 base::ResetAndReturn(&relinquish_callback_
).Run();
323 void GpuProcessHostUIShim::OnAddSubscription(
324 int32 process_id
, unsigned int target
) {
325 RenderProcessHost
* rph
= RenderProcessHost::FromID(process_id
);
327 rph
->OnAddSubscription(target
);
331 void GpuProcessHostUIShim::OnRemoveSubscription(
332 int32 process_id
, unsigned int target
) {
333 RenderProcessHost
* rph
= RenderProcessHost::FromID(process_id
);
335 rph
->OnRemoveSubscription(target
);
339 } // namespace content