1 | // Copyright 2013 The Flutter 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 "flutter/shell/common/vsync_waiter.h" |
6 | |
7 | #include "flutter/fml/task_runner.h" |
8 | #include "flutter/fml/trace_event.h" |
9 | |
10 | namespace flutter { |
11 | |
12 | static constexpr const char* kVsyncFlowName = "VsyncFlow" ; |
13 | |
14 | #if defined(OS_FUCHSIA) |
15 | // ________ _________ ________ ________ |
16 | // |\ ____\|\___ ___\\ __ \|\ __ \ |
17 | // \ \ \___|\|___ \ \_\ \ \|\ \ \ \|\ \ |
18 | // \ \_____ \ \ \ \ \ \ \\\ \ \ ____\ |
19 | // \|____|\ \ \ \ \ \ \ \\\ \ \ \___| |
20 | // ____\_\ \ \ \__\ \ \_______\ \__\ |
21 | // |\_________\ \|__| \|_______|\|__| |
22 | // \|_________| |
23 | // |
24 | // Fuchsia benchmarks depend on this trace event's name. Please do not change |
25 | // it without checking that the changes are compatible with Fuchsia benchmarks |
26 | // first! |
27 | static constexpr const char* kVsyncTraceName = "vsync callback" ; |
28 | #else |
29 | static constexpr const char* kVsyncTraceName = "VsyncProcessCallback" ; |
30 | #endif |
31 | |
32 | VsyncWaiter::VsyncWaiter(TaskRunners task_runners) |
33 | : task_runners_(std::move(task_runners)) {} |
34 | |
35 | VsyncWaiter::~VsyncWaiter() = default; |
36 | |
37 | // Public method invoked by the animator. |
38 | void VsyncWaiter::AsyncWaitForVsync(const Callback& callback) { |
39 | if (!callback) { |
40 | return; |
41 | } |
42 | |
43 | TRACE_EVENT0("flutter" , "AsyncWaitForVsync" ); |
44 | |
45 | { |
46 | std::scoped_lock lock(callback_mutex_); |
47 | if (callback_) { |
48 | // The animator may request a frame more than once within a frame |
49 | // interval. Multiple calls to request frame must result in a single |
50 | // callback per frame interval. |
51 | TRACE_EVENT_INSTANT0("flutter" , "MultipleCallsToVsyncInFrameInterval" ); |
52 | return; |
53 | } |
54 | callback_ = std::move(callback); |
55 | if (secondary_callback_) { |
56 | // Return directly as `AwaitVSync` is already called by |
57 | // `ScheduleSecondaryCallback`. |
58 | return; |
59 | } |
60 | } |
61 | AwaitVSync(); |
62 | } |
63 | |
64 | void VsyncWaiter::ScheduleSecondaryCallback(const fml::closure& callback) { |
65 | FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); |
66 | |
67 | if (!callback) { |
68 | return; |
69 | } |
70 | |
71 | TRACE_EVENT0("flutter" , "ScheduleSecondaryCallback" ); |
72 | |
73 | { |
74 | std::scoped_lock lock(callback_mutex_); |
75 | if (secondary_callback_) { |
76 | // Multiple schedules must result in a single callback per frame interval. |
77 | TRACE_EVENT_INSTANT0("flutter" , |
78 | "MultipleCallsToSecondaryVsyncInFrameInterval" ); |
79 | return; |
80 | } |
81 | secondary_callback_ = std::move(callback); |
82 | if (callback_) { |
83 | // Return directly as `AwaitVSync` is already called by |
84 | // `AsyncWaitForVsync`. |
85 | return; |
86 | } |
87 | } |
88 | AwaitVSync(); |
89 | } |
90 | |
91 | void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time, |
92 | fml::TimePoint frame_target_time) { |
93 | Callback callback; |
94 | fml::closure secondary_callback; |
95 | |
96 | { |
97 | std::scoped_lock lock(callback_mutex_); |
98 | callback = std::move(callback_); |
99 | secondary_callback = std::move(secondary_callback_); |
100 | } |
101 | |
102 | if (!callback && !secondary_callback) { |
103 | // This means that the vsync waiter implementation fired a callback for a |
104 | // request we did not make. This is a paranoid check but we still want to |
105 | // make sure we catch misbehaving vsync implementations. |
106 | TRACE_EVENT_INSTANT0("flutter" , "MismatchedFrameCallback" ); |
107 | return; |
108 | } |
109 | |
110 | if (callback) { |
111 | auto flow_identifier = fml::tracing::TraceNonce(); |
112 | |
113 | // The base trace ensures that flows have a root to begin from if one does |
114 | // not exist. The trace viewer will ignore traces that have no base event |
115 | // trace. While all our message loops insert a base trace trace |
116 | // (MessageLoop::RunExpiredTasks), embedders may not. |
117 | TRACE_EVENT0("flutter" , "VsyncFireCallback" ); |
118 | |
119 | TRACE_FLOW_BEGIN("flutter" , kVsyncFlowName, flow_identifier); |
120 | |
121 | task_runners_.GetUITaskRunner()->PostTaskForTime( |
122 | [callback, flow_identifier, frame_start_time, frame_target_time]() { |
123 | FML_TRACE_EVENT("flutter" , kVsyncTraceName, "StartTime" , |
124 | frame_start_time, "TargetTime" , frame_target_time); |
125 | callback(frame_start_time, frame_target_time); |
126 | TRACE_FLOW_END("flutter" , kVsyncFlowName, flow_identifier); |
127 | }, |
128 | frame_start_time); |
129 | } |
130 | |
131 | if (secondary_callback) { |
132 | task_runners_.GetUITaskRunner()->PostTaskForTime( |
133 | std::move(secondary_callback), frame_start_time); |
134 | } |
135 | } |
136 | |
137 | float VsyncWaiter::GetDisplayRefreshRate() const { |
138 | return kUnknownRefreshRateFPS; |
139 | } |
140 | |
141 | } // namespace flutter |
142 | |