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