Loading services/surfaceflinger/Scheduler/ISchedulerCallback.h 0 → 100644 +35 −0 Original line number Diff line number Diff line /* * Copyright 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <vector> #include "Display/DisplayModeRequest.h" namespace android::scheduler { struct ISchedulerCallback { virtual void setVsyncEnabled(bool) = 0; virtual void requestDisplayModes(std::vector<display::DisplayModeRequest>) = 0; virtual void kernelTimerChanged(bool expired) = 0; virtual void triggerOnFrameRateOverridesChanged() = 0; protected: ~ISchedulerCallback() = default; }; } // namespace android::scheduler services/surfaceflinger/Scheduler/Scheduler.cpp +13 −67 Original line number Diff line number Diff line Loading @@ -155,7 +155,7 @@ void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId, } void Scheduler::createVsyncSchedule(FeatureFlags features) { mVsyncSchedule.emplace(features); mVsyncSchedule = std::make_unique<VsyncSchedule>(features); } std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const { Loading Loading @@ -394,38 +394,17 @@ void Scheduler::setVsyncConfig(const VsyncConfig& config, Period vsyncPeriod) { } void Scheduler::enableHardwareVsync() { std::lock_guard<std::mutex> lock(mHWVsyncLock); if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) { mVsyncSchedule->getTracker().resetModel(); mSchedulerCallback.setVsyncEnabled(true); mPrimaryHWVsyncEnabled = true; } mVsyncSchedule->enableHardwareVsync(mSchedulerCallback); } void Scheduler::disableHardwareVsync(bool makeUnavailable) { std::lock_guard<std::mutex> lock(mHWVsyncLock); if (mPrimaryHWVsyncEnabled) { mSchedulerCallback.setVsyncEnabled(false); mPrimaryHWVsyncEnabled = false; } if (makeUnavailable) { mHWVsyncAvailable = false; } void Scheduler::disableHardwareVsync(bool disallow) { mVsyncSchedule->disableHardwareVsync(mSchedulerCallback, disallow); } void Scheduler::resyncToHardwareVsync(bool makeAvailable, Fps refreshRate) { { std::lock_guard<std::mutex> lock(mHWVsyncLock); if (makeAvailable) { mHWVsyncAvailable = makeAvailable; } else if (!mHWVsyncAvailable) { // Hardware vsync is not currently available, so abort the resync // attempt for now return; } void Scheduler::resyncToHardwareVsync(bool allowToEnable, Fps refreshRate) { if (mVsyncSchedule->isHardwareVsyncAllowed(allowToEnable) && refreshRate.isValid()) { mVsyncSchedule->startPeriodTransition(mSchedulerCallback, refreshRate.getPeriod()); } setVsyncPeriod(refreshRate.getPeriodNsecs()); } void Scheduler::setRenderRate(Fps renderFrameRate) { Loading Loading @@ -458,37 +437,12 @@ void Scheduler::resync() { } } void Scheduler::setVsyncPeriod(nsecs_t period) { if (period <= 0) return; std::lock_guard<std::mutex> lock(mHWVsyncLock); mVsyncSchedule->getController().startPeriodTransition(period); if (!mPrimaryHWVsyncEnabled) { mVsyncSchedule->getTracker().resetModel(); mSchedulerCallback.setVsyncEnabled(true); mPrimaryHWVsyncEnabled = true; } } void Scheduler::addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod, bool* periodFlushed) { bool needsHwVsync = false; *periodFlushed = false; { // Scope for the lock std::lock_guard<std::mutex> lock(mHWVsyncLock); if (mPrimaryHWVsyncEnabled) { needsHwVsync = mVsyncSchedule->getController().addHwVsyncTimestamp(timestamp, hwcVsyncPeriod, periodFlushed); } } if (needsHwVsync) { enableHardwareVsync(); } else { disableHardwareVsync(false); } bool Scheduler::addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriodIn) { const auto hwcVsyncPeriod = ftl::Optional(hwcVsyncPeriodIn).transform([](nsecs_t nanos) { return Period::fromNs(nanos); }); return mVsyncSchedule->addResyncSample(mSchedulerCallback, TimePoint::fromNs(timestamp), hwcVsyncPeriod); } void Scheduler::addPresentFence(std::shared_ptr<FenceTime> fence) { Loading Loading @@ -636,14 +590,6 @@ void Scheduler::dump(utils::Dumper& dumper) const { mFrameRateOverrideMappings.dump(dumper); dumper.eol(); { utils::Dumper::Section section(dumper, "Hardware VSYNC"sv); std::lock_guard lock(mHWVsyncLock); dumper.dump("hwVsyncAvailable"sv, mHWVsyncAvailable); dumper.dump("hwVsyncEnabled"sv, mPrimaryHWVsyncEnabled); } } void Scheduler::dumpVsync(std::string& out) const { Loading services/surfaceflinger/Scheduler/Scheduler.h +9 −23 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ #include "Display/DisplayModeRequest.h" #include "EventThread.h" #include "FrameRateOverrideMappings.h" #include "ISchedulerCallback.h" #include "LayerHistory.h" #include "MessageQueue.h" #include "OneShotTimer.h" Loading Loading @@ -92,16 +93,6 @@ namespace scheduler { using GlobalSignals = RefreshRateSelector::GlobalSignals; struct ISchedulerCallback { virtual void setVsyncEnabled(bool) = 0; virtual void requestDisplayModes(std::vector<display::DisplayModeRequest>) = 0; virtual void kernelTimerChanged(bool expired) = 0; virtual void triggerOnFrameRateOverridesChanged() = 0; protected: ~ISchedulerCallback() = default; }; class Scheduler : android::impl::MessageQueue { using Impl = android::impl::MessageQueue; Loading Loading @@ -192,20 +183,20 @@ public: void setRenderRate(Fps); void enableHardwareVsync(); void disableHardwareVsync(bool makeUnavailable); void disableHardwareVsync(bool disallow); // Resyncs the scheduler to hardware vsync. // If makeAvailable is true, then hardware vsync will be turned on. // If allowToEnable is true, then hardware vsync will be turned on. // Otherwise, if hardware vsync is not already enabled then this method will // no-op. void resyncToHardwareVsync(bool makeAvailable, Fps refreshRate); void resyncToHardwareVsync(bool allowToEnable, Fps refreshRate); void resync() EXCLUDES(mDisplayLock); void forceNextResync() { mLastResyncTime = 0; } // Passes a vsync sample to VsyncController. periodFlushed will be true if // VsyncController detected that the vsync period changed, and false otherwise. void addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod, bool* periodFlushed); // Passes a vsync sample to VsyncController. Returns true if // VsyncController detected that the vsync period changed and false // otherwise. bool addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod); void addPresentFence(std::shared_ptr<FenceTime>); // Layers are registered on creation, and unregistered when the weak reference expires. Loading Loading @@ -297,7 +288,6 @@ private: void touchTimerCallback(TimerState); void displayPowerTimerCallback(TimerState); void setVsyncPeriod(nsecs_t period); void setVsyncConfig(const VsyncConfig&, Period vsyncPeriod); // Chooses a leader among the registered displays, unless `leaderIdOpt` is specified. The new Loading Loading @@ -362,14 +352,10 @@ private: ConnectionHandle mAppConnectionHandle; ConnectionHandle mSfConnectionHandle; mutable std::mutex mHWVsyncLock; bool mPrimaryHWVsyncEnabled GUARDED_BY(mHWVsyncLock) = false; bool mHWVsyncAvailable GUARDED_BY(mHWVsyncLock) = false; std::atomic<nsecs_t> mLastResyncTime = 0; const FeatureFlags mFeatures; std::optional<VsyncSchedule> mVsyncSchedule; std::unique_ptr<VsyncSchedule> mVsyncSchedule; // Shifts the VSYNC phase during certain transactions and refresh rate changes. const sp<VsyncModulator> mVsyncModulator; Loading services/surfaceflinger/Scheduler/VsyncSchedule.cpp +80 −6 Original line number Diff line number Diff line Loading @@ -16,11 +16,14 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include <ftl/fake_guard.h> #include <scheduler/Fps.h> #include <scheduler/Timer.h> #include "VsyncSchedule.h" #include "ISchedulerCallback.h" #include "Utils/Dumper.h" #include "VSyncDispatchTimerQueue.h" #include "VSyncPredictor.h" #include "VSyncReactor.h" Loading Loading @@ -54,18 +57,16 @@ private: VsyncSchedule::VsyncSchedule(FeatureFlags features) : mTracker(createTracker()), mDispatch(createDispatch(*mTracker)), mController(createController(*mTracker, features)) { if (features.test(Feature::kTracePredictedVsync)) { mTracer = std::make_unique<PredictedVsyncTracer>(*mDispatch); } } mController(createController(*mTracker, features)), mTracer(features.test(Feature::kTracePredictedVsync) ? std::make_unique<PredictedVsyncTracer>(*mDispatch) : nullptr) {} VsyncSchedule::VsyncSchedule(TrackerPtr tracker, DispatchPtr dispatch, ControllerPtr controller) : mTracker(std::move(tracker)), mDispatch(std::move(dispatch)), mController(std::move(controller)) {} VsyncSchedule::VsyncSchedule(VsyncSchedule&&) = default; VsyncSchedule::~VsyncSchedule() = default; Period VsyncSchedule::period() const { Loading @@ -77,6 +78,16 @@ TimePoint VsyncSchedule::vsyncDeadlineAfter(TimePoint timePoint) const { } void VsyncSchedule::dump(std::string& out) const { utils::Dumper dumper(out); { std::lock_guard<std::mutex> lock(mHwVsyncLock); dumper.dump("hwVsyncState", ftl::enum_string(mHwVsyncState)); ftl::FakeGuard guard(kMainThreadContext); dumper.dump("pendingHwVsyncState", ftl::enum_string(mPendingHwVsyncState)); dumper.eol(); } out.append("VsyncController:\n"); mController->dump(out); Loading Loading @@ -120,4 +131,67 @@ VsyncSchedule::ControllerPtr VsyncSchedule::createController(VsyncTracker& track return reactor; } void VsyncSchedule::startPeriodTransition(ISchedulerCallback& callback, Period period) { std::lock_guard<std::mutex> lock(mHwVsyncLock); mController->startPeriodTransition(period.ns()); enableHardwareVsyncLocked(callback); } bool VsyncSchedule::addResyncSample(ISchedulerCallback& callback, TimePoint timestamp, ftl::Optional<Period> hwcVsyncPeriod) { bool needsHwVsync = false; bool periodFlushed = false; { std::lock_guard<std::mutex> lock(mHwVsyncLock); if (mHwVsyncState == HwVsyncState::Enabled) { needsHwVsync = mController->addHwVsyncTimestamp(timestamp.ns(), hwcVsyncPeriod.transform(&Period::ns), &periodFlushed); } } if (needsHwVsync) { enableHardwareVsync(callback); } else { disableHardwareVsync(callback, false /* disallow */); } return periodFlushed; } void VsyncSchedule::enableHardwareVsync(ISchedulerCallback& callback) { std::lock_guard<std::mutex> lock(mHwVsyncLock); enableHardwareVsyncLocked(callback); } void VsyncSchedule::enableHardwareVsyncLocked(ISchedulerCallback& callback) { if (mHwVsyncState == HwVsyncState::Disabled) { getTracker().resetModel(); callback.setVsyncEnabled(true); mHwVsyncState = HwVsyncState::Enabled; } } void VsyncSchedule::disableHardwareVsync(ISchedulerCallback& callback, bool disallow) { std::lock_guard<std::mutex> lock(mHwVsyncLock); if (mHwVsyncState == HwVsyncState::Enabled) { callback.setVsyncEnabled(false); } mHwVsyncState = disallow ? HwVsyncState::Disallowed : HwVsyncState::Disabled; } bool VsyncSchedule::isHardwareVsyncAllowed(bool makeAllowed) { std::lock_guard<std::mutex> lock(mHwVsyncLock); if (makeAllowed && mHwVsyncState == HwVsyncState::Disallowed) { mHwVsyncState = HwVsyncState::Disabled; } return mHwVsyncState != HwVsyncState::Disallowed; } void VsyncSchedule::setPendingHardwareVsyncState(bool enabled) { mPendingHwVsyncState = enabled ? HwVsyncState::Enabled : HwVsyncState::Disabled; } bool VsyncSchedule::getPendingHardwareVsyncState() const { return mPendingHwVsyncState == HwVsyncState::Enabled; } } // namespace android::scheduler services/surfaceflinger/Scheduler/VsyncSchedule.h +61 −6 Original line number Diff line number Diff line Loading @@ -19,6 +19,9 @@ #include <memory> #include <string> #include <ThreadContext.h> #include <ftl/enum.h> #include <ftl/optional.h> #include <scheduler/Features.h> #include <scheduler/Time.h> Loading @@ -32,6 +35,8 @@ class SchedulerFuzzer; namespace android::scheduler { struct ISchedulerCallback; // TODO(b/185535769): Rename classes, and remove aliases. class VSyncDispatch; class VSyncTracker; Loading @@ -44,12 +49,24 @@ using VsyncTracker = VSyncTracker; class VsyncSchedule { public: explicit VsyncSchedule(FeatureFlags); VsyncSchedule(VsyncSchedule&&); ~VsyncSchedule(); Period period() const; TimePoint vsyncDeadlineAfter(TimePoint) const; // Inform the schedule that the period is changing and the schedule needs to recalibrate // itself. The schedule will end the period transition internally. This will // enable hardware VSYNCs in order to calibrate. // // \param [in] period The period that the system is changing into. void startPeriodTransition(ISchedulerCallback&, Period period); // Pass a VSYNC sample to VsyncController. Return true if // VsyncController detected that the VSYNC period changed. Enable or disable // hardware VSYNCs depending on whether more samples are needed. bool addResyncSample(ISchedulerCallback&, TimePoint timestamp, ftl::Optional<Period> hwcVsyncPeriod); // TODO(b/185535769): Hide behind API. const VsyncTracker& getTracker() const { return *mTracker; } VsyncTracker& getTracker() { return *mTracker; } Loading @@ -60,6 +77,22 @@ public: void dump(std::string&) const; // Turn on hardware VSYNCs, unless mHwVsyncState is Disallowed, in which // case this call is ignored. void enableHardwareVsync(ISchedulerCallback&) EXCLUDES(mHwVsyncLock); // Disable hardware VSYNCs. If `disallow` is true, future calls to // enableHardwareVsync are ineffective until allowHardwareVsync is called. void disableHardwareVsync(ISchedulerCallback&, bool disallow) EXCLUDES(mHwVsyncLock); // If true, enableHardwareVsync can enable hardware VSYNC (if not already // enabled). If false, enableHardwareVsync does nothing. bool isHardwareVsyncAllowed(bool makeAllowed) EXCLUDES(mHwVsyncLock); void setPendingHardwareVsyncState(bool enabled) REQUIRES(kMainThreadContext); bool getPendingHardwareVsyncState() const REQUIRES(kMainThreadContext); private: friend class TestableScheduler; friend class android::EventThreadTest; Loading @@ -76,14 +109,36 @@ private: static DispatchPtr createDispatch(VsyncTracker&); static ControllerPtr createController(VsyncTracker&, FeatureFlags); void enableHardwareVsyncLocked(ISchedulerCallback&) REQUIRES(mHwVsyncLock); mutable std::mutex mHwVsyncLock; enum class HwVsyncState { // Hardware VSYNCs are currently enabled. Enabled, // Hardware VSYNCs are currently disabled. They can be enabled by a call // to `enableHardwareVsync`. Disabled, // Hardware VSYNCs are not currently allowed (e.g. because the display // is off). Disallowed, ftl_last = Disallowed, }; HwVsyncState mHwVsyncState GUARDED_BY(mHwVsyncLock) = HwVsyncState::Disallowed; // Pending state, in case an attempt is made to set the state while the // device is off. HwVsyncState mPendingHwVsyncState GUARDED_BY(kMainThreadContext) = HwVsyncState::Disabled; class PredictedVsyncTracer; using TracerPtr = std::unique_ptr<PredictedVsyncTracer>; // Effectively const except in move constructor. TrackerPtr mTracker; DispatchPtr mDispatch; ControllerPtr mController; TracerPtr mTracer; const TrackerPtr mTracker; const DispatchPtr mDispatch; const ControllerPtr mController; const TracerPtr mTracer; }; } // namespace android::scheduler Loading
services/surfaceflinger/Scheduler/ISchedulerCallback.h 0 → 100644 +35 −0 Original line number Diff line number Diff line /* * Copyright 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <vector> #include "Display/DisplayModeRequest.h" namespace android::scheduler { struct ISchedulerCallback { virtual void setVsyncEnabled(bool) = 0; virtual void requestDisplayModes(std::vector<display::DisplayModeRequest>) = 0; virtual void kernelTimerChanged(bool expired) = 0; virtual void triggerOnFrameRateOverridesChanged() = 0; protected: ~ISchedulerCallback() = default; }; } // namespace android::scheduler
services/surfaceflinger/Scheduler/Scheduler.cpp +13 −67 Original line number Diff line number Diff line Loading @@ -155,7 +155,7 @@ void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId, } void Scheduler::createVsyncSchedule(FeatureFlags features) { mVsyncSchedule.emplace(features); mVsyncSchedule = std::make_unique<VsyncSchedule>(features); } std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const { Loading Loading @@ -394,38 +394,17 @@ void Scheduler::setVsyncConfig(const VsyncConfig& config, Period vsyncPeriod) { } void Scheduler::enableHardwareVsync() { std::lock_guard<std::mutex> lock(mHWVsyncLock); if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) { mVsyncSchedule->getTracker().resetModel(); mSchedulerCallback.setVsyncEnabled(true); mPrimaryHWVsyncEnabled = true; } mVsyncSchedule->enableHardwareVsync(mSchedulerCallback); } void Scheduler::disableHardwareVsync(bool makeUnavailable) { std::lock_guard<std::mutex> lock(mHWVsyncLock); if (mPrimaryHWVsyncEnabled) { mSchedulerCallback.setVsyncEnabled(false); mPrimaryHWVsyncEnabled = false; } if (makeUnavailable) { mHWVsyncAvailable = false; } void Scheduler::disableHardwareVsync(bool disallow) { mVsyncSchedule->disableHardwareVsync(mSchedulerCallback, disallow); } void Scheduler::resyncToHardwareVsync(bool makeAvailable, Fps refreshRate) { { std::lock_guard<std::mutex> lock(mHWVsyncLock); if (makeAvailable) { mHWVsyncAvailable = makeAvailable; } else if (!mHWVsyncAvailable) { // Hardware vsync is not currently available, so abort the resync // attempt for now return; } void Scheduler::resyncToHardwareVsync(bool allowToEnable, Fps refreshRate) { if (mVsyncSchedule->isHardwareVsyncAllowed(allowToEnable) && refreshRate.isValid()) { mVsyncSchedule->startPeriodTransition(mSchedulerCallback, refreshRate.getPeriod()); } setVsyncPeriod(refreshRate.getPeriodNsecs()); } void Scheduler::setRenderRate(Fps renderFrameRate) { Loading Loading @@ -458,37 +437,12 @@ void Scheduler::resync() { } } void Scheduler::setVsyncPeriod(nsecs_t period) { if (period <= 0) return; std::lock_guard<std::mutex> lock(mHWVsyncLock); mVsyncSchedule->getController().startPeriodTransition(period); if (!mPrimaryHWVsyncEnabled) { mVsyncSchedule->getTracker().resetModel(); mSchedulerCallback.setVsyncEnabled(true); mPrimaryHWVsyncEnabled = true; } } void Scheduler::addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod, bool* periodFlushed) { bool needsHwVsync = false; *periodFlushed = false; { // Scope for the lock std::lock_guard<std::mutex> lock(mHWVsyncLock); if (mPrimaryHWVsyncEnabled) { needsHwVsync = mVsyncSchedule->getController().addHwVsyncTimestamp(timestamp, hwcVsyncPeriod, periodFlushed); } } if (needsHwVsync) { enableHardwareVsync(); } else { disableHardwareVsync(false); } bool Scheduler::addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriodIn) { const auto hwcVsyncPeriod = ftl::Optional(hwcVsyncPeriodIn).transform([](nsecs_t nanos) { return Period::fromNs(nanos); }); return mVsyncSchedule->addResyncSample(mSchedulerCallback, TimePoint::fromNs(timestamp), hwcVsyncPeriod); } void Scheduler::addPresentFence(std::shared_ptr<FenceTime> fence) { Loading Loading @@ -636,14 +590,6 @@ void Scheduler::dump(utils::Dumper& dumper) const { mFrameRateOverrideMappings.dump(dumper); dumper.eol(); { utils::Dumper::Section section(dumper, "Hardware VSYNC"sv); std::lock_guard lock(mHWVsyncLock); dumper.dump("hwVsyncAvailable"sv, mHWVsyncAvailable); dumper.dump("hwVsyncEnabled"sv, mPrimaryHWVsyncEnabled); } } void Scheduler::dumpVsync(std::string& out) const { Loading
services/surfaceflinger/Scheduler/Scheduler.h +9 −23 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ #include "Display/DisplayModeRequest.h" #include "EventThread.h" #include "FrameRateOverrideMappings.h" #include "ISchedulerCallback.h" #include "LayerHistory.h" #include "MessageQueue.h" #include "OneShotTimer.h" Loading Loading @@ -92,16 +93,6 @@ namespace scheduler { using GlobalSignals = RefreshRateSelector::GlobalSignals; struct ISchedulerCallback { virtual void setVsyncEnabled(bool) = 0; virtual void requestDisplayModes(std::vector<display::DisplayModeRequest>) = 0; virtual void kernelTimerChanged(bool expired) = 0; virtual void triggerOnFrameRateOverridesChanged() = 0; protected: ~ISchedulerCallback() = default; }; class Scheduler : android::impl::MessageQueue { using Impl = android::impl::MessageQueue; Loading Loading @@ -192,20 +183,20 @@ public: void setRenderRate(Fps); void enableHardwareVsync(); void disableHardwareVsync(bool makeUnavailable); void disableHardwareVsync(bool disallow); // Resyncs the scheduler to hardware vsync. // If makeAvailable is true, then hardware vsync will be turned on. // If allowToEnable is true, then hardware vsync will be turned on. // Otherwise, if hardware vsync is not already enabled then this method will // no-op. void resyncToHardwareVsync(bool makeAvailable, Fps refreshRate); void resyncToHardwareVsync(bool allowToEnable, Fps refreshRate); void resync() EXCLUDES(mDisplayLock); void forceNextResync() { mLastResyncTime = 0; } // Passes a vsync sample to VsyncController. periodFlushed will be true if // VsyncController detected that the vsync period changed, and false otherwise. void addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod, bool* periodFlushed); // Passes a vsync sample to VsyncController. Returns true if // VsyncController detected that the vsync period changed and false // otherwise. bool addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod); void addPresentFence(std::shared_ptr<FenceTime>); // Layers are registered on creation, and unregistered when the weak reference expires. Loading Loading @@ -297,7 +288,6 @@ private: void touchTimerCallback(TimerState); void displayPowerTimerCallback(TimerState); void setVsyncPeriod(nsecs_t period); void setVsyncConfig(const VsyncConfig&, Period vsyncPeriod); // Chooses a leader among the registered displays, unless `leaderIdOpt` is specified. The new Loading Loading @@ -362,14 +352,10 @@ private: ConnectionHandle mAppConnectionHandle; ConnectionHandle mSfConnectionHandle; mutable std::mutex mHWVsyncLock; bool mPrimaryHWVsyncEnabled GUARDED_BY(mHWVsyncLock) = false; bool mHWVsyncAvailable GUARDED_BY(mHWVsyncLock) = false; std::atomic<nsecs_t> mLastResyncTime = 0; const FeatureFlags mFeatures; std::optional<VsyncSchedule> mVsyncSchedule; std::unique_ptr<VsyncSchedule> mVsyncSchedule; // Shifts the VSYNC phase during certain transactions and refresh rate changes. const sp<VsyncModulator> mVsyncModulator; Loading
services/surfaceflinger/Scheduler/VsyncSchedule.cpp +80 −6 Original line number Diff line number Diff line Loading @@ -16,11 +16,14 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include <ftl/fake_guard.h> #include <scheduler/Fps.h> #include <scheduler/Timer.h> #include "VsyncSchedule.h" #include "ISchedulerCallback.h" #include "Utils/Dumper.h" #include "VSyncDispatchTimerQueue.h" #include "VSyncPredictor.h" #include "VSyncReactor.h" Loading Loading @@ -54,18 +57,16 @@ private: VsyncSchedule::VsyncSchedule(FeatureFlags features) : mTracker(createTracker()), mDispatch(createDispatch(*mTracker)), mController(createController(*mTracker, features)) { if (features.test(Feature::kTracePredictedVsync)) { mTracer = std::make_unique<PredictedVsyncTracer>(*mDispatch); } } mController(createController(*mTracker, features)), mTracer(features.test(Feature::kTracePredictedVsync) ? std::make_unique<PredictedVsyncTracer>(*mDispatch) : nullptr) {} VsyncSchedule::VsyncSchedule(TrackerPtr tracker, DispatchPtr dispatch, ControllerPtr controller) : mTracker(std::move(tracker)), mDispatch(std::move(dispatch)), mController(std::move(controller)) {} VsyncSchedule::VsyncSchedule(VsyncSchedule&&) = default; VsyncSchedule::~VsyncSchedule() = default; Period VsyncSchedule::period() const { Loading @@ -77,6 +78,16 @@ TimePoint VsyncSchedule::vsyncDeadlineAfter(TimePoint timePoint) const { } void VsyncSchedule::dump(std::string& out) const { utils::Dumper dumper(out); { std::lock_guard<std::mutex> lock(mHwVsyncLock); dumper.dump("hwVsyncState", ftl::enum_string(mHwVsyncState)); ftl::FakeGuard guard(kMainThreadContext); dumper.dump("pendingHwVsyncState", ftl::enum_string(mPendingHwVsyncState)); dumper.eol(); } out.append("VsyncController:\n"); mController->dump(out); Loading Loading @@ -120,4 +131,67 @@ VsyncSchedule::ControllerPtr VsyncSchedule::createController(VsyncTracker& track return reactor; } void VsyncSchedule::startPeriodTransition(ISchedulerCallback& callback, Period period) { std::lock_guard<std::mutex> lock(mHwVsyncLock); mController->startPeriodTransition(period.ns()); enableHardwareVsyncLocked(callback); } bool VsyncSchedule::addResyncSample(ISchedulerCallback& callback, TimePoint timestamp, ftl::Optional<Period> hwcVsyncPeriod) { bool needsHwVsync = false; bool periodFlushed = false; { std::lock_guard<std::mutex> lock(mHwVsyncLock); if (mHwVsyncState == HwVsyncState::Enabled) { needsHwVsync = mController->addHwVsyncTimestamp(timestamp.ns(), hwcVsyncPeriod.transform(&Period::ns), &periodFlushed); } } if (needsHwVsync) { enableHardwareVsync(callback); } else { disableHardwareVsync(callback, false /* disallow */); } return periodFlushed; } void VsyncSchedule::enableHardwareVsync(ISchedulerCallback& callback) { std::lock_guard<std::mutex> lock(mHwVsyncLock); enableHardwareVsyncLocked(callback); } void VsyncSchedule::enableHardwareVsyncLocked(ISchedulerCallback& callback) { if (mHwVsyncState == HwVsyncState::Disabled) { getTracker().resetModel(); callback.setVsyncEnabled(true); mHwVsyncState = HwVsyncState::Enabled; } } void VsyncSchedule::disableHardwareVsync(ISchedulerCallback& callback, bool disallow) { std::lock_guard<std::mutex> lock(mHwVsyncLock); if (mHwVsyncState == HwVsyncState::Enabled) { callback.setVsyncEnabled(false); } mHwVsyncState = disallow ? HwVsyncState::Disallowed : HwVsyncState::Disabled; } bool VsyncSchedule::isHardwareVsyncAllowed(bool makeAllowed) { std::lock_guard<std::mutex> lock(mHwVsyncLock); if (makeAllowed && mHwVsyncState == HwVsyncState::Disallowed) { mHwVsyncState = HwVsyncState::Disabled; } return mHwVsyncState != HwVsyncState::Disallowed; } void VsyncSchedule::setPendingHardwareVsyncState(bool enabled) { mPendingHwVsyncState = enabled ? HwVsyncState::Enabled : HwVsyncState::Disabled; } bool VsyncSchedule::getPendingHardwareVsyncState() const { return mPendingHwVsyncState == HwVsyncState::Enabled; } } // namespace android::scheduler
services/surfaceflinger/Scheduler/VsyncSchedule.h +61 −6 Original line number Diff line number Diff line Loading @@ -19,6 +19,9 @@ #include <memory> #include <string> #include <ThreadContext.h> #include <ftl/enum.h> #include <ftl/optional.h> #include <scheduler/Features.h> #include <scheduler/Time.h> Loading @@ -32,6 +35,8 @@ class SchedulerFuzzer; namespace android::scheduler { struct ISchedulerCallback; // TODO(b/185535769): Rename classes, and remove aliases. class VSyncDispatch; class VSyncTracker; Loading @@ -44,12 +49,24 @@ using VsyncTracker = VSyncTracker; class VsyncSchedule { public: explicit VsyncSchedule(FeatureFlags); VsyncSchedule(VsyncSchedule&&); ~VsyncSchedule(); Period period() const; TimePoint vsyncDeadlineAfter(TimePoint) const; // Inform the schedule that the period is changing and the schedule needs to recalibrate // itself. The schedule will end the period transition internally. This will // enable hardware VSYNCs in order to calibrate. // // \param [in] period The period that the system is changing into. void startPeriodTransition(ISchedulerCallback&, Period period); // Pass a VSYNC sample to VsyncController. Return true if // VsyncController detected that the VSYNC period changed. Enable or disable // hardware VSYNCs depending on whether more samples are needed. bool addResyncSample(ISchedulerCallback&, TimePoint timestamp, ftl::Optional<Period> hwcVsyncPeriod); // TODO(b/185535769): Hide behind API. const VsyncTracker& getTracker() const { return *mTracker; } VsyncTracker& getTracker() { return *mTracker; } Loading @@ -60,6 +77,22 @@ public: void dump(std::string&) const; // Turn on hardware VSYNCs, unless mHwVsyncState is Disallowed, in which // case this call is ignored. void enableHardwareVsync(ISchedulerCallback&) EXCLUDES(mHwVsyncLock); // Disable hardware VSYNCs. If `disallow` is true, future calls to // enableHardwareVsync are ineffective until allowHardwareVsync is called. void disableHardwareVsync(ISchedulerCallback&, bool disallow) EXCLUDES(mHwVsyncLock); // If true, enableHardwareVsync can enable hardware VSYNC (if not already // enabled). If false, enableHardwareVsync does nothing. bool isHardwareVsyncAllowed(bool makeAllowed) EXCLUDES(mHwVsyncLock); void setPendingHardwareVsyncState(bool enabled) REQUIRES(kMainThreadContext); bool getPendingHardwareVsyncState() const REQUIRES(kMainThreadContext); private: friend class TestableScheduler; friend class android::EventThreadTest; Loading @@ -76,14 +109,36 @@ private: static DispatchPtr createDispatch(VsyncTracker&); static ControllerPtr createController(VsyncTracker&, FeatureFlags); void enableHardwareVsyncLocked(ISchedulerCallback&) REQUIRES(mHwVsyncLock); mutable std::mutex mHwVsyncLock; enum class HwVsyncState { // Hardware VSYNCs are currently enabled. Enabled, // Hardware VSYNCs are currently disabled. They can be enabled by a call // to `enableHardwareVsync`. Disabled, // Hardware VSYNCs are not currently allowed (e.g. because the display // is off). Disallowed, ftl_last = Disallowed, }; HwVsyncState mHwVsyncState GUARDED_BY(mHwVsyncLock) = HwVsyncState::Disallowed; // Pending state, in case an attempt is made to set the state while the // device is off. HwVsyncState mPendingHwVsyncState GUARDED_BY(kMainThreadContext) = HwVsyncState::Disabled; class PredictedVsyncTracer; using TracerPtr = std::unique_ptr<PredictedVsyncTracer>; // Effectively const except in move constructor. TrackerPtr mTracker; DispatchPtr mDispatch; ControllerPtr mController; TracerPtr mTracer; const TrackerPtr mTracker; const DispatchPtr mDispatch; const ControllerPtr mController; const TracerPtr mTracer; }; } // namespace android::scheduler