forked from flutter/engine
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvsync_waiter.cc
138 lines (114 loc) · 4.5 KB
/
vsync_waiter.cc
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
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/shell/common/vsync_waiter.h"
#include "flutter/fml/task_runner.h"
#include "flutter/fml/trace_event.h"
namespace flutter {
#if defined(OS_FUCHSIA)
// In general, traces on Fuchsia are recorded across the whole system.
// Because of this, emitting a "VSYNC" event per flutter process is
// undesirable, as the events will collide with each other. We
// instead let another area of the system emit them.
static constexpr const char* kVsyncTraceName = "vsync callback";
#else // defined(OS_FUCHSIA)
// Note: The tag name must be "VSYNC" (it is special) so that the
// "Highlight Vsync" checkbox in the timeline can be enabled.
static constexpr const char* kVsyncTraceName = "VSYNC";
#endif // defined(OS_FUCHSIA)
static constexpr const char* kVsyncFlowName = "VsyncFlow";
VsyncWaiter::VsyncWaiter(TaskRunners task_runners)
: task_runners_(std::move(task_runners)) {}
VsyncWaiter::~VsyncWaiter() = default;
// Public method invoked by the animator.
void VsyncWaiter::AsyncWaitForVsync(const Callback& callback) {
if (!callback) {
return;
}
TRACE_EVENT0("flutter", "AsyncWaitForVsync");
{
std::scoped_lock lock(callback_mutex_);
if (callback_) {
// The animator may request a frame more than once within a frame
// interval. Multiple calls to request frame must result in a single
// callback per frame interval.
TRACE_EVENT_INSTANT0("flutter", "MultipleCallsToVsyncInFrameInterval");
return;
}
callback_ = std::move(callback);
if (secondary_callback_) {
// Return directly as `AwaitVSync` is already called by
// `ScheduleSecondaryCallback`.
return;
}
}
AwaitVSync();
}
void VsyncWaiter::ScheduleSecondaryCallback(const fml::closure& callback) {
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
if (!callback) {
return;
}
TRACE_EVENT0("flutter", "ScheduleSecondaryCallback");
{
std::scoped_lock lock(callback_mutex_);
if (secondary_callback_) {
// Multiple schedules must result in a single callback per frame interval.
TRACE_EVENT_INSTANT0("flutter",
"MultipleCallsToSecondaryVsyncInFrameInterval");
return;
}
secondary_callback_ = std::move(callback);
if (callback_) {
// Return directly as `AwaitVSync` is already called by
// `AsyncWaitForVsync`.
return;
}
}
AwaitVSync();
}
void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time,
fml::TimePoint frame_target_time) {
Callback callback;
fml::closure secondary_callback;
{
std::scoped_lock lock(callback_mutex_);
callback = std::move(callback_);
secondary_callback = std::move(secondary_callback_);
}
if (!callback && !secondary_callback) {
// This means that the vsync waiter implementation fired a callback for a
// request we did not make. This is a paranoid check but we still want to
// make sure we catch misbehaving vsync implementations.
TRACE_EVENT_INSTANT0("flutter", "MismatchedFrameCallback");
return;
}
if (callback) {
auto flow_identifier = fml::tracing::TraceNonce();
// The base trace ensures that flows have a root to begin from if one does
// not exist. The trace viewer will ignore traces that have no base event
// trace. While all our message loops insert a base trace trace
// (MessageLoop::RunExpiredTasks), embedders may not.
TRACE_EVENT0("flutter", "VsyncFireCallback");
TRACE_FLOW_BEGIN("flutter", kVsyncFlowName, flow_identifier);
task_runners_.GetUITaskRunner()->PostTaskForTime(
[callback, flow_identifier, frame_start_time, frame_target_time]() {
FML_TRACE_EVENT("flutter", kVsyncTraceName, "StartTime",
frame_start_time, "TargetTime", frame_target_time);
fml::tracing::TraceEventAsyncComplete(
"flutter", "VsyncSchedulingOverhead", fml::TimePoint::Now(),
frame_start_time);
callback(frame_start_time, frame_target_time);
TRACE_FLOW_END("flutter", kVsyncFlowName, flow_identifier);
},
frame_start_time);
}
if (secondary_callback) {
task_runners_.GetUITaskRunner()->PostTaskForTime(
std::move(secondary_callback), frame_start_time);
}
}
float VsyncWaiter::GetDisplayRefreshRate() const {
return kUnknownRefreshRateFPS;
}
} // namespace flutter