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 "VsyncController.h"
27
28 namespace android::scheduler {
29 using base::StringAppendF;
30 using namespace std::chrono_literals;
31
32 class CallbackRepeater {
33 public:
CallbackRepeater(VSyncDispatch & dispatch,VSyncDispatch::Callback cb,const char * name,std::chrono::nanoseconds workDuration,std::chrono::nanoseconds readyDuration,std::chrono::nanoseconds notBefore)34 CallbackRepeater(VSyncDispatch& dispatch, VSyncDispatch::Callback cb, const char* name,
35 std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration,
36 std::chrono::nanoseconds notBefore)
37 : mName(name),
38 mCallback(cb),
39 mRegistration(dispatch,
40 std::bind(&CallbackRepeater::callback, this, std::placeholders::_1,
41 std::placeholders::_2, std::placeholders::_3),
42 mName),
43 mStarted(false),
44 mWorkDuration(workDuration),
45 mReadyDuration(readyDuration),
46 mLastCallTime(notBefore) {}
47
~CallbackRepeater()48 ~CallbackRepeater() {
49 std::lock_guard lock(mMutex);
50 mRegistration.cancel();
51 }
52
start(std::chrono::nanoseconds workDuration,std::chrono::nanoseconds readyDuration)53 void start(std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration) {
54 std::lock_guard lock(mMutex);
55 mStarted = true;
56 mWorkDuration = workDuration;
57 mReadyDuration = readyDuration;
58
59 auto const scheduleResult =
60 mRegistration.schedule({.workDuration = mWorkDuration.count(),
61 .readyDuration = mReadyDuration.count(),
62 .earliestVsync = mLastCallTime.count()});
63 LOG_ALWAYS_FATAL_IF((!scheduleResult.has_value()), "Error scheduling callback");
64 }
65
stop()66 void stop() {
67 std::lock_guard lock(mMutex);
68 LOG_ALWAYS_FATAL_IF(!mStarted, "DispSyncInterface misuse: callback already stopped");
69 mStarted = false;
70 mRegistration.cancel();
71 }
72
dump(std::string & result) const73 void dump(std::string& result) const {
74 std::lock_guard lock(mMutex);
75 const auto relativeLastCallTime =
76 mLastCallTime - std::chrono::steady_clock::now().time_since_epoch();
77 StringAppendF(&result, "\t%s: ", mName.c_str());
78 StringAppendF(&result, "mWorkDuration=%.2f mReadyDuration=%.2f last vsync time ",
79 mWorkDuration.count() / 1e6f, mReadyDuration.count() / 1e6f);
80 StringAppendF(&result, "%.2fms relative to now (%s)\n", relativeLastCallTime.count() / 1e6f,
81 mStarted ? "running" : "stopped");
82 }
83
84 private:
callback(nsecs_t vsyncTime,nsecs_t wakeupTime,nsecs_t readyTime)85 void callback(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) {
86 {
87 std::lock_guard lock(mMutex);
88 mLastCallTime = std::chrono::nanoseconds(vsyncTime);
89 }
90
91 mCallback(vsyncTime, wakeupTime, readyTime);
92
93 {
94 std::lock_guard lock(mMutex);
95 if (!mStarted) {
96 return;
97 }
98 auto const scheduleResult =
99 mRegistration.schedule({.workDuration = mWorkDuration.count(),
100 .readyDuration = mReadyDuration.count(),
101 .earliestVsync = vsyncTime});
102 LOG_ALWAYS_FATAL_IF(!scheduleResult.has_value(), "Error rescheduling callback");
103 }
104 }
105
106 const std::string mName;
107 scheduler::VSyncDispatch::Callback mCallback;
108
109 mutable std::mutex mMutex;
110 VSyncCallbackRegistration mRegistration GUARDED_BY(mMutex);
111 bool mStarted GUARDED_BY(mMutex) = false;
112 std::chrono::nanoseconds mWorkDuration GUARDED_BY(mMutex) = 0ns;
113 std::chrono::nanoseconds mReadyDuration GUARDED_BY(mMutex) = 0ns;
114 std::chrono::nanoseconds mLastCallTime GUARDED_BY(mMutex) = 0ns;
115 };
116
DispSyncSource(scheduler::VSyncDispatch & vSyncDispatch,std::chrono::nanoseconds workDuration,std::chrono::nanoseconds readyDuration,bool traceVsync,const char * name)117 DispSyncSource::DispSyncSource(scheduler::VSyncDispatch& vSyncDispatch,
118 std::chrono::nanoseconds workDuration,
119 std::chrono::nanoseconds readyDuration, bool traceVsync,
120 const char* name)
121 : mName(name),
122 mValue(base::StringPrintf("VSYNC-%s", name), 0),
123 mTraceVsync(traceVsync),
124 mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)),
125 mWorkDuration(base::StringPrintf("VsyncWorkDuration-%s", name), workDuration),
126 mReadyDuration(readyDuration) {
127 mCallbackRepeater =
128 std::make_unique<CallbackRepeater>(vSyncDispatch,
129 std::bind(&DispSyncSource::onVsyncCallback, this,
130 std::placeholders::_1,
131 std::placeholders::_2,
132 std::placeholders::_3),
133 name, workDuration, readyDuration,
134 std::chrono::steady_clock::now().time_since_epoch());
135 }
136
137 DispSyncSource::~DispSyncSource() = default;
138
setVSyncEnabled(bool enable)139 void DispSyncSource::setVSyncEnabled(bool enable) {
140 std::lock_guard lock(mVsyncMutex);
141 if (enable) {
142 mCallbackRepeater->start(mWorkDuration, mReadyDuration);
143 // ATRACE_INT(mVsyncOnLabel.c_str(), 1);
144 } else {
145 mCallbackRepeater->stop();
146 // ATRACE_INT(mVsyncOnLabel.c_str(), 0);
147 }
148 mEnabled = enable;
149 }
150
setCallback(VSyncSource::Callback * callback)151 void DispSyncSource::setCallback(VSyncSource::Callback* callback) {
152 std::lock_guard lock(mCallbackMutex);
153 mCallback = callback;
154 }
155
setDuration(std::chrono::nanoseconds workDuration,std::chrono::nanoseconds readyDuration)156 void DispSyncSource::setDuration(std::chrono::nanoseconds workDuration,
157 std::chrono::nanoseconds readyDuration) {
158 std::lock_guard lock(mVsyncMutex);
159 mWorkDuration = workDuration;
160 mReadyDuration = readyDuration;
161
162 // If we're not enabled, we don't need to mess with the listeners
163 if (!mEnabled) {
164 return;
165 }
166
167 mCallbackRepeater->start(mWorkDuration, mReadyDuration);
168 }
169
onVsyncCallback(nsecs_t vsyncTime,nsecs_t targetWakeupTime,nsecs_t readyTime)170 void DispSyncSource::onVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime,
171 nsecs_t readyTime) {
172 VSyncSource::Callback* callback;
173 {
174 std::lock_guard lock(mCallbackMutex);
175 callback = mCallback;
176 }
177
178 if (mTraceVsync) {
179 mValue = (mValue + 1) % 2;
180 }
181
182 if (callback != nullptr) {
183 callback->onVSyncEvent(targetWakeupTime, vsyncTime, readyTime);
184 }
185 }
186
dump(std::string & result) const187 void DispSyncSource::dump(std::string& result) const {
188 std::lock_guard lock(mVsyncMutex);
189 StringAppendF(&result, "DispSyncSource: %s(%s)\n", mName, mEnabled ? "enabled" : "disabled");
190 }
191
192 } // namespace android::scheduler
193