Loading services/surfaceflinger/Scheduler/VsyncModulator.cpp +28 −12 Original line number Diff line number Diff line Loading @@ -46,27 +46,36 @@ VsyncModulator::VsyncConfig VsyncModulator::setVsyncConfigSet(const VsyncConfigS return updateVsyncConfigLocked(); } VsyncModulator::VsyncConfigOpt VsyncModulator::setTransactionSchedule( TransactionSchedule schedule) { VsyncModulator::VsyncConfigOpt VsyncModulator::setTransactionSchedule(TransactionSchedule schedule, const sp<IBinder>& token) { std::lock_guard<std::mutex> lock(mMutex); switch (schedule) { case Schedule::EarlyStart: ALOGW_IF(mEarlyWakeup, "%s: Duplicate EarlyStart", __FUNCTION__); mEarlyWakeup = true; if (token) { mEarlyWakeupRequests.emplace(token); token->linkToDeath(this); } else { ALOGW("%s: EarlyStart requested without a valid token", __func__); } break; case Schedule::EarlyEnd: ALOGW_IF(!mEarlyWakeup, "%s: Unexpected EarlyEnd", __FUNCTION__); mEarlyWakeup = false; case Schedule::EarlyEnd: { if (token && mEarlyWakeupRequests.erase(token) > 0) { token->unlinkToDeath(this); } else { ALOGW("%s: Unexpected EarlyEnd", __func__); } break; } case Schedule::Late: // No change to mEarlyWakeup for non-explicit states. break; } if (mTraceDetailedInfo) { ATRACE_INT("mEarlyWakeup", mEarlyWakeup); ATRACE_INT("mEarlyWakeup", static_cast<int>(mEarlyWakeupRequests.size())); } if (!mEarlyWakeup && schedule == Schedule::EarlyEnd) { if (mEarlyWakeupRequests.empty() && schedule == Schedule::EarlyEnd) { mEarlyTransactionFrames = MIN_EARLY_TRANSACTION_FRAMES; mEarlyTransactionStartTime = mNow(); } Loading @@ -76,7 +85,7 @@ VsyncModulator::VsyncConfigOpt VsyncModulator::setTransactionSchedule( return std::nullopt; } mTransactionSchedule = schedule; return updateVsyncConfig(); return updateVsyncConfigLocked(); } VsyncModulator::VsyncConfigOpt VsyncModulator::onTransactionCommit() { Loading Loading @@ -128,8 +137,8 @@ VsyncModulator::VsyncConfig VsyncModulator::getVsyncConfig() const { const VsyncModulator::VsyncConfig& VsyncModulator::getNextVsyncConfig() const { // Early offsets are used if we're in the middle of a refresh rate // change, or if we recently begin a transaction. if (mEarlyWakeup || mTransactionSchedule == Schedule::EarlyEnd || mEarlyTransactionFrames > 0 || mRefreshRateChangePending) { if (!mEarlyWakeupRequests.empty() || mTransactionSchedule == Schedule::EarlyEnd || mEarlyTransactionFrames > 0 || mRefreshRateChangePending) { return mVsyncConfigSet.early; } else if (mEarlyGpuFrames > 0) { return mVsyncConfigSet.earlyGpu; Loading Loading @@ -160,4 +169,11 @@ VsyncModulator::VsyncConfig VsyncModulator::updateVsyncConfigLocked() { return offsets; } void VsyncModulator::binderDied(const wp<IBinder>& who) { std::lock_guard<std::mutex> lock(mMutex); mEarlyWakeupRequests.erase(who); static_cast<void>(updateVsyncConfigLocked()); } } // namespace android::scheduler services/surfaceflinger/Scheduler/VsyncModulator.h +16 −3 Original line number Diff line number Diff line Loading @@ -19,8 +19,10 @@ #include <chrono> #include <mutex> #include <optional> #include <unordered_set> #include <android-base/thread_annotations.h> #include <binder/IBinder.h> #include <utils/Timers.h> namespace android::scheduler { Loading @@ -35,7 +37,7 @@ enum class TransactionSchedule { }; // Modulates VSYNC phase depending on transaction schedule and refresh rate changes. class VsyncModulator { class VsyncModulator : public IBinder::DeathRecipient { public: // Number of frames to keep early offsets after an early transaction or GPU composition. // This acts as a low-pass filter in case subsequent transactions are delayed, or if the Loading Loading @@ -91,7 +93,8 @@ public: [[nodiscard]] VsyncConfig setVsyncConfigSet(const VsyncConfigSet&) EXCLUDES(mMutex); // Changes offsets in response to transaction flags or commit. [[nodiscard]] VsyncConfigOpt setTransactionSchedule(TransactionSchedule); [[nodiscard]] VsyncConfigOpt setTransactionSchedule(TransactionSchedule, const sp<IBinder>& = {}) EXCLUDES(mMutex); [[nodiscard]] VsyncConfigOpt onTransactionCommit(); // Called when we send a refresh rate change to hardware composer, so that Loading @@ -104,6 +107,10 @@ public: [[nodiscard]] VsyncConfigOpt onDisplayRefresh(bool usedGpuComposition); protected: // Called from unit tests as well void binderDied(const wp<IBinder>&) override EXCLUDES(mMutex); private: const VsyncConfig& getNextVsyncConfig() const REQUIRES(mMutex); [[nodiscard]] VsyncConfig updateVsyncConfig() EXCLUDES(mMutex); Loading @@ -116,8 +123,14 @@ private: using Schedule = TransactionSchedule; std::atomic<Schedule> mTransactionSchedule = Schedule::Late; std::atomic<bool> mEarlyWakeup = false; struct WpHash { size_t operator()(const wp<IBinder>& p) const { return std::hash<IBinder*>()(p.unsafe_get()); } }; std::unordered_set<wp<IBinder>, WpHash> mEarlyWakeupRequests GUARDED_BY(mMutex); std::atomic<bool> mRefreshRateChangePending = false; std::atomic<int> mEarlyTransactionFrames = 0; Loading services/surfaceflinger/SurfaceFlinger.cpp +5 −4 Original line number Diff line number Diff line Loading @@ -3157,7 +3157,7 @@ void SurfaceFlinger::initScheduler(const DisplayDeviceState& displayState) { hal::PowerMode::OFF); mVsyncConfiguration = getFactory().createVsyncConfiguration(currRefreshRate); mVsyncModulator.emplace(mVsyncConfiguration->getCurrentConfigs()); mVsyncModulator = sp<VsyncModulator>::make(mVsyncConfiguration->getCurrentConfigs()); // start the EventThread mScheduler = getFactory().createScheduler(*mRefreshRateConfigs, *this); Loading Loading @@ -3437,9 +3437,10 @@ uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) { return setTransactionFlags(flags, TransactionSchedule::Late); } uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, TransactionSchedule schedule) { uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, TransactionSchedule schedule, const sp<IBinder>& token) { uint32_t old = mTransactionFlags.fetch_or(flags); modulateVsync(&VsyncModulator::setTransactionSchedule, schedule); modulateVsync(&VsyncModulator::setTransactionSchedule, schedule, token); if ((old & flags) == 0) signalTransaction(); return old; } Loading Loading @@ -3659,7 +3660,7 @@ void SurfaceFlinger::queueTransaction(TransactionState& state) { return TransactionSchedule::Late; }(state.flags); setTransactionFlags(eTransactionFlushNeeded, schedule); setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken); } void SurfaceFlinger::waitForSynchronousTransaction( Loading services/surfaceflinger/SurfaceFlinger.h +2 −2 Original line number Diff line number Diff line Loading @@ -851,7 +851,7 @@ private: // but there is no need to try and wake up immediately to do it. Rather we rely on // onFrameAvailable or another layer update to wake us up. void setTraversalNeeded(); uint32_t setTransactionFlags(uint32_t flags, TransactionSchedule); uint32_t setTransactionFlags(uint32_t flags, TransactionSchedule, const sp<IBinder>& = {}); void commitTransaction() REQUIRES(mStateLock); void commitOffscreenLayers(); bool transactionIsReadyToBeApplied( Loading Loading @@ -1389,7 +1389,7 @@ private: std::unique_ptr<scheduler::VsyncConfiguration> mVsyncConfiguration; // Optional to defer construction until PhaseConfiguration is created. std::optional<scheduler::VsyncModulator> mVsyncModulator; sp<VsyncModulator> mVsyncModulator; std::unique_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs; std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats; Loading services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +2 −1 Original line number Diff line number Diff line Loading @@ -230,7 +230,8 @@ public: std::make_unique<scheduler::RefreshRateStats>(*mFlinger->mTimeStats, currFps, /*powerMode=*/hal::PowerMode::OFF); mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(currFps); mFlinger->mVsyncModulator.emplace(mFlinger->mVsyncConfiguration->getCurrentConfigs()); mFlinger->mVsyncModulator = sp<scheduler::VsyncModulator>::make( mFlinger->mVsyncConfiguration->getCurrentConfigs()); mScheduler = new TestableScheduler(std::move(vsyncController), std::move(vsyncTracker), *mFlinger->mRefreshRateConfigs, *(callback ?: this)); Loading Loading
services/surfaceflinger/Scheduler/VsyncModulator.cpp +28 −12 Original line number Diff line number Diff line Loading @@ -46,27 +46,36 @@ VsyncModulator::VsyncConfig VsyncModulator::setVsyncConfigSet(const VsyncConfigS return updateVsyncConfigLocked(); } VsyncModulator::VsyncConfigOpt VsyncModulator::setTransactionSchedule( TransactionSchedule schedule) { VsyncModulator::VsyncConfigOpt VsyncModulator::setTransactionSchedule(TransactionSchedule schedule, const sp<IBinder>& token) { std::lock_guard<std::mutex> lock(mMutex); switch (schedule) { case Schedule::EarlyStart: ALOGW_IF(mEarlyWakeup, "%s: Duplicate EarlyStart", __FUNCTION__); mEarlyWakeup = true; if (token) { mEarlyWakeupRequests.emplace(token); token->linkToDeath(this); } else { ALOGW("%s: EarlyStart requested without a valid token", __func__); } break; case Schedule::EarlyEnd: ALOGW_IF(!mEarlyWakeup, "%s: Unexpected EarlyEnd", __FUNCTION__); mEarlyWakeup = false; case Schedule::EarlyEnd: { if (token && mEarlyWakeupRequests.erase(token) > 0) { token->unlinkToDeath(this); } else { ALOGW("%s: Unexpected EarlyEnd", __func__); } break; } case Schedule::Late: // No change to mEarlyWakeup for non-explicit states. break; } if (mTraceDetailedInfo) { ATRACE_INT("mEarlyWakeup", mEarlyWakeup); ATRACE_INT("mEarlyWakeup", static_cast<int>(mEarlyWakeupRequests.size())); } if (!mEarlyWakeup && schedule == Schedule::EarlyEnd) { if (mEarlyWakeupRequests.empty() && schedule == Schedule::EarlyEnd) { mEarlyTransactionFrames = MIN_EARLY_TRANSACTION_FRAMES; mEarlyTransactionStartTime = mNow(); } Loading @@ -76,7 +85,7 @@ VsyncModulator::VsyncConfigOpt VsyncModulator::setTransactionSchedule( return std::nullopt; } mTransactionSchedule = schedule; return updateVsyncConfig(); return updateVsyncConfigLocked(); } VsyncModulator::VsyncConfigOpt VsyncModulator::onTransactionCommit() { Loading Loading @@ -128,8 +137,8 @@ VsyncModulator::VsyncConfig VsyncModulator::getVsyncConfig() const { const VsyncModulator::VsyncConfig& VsyncModulator::getNextVsyncConfig() const { // Early offsets are used if we're in the middle of a refresh rate // change, or if we recently begin a transaction. if (mEarlyWakeup || mTransactionSchedule == Schedule::EarlyEnd || mEarlyTransactionFrames > 0 || mRefreshRateChangePending) { if (!mEarlyWakeupRequests.empty() || mTransactionSchedule == Schedule::EarlyEnd || mEarlyTransactionFrames > 0 || mRefreshRateChangePending) { return mVsyncConfigSet.early; } else if (mEarlyGpuFrames > 0) { return mVsyncConfigSet.earlyGpu; Loading Loading @@ -160,4 +169,11 @@ VsyncModulator::VsyncConfig VsyncModulator::updateVsyncConfigLocked() { return offsets; } void VsyncModulator::binderDied(const wp<IBinder>& who) { std::lock_guard<std::mutex> lock(mMutex); mEarlyWakeupRequests.erase(who); static_cast<void>(updateVsyncConfigLocked()); } } // namespace android::scheduler
services/surfaceflinger/Scheduler/VsyncModulator.h +16 −3 Original line number Diff line number Diff line Loading @@ -19,8 +19,10 @@ #include <chrono> #include <mutex> #include <optional> #include <unordered_set> #include <android-base/thread_annotations.h> #include <binder/IBinder.h> #include <utils/Timers.h> namespace android::scheduler { Loading @@ -35,7 +37,7 @@ enum class TransactionSchedule { }; // Modulates VSYNC phase depending on transaction schedule and refresh rate changes. class VsyncModulator { class VsyncModulator : public IBinder::DeathRecipient { public: // Number of frames to keep early offsets after an early transaction or GPU composition. // This acts as a low-pass filter in case subsequent transactions are delayed, or if the Loading Loading @@ -91,7 +93,8 @@ public: [[nodiscard]] VsyncConfig setVsyncConfigSet(const VsyncConfigSet&) EXCLUDES(mMutex); // Changes offsets in response to transaction flags or commit. [[nodiscard]] VsyncConfigOpt setTransactionSchedule(TransactionSchedule); [[nodiscard]] VsyncConfigOpt setTransactionSchedule(TransactionSchedule, const sp<IBinder>& = {}) EXCLUDES(mMutex); [[nodiscard]] VsyncConfigOpt onTransactionCommit(); // Called when we send a refresh rate change to hardware composer, so that Loading @@ -104,6 +107,10 @@ public: [[nodiscard]] VsyncConfigOpt onDisplayRefresh(bool usedGpuComposition); protected: // Called from unit tests as well void binderDied(const wp<IBinder>&) override EXCLUDES(mMutex); private: const VsyncConfig& getNextVsyncConfig() const REQUIRES(mMutex); [[nodiscard]] VsyncConfig updateVsyncConfig() EXCLUDES(mMutex); Loading @@ -116,8 +123,14 @@ private: using Schedule = TransactionSchedule; std::atomic<Schedule> mTransactionSchedule = Schedule::Late; std::atomic<bool> mEarlyWakeup = false; struct WpHash { size_t operator()(const wp<IBinder>& p) const { return std::hash<IBinder*>()(p.unsafe_get()); } }; std::unordered_set<wp<IBinder>, WpHash> mEarlyWakeupRequests GUARDED_BY(mMutex); std::atomic<bool> mRefreshRateChangePending = false; std::atomic<int> mEarlyTransactionFrames = 0; Loading
services/surfaceflinger/SurfaceFlinger.cpp +5 −4 Original line number Diff line number Diff line Loading @@ -3157,7 +3157,7 @@ void SurfaceFlinger::initScheduler(const DisplayDeviceState& displayState) { hal::PowerMode::OFF); mVsyncConfiguration = getFactory().createVsyncConfiguration(currRefreshRate); mVsyncModulator.emplace(mVsyncConfiguration->getCurrentConfigs()); mVsyncModulator = sp<VsyncModulator>::make(mVsyncConfiguration->getCurrentConfigs()); // start the EventThread mScheduler = getFactory().createScheduler(*mRefreshRateConfigs, *this); Loading Loading @@ -3437,9 +3437,10 @@ uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) { return setTransactionFlags(flags, TransactionSchedule::Late); } uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, TransactionSchedule schedule) { uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, TransactionSchedule schedule, const sp<IBinder>& token) { uint32_t old = mTransactionFlags.fetch_or(flags); modulateVsync(&VsyncModulator::setTransactionSchedule, schedule); modulateVsync(&VsyncModulator::setTransactionSchedule, schedule, token); if ((old & flags) == 0) signalTransaction(); return old; } Loading Loading @@ -3659,7 +3660,7 @@ void SurfaceFlinger::queueTransaction(TransactionState& state) { return TransactionSchedule::Late; }(state.flags); setTransactionFlags(eTransactionFlushNeeded, schedule); setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken); } void SurfaceFlinger::waitForSynchronousTransaction( Loading
services/surfaceflinger/SurfaceFlinger.h +2 −2 Original line number Diff line number Diff line Loading @@ -851,7 +851,7 @@ private: // but there is no need to try and wake up immediately to do it. Rather we rely on // onFrameAvailable or another layer update to wake us up. void setTraversalNeeded(); uint32_t setTransactionFlags(uint32_t flags, TransactionSchedule); uint32_t setTransactionFlags(uint32_t flags, TransactionSchedule, const sp<IBinder>& = {}); void commitTransaction() REQUIRES(mStateLock); void commitOffscreenLayers(); bool transactionIsReadyToBeApplied( Loading Loading @@ -1389,7 +1389,7 @@ private: std::unique_ptr<scheduler::VsyncConfiguration> mVsyncConfiguration; // Optional to defer construction until PhaseConfiguration is created. std::optional<scheduler::VsyncModulator> mVsyncModulator; sp<VsyncModulator> mVsyncModulator; std::unique_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs; std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats; Loading
services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +2 −1 Original line number Diff line number Diff line Loading @@ -230,7 +230,8 @@ public: std::make_unique<scheduler::RefreshRateStats>(*mFlinger->mTimeStats, currFps, /*powerMode=*/hal::PowerMode::OFF); mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(currFps); mFlinger->mVsyncModulator.emplace(mFlinger->mVsyncConfiguration->getCurrentConfigs()); mFlinger->mVsyncModulator = sp<scheduler::VsyncModulator>::make( mFlinger->mVsyncConfiguration->getCurrentConfigs()); mScheduler = new TestableScheduler(std::move(vsyncController), std::move(vsyncTracker), *mFlinger->mRefreshRateConfigs, *(callback ?: this)); Loading