• 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 "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