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