Ana Krulec | 241cf83 | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 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 | |
Midas Chien | bc5f22f | 2018-08-16 15:51:19 +0800 | [diff] [blame] | 17 | #define ATRACE_TAG ATRACE_TAG_GRAPHICS |
| 18 | |
Ana Krulec | 241cf83 | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 19 | #include "DispSyncSource.h" |
| 20 | |
Ana Krulec | 072233f | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 21 | #include <android-base/stringprintf.h> |
Ana Krulec | 241cf83 | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 22 | #include <utils/Trace.h> |
Ana Krulec | 072233f | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 23 | #include <mutex> |
Ana Krulec | 241cf83 | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 24 | |
Ana Krulec | 241cf83 | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 25 | #include "EventThread.h" |
Ady Abraham | 8cb2188 | 2020-08-26 18:22:05 -0700 | [diff] [blame] | 26 | #include "VsyncController.h" |
Ana Krulec | 241cf83 | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 27 | |
Ady Abraham | 9c53ee7 | 2020-07-22 21:16:18 -0700 | [diff] [blame] | 28 | namespace android::scheduler { |
Ady Abraham | 5e7371c | 2020-03-24 14:47:24 -0700 | [diff] [blame] | 29 | using base::StringAppendF; |
Ady Abraham | 9c53ee7 | 2020-07-22 21:16:18 -0700 | [diff] [blame] | 30 | using namespace std::chrono_literals; |
Ana Krulec | 241cf83 | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 31 | |
Ady Abraham | 9c53ee7 | 2020-07-22 21:16:18 -0700 | [diff] [blame] | 32 | class CallbackRepeater { |
| 33 | public: |
| 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 | |
| 48 | ~CallbackRepeater() { |
| 49 | std::lock_guard lock(mMutex); |
| 50 | mRegistration.cancel(); |
| 51 | } |
| 52 | |
| 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()}); |
Ady Abraham | b5d3afa | 2021-05-07 11:22:23 -0700 | [diff] [blame] | 63 | LOG_ALWAYS_FATAL_IF((!scheduleResult.has_value()), "Error scheduling callback"); |
Ady Abraham | 9c53ee7 | 2020-07-22 21:16:18 -0700 | [diff] [blame] | 64 | } |
| 65 | |
| 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 | |
| 73 | 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: |
| 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}); |
Ady Abraham | b5d3afa | 2021-05-07 11:22:23 -0700 | [diff] [blame] | 102 | LOG_ALWAYS_FATAL_IF(!scheduleResult.has_value(), "Error rescheduling callback"); |
Ady Abraham | 9c53ee7 | 2020-07-22 21:16:18 -0700 | [diff] [blame] | 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 | |
| 117 | DispSyncSource::DispSyncSource(scheduler::VSyncDispatch& vSyncDispatch, |
| 118 | std::chrono::nanoseconds workDuration, |
| 119 | std::chrono::nanoseconds readyDuration, bool traceVsync, |
Ana Krulec | 241cf83 | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 120 | const char* name) |
| 121 | : mName(name), |
Ady Abraham | 50204dd | 2019-07-19 15:47:11 -0700 | [diff] [blame] | 122 | mValue(base::StringPrintf("VSYNC-%s", name), 0), |
Ana Krulec | 241cf83 | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 123 | mTraceVsync(traceVsync), |
Ana Krulec | 072233f | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 124 | mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)), |
Ady Abraham | 9c53ee7 | 2020-07-22 21:16:18 -0700 | [diff] [blame] | 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; |
Ana Krulec | 241cf83 | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 138 | |
| 139 | void DispSyncSource::setVSyncEnabled(bool enable) { |
Ana Krulec | 072233f | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 140 | std::lock_guard lock(mVsyncMutex); |
Ana Krulec | 241cf83 | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 141 | if (enable) { |
Ady Abraham | 9c53ee7 | 2020-07-22 21:16:18 -0700 | [diff] [blame] | 142 | mCallbackRepeater->start(mWorkDuration, mReadyDuration); |
Ana Krulec | 072233f | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 143 | // ATRACE_INT(mVsyncOnLabel.c_str(), 1); |
Ana Krulec | 241cf83 | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 144 | } else { |
Ady Abraham | 9c53ee7 | 2020-07-22 21:16:18 -0700 | [diff] [blame] | 145 | mCallbackRepeater->stop(); |
Ana Krulec | 072233f | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 146 | // ATRACE_INT(mVsyncOnLabel.c_str(), 0); |
Ana Krulec | 241cf83 | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 147 | } |
| 148 | mEnabled = enable; |
| 149 | } |
| 150 | |
| 151 | void DispSyncSource::setCallback(VSyncSource::Callback* callback) { |
Ana Krulec | 072233f | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 152 | std::lock_guard lock(mCallbackMutex); |
Ana Krulec | 241cf83 | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 153 | mCallback = callback; |
| 154 | } |
| 155 | |
Ady Abraham | 9c53ee7 | 2020-07-22 21:16:18 -0700 | [diff] [blame] | 156 | void DispSyncSource::setDuration(std::chrono::nanoseconds workDuration, |
| 157 | std::chrono::nanoseconds readyDuration) { |
Ana Krulec | 072233f | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 158 | std::lock_guard lock(mVsyncMutex); |
Ady Abraham | 9c53ee7 | 2020-07-22 21:16:18 -0700 | [diff] [blame] | 159 | mWorkDuration = workDuration; |
| 160 | mReadyDuration = readyDuration; |
Ana Krulec | 241cf83 | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 161 | |
| 162 | // If we're not enabled, we don't need to mess with the listeners |
| 163 | if (!mEnabled) { |
| 164 | return; |
| 165 | } |
| 166 | |
Ady Abraham | 9c53ee7 | 2020-07-22 21:16:18 -0700 | [diff] [blame] | 167 | mCallbackRepeater->start(mWorkDuration, mReadyDuration); |
Ana Krulec | 241cf83 | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 168 | } |
| 169 | |
Ady Abraham | 9c53ee7 | 2020-07-22 21:16:18 -0700 | [diff] [blame] | 170 | void DispSyncSource::onVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, |
| 171 | nsecs_t readyTime) { |
Ana Krulec | 241cf83 | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 172 | VSyncSource::Callback* callback; |
| 173 | { |
Ana Krulec | 072233f | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 174 | std::lock_guard lock(mCallbackMutex); |
Ana Krulec | 241cf83 | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 175 | callback = mCallback; |
Alec Mouri | d7599d8 | 2019-05-22 19:58:00 -0700 | [diff] [blame] | 176 | } |
Ana Krulec | 241cf83 | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 177 | |
Alec Mouri | d7599d8 | 2019-05-22 19:58:00 -0700 | [diff] [blame] | 178 | if (mTraceVsync) { |
| 179 | mValue = (mValue + 1) % 2; |
Ana Krulec | 241cf83 | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 180 | } |
| 181 | |
| 182 | if (callback != nullptr) { |
Ady Abraham | 9c53ee7 | 2020-07-22 21:16:18 -0700 | [diff] [blame] | 183 | callback->onVSyncEvent(targetWakeupTime, vsyncTime, readyTime); |
Ana Krulec | 241cf83 | 2018-08-10 15:03:23 -0700 | [diff] [blame] | 184 | } |
| 185 | } |
| 186 | |
Ady Abraham | 5e7371c | 2020-03-24 14:47:24 -0700 | [diff] [blame] | 187 | void DispSyncSource::dump(std::string& result) const { |
| 188 | std::lock_guard lock(mVsyncMutex); |
| 189 | StringAppendF(&result, "DispSyncSource: %s(%s)\n", mName, mEnabled ? "enabled" : "disabled"); |
Ady Abraham | 5e7371c | 2020-03-24 14:47:24 -0700 | [diff] [blame] | 190 | } |
| 191 | |
Ady Abraham | 9c53ee7 | 2020-07-22 21:16:18 -0700 | [diff] [blame] | 192 | } // namespace android::scheduler |