1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
ash / frame_throttler / frame_throttling_controller.h [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_FRAME_THROTTLER_FRAME_THROTTLING_CONTROLLER_H_
#define ASH_FRAME_THROTTLER_FRAME_THROTTLING_CONTROLLER_H_
#include <stdint.h>
#include <vector>
#include "ash/ash_export.h"
#include "ash/frame_throttler/frame_throttling_observer.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "ui/aura/window_observer.h"
#include "ui/aura/window_tree_host_observer.h"
namespace aura {
class WindowTreeHost;
class Window;
}
namespace viz {
class HostFrameSinkManager;
} // namespace viz
namespace ash {
class ASH_EXPORT ThottleControllerWindowDelegate {
public:
virtual ~ThottleControllerWindowDelegate() = default;
virtual viz::FrameSinkId GetFrameSinkIdForWindow(
const aura::Window* window) const = 0;
};
ASH_EXPORT void SetThottleControllerWindowDelegate(
std::unique_ptr<ThottleControllerWindowDelegate> delegate);
constexpr uint8_t kDefaultThrottleFps = 20;
struct ThrottleCandidates {
ThrottleCandidates();
~ThrottleCandidates();
ThrottleCandidates(const ThrottleCandidates&);
ThrottleCandidates& operator=(const ThrottleCandidates&);
// Returns true if there are no candidates to throttle.
bool IsEmpty() const;
// The frame sink ids of the browser windows to be throttled this frame.
base::flat_set<viz::FrameSinkId> browser_frame_sink_ids;
};
class ASH_EXPORT FrameThrottlingController final
: public aura::WindowTreeHostObserver,
public aura::WindowObserver {
public:
explicit FrameThrottlingController(
viz::HostFrameSinkManager* host_frame_sink_manager);
FrameThrottlingController(const FrameThrottlingController&) = delete;
FrameThrottlingController& operator=(const FrameThrottlingController&) =
delete;
~FrameThrottlingController() override;
// ui::WindowTreeHostObserver overrides
void OnCompositingFrameSinksToThrottleUpdated(
const aura::WindowTreeHost* host,
const base::flat_set<viz::FrameSinkId>& ids) override;
// ui::WindowObserver overrides
void OnWindowDestroying(aura::Window* window) override;
void OnWindowTreeHostCreated(aura::WindowTreeHost* host);
// Starts to throttle the frame rate of |windows| at the custom
// |requested_frame_interval|. The |requested_frame_interval| is used unless
// the controller is actively throttling other windows not specified via
// StartThrottling() at a frame rate higher than the one requested here.
//
// Examples:
// Case 1: Controller is throttling a window specified via
// OnCompositingFrameSinksToThrottleUpdated() at 20 fps, and
// StartThrottling(<new window>, 30fps) is called. Both windows
// will be throttled at 30 fps.
// Case 2: Controller is throttling a window specified via
// OnCompositingFrameSinksToThrottleUpdated() at 20 fps, and
// StartThrottling(<new window>, 15fps) is called. Both windows
// will be throttled at 20 fps.
// Case 3: Controller is not throttling any windows, and
// StartThrottling(<new window>, 15fps) is called. The new window
// will be throttled at 15 fps.
//
// The higher frame rate is always picked to ensure all UIs are smooth enough,
// even if it comes at the cost of more power consumption.
//
// If the |requested_frame_interval| is zero, the default throttled frame rate
// is used internally.
void StartThrottling(
const std::vector<raw_ptr<aura::Window, VectorExperimental>>& windows,
base::TimeDelta requested_frame_interval = base::TimeDelta());
// Ends throttling of all windows specified via StartThrottling(). The
// throttled frame rate for any remaining windows returns to the default.
void EndThrottling();
std::vector<viz::FrameSinkId> GetFrameSinkIdsToThrottle() const;
void AddArcObserver(FrameThrottlingObserver* observer);
void RemoveArcObserver(FrameThrottlingObserver* observer);
bool HasArcObserver(FrameThrottlingObserver* observer);
// The current frame interval being used. Note this applies to all windows
// that the controller is currently throttling. The viz service does not allow
// for multiple simultaneous frame rates.
base::TimeDelta current_throttled_frame_interval() const {
return current_throttled_frame_interval_;
}
// Returns 1 / current_throttled_frame_interval() rounded to the nearest
// integer. Note if the frame interval is very large, this may legitimately
// return 0 fps.
uint8_t GetCurrentThrottledFrameRate() const;
private:
void StartThrottlingArc(const std::vector<aura::Window*>& windows,
uint8_t throttled_fps);
void EndThrottlingArc();
void UpdateThrottlingOnFrameSinks();
void SetWindowsManuallyThrottled(bool windows_manually_throttled);
void SetCurrentThrottledFrameInterval();
// Whether there are any windows to throttle besides the ones specified via
// StartThrottling().
bool HasCompositingBasedThrottling() const;
void ResetThrottleCandidates(ThrottleCandidates* candidates);
const raw_ptr<viz::HostFrameSinkManager> host_frame_sink_manager_;
base::ObserverList<FrameThrottlingObserver> arc_observers_;
// Maps aura::WindowTreeHost* to a set of FrameSinkIds to be throttled.
using WindowTreeHostMap =
base::flat_map<const aura::WindowTreeHost*, ThrottleCandidates>;
// Compositing-based throttling updates the set of FrameSinkIds per tree and
// this map keeps each aura::WindowTreeHost* to the most recently updated
// candidates, including browser and lacros windows.
WindowTreeHostMap host_to_candidates_map_;
// Window candidates (browser and lacros windows inclusive) to be throttled in
// special UI modes, such as overview and window cycling. This will be empty
// when UI is not in such modes.
ThrottleCandidates manually_throttled_candidates_;
// The default frame interval that should be used when a custom interval is
// not requested via StartThrottling(). This value is effectively immutable.
base::TimeDelta default_throttled_frame_interval_;
// The current frame interval used for throttling. Changes according to which
// windows are throttled and what frame rates were requested by the caller.
base::TimeDelta current_throttled_frame_interval_;
// The latest |requested_frame_interval| provided in StartThrottling().
// May be zero if one was not requested.
base::TimeDelta latest_custom_throttled_frame_interval_;
bool windows_manually_throttled_ = false;
};
} // namespace ash
#endif // ASH_FRAME_THROTTLER_FRAME_THROTTLING_CONTROLLER_H_