1// Copyright 2014 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/compositor/browser_compositor_view_mac.h"
6
7#include "base/debug/trace_event.h"
8#include "base/lazy_instance.h"
9#include "content/browser/gpu/gpu_process_host_ui_shim.h"
10#include "content/browser/compositor/browser_compositor_view_private_mac.h"
11#include "content/common/gpu/gpu_messages.h"
12
13////////////////////////////////////////////////////////////////////////////////
14// BrowserCompositorViewMac
15
16namespace content {
17namespace {
18
19// The number of placeholder objects allocated. If this reaches zero, then
20// the BrowserCompositorViewMacInternal being held on to for recycling,
21// |g_recyclable_internal_view|, will be freed.
22uint32 g_placeholder_count = 0;
23
24// A spare BrowserCompositorViewMacInternal kept around for recycling.
25base::LazyInstance<scoped_ptr<BrowserCompositorViewMacInternal>>
26  g_recyclable_internal_view;
27
28}  // namespace
29
30BrowserCompositorViewMac::BrowserCompositorViewMac(
31    BrowserCompositorViewMacClient* client) : client_(client) {
32  // Try to use the recyclable BrowserCompositorViewMacInternal if there is one,
33  // otherwise allocate a new one.
34  // TODO(ccameron): If there exists a frame in flight (swap has been called
35  // by the compositor, but the frame has not arrived from the GPU process
36  // yet), then that frame may inappropriately flash in the new view.
37  internal_view_ = g_recyclable_internal_view.Get().Pass();
38  if (!internal_view_)
39    internal_view_.reset(new BrowserCompositorViewMacInternal);
40  internal_view_->SetClient(client_);
41}
42
43BrowserCompositorViewMac::~BrowserCompositorViewMac() {
44  // Make this BrowserCompositorViewMacInternal recyclable for future instances.
45  internal_view_->ResetClient();
46  g_recyclable_internal_view.Get() = internal_view_.Pass();
47
48  // If there are no placeholders allocated, destroy the recyclable
49  // BrowserCompositorViewMacInternal that we just populated.
50  if (!g_placeholder_count)
51    g_recyclable_internal_view.Get().reset();
52}
53
54ui::Compositor* BrowserCompositorViewMac::GetCompositor() const {
55  DCHECK(internal_view_);
56  return internal_view_->compositor();
57}
58
59bool BrowserCompositorViewMac::HasFrameOfSize(
60    const gfx::Size& dip_size) const {
61  if (internal_view_)
62    return internal_view_->HasFrameOfSize(dip_size);
63  return false;
64}
65
66void BrowserCompositorViewMac::BeginPumpingFrames() {
67  if (internal_view_)
68    internal_view_->BeginPumpingFrames();
69}
70
71void BrowserCompositorViewMac::EndPumpingFrames() {
72  if (internal_view_)
73    internal_view_->EndPumpingFrames();
74}
75
76// static
77void BrowserCompositorViewMac::GotAcceleratedFrame(
78    gfx::AcceleratedWidget widget,
79    uint64 surface_handle, int surface_id,
80    const std::vector<ui::LatencyInfo>& latency_info,
81    gfx::Size pixel_size, float scale_factor,
82    int gpu_host_id, int gpu_route_id) {
83  BrowserCompositorViewMacInternal* internal_view =
84      BrowserCompositorViewMacInternal::FromAcceleratedWidget(widget);
85  int renderer_id = 0;
86  if (internal_view) {
87    internal_view->GotAcceleratedFrame(
88        surface_handle, surface_id, latency_info, pixel_size, scale_factor);
89    renderer_id = internal_view->GetRendererID();
90  }
91
92  // Acknowledge the swap, now that it has been processed.
93  AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
94  ack_params.sync_point = 0;
95  ack_params.renderer_id = renderer_id;
96  GpuProcessHostUIShim* ui_shim = GpuProcessHostUIShim::FromID(gpu_host_id);
97  if (ui_shim) {
98    ui_shim->Send(new AcceleratedSurfaceMsg_BufferPresented(
99        gpu_route_id, ack_params));
100  }
101}
102
103// static
104void BrowserCompositorViewMac::GotSoftwareFrame(
105    gfx::AcceleratedWidget widget,
106    cc::SoftwareFrameData* frame_data, float scale_factor, SkCanvas* canvas) {
107  BrowserCompositorViewMacInternal* internal_view =
108      BrowserCompositorViewMacInternal::FromAcceleratedWidget(widget);
109  if (internal_view)
110    internal_view->GotSoftwareFrame(frame_data, scale_factor, canvas);
111}
112
113////////////////////////////////////////////////////////////////////////////////
114// BrowserCompositorViewPlaceholderMac
115
116BrowserCompositorViewPlaceholderMac::BrowserCompositorViewPlaceholderMac() {
117  g_placeholder_count += 1;
118}
119
120BrowserCompositorViewPlaceholderMac::~BrowserCompositorViewPlaceholderMac() {
121  DCHECK_GT(g_placeholder_count, 0u);
122  g_placeholder_count -= 1;
123
124  // If there are no placeholders allocated, destroy the recyclable
125  // BrowserCompositorViewMacInternal.
126  if (!g_placeholder_count)
127    g_recyclable_internal_view.Get().reset();
128}
129
130}  // namespace content
131