| Dominik Laskowski | 068173d | 2021-08-11 17:22:59 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright 2021 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 |  | 
| Ady Abraham | c621d8d | 2022-06-22 17:01:25 +0000 | [diff] [blame] | 17 | #define ATRACE_TAG ATRACE_TAG_GRAPHICS | 
|  | 18 |  | 
| Leon Scroggins III | c275df4 | 2023-02-07 16:40:21 -0500 | [diff] [blame] | 19 | #include <ftl/fake_guard.h> | 
| Dominik Laskowski | 068173d | 2021-08-11 17:22:59 -0700 | [diff] [blame] | 20 | #include <scheduler/Fps.h> | 
| Dominik Laskowski | 4e0d20d | 2021-12-06 11:31:02 -0800 | [diff] [blame] | 21 | #include <scheduler/Timer.h> | 
| Dominik Laskowski | 068173d | 2021-08-11 17:22:59 -0700 | [diff] [blame] | 22 |  | 
|  | 23 | #include "VsyncSchedule.h" | 
|  | 24 |  | 
| Leon Scroggins III | c275df4 | 2023-02-07 16:40:21 -0500 | [diff] [blame] | 25 | #include "ISchedulerCallback.h" | 
|  | 26 | #include "Utils/Dumper.h" | 
| Dominik Laskowski | 068173d | 2021-08-11 17:22:59 -0700 | [diff] [blame] | 27 | #include "VSyncDispatchTimerQueue.h" | 
|  | 28 | #include "VSyncPredictor.h" | 
|  | 29 | #include "VSyncReactor.h" | 
|  | 30 |  | 
|  | 31 | #include "../TracedOrdinal.h" | 
|  | 32 |  | 
|  | 33 | namespace android::scheduler { | 
|  | 34 |  | 
|  | 35 | class VsyncSchedule::PredictedVsyncTracer { | 
|  | 36 | // Invoked from the thread of the VsyncDispatch owned by this VsyncSchedule. | 
|  | 37 | constexpr auto makeVsyncCallback() { | 
|  | 38 | return [this](nsecs_t, nsecs_t, nsecs_t) { | 
|  | 39 | mParity = !mParity; | 
|  | 40 | schedule(); | 
|  | 41 | }; | 
|  | 42 | } | 
|  | 43 |  | 
|  | 44 | public: | 
| Leon Scroggins III | 6738862 | 2023-02-06 20:36:20 -0500 | [diff] [blame] | 45 | explicit PredictedVsyncTracer(std::shared_ptr<VsyncDispatch> dispatch) | 
|  | 46 | : mRegistration(std::move(dispatch), makeVsyncCallback(), __func__) { | 
| Dominik Laskowski | 068173d | 2021-08-11 17:22:59 -0700 | [diff] [blame] | 47 | schedule(); | 
|  | 48 | } | 
|  | 49 |  | 
|  | 50 | private: | 
|  | 51 | void schedule() { mRegistration.schedule({0, 0, 0}); } | 
|  | 52 |  | 
|  | 53 | TracedOrdinal<bool> mParity = {"VSYNC-predicted", 0}; | 
|  | 54 | VSyncCallbackRegistration mRegistration; | 
|  | 55 | }; | 
|  | 56 |  | 
| Leon Scroggins III | 6738862 | 2023-02-06 20:36:20 -0500 | [diff] [blame] | 57 | VsyncSchedule::VsyncSchedule(PhysicalDisplayId id, FeatureFlags features) | 
|  | 58 | : mId(id), | 
|  | 59 | mTracker(createTracker(id)), | 
|  | 60 | mDispatch(createDispatch(mTracker)), | 
|  | 61 | mController(createController(id, *mTracker, features)), | 
| Leon Scroggins III | c275df4 | 2023-02-07 16:40:21 -0500 | [diff] [blame] | 62 | mTracer(features.test(Feature::kTracePredictedVsync) | 
| Leon Scroggins III | 6738862 | 2023-02-06 20:36:20 -0500 | [diff] [blame] | 63 | ? std::make_unique<PredictedVsyncTracer>(mDispatch) | 
| Leon Scroggins III | c275df4 | 2023-02-07 16:40:21 -0500 | [diff] [blame] | 64 | : nullptr) {} | 
| Dominik Laskowski | 068173d | 2021-08-11 17:22:59 -0700 | [diff] [blame] | 65 |  | 
| Leon Scroggins III | 6738862 | 2023-02-06 20:36:20 -0500 | [diff] [blame] | 66 | VsyncSchedule::VsyncSchedule(PhysicalDisplayId id, TrackerPtr tracker, DispatchPtr dispatch, | 
|  | 67 | ControllerPtr controller) | 
|  | 68 | : mId(id), | 
|  | 69 | mTracker(std::move(tracker)), | 
| Dominik Laskowski | 068173d | 2021-08-11 17:22:59 -0700 | [diff] [blame] | 70 | mDispatch(std::move(dispatch)), | 
|  | 71 | mController(std::move(controller)) {} | 
|  | 72 |  | 
| Dominik Laskowski | 068173d | 2021-08-11 17:22:59 -0700 | [diff] [blame] | 73 | VsyncSchedule::~VsyncSchedule() = default; | 
|  | 74 |  | 
| Dominik Laskowski | 5d164f2 | 2022-07-07 07:56:07 -0700 | [diff] [blame] | 75 | Period VsyncSchedule::period() const { | 
|  | 76 | return Period::fromNs(mTracker->currentPeriod()); | 
|  | 77 | } | 
|  | 78 |  | 
|  | 79 | TimePoint VsyncSchedule::vsyncDeadlineAfter(TimePoint timePoint) const { | 
|  | 80 | return TimePoint::fromNs(mTracker->nextAnticipatedVSyncTimeFrom(timePoint.ns())); | 
|  | 81 | } | 
|  | 82 |  | 
| Dominik Laskowski | 068173d | 2021-08-11 17:22:59 -0700 | [diff] [blame] | 83 | void VsyncSchedule::dump(std::string& out) const { | 
| Leon Scroggins III | c275df4 | 2023-02-07 16:40:21 -0500 | [diff] [blame] | 84 | utils::Dumper dumper(out); | 
|  | 85 | { | 
|  | 86 | std::lock_guard<std::mutex> lock(mHwVsyncLock); | 
|  | 87 | dumper.dump("hwVsyncState", ftl::enum_string(mHwVsyncState)); | 
|  | 88 |  | 
|  | 89 | ftl::FakeGuard guard(kMainThreadContext); | 
|  | 90 | dumper.dump("pendingHwVsyncState", ftl::enum_string(mPendingHwVsyncState)); | 
|  | 91 | dumper.eol(); | 
|  | 92 | } | 
|  | 93 |  | 
| Dominik Laskowski | 068173d | 2021-08-11 17:22:59 -0700 | [diff] [blame] | 94 | out.append("VsyncController:\n"); | 
|  | 95 | mController->dump(out); | 
|  | 96 |  | 
|  | 97 | out.append("VsyncDispatch:\n"); | 
|  | 98 | mDispatch->dump(out); | 
|  | 99 | } | 
|  | 100 |  | 
| Leon Scroggins III | 6738862 | 2023-02-06 20:36:20 -0500 | [diff] [blame] | 101 | VsyncSchedule::TrackerPtr VsyncSchedule::createTracker(PhysicalDisplayId id) { | 
| Dominik Laskowski | 068173d | 2021-08-11 17:22:59 -0700 | [diff] [blame] | 102 | // TODO(b/144707443): Tune constants. | 
|  | 103 | constexpr nsecs_t kInitialPeriod = (60_Hz).getPeriodNsecs(); | 
|  | 104 | constexpr size_t kHistorySize = 20; | 
|  | 105 | constexpr size_t kMinSamplesForPrediction = 6; | 
|  | 106 | constexpr uint32_t kDiscardOutlierPercent = 20; | 
|  | 107 |  | 
| Leon Scroggins III | 6738862 | 2023-02-06 20:36:20 -0500 | [diff] [blame] | 108 | return std::make_unique<VSyncPredictor>(id, kInitialPeriod, kHistorySize, | 
|  | 109 | kMinSamplesForPrediction, kDiscardOutlierPercent); | 
| Dominik Laskowski | 068173d | 2021-08-11 17:22:59 -0700 | [diff] [blame] | 110 | } | 
|  | 111 |  | 
| Leon Scroggins III | 6738862 | 2023-02-06 20:36:20 -0500 | [diff] [blame] | 112 | VsyncSchedule::DispatchPtr VsyncSchedule::createDispatch(TrackerPtr tracker) { | 
| Dominik Laskowski | 068173d | 2021-08-11 17:22:59 -0700 | [diff] [blame] | 113 | using namespace std::chrono_literals; | 
|  | 114 |  | 
|  | 115 | // TODO(b/144707443): Tune constants. | 
|  | 116 | constexpr std::chrono::nanoseconds kGroupDispatchWithin = 500us; | 
|  | 117 | constexpr std::chrono::nanoseconds kSnapToSameVsyncWithin = 3ms; | 
|  | 118 |  | 
| Leon Scroggins III | 6738862 | 2023-02-06 20:36:20 -0500 | [diff] [blame] | 119 | return std::make_unique<VSyncDispatchTimerQueue>(std::make_unique<Timer>(), std::move(tracker), | 
| Dominik Laskowski | 068173d | 2021-08-11 17:22:59 -0700 | [diff] [blame] | 120 | kGroupDispatchWithin.count(), | 
|  | 121 | kSnapToSameVsyncWithin.count()); | 
|  | 122 | } | 
|  | 123 |  | 
| Leon Scroggins III | 6738862 | 2023-02-06 20:36:20 -0500 | [diff] [blame] | 124 | VsyncSchedule::ControllerPtr VsyncSchedule::createController(PhysicalDisplayId id, | 
|  | 125 | VsyncTracker& tracker, | 
| Dominik Laskowski | 068173d | 2021-08-11 17:22:59 -0700 | [diff] [blame] | 126 | FeatureFlags features) { | 
|  | 127 | // TODO(b/144707443): Tune constants. | 
|  | 128 | constexpr size_t kMaxPendingFences = 20; | 
|  | 129 | const bool hasKernelIdleTimer = features.test(Feature::kKernelIdleTimer); | 
|  | 130 |  | 
| Leon Scroggins III | 6738862 | 2023-02-06 20:36:20 -0500 | [diff] [blame] | 131 | auto reactor = std::make_unique<VSyncReactor>(id, std::make_unique<SystemClock>(), tracker, | 
| Leon Scroggins III | db16a2b | 2023-02-06 17:50:05 -0500 | [diff] [blame] | 132 | kMaxPendingFences, hasKernelIdleTimer); | 
| Dominik Laskowski | 068173d | 2021-08-11 17:22:59 -0700 | [diff] [blame] | 133 |  | 
|  | 134 | reactor->setIgnorePresentFences(!features.test(Feature::kPresentFences)); | 
|  | 135 | return reactor; | 
|  | 136 | } | 
|  | 137 |  | 
| Leon Scroggins III | 6738862 | 2023-02-06 20:36:20 -0500 | [diff] [blame] | 138 | void VsyncSchedule::startPeriodTransition(ISchedulerCallback& callback, Period period, bool force) { | 
| Leon Scroggins III | c275df4 | 2023-02-07 16:40:21 -0500 | [diff] [blame] | 139 | std::lock_guard<std::mutex> lock(mHwVsyncLock); | 
| Leon Scroggins III | 6738862 | 2023-02-06 20:36:20 -0500 | [diff] [blame] | 140 | mController->startPeriodTransition(period.ns(), force); | 
| Leon Scroggins III | c275df4 | 2023-02-07 16:40:21 -0500 | [diff] [blame] | 141 | enableHardwareVsyncLocked(callback); | 
|  | 142 | } | 
|  | 143 |  | 
|  | 144 | bool VsyncSchedule::addResyncSample(ISchedulerCallback& callback, TimePoint timestamp, | 
|  | 145 | ftl::Optional<Period> hwcVsyncPeriod) { | 
|  | 146 | bool needsHwVsync = false; | 
|  | 147 | bool periodFlushed = false; | 
|  | 148 | { | 
|  | 149 | std::lock_guard<std::mutex> lock(mHwVsyncLock); | 
|  | 150 | if (mHwVsyncState == HwVsyncState::Enabled) { | 
|  | 151 | needsHwVsync = mController->addHwVsyncTimestamp(timestamp.ns(), | 
|  | 152 | hwcVsyncPeriod.transform(&Period::ns), | 
|  | 153 | &periodFlushed); | 
|  | 154 | } | 
|  | 155 | } | 
|  | 156 | if (needsHwVsync) { | 
|  | 157 | enableHardwareVsync(callback); | 
|  | 158 | } else { | 
|  | 159 | disableHardwareVsync(callback, false /* disallow */); | 
|  | 160 | } | 
|  | 161 | return periodFlushed; | 
|  | 162 | } | 
|  | 163 |  | 
|  | 164 | void VsyncSchedule::enableHardwareVsync(ISchedulerCallback& callback) { | 
|  | 165 | std::lock_guard<std::mutex> lock(mHwVsyncLock); | 
|  | 166 | enableHardwareVsyncLocked(callback); | 
|  | 167 | } | 
|  | 168 |  | 
|  | 169 | void VsyncSchedule::enableHardwareVsyncLocked(ISchedulerCallback& callback) { | 
|  | 170 | if (mHwVsyncState == HwVsyncState::Disabled) { | 
|  | 171 | getTracker().resetModel(); | 
| Leon Scroggins III | 6738862 | 2023-02-06 20:36:20 -0500 | [diff] [blame] | 172 | callback.setVsyncEnabled(mId, true); | 
| Leon Scroggins III | c275df4 | 2023-02-07 16:40:21 -0500 | [diff] [blame] | 173 | mHwVsyncState = HwVsyncState::Enabled; | 
|  | 174 | } | 
|  | 175 | } | 
|  | 176 |  | 
|  | 177 | void VsyncSchedule::disableHardwareVsync(ISchedulerCallback& callback, bool disallow) { | 
|  | 178 | std::lock_guard<std::mutex> lock(mHwVsyncLock); | 
| Leon Scroggins III | aadc62d | 2023-03-03 11:07:50 -0500 | [diff] [blame] | 179 | switch (mHwVsyncState) { | 
|  | 180 | case HwVsyncState::Enabled: | 
|  | 181 | callback.setVsyncEnabled(mId, false); | 
|  | 182 | [[fallthrough]]; | 
|  | 183 | case HwVsyncState::Disabled: | 
|  | 184 | mHwVsyncState = disallow ? HwVsyncState::Disallowed : HwVsyncState::Disabled; | 
|  | 185 | break; | 
|  | 186 | case HwVsyncState::Disallowed: | 
|  | 187 | break; | 
| Leon Scroggins III | c275df4 | 2023-02-07 16:40:21 -0500 | [diff] [blame] | 188 | } | 
| Leon Scroggins III | c275df4 | 2023-02-07 16:40:21 -0500 | [diff] [blame] | 189 | } | 
|  | 190 |  | 
|  | 191 | bool VsyncSchedule::isHardwareVsyncAllowed(bool makeAllowed) { | 
|  | 192 | std::lock_guard<std::mutex> lock(mHwVsyncLock); | 
|  | 193 | if (makeAllowed && mHwVsyncState == HwVsyncState::Disallowed) { | 
|  | 194 | mHwVsyncState = HwVsyncState::Disabled; | 
|  | 195 | } | 
|  | 196 | return mHwVsyncState != HwVsyncState::Disallowed; | 
|  | 197 | } | 
|  | 198 |  | 
|  | 199 | void VsyncSchedule::setPendingHardwareVsyncState(bool enabled) { | 
|  | 200 | mPendingHwVsyncState = enabled ? HwVsyncState::Enabled : HwVsyncState::Disabled; | 
|  | 201 | } | 
|  | 202 |  | 
|  | 203 | bool VsyncSchedule::getPendingHardwareVsyncState() const { | 
|  | 204 | return mPendingHwVsyncState == HwVsyncState::Enabled; | 
|  | 205 | } | 
|  | 206 |  | 
| Dominik Laskowski | 068173d | 2021-08-11 17:22:59 -0700 | [diff] [blame] | 207 | } // namespace android::scheduler |