summaryrefslogtreecommitdiffstats
path: root/cc/scheduler/begin_frame_source.h
blob: 3d849a40d638708ad37acca859aaeaa98e9e911e (plain)
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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CC_SCHEDULER_BEGIN_FRAME_SOURCE_H_
#define CC_SCHEDULER_BEGIN_FRAME_SOURCE_H_

#include <set>
#include <string>

#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "cc/output/begin_frame_args.h"
#include "cc/output/vsync_parameter_observer.h"
#include "cc/scheduler/delay_based_time_source.h"

namespace cc {

// (Pure) Interface for observing BeginFrame messages from BeginFrameSource
// objects.
class CC_EXPORT BeginFrameObserver {
 public:
  virtual ~BeginFrameObserver() {}

  // The |args| given to OnBeginFrame is guaranteed to have
  // |args|.IsValid()==true and have |args|.frame_time
  // field be strictly greater than the previous call.
  //
  // Side effects: This function can (and most of the time *will*) change the
  // return value of the LastUsedBeginFrameArgs method. See the documentation
  // on that method for more information.
  virtual void OnBeginFrame(const BeginFrameArgs& args) = 0;

  // Returns the last BeginFrameArgs used by the observer. This method's return
  // value is affected by the OnBeginFrame method!
  //
  //  - Before the first call of OnBeginFrame, this method should return a
  //    BeginFrameArgs on which IsValid() returns false.
  //
  //  - If the |args| passed to OnBeginFrame is (or *will be*) used, then
  //    LastUsedBeginFrameArgs return value should become the |args| given to
  //    OnBeginFrame.
  //
  //  - If the |args| passed to OnBeginFrame is dropped, then
  //    LastUsedBeginFrameArgs return value should *not* change.
  //
  // These requirements are designed to allow chaining and nesting of
  // BeginFrameObservers which filter the incoming BeginFrame messages while
  // preventing "double dropping" and other bad side effects.
  virtual const BeginFrameArgs LastUsedBeginFrameArgs() const = 0;

  // Tracing support
  virtual void AsValueInto(base::debug::TracedValue* dict) const = 0;
};

// Simple mix in which implements a BeginFrameObserver which checks the
// incoming values meet the BeginFrameObserver requirements and implements the
// required LastUsedBeginFrameArgs behaviour.
//
// Users of this mix in should;
//  - Implement the OnBeginFrameMixInDelegate function.
//  - Recommended (but not required) to call
//    BeginFrameObserverMixIn::OnValueInto in their overridden OnValueInto
//    function.
class CC_EXPORT BeginFrameObserverMixIn : public BeginFrameObserver {
 public:
  BeginFrameObserverMixIn();

  // BeginFrameObserver

  // Traces |args| and DCHECK |args| satisfies pre-conditions then calls
  // OnBeginFrameMixInDelegate and updates the last_begin_frame_args_ value on
  // true.
  void OnBeginFrame(const BeginFrameArgs& args) override;
  const BeginFrameArgs LastUsedBeginFrameArgs() const override;

  // Outputs last_begin_frame_args_
  void AsValueInto(base::debug::TracedValue* dict) const override;

 protected:
  // Subclasses should override this method!
  // Return true if the given argument is (or will be) used.
  virtual bool OnBeginFrameMixInDelegate(const BeginFrameArgs& args) = 0;

  BeginFrameArgs last_begin_frame_args_;
  int64_t dropped_begin_frame_args_;
};

// Interface for a class which produces BeginFrame calls to a
// BeginFrameObserver.
//
// BeginFrame calls *normally* occur just after a vsync interrupt when input
// processing has been finished and provide information about the time values
// of the vsync times. *However*, these values can be heavily modified or even
// plain made up (when no vsync signal is available or vsync throttling is
// turned off). See the BeginFrameObserver for information about the guarantees
// all BeginFrameSources *must* provide.
class CC_EXPORT BeginFrameSource {
 public:
  virtual ~BeginFrameSource() {}

  // SetNeedsBeginFrames is the on/off "switch" for the BeginFrameSource. When
  // set to false no more BeginFrame messages should be sent to observer.
  virtual bool NeedsBeginFrames() const = 0;
  virtual void SetNeedsBeginFrames(bool needs_begin_frames) = 0;

  // DidFinishFrame provides back pressure to a frame source about frame
  // processing (rather than toggling SetNeedsBeginFrames every frame). It is
  // used by systems like the BackToBackFrameSource to make sure only one frame
  // is pending at a time.
  virtual void DidFinishFrame(size_t remaining_frames) = 0;

  // Add/Remove an observer from the source.
  // *At the moment* only a single observer can be added to the source, however
  // in the future this may be extended to allow multiple observers.
  // If making this change, please use base::ObserverList to do so.
  virtual void AddObserver(BeginFrameObserver* obs) = 0;
  virtual void RemoveObserver(BeginFrameObserver* obs) = 0;

  // Tracing support - Recommend (but not required) to call this implementation
  // in any override.
  virtual void AsValueInto(base::debug::TracedValue* dict) const = 0;
};

// Simple mix in which implements a BeginFrameSource.
// Implementation classes should:
//  - Implement the pure virtual (Set)NeedsBeginFrames methods from
//    BeginFrameSource.
//  - Use the CallOnBeginFrame method to call to the observer(s).
//  - Recommended (but not required) to call BeginFrameSourceMixIn::AsValueInto
//    in their own AsValueInto implementation.
class CC_EXPORT BeginFrameSourceMixIn : public BeginFrameSource {
 public:
  ~BeginFrameSourceMixIn() override {}

