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