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 void StopGpuProcessOnIO(int host_id
) {
64 GpuProcessHost
* host
= GpuProcessHost::FromID(host_id
);
66 host
->StopGpuProcess();
69 class ScopedSendOnIOThread
{
71 ScopedSendOnIOThread(int host_id
, IPC::Message
* msg
)
77 ~ScopedSendOnIOThread() {
79 BrowserThread::PostTask(BrowserThread::IO
,
81 base::Bind(&SendOnIOThreadTask
,
87 void Cancel() { cancelled_
= true; }
91 scoped_ptr
<IPC::Message
> msg_
;
95 RenderWidgetHostViewBase
* GetRenderWidgetHostViewFromSurfaceID(
97 int render_process_id
= 0;
98 int render_widget_id
= 0;
99 if (!GpuSurfaceTracker::Get()->GetRenderWidgetIDForSurface(
100 surface_id
, &render_process_id
, &render_widget_id
))
103 RenderWidgetHost
* host
=
104 RenderWidgetHost::FromID(render_process_id
, render_widget_id
);
105 return host
? static_cast<RenderWidgetHostViewBase
*>(host
->GetView()) : NULL
;
110 void RouteToGpuProcessHostUIShimTask(int host_id
, const IPC::Message
& msg
) {
111 GpuProcessHostUIShim
* ui_shim
= GpuProcessHostUIShim::FromID(host_id
);
113 ui_shim
->OnMessageReceived(msg
);
116 GpuProcessHostUIShim::GpuProcessHostUIShim(int host_id
)
117 : host_id_(host_id
) {
118 g_hosts_by_id
.Pointer()->AddWithID(this, host_id_
);
119 #if defined(USE_OZONE)
120 ui::OzonePlatform::GetInstance()
121 ->GetGpuPlatformSupportHost()
122 ->OnChannelEstablished(
124 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO
),
125 base::Bind(&SendOnIOThreadTask
, host_id_
));
130 GpuProcessHostUIShim
* GpuProcessHostUIShim::Create(int host_id
) {
131 DCHECK(!FromID(host_id
));
132 return new GpuProcessHostUIShim(host_id
);
136 void GpuProcessHostUIShim::Destroy(int host_id
, const std::string
& message
) {
137 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
139 GpuDataManagerImpl::GetInstance()->AddLogMessage(
140 logging::LOG_ERROR
, "GpuProcessHostUIShim",
143 #if defined(USE_OZONE)
144 ui::OzonePlatform::GetInstance()
145 ->GetGpuPlatformSupportHost()
146 ->OnChannelDestroyed(host_id
);
149 delete FromID(host_id
);
153 void GpuProcessHostUIShim::DestroyAll() {
154 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
155 while (!g_hosts_by_id
.Pointer()->IsEmpty()) {
156 IDMap
<GpuProcessHostUIShim
>::iterator
it(g_hosts_by_id
.Pointer());
157 delete it
.GetCurrentValue();
162 GpuProcessHostUIShim
* GpuProcessHostUIShim::FromID(int host_id
) {
163 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
164 return g_hosts_by_id
.Pointer()->Lookup(host_id
);
168 GpuProcessHostUIShim
* GpuProcessHostUIShim::GetOneInstance() {
169 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
170 if (g_hosts_by_id
.Pointer()->IsEmpty())
172 IDMap
<GpuProcessHostUIShim
>::iterator
it(g_hosts_by_id
.Pointer());
173 return it
.GetCurrentValue();
176 bool GpuProcessHostUIShim::Send(IPC::Message
* msg
) {
177 DCHECK(CalledOnValidThread());
178 return BrowserThread::PostTask(BrowserThread::IO
,
180 base::Bind(&SendOnIOThreadTask
,
185 bool GpuProcessHostUIShim::OnMessageReceived(const IPC::Message
& message
) {
186 DCHECK(CalledOnValidThread());
188 #if defined(USE_OZONE)
189 if (ui::OzonePlatform::GetInstance()
190 ->GetGpuPlatformSupportHost()
191 ->OnMessageReceived(message
))
195 if (message
.routing_id() != MSG_ROUTING_CONTROL
)
198 return OnControlMessageReceived(message
);
201 void GpuProcessHostUIShim::StopGpuProcess(const base::Closure
& callback
) {
202 close_callback_
= callback
;
204 BrowserThread::PostTask(
205 BrowserThread::IO
, FROM_HERE
, base::Bind(&StopGpuProcessOnIO
, host_id_
));
208 void GpuProcessHostUIShim::SimulateRemoveAllContext() {
209 Send(new GpuMsg_Clean());
212 void GpuProcessHostUIShim::SimulateCrash() {
213 Send(new GpuMsg_Crash());
216 void GpuProcessHostUIShim::SimulateHang() {
217 Send(new GpuMsg_Hang());
220 GpuProcessHostUIShim::~GpuProcessHostUIShim() {
221 DCHECK(CalledOnValidThread());
222 if (!close_callback_
.is_null())
223 base::ResetAndReturn(&close_callback_
).Run();
224 g_hosts_by_id
.Pointer()->Remove(host_id_
);
227 bool GpuProcessHostUIShim::OnControlMessageReceived(
228 const IPC::Message
& message
) {
229 DCHECK(CalledOnValidThread());
231 IPC_BEGIN_MESSAGE_MAP(GpuProcessHostUIShim
, message
)
232 IPC_MESSAGE_HANDLER(GpuHostMsg_OnLogMessage
,
234 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceInitialized
,
235 OnAcceleratedSurfaceInitialized
)
236 #if defined(OS_MACOSX)
237 IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped
,
238 OnAcceleratedSurfaceBuffersSwapped
)
240 IPC_MESSAGE_HANDLER(GpuHostMsg_GraphicsInfoCollected
,
241 OnGraphicsInfoCollected
)
242 IPC_MESSAGE_HANDLER(GpuHostMsg_VideoMemoryUsageStats
,
243 OnVideoMemoryUsageStatsReceived
);
244 IPC_MESSAGE_HANDLER(GpuHostMsg_AddSubscription
, OnAddSubscription
);
245 IPC_MESSAGE_HANDLER(GpuHostMsg_RemoveSubscription
, OnRemoveSubscription
);
247 IPC_MESSAGE_UNHANDLED_ERROR()
248 IPC_END_MESSAGE_MAP()
253 void GpuProcessHostUIShim::OnLogMessage(
255 const std::string
& header
,
256 const std::string
& message
) {
257 GpuDataManagerImpl::GetInstance()->AddLogMessage(
258 level
, header
, message
);
261 void GpuProcessHostUIShim::OnGraphicsInfoCollected(
262 const gpu::GPUInfo
& gpu_info
) {
263 // OnGraphicsInfoCollected is sent back after the GPU process successfully
265 TRACE_EVENT0("test_gpu", "OnGraphicsInfoCollected");
267 GpuDataManagerImpl::GetInstance()->UpdateGpuInfo(gpu_info
);
270 void GpuProcessHostUIShim::OnAcceleratedSurfaceInitialized(int32 surface_id
,
272 RenderWidgetHostViewBase
* view
=
273 GetRenderWidgetHostViewFromSurfaceID(surface_id
);
276 view
->AcceleratedSurfaceInitialized(route_id
);
279 #if defined(OS_MACOSX)
280 void GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped(
281 const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params
& params
) {
282 TRACE_EVENT0("renderer",
283 "GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped");
284 if (!ui::LatencyInfo::Verify(params
.latency_info
,
285 "GpuHostMsg_AcceleratedSurfaceBuffersSwapped")) {
289 // On Mac with delegated rendering, accelerated surfaces are not necessarily
290 // associated with a RenderWidgetHostViewBase.
291 AcceleratedSurfaceMsg_BufferPresented_Params ack_params
;
292 DCHECK(IsDelegatedRendererEnabled());
294 // If the frame was intended for an NSView that the gfx::AcceleratedWidget is
295 // no longer attached to, do not pass the frame along to the widget. Just ack
296 // it to the GPU process immediately, so we can proceed to the next frame.
297 bool should_not_show_frame
=
298 content::ImageTransportFactory::GetInstance()
299 ->SurfaceShouldNotShowFramesAfterSuspendForRecycle(params
.surface_id
);
300 if (should_not_show_frame
) {
301 OnSurfaceDisplayedCallback(params
.surface_id
);
303 gfx::AcceleratedWidget native_widget
=
304 content::GpuSurfaceTracker::Get()->AcquireNativeWidget(
306 ui::AcceleratedWidgetMacGotAcceleratedFrame(
307 native_widget
, params
.surface_handle
, params
.latency_info
, params
.size
,
310 base::Bind(&OnSurfaceDisplayedCallback
, params
.surface_id
),
311 &ack_params
.disable_throttling
, &ack_params
.renderer_id
,
312 &ack_params
.vsync_timebase
, &ack_params
.vsync_interval
);
314 Send(new AcceleratedSurfaceMsg_BufferPresented(params
.route_id
, ack_params
));
318 void GpuProcessHostUIShim::OnVideoMemoryUsageStatsReceived(
319 const GPUVideoMemoryUsageStats
& video_memory_usage_stats
) {
320 GpuDataManagerImpl::GetInstance()->UpdateVideoMemoryUsageStats(
321 video_memory_usage_stats
);
324 void GpuProcessHostUIShim::OnAddSubscription(
325 int32 process_id
, unsigned int target
) {
326 RenderProcessHost
* rph
= RenderProcessHost::FromID(process_id
);
328 rph
->OnAddSubscription(target
);
332 void GpuProcessHostUIShim::OnRemoveSubscription(
333 int32 process_id
, unsigned int target
) {
334 RenderProcessHost
* rph
= RenderProcessHost::FromID(process_id
);
336 rph
->OnRemoveSubscription(target
);
340 } // namespace content