• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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