1 /*
2 * Copyright 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
18
19 #include "DispSyncSource.h"
20
21 #include <android-base/stringprintf.h>
22 #include <utils/Trace.h>
23 #include <mutex>
24
25 #include "EventThread.h"
26 #include "VSyncTracker.h"
27 #include "VsyncController.h"
28
29 namespace android::scheduler {
30 using base::StringAppendF;
31 using namespace std::chrono_literals;
32
33 class CallbackRepeater {
34 public:
CallbackRepeater(VSyncDispatch & dispatch,VSyncDispatch::Callback cb,const char * name,std::chrono::nanoseconds workDuration,std::chrono::nanoseconds readyDuration,std::chrono::nanoseconds notBefore)35 CallbackRepeater(VSyncDispatch& dispatch, VSyncDispatch::Callback cb, const char* name,
36 std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration,
37 std::chrono::nanoseconds notBefore)
38 : mName(name),
39 mCallback(cb),
40 mRegistration(dispatch,
41 std::bind(&CallbackRepeater::callback, this, std::placeholders::_1,
42 std::placeholders::_2, std::placeholders::_3),
43 mName),
44 mStarted(false),
45 mWorkDuration(workDuration),
46 mReadyDuration(readyDuration),
47 mLastCallTime(notBefore) {}
48
~CallbackRepeater()49 ~CallbackRepeater() {
50 std::lock_guard lock(mMutex);
51 mRegistration.cancel();
52 }
53
start(std::chrono::nanoseconds workDuration,std::chrono::nanoseconds readyDuration)54 void start(std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration) {
55 std::lock_guard lock(mMutex);
56 mStarted = true;
57 mWorkDuration = workDuration;
58 mReadyDuration = readyDuration;
59
60 auto const scheduleResult =
61 mRegistration.schedule({.workDuration = mWorkDuration.count(),
62 .readyDuration = mReadyDuration.count(),
63 .earliestVsync = mLastCallTime.count()});
64 LOG_ALWAYS_FATAL_IF((!scheduleResult.has_value()), "Error scheduling callback");
65 }
66
stop()67 void stop() {
68 std::lock_guard lock(mMutex);
69 LOG_ALWAYS_FATAL_IF(!mStarted, "DispSyncInterface misuse: callback already stopped");
70 mStarted = false;
71 mRegistration.cancel();
72 }
73
dump(std::string & result) const74 void dump(std::string& result) const {
75 std::lock_guard lock(mMutex);
76 const auto relativeLastCallTime =
77 mLastCallTime - std::chrono::steady_clock::now().time_since_epoch();
78 StringAppendF(&result, "\t%s: ", mName.c_str());
79 StringAppendF(&result, "mWorkDuration=%.2f mReadyDuration=%.2f last vsync time ",
80 mWorkDuration.count() / 1e6f, mReadyDuration.count() / 1e6f);
81 StringAppendF(&result, "%.2fms relative to now (%s)\n", relativeLastCallTime.count() / 1e6f,
82 mStarted ? "running" : "stopped");
83 }
84
85 private:
callback(nsecs_t vsyncTime,nsecs_t wakeupTime,nsecs_t readyTime)86 void callback(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) {
87 {
88 std::lock_guard lock(mMutex);
89 mLastCallTime = std::chrono::nanoseconds(vsyncTime);
90 }
91
92 mCallback(vsyncTime, wakeupTime, readyTime);
93
94 {
95 std::lock_guard lock(mMutex);
96 if (!mStarted) {
97 return;
98 }
99 auto const scheduleResult =
100 mRegistration.schedule({.workDuration = mWorkDuration.count(),
101 .readyDuration = mReadyDuration.count(),
102 .earliestVsync = vsyncTime});
103 LOG_ALWAYS_FATAL_IF(!scheduleResult.has_value(), "Error rescheduling callback");
104 }
105 }
106
107 const std::string mName;
108 scheduler::VSyncDispatch::Callback mCallback;
109
110 mutable std::mutex mMutex;
111 VSyncCallbackRegistration mRegistration GUARDED_BY(mMutex);
112 bool mStarted GUARDED_BY(mMutex) = false;
113 std::chrono::nanoseconds mWorkDuration GUARDED_BY(mMutex) = 0ns;
114 std::chrono::nanoseconds mReadyDuration GUARDED_BY(mMutex) = 0ns;
115 std::chrono::nanoseconds mLastCallTime GUARDED_BY(mMutex) = 0ns;
116 };
117
DispSyncSource(VSyncDispatch & vSyncDispatch,VSyncTracker & vSyncTracker,std::chrono::nanoseconds workDuration,std::chrono::nanoseconds readyDuration,bool traceVsync,const char * name)118 DispSyncSource::DispSyncSource(VSyncDispatch& vSyncDispatch, VSyncTracker& vSyncTracker,
119 std::chrono::nanoseconds workDuration,
120 std::chrono::nanoseconds readyDuration, bool traceVsync,
121 const char* name)
122 : mName(name),
123 mValue(base::StringPrintf("VSYNC-%s", name), 0),
124 mTraceVsync(traceVsync),
125 mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)),
126 mVSyncTracker(vSyncTracker),
127 mWorkDuration(base::StringPrintf("VsyncWorkDuration-%s", name), workDuration),
128 mReadyDuration(readyDuration) {
129 mCallbackRepeater =
130 std::make_unique<CallbackRepeater>(vSyncDispatch,
131 std::bind(&DispSyncSource::onVsyncCallback, this,
132 std::placeholders::_1,
133 std::placeholders::_2,
134 std::placeholders::_3),
135 name, workDuration, readyDuration,
136 std::chrono::steady_clock::now().time_since_epoch());
137 }
138
139 DispSyncSource::~DispSyncSource() = default;
140
setVSyncEnabled(bool enable)141 void DispSyncSource::setVSyncEnabled(bool enable) {
142 std::lock_guard lock(mVsyncMutex);
143 if (enable) {
144 mCallbackRepeater->start(mWorkDuration, mReadyDuration);
145 // ATRACE_INT(mVsyncOnLabel.c_str(), 1);
146 } else {
147 mCallbackRepeater->stop();
148 // ATRACE_INT(mVsyncOnLabel.c_str(), 0);
149 }
150 mEnabled = enable;
151 }
152
setCallback(VSyncSource::Callback * callback)153 void DispSyncSource::setCallback(VSyncSource::Callback* callback) {
154 std::lock_guard lock(mCallbackMutex);
155 mCallback = callback;
156 }
157
setDuration(std::chrono::nanoseconds workDuration,std::chrono::nanoseconds readyDuration)158 void DispSyncSource::setDuration(std::chrono::nanoseconds workDuration,
159 std::chrono::nanoseconds readyDuration) {
160 std::lock_guard lock(mVsyncMutex);
161 mWorkDuration = workDuration;
162 mReadyDuration = readyDuration;
163
164 // If we're not enabled, we don't need to mess with the listeners
165 if (!mEnabled) {
166 return;
167 }
168
169 mCallbackRepeater->start(mWorkDuration, mReadyDuration);
170 }
171
onVsyncCallback(nsecs_t vsyncTime,nsecs_t targetWakeupTime,nsecs_t readyTime)172 void DispSyncSource::onVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime,
173 nsecs_t readyTime) {
174 VSyncSource::Callback* callback;
175 {
176 std::lock_guard lock(mCallbackMutex);
177 callback = mCallback;
178 }
179
180 if (mTraceVsync) {
181 mValue = (mValue + 1) % 2;
182 }
183
184 if (callback != nullptr) {
185 callback->onVSyncEvent(targetWakeupTime, {vsyncTime, readyTime});
186 }
187 }
188
getLatestVSyncData() const189 VSyncSource::VSyncData DispSyncSource::getLatestVSyncData() const {
190 std::lock_guard lock(mVsyncMutex);
191 nsecs_t expectedPresentationTime = mVSyncTracker.nextAnticipatedVSyncTimeFrom(
192 systemTime() + mWorkDuration.get().count() + mReadyDuration.count());
193 nsecs_t deadline = expectedPresentationTime - mReadyDuration.count();
194 return {expectedPresentationTime, deadline};
195 }
196
dump(std::string & result) const197 void DispSyncSource::dump(std::string& result) const {
198 std::lock_guard lock(mVsyncMutex);
199 StringAppendF(&result, "DispSyncSource: %s(%s)\n", mName, mEnabled ? "enabled" : "disabled");
200 }
201
202 } // namespace android::scheduler
203