  // BeginFrameSource
  bool NeedsBeginFrames() const override;
  void SetNeedsBeginFrames(bool needs_begin_frames) override;
  void DidFinishFrame(size_t remaining_frames) override {}
  void AddObserver(BeginFrameObserver* obs) override;
  void RemoveObserver(BeginFrameObserver* obs) override;

  // Tracing support - Recommend (but not required) to call this implementation
  // in any override.
  void AsValueInto(base::debug::TracedValue* dict) const override;

 protected:
  BeginFrameSourceMixIn();

  // These methods should be used by subclasses to make the call to the
  // observers.
  void CallOnBeginFrame(const BeginFrameArgs& args);

  // This method should be overridden if you want to change some behaviour on
  // needs_begin_frames change.
  virtual void OnNeedsBeginFramesChange(bool needs_begin_frames) {}

  BeginFrameObserver* observer_;
  bool needs_begin_frames_;

 private:
  bool inside_as_value_into_;
};

// A frame source which calls BeginFrame (at the next possible time) as soon as
// remaining frames reaches zero.
class CC_EXPORT BackToBackBeginFrameSource : public BeginFrameSourceMixIn {
 public:
  static scoped_ptr<BackToBackBeginFrameSource> Create(
      base::SingleThreadTaskRunner* task_runner);
  ~BackToBackBeginFrameSource() override;

  // BeginFrameSource
  void DidFinishFrame(size_t remaining_frames) override;

  // Tracing
  void AsValueInto(base::debug::TracedValue* dict) const override;

 protected:
  explicit BackToBackBeginFrameSource(
      base::SingleThreadTaskRunner* task_runner);
  virtual base::TimeTicks Now();  // Now overridable for testing

  base::WeakPtrFactory<BackToBackBeginFrameSource> weak_factory_;
  base::SingleThreadTaskRunner* task_runner_;

  bool send_begin_frame_posted_;

  // BeginFrameSourceMixIn
  void OnNeedsBeginFramesChange(bool needs_begin_frames) override;

  void BeginFrame();
};

// A frame source which is locked to an external parameters provides from a
// vsync source and generates BeginFrameArgs for it.
class CC_EXPORT SyntheticBeginFrameSource : public BeginFrameSourceMixIn,
                                            public VSyncParameterObserver,
                                            public TimeSourceClient {
 public:
  static scoped_ptr<SyntheticBeginFrameSource> Create(
      base::SingleThreadTaskRunner* task_runner,
      base::TimeTicks initial_vsync_timebase,
      base::TimeDelta initial_vsync_interval);
  ~SyntheticBeginFrameSource() override;

  // BeginFrameSource
  bool NeedsBeginFrames() const override;

  // Tracing
  void AsValueInto(base::debug::TracedValue* dict) const override;

  // VSyncParameterObserver
  void OnUpdateVSyncParameters(base::TimeTicks new_vsync_timebase,
                               base::TimeDelta new_vsync_interval) override;

  // TimeSourceClient
  void OnTimerTick() override;

 protected:
  explicit SyntheticBeginFrameSource(
      scoped_refptr<DelayBasedTimeSource> time_source);

  BeginFrameArgs CreateBeginFrameArgs(base::TimeTicks frame_time,
                                      BeginFrameArgs::BeginFrameArgsType type);

  // BeginFrameSourceMixIn
  void OnNeedsBeginFramesChange(bool needs_begin_frames) override;

  scoped_refptr<DelayBasedTimeSource> time_source_;
};

// A "virtual" frame source which lets you switch between multiple other frame
// sources while making sure the BeginFrameArgs stays increasing (possibly
// enforcing minimum boundry between BeginFrameArgs messages).
class CC_EXPORT BeginFrameSourceMultiplexer : public BeginFrameSourceMixIn,
                                              public BeginFrameObserver {
 public:
  static scoped_ptr<BeginFrameSourceMultiplexer> Create();
  ~BeginFrameSourceMultiplexer() override;

  void SetMinimumInterval(base::TimeDelta new_minimum_interval);

  void AddSource(BeginFrameSource* new_source);
  void RemoveSource(BeginFrameSource* existing_source);
  void SetActiveSource(BeginFrameSource* new_source);
  const BeginFrameSource* ActiveSource();

  // BeginFrameObserver
  // The mux is an BeginFrameObserver as it needs to proxy the OnBeginFrame
  // calls to preserve the monotonicity of the BeginFrameArgs when switching
  // sources.
  void OnBeginFrame(const BeginFrameArgs& args) override;
  const BeginFrameArgs LastUsedBeginFrameArgs() const override;

  // BeginFrameSource
  bool NeedsBeginFrames() const override;
  void SetNeedsBeginFrames(bool needs_begin_frames) override;
  void DidFinishFrame(size_t remaining_frames) override;

  // Tracing
  void AsValueInto(base::debug::TracedValue* dict) const override;

 protected:
  BeginFrameSourceMultiplexer();
  explicit BeginFrameSourceMultiplexer(base::TimeDelta minimum_interval);

  bool HasSource(BeginFrameSource* source);
  bool IsIncreasing(const BeginFrameArgs& args);

  base::TimeDelta minimum_interval_;

  BeginFrameSource* active_source_;
  std::set<BeginFrameSource*> source_list_;
};

}  // namespace cc

#endif  // CC_SCHEDULER_BEGIN_FRAME_SOURCE_H_