diff options
author | 2021-08-11 17:22:59 -0700 | |
---|---|---|
committer | 2021-11-19 15:58:39 +0000 | |
commit | 068173d9076ca25fa5cc008a116e4ec22503b9be (patch) | |
tree | 8a4a8e603eaa40dcf79a2a75f8c64ecf3d0717b3 | |
parent | 079ec332de6012a59a4bfa4ed9ba967189e0f4da (diff) |
SF: Add VsyncSchedule skeleton
Pull the Scheduler::VsyncSchedule struct and related code into its own
file, as it will be extended with more per-display state, e.g. reactor
registrations, resync state machine, etc.
Add <scheduler/Features.h> for feature flags. Move Scheduler into its
namespace.
Bug: 185535769
Test: libsurfaceflinger_unittest
Change-Id: I6e10893632c5abf40380df924791d1fcc27c3cc2
32 files changed, 461 insertions, 342 deletions
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 29636f84f5..c9fb7bc876 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -194,9 +194,10 @@ filegroup { "Scheduler/Timer.cpp", "Scheduler/VSyncDispatchTimerQueue.cpp", "Scheduler/VSyncPredictor.cpp", - "Scheduler/VsyncModulator.cpp", "Scheduler/VSyncReactor.cpp", "Scheduler/VsyncConfiguration.cpp", + "Scheduler/VsyncModulator.cpp", + "Scheduler/VsyncSchedule.cpp", "StartPropertySetThread.cpp", "SurfaceFlinger.cpp", "SurfaceFlingerDefaultFactory.cpp", diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index dec7cc0806..926aa1dfb2 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -372,8 +372,9 @@ void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { // Add this buffer from our internal queue tracker { // Autolock scope const nsecs_t presentTime = item.mIsAutoTimestamp ? 0 : item.mTimestamp; - mFlinger->mScheduler->recordLayerHistory(this, presentTime, - LayerHistory::LayerUpdateType::Buffer); + + using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType; + mFlinger->mScheduler->recordLayerHistory(this, presentTime, LayerUpdateType::Buffer); Mutex::Autolock lock(mQueueItemLock); // Reset the frame number tracker when we receive the first buffer after diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index b4ccb803e9..7d40fc87f9 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -476,8 +476,9 @@ bool BufferStateLayer::setBuffer(const BufferData& bufferData, nsecs_t postTime, return static_cast<nsecs_t>(0); }(); - mFlinger->mScheduler->recordLayerHistory(this, presentTime, - LayerHistory::LayerUpdateType::Buffer); + + using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType; + mFlinger->mScheduler->recordLayerHistory(this, presentTime, LayerUpdateType::Buffer); addFrameEvent(mDrawingState.acquireFence, postTime, isAutoTimestamp ? 0 : desiredPresentTime); diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index fd09ae4066..76bbe2c58f 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -483,7 +483,7 @@ bool DisplayDevice::setDesiredActiveMode(const ActiveModeInfo& info) { std::scoped_lock lock(mActiveModeLock); if (mDesiredActiveModeChanged) { // If a mode change is pending, just cache the latest request in mDesiredActiveMode - const Scheduler::ModeEvent prevConfig = mDesiredActiveMode.event; + const auto prevConfig = mDesiredActiveMode.event; mDesiredActiveMode = info; mDesiredActiveMode.event = mDesiredActiveMode.event | prevConfig; return false; @@ -508,7 +508,7 @@ std::optional<DisplayDevice::ActiveModeInfo> DisplayDevice::getDesiredActiveMode void DisplayDevice::clearDesiredActiveModeState() { std::scoped_lock lock(mActiveModeLock); - mDesiredActiveMode.event = Scheduler::ModeEvent::None; + mDesiredActiveMode.event = scheduler::DisplayModeEvent::None; mDesiredActiveModeChanged = false; } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 4b9718f608..324145ef47 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -190,7 +190,7 @@ public: struct ActiveModeInfo { DisplayModePtr mode; - scheduler::RefreshRateConfigEvent event = scheduler::RefreshRateConfigEvent::None; + scheduler::DisplayModeEvent event = scheduler::DisplayModeEvent::None; bool operator!=(const ActiveModeInfo& other) const { return mode != other.mode || event != other.event; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 968a49d526..b3ea94fd94 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1293,8 +1293,8 @@ bool Layer::setFrameRateForLayerTree(FrameRate frameRate) { mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); - mFlinger->mScheduler->recordLayerHistory(this, systemTime(), - LayerHistory::LayerUpdateType::SetFrameRate); + using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType; + mFlinger->mScheduler->recordLayerHistory(this, systemTime(), LayerUpdateType::SetFrameRate); return true; } diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h index 92236f560a..8d56951363 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.h +++ b/services/surfaceflinger/Scheduler/LayerHistory.h @@ -31,11 +31,9 @@ namespace android { class Layer; -class TestableScheduler; namespace scheduler { -class LayerHistoryTest; class LayerInfo; class LayerHistory { @@ -75,8 +73,8 @@ public: std::string dump() const; private: - friend LayerHistoryTest; - friend TestableScheduler; + friend class LayerHistoryTest; + friend class TestableScheduler; using LayerPair = std::pair<Layer*, std::unique_ptr<LayerInfo>>; using LayerInfos = std::vector<LayerPair>; diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 8a1c2062a6..492feb14df 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -37,11 +37,11 @@ namespace android::scheduler { using namespace std::chrono_literals; -enum class RefreshRateConfigEvent : unsigned { None = 0b0, Changed = 0b1 }; +enum class DisplayModeEvent : unsigned { None = 0b0, Changed = 0b1 }; -inline RefreshRateConfigEvent operator|(RefreshRateConfigEvent lhs, RefreshRateConfigEvent rhs) { - using T = std::underlying_type_t<RefreshRateConfigEvent>; - return static_cast<RefreshRateConfigEvent>(static_cast<T>(lhs) | static_cast<T>(rhs)); +inline DisplayModeEvent operator|(DisplayModeEvent lhs, DisplayModeEvent rhs) { + using T = std::underlying_type_t<DisplayModeEvent>; + return static_cast<DisplayModeEvent>(static_cast<T>(lhs) | static_cast<T>(rhs)); } using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 4d72798086..cbe4552b0b 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -46,11 +46,8 @@ #include "OneShotTimer.h" #include "SchedulerUtils.h" #include "SurfaceFlingerProperties.h" -#include "Timer.h" -#include "VSyncDispatchTimerQueue.h" #include "VSyncPredictor.h" #include "VSyncReactor.h" -#include "VsyncController.h" #define RETURN_IF_INVALID_HANDLE(handle, ...) \ do { \ @@ -60,68 +57,14 @@ } \ } while (false) -using namespace std::string_literals; +namespace android::scheduler { -namespace android { - -using gui::WindowInfo; - -namespace { - -std::unique_ptr<scheduler::VSyncTracker> createVSyncTracker() { - // TODO(b/144707443): Tune constants. - constexpr int kDefaultRate = 60; - constexpr auto initialPeriod = std::chrono::duration<nsecs_t, std::ratio<1, kDefaultRate>>(1); - constexpr nsecs_t idealPeriod = - std::chrono::duration_cast<std::chrono::nanoseconds>(initialPeriod).count(); - constexpr size_t vsyncTimestampHistorySize = 20; - constexpr size_t minimumSamplesForPrediction = 6; - constexpr uint32_t discardOutlierPercent = 20; - return std::make_unique<scheduler::VSyncPredictor>(idealPeriod, vsyncTimestampHistorySize, - minimumSamplesForPrediction, - discardOutlierPercent); -} - -std::unique_ptr<scheduler::VSyncDispatch> createVSyncDispatch(scheduler::VSyncTracker& tracker) { - // TODO(b/144707443): Tune constants. - constexpr std::chrono::nanoseconds vsyncMoveThreshold = 3ms; - constexpr std::chrono::nanoseconds timerSlack = 500us; - return std::make_unique< - scheduler::VSyncDispatchTimerQueue>(std::make_unique<scheduler::Timer>(), tracker, - timerSlack.count(), vsyncMoveThreshold.count()); -} - -const char* toContentDetectionString(bool useContentDetection) { - return useContentDetection ? "on" : "off"; -} - -} // namespace - -class PredictedVsyncTracer { -public: - PredictedVsyncTracer(scheduler::VSyncDispatch& dispatch) - : mRegistration(dispatch, std::bind(&PredictedVsyncTracer::callback, this), - "PredictedVsyncTracer") { - scheduleRegistration(); - } - -private: - TracedOrdinal<bool> mParity = {"VSYNC-predicted", 0}; - scheduler::VSyncCallbackRegistration mRegistration; - - void scheduleRegistration() { mRegistration.schedule({0, 0, 0}); } - - void callback() { - mParity = !mParity; - scheduleRegistration(); - } -}; - -Scheduler::Scheduler(ICompositor& compositor, ISchedulerCallback& callback, Options options) - : impl::MessageQueue(compositor), mOptions(options), mSchedulerCallback(callback) {} +Scheduler::Scheduler(ICompositor& compositor, ISchedulerCallback& callback, FeatureFlags features) + : impl::MessageQueue(compositor), mFeatures(features), mSchedulerCallback(callback) {} void Scheduler::startTimers() { using namespace sysprop; + using namespace std::string_literals; if (const int64_t millis = set_touch_timer_ms(0); millis > 0) { // Touch events are coming to SF every 100ms, so the timer needs to be higher than that @@ -154,27 +97,14 @@ void Scheduler::run() { } } -void Scheduler::createVsyncSchedule(bool supportKernelTimer) { - auto clock = std::make_unique<scheduler::SystemClock>(); - auto tracker = createVSyncTracker(); - auto dispatch = createVSyncDispatch(*tracker); - - // TODO(b/144707443): Tune constants. - constexpr size_t pendingFenceLimit = 20; - auto controller = - std::make_unique<scheduler::VSyncReactor>(std::move(clock), *tracker, pendingFenceLimit, - supportKernelTimer); - mVsyncSchedule = {std::move(controller), std::move(tracker), std::move(dispatch)}; - - if (base::GetBoolProperty("debug.sf.show_predicted_vsync", false)) { - mPredictedVsyncTracer = std::make_unique<PredictedVsyncTracer>(*mVsyncSchedule.dispatch); - } +void Scheduler::createVsyncSchedule(FeatureFlags features) { + mVsyncSchedule.emplace(features); } std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource( const char* name, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration, bool traceVsync) { - return std::make_unique<scheduler::DispSyncSource>(*mVsyncSchedule.dispatch, workDuration, + return std::make_unique<scheduler::DispSyncSource>(getVsyncDispatch(), workDuration, readyDuration, traceVsync, name); } @@ -210,7 +140,7 @@ bool Scheduler::isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const { return true; } - return mVsyncSchedule.tracker->isVSyncInPhase(expectedVsyncTimestamp, *frameRate); + return mVsyncSchedule->getTracker().isVSyncInPhase(expectedVsyncTimestamp, *frameRate); } impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() const { @@ -245,7 +175,7 @@ impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction( }; } -Scheduler::ConnectionHandle Scheduler::createConnection( +ConnectionHandle Scheduler::createConnection( const char* connectionName, frametimeline::TokenManager* tokenManager, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration, impl::EventThread::InterceptVSyncsCallback interceptCallback) { @@ -259,7 +189,7 @@ Scheduler::ConnectionHandle Scheduler::createConnection( return createConnection(std::move(eventThread)); } -Scheduler::ConnectionHandle Scheduler::createConnection(std::unique_ptr<EventThread> eventThread) { +ConnectionHandle Scheduler::createConnection(std::unique_ptr<EventThread> eventThread) { const ConnectionHandle handle = ConnectionHandle{mNextConnectionHandleId++}; ALOGV("Creating a connection handle with ID %" PRIuPTR, handle.id); @@ -346,24 +276,24 @@ void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDis void Scheduler::onPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) { { - std::lock_guard<std::mutex> lock(mFeatureStateLock); + std::lock_guard<std::mutex> lock(mPolicyLock); // Cache the last reported modes for primary display. - mFeatures.cachedModeChangedParams = {handle, mode}; + mPolicy.cachedModeChangedParams = {handle, mode}; // Invalidate content based refresh rate selection so it could be calculated // again for the new refresh rate. - mFeatures.contentRequirements.clear(); + mPolicy.contentRequirements.clear(); } onNonPrimaryDisplayModeChanged(handle, mode); } void Scheduler::dispatchCachedReportedMode() { // Check optional fields first. - if (!mFeatures.mode) { + if (!mPolicy.mode) { ALOGW("No mode ID found, not dispatching cached mode."); return; } - if (!mFeatures.cachedModeChangedParams.has_value()) { + if (!mPolicy.cachedModeChangedParams) { ALOGW("No mode changed params found, not dispatching cached mode."); return; } @@ -372,18 +302,18 @@ void Scheduler::dispatchCachedReportedMode() { // mode change is in progress. In that case we shouldn't dispatch an event // as it will be dispatched when the current mode changes. if (std::scoped_lock lock(mRefreshRateConfigsLock); - mRefreshRateConfigs->getCurrentRefreshRate().getMode() != mFeatures.mode) { + mRefreshRateConfigs->getCurrentRefreshRate().getMode() != mPolicy.mode) { return; } // If there is no change from cached mode, there is no need to dispatch an event - if (mFeatures.mode == mFeatures.cachedModeChangedParams->mode) { + if (mPolicy.mode == mPolicy.cachedModeChangedParams->mode) { return; } - mFeatures.cachedModeChangedParams->mode = mFeatures.mode; - onNonPrimaryDisplayModeChanged(mFeatures.cachedModeChangedParams->handle, - mFeatures.cachedModeChangedParams->mode); + mPolicy.cachedModeChangedParams->mode = mPolicy.mode; + onNonPrimaryDisplayModeChanged(mPolicy.cachedModeChangedParams->handle, + mPolicy.cachedModeChangedParams->mode); } void Scheduler::onNonPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) { @@ -424,12 +354,12 @@ void Scheduler::setDuration(ConnectionHandle handle, std::chrono::nanoseconds wo } DisplayStatInfo Scheduler::getDisplayStatInfo(nsecs_t now) { - const auto vsyncTime = mVsyncSchedule.tracker->nextAnticipatedVSyncTimeFrom(now); - const auto vsyncPeriod = mVsyncSchedule.tracker->currentPeriod(); + const auto vsyncTime = mVsyncSchedule->getTracker().nextAnticipatedVSyncTimeFrom(now); + const auto vsyncPeriod = mVsyncSchedule->getTracker().currentPeriod(); return DisplayStatInfo{.vsyncTime = vsyncTime, .vsyncPeriod = vsyncPeriod}; } -Scheduler::ConnectionHandle Scheduler::enableVSyncInjection(bool enable) { +ConnectionHandle Scheduler::enableVSyncInjection(bool enable) { if (mInjectVSyncs == enable) { return {}; } @@ -470,7 +400,7 @@ bool Scheduler::injectVSync(nsecs_t when, nsecs_t expectedVSyncTime, nsecs_t dea void Scheduler::enableHardwareVsync() { std::lock_guard<std::mutex> lock(mHWVsyncLock); if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) { - mVsyncSchedule.tracker->resetModel(); + mVsyncSchedule->getTracker().resetModel(); mSchedulerCallback.setVsyncEnabled(true); mPrimaryHWVsyncEnabled = true; } @@ -523,10 +453,10 @@ void Scheduler::resync() { void Scheduler::setVsyncPeriod(nsecs_t period) { std::lock_guard<std::mutex> lock(mHWVsyncLock); - mVsyncSchedule.controller->startPeriodTransition(period); + mVsyncSchedule->getController().startPeriodTransition(period); if (!mPrimaryHWVsyncEnabled) { - mVsyncSchedule.tracker->resetModel(); + mVsyncSchedule->getTracker().resetModel(); mSchedulerCallback.setVsyncEnabled(true); mPrimaryHWVsyncEnabled = true; } @@ -539,8 +469,9 @@ void Scheduler::addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsy { // Scope for the lock std::lock_guard<std::mutex> lock(mHWVsyncLock); if (mPrimaryHWVsyncEnabled) { - needsHwVsync = mVsyncSchedule.controller->addHwVsyncTimestamp(timestamp, hwcVsyncPeriod, - periodFlushed); + needsHwVsync = + mVsyncSchedule->getController().addHwVsyncTimestamp(timestamp, hwcVsyncPeriod, + periodFlushed); } } @@ -551,24 +482,23 @@ void Scheduler::addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsy } } -void Scheduler::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) { - if (mVsyncSchedule.controller->addPresentFence(fenceTime)) { +void Scheduler::addPresentFence(std::shared_ptr<FenceTime> fence) { + if (mVsyncSchedule->getController().addPresentFence(std::move(fence))) { enableHardwareVsync(); } else { disableHardwareVsync(false); } } -void Scheduler::setIgnorePresentFences(bool ignore) { - mVsyncSchedule.controller->setIgnorePresentFences(ignore); -} - void Scheduler::registerLayer(Layer* layer) { + using WindowType = gui::WindowInfo::Type; + scheduler::LayerHistory::LayerVoteType voteType; - if (!mOptions.useContentDetection || layer->getWindowType() == WindowInfo::Type::STATUS_BAR) { + if (!mFeatures.test(Feature::kContentDetection) || + layer->getWindowType() == WindowType::STATUS_BAR) { voteType = scheduler::LayerHistory::LayerVoteType::NoVote; - } else if (layer->getWindowType() == WindowInfo::Type::WALLPAPER) { + } else if (layer->getWindowType() == WindowType::WALLPAPER) { // Running Wallpaper at Min is considered as part of content detection. voteType = scheduler::LayerHistory::LayerVoteType::Min; } else { @@ -615,13 +545,13 @@ void Scheduler::chooseRefreshRateForContent() { bool frameRateChanged; bool frameRateOverridesChanged; { - std::lock_guard<std::mutex> lock(mFeatureStateLock); - mFeatures.contentRequirements = summary; + std::lock_guard<std::mutex> lock(mPolicyLock); + mPolicy.contentRequirements = summary; newMode = calculateRefreshRateModeId(&consideredSignals); frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps()); - if (mFeatures.mode == newMode) { + if (mPolicy.mode == newMode) { // We don't need to change the display mode, but we might need to send an event // about a mode change, since it was suppressed due to a previous idleConsidered if (!consideredSignals.idle) { @@ -629,15 +559,16 @@ void Scheduler::chooseRefreshRateForContent() { } frameRateChanged = false; } else { - mFeatures.mode = newMode; + mPolicy.mode = newMode; frameRateChanged = true; } } if (frameRateChanged) { - auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); + const auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); + mSchedulerCallback.changeRefreshRate(newRefreshRate, - consideredSignals.idle ? ModeEvent::None - : ModeEvent::Changed); + consideredSignals.idle ? DisplayModeEvent::None + : DisplayModeEvent::Changed); } if (frameRateOverridesChanged) { mSchedulerCallback.triggerOnFrameRateOverridesChanged(); @@ -660,8 +591,8 @@ void Scheduler::onTouchHint() { void Scheduler::setDisplayPowerState(bool normal) { { - std::lock_guard<std::mutex> lock(mFeatureStateLock); - mFeatures.isDisplayPowerStateNormal = normal; + std::lock_guard<std::mutex> lock(mPolicyLock); + mPolicy.isDisplayPowerStateNormal = normal; } if (mDisplayPowerTimer) { @@ -703,7 +634,7 @@ void Scheduler::kernelIdleTimerCallback(TimerState state) { } void Scheduler::idleTimerCallback(TimerState state) { - handleTimerStateChanged(&mFeatures.idleTimer, state); + handleTimerStateChanged(&mPolicy.idleTimer, state); ATRACE_INT("ExpiredIdleTimer", static_cast<int>(state)); } @@ -713,14 +644,14 @@ void Scheduler::touchTimerCallback(TimerState state) { // Clear layer history to get fresh FPS detection. // NOTE: Instead of checking all the layers, we should be checking the layer // that is currently on top. b/142507166 will give us this capability. - if (handleTimerStateChanged(&mFeatures.touch, touch)) { + if (handleTimerStateChanged(&mPolicy.touch, touch)) { mLayerHistory.clear(); } ATRACE_INT("TouchState", static_cast<int>(touch)); } void Scheduler::displayPowerTimerCallback(TimerState state) { - handleTimerStateChanged(&mFeatures.displayPowerTimer, state); + handleTimerStateChanged(&mPolicy.displayPowerTimer, state); ATRACE_INT("ExpiredDisplayPowerTimer", static_cast<int>(state)); } @@ -730,7 +661,7 @@ void Scheduler::dump(std::string& result) const { StringAppendF(&result, "+ Touch timer: %s\n", mTouchTimer ? mTouchTimer->dump().c_str() : "off"); StringAppendF(&result, "+ Content detection: %s %s\n\n", - toContentDetectionString(mOptions.useContentDetection), + mFeatures.test(Feature::kContentDetection) ? "on" : "off", mLayerHistory.dump().c_str()); { @@ -756,13 +687,8 @@ void Scheduler::dump(std::string& result) const { } } -void Scheduler::dumpVsync(std::string& s) const { - using base::StringAppendF; - - StringAppendF(&s, "VSyncReactor:\n"); - mVsyncSchedule.controller->dump(s); - StringAppendF(&s, "VSyncDispatch:\n"); - mVsyncSchedule.dispatch->dump(s); +void Scheduler::dumpVsync(std::string& out) const { + mVsyncSchedule->dump(out); } bool Scheduler::updateFrameRateOverrides( @@ -774,7 +700,7 @@ bool Scheduler::updateFrameRateOverrides( if (!consideredSignals.idle) { const auto frameRateOverrides = - refreshRateConfigs->getFrameRateOverrides(mFeatures.contentRequirements, + refreshRateConfigs->getFrameRateOverrides(mPolicy.contentRequirements, displayRefreshRate, consideredSignals); std::lock_guard lock(mFrameRateOverridesLock); if (!std::equal(mFrameRateOverridesByContent.begin(), mFrameRateOverridesByContent.end(), @@ -797,31 +723,30 @@ bool Scheduler::handleTimerStateChanged(T* currentState, T newState) { scheduler::RefreshRateConfigs::GlobalSignals consideredSignals; const auto refreshRateConfigs = holdRefreshRateConfigs(); { - std::lock_guard<std::mutex> lock(mFeatureStateLock); + std::lock_guard<std::mutex> lock(mPolicyLock); if (*currentState == newState) { return false; } *currentState = newState; newMode = calculateRefreshRateModeId(&consideredSignals); frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps()); - if (mFeatures.mode == newMode) { + if (mPolicy.mode == newMode) { // We don't need to change the display mode, but we might need to send an event // about a mode change, since it was suppressed due to a previous idleConsidered if (!consideredSignals.idle) { dispatchCachedReportedMode(); } } else { - mFeatures.mode = newMode; + mPolicy.mode = newMode; refreshRateChanged = true; } } if (refreshRateChanged) { - const RefreshRate& newRefreshRate = - refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); + const auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); mSchedulerCallback.changeRefreshRate(newRefreshRate, - consideredSignals.idle ? ModeEvent::None - : ModeEvent::Changed); + consideredSignals.idle ? DisplayModeEvent::None + : DisplayModeEvent::Changed); } if (frameRateOverridesChanged) { mSchedulerCallback.triggerOnFrameRateOverridesChanged(); @@ -838,27 +763,26 @@ DisplayModePtr Scheduler::calculateRefreshRateModeId( // If Display Power is not in normal operation we want to be in performance mode. When coming // back to normal mode, a grace period is given with DisplayPowerTimer. if (mDisplayPowerTimer && - (!mFeatures.isDisplayPowerStateNormal || - mFeatures.displayPowerTimer == TimerState::Reset)) { + (!mPolicy.isDisplayPowerStateNormal || mPolicy.displayPowerTimer == TimerState::Reset)) { return refreshRateConfigs->getMaxRefreshRateByPolicy().getMode(); } - const bool touchActive = mTouchTimer && mFeatures.touch == TouchState::Active; - const bool idle = mFeatures.idleTimer == TimerState::Expired; + const bool touchActive = mTouchTimer && mPolicy.touch == TouchState::Active; + const bool idle = mPolicy.idleTimer == TimerState::Expired; return refreshRateConfigs - ->getBestRefreshRate(mFeatures.contentRequirements, - {.touch = touchActive, .idle = idle}, consideredSignals) + ->getBestRefreshRate(mPolicy.contentRequirements, {.touch = touchActive, .idle = idle}, + consideredSignals) .getMode(); } DisplayModePtr Scheduler::getPreferredDisplayMode() { - std::lock_guard<std::mutex> lock(mFeatureStateLock); + std::lock_guard<std::mutex> lock(mPolicyLock); // Make sure that the default mode ID is first updated, before returned. - if (mFeatures.mode) { - mFeatures.mode = calculateRefreshRateModeId(); + if (mPolicy.mode) { + mPolicy.mode = calculateRefreshRateModeId(); } - return mFeatures.mode; + return mPolicy.mode; } void Scheduler::onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline) { @@ -915,8 +839,8 @@ void Scheduler::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverrid std::chrono::steady_clock::time_point Scheduler::getPreviousVsyncFrom( nsecs_t expectedPresentTime) const { const auto presentTime = std::chrono::nanoseconds(expectedPresentTime); - const auto vsyncPeriod = std::chrono::nanoseconds(mVsyncSchedule.tracker->currentPeriod()); + const auto vsyncPeriod = std::chrono::nanoseconds(mVsyncSchedule->getTracker().currentPeriod()); return std::chrono::steady_clock::time_point(presentTime - vsyncPeriod); } -} // namespace android +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 2a6de54e93..e127ff7371 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -31,40 +31,37 @@ #include <ui/GraphicTypes.h> #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" +#include <scheduler/Features.h> + #include "EventThread.h" #include "LayerHistory.h" #include "MessageQueue.h" #include "OneShotTimer.h" #include "RefreshRateConfigs.h" #include "SchedulerUtils.h" +#include "VsyncSchedule.h" namespace android { -using namespace std::chrono_literals; -using scheduler::LayerHistory; - class FenceTime; class InjectVSyncSource; -class PredictedVsyncTracer; - -namespace scheduler { -class VsyncController; -class VSyncDispatch; -class VSyncTracker; -} // namespace scheduler namespace frametimeline { class TokenManager; } // namespace frametimeline +namespace scheduler { + struct ISchedulerCallback { // Indicates frame activity, i.e. whether commit and/or composite is taking place. enum class FrameHint { kNone, kActive }; + using RefreshRate = RefreshRateConfigs::RefreshRate; + using DisplayModeEvent = scheduler::DisplayModeEvent; + virtual void scheduleComposite(FrameHint) = 0; virtual void setVsyncEnabled(bool) = 0; - virtual void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&, - scheduler::RefreshRateConfigEvent) = 0; + virtual void changeRefreshRate(const RefreshRate&, DisplayModeEvent) = 0; virtual void kernelTimerChanged(bool expired) = 0; virtual void triggerOnFrameRateOverridesChanged() = 0; @@ -76,18 +73,10 @@ class Scheduler : impl::MessageQueue { using Impl = impl::MessageQueue; public: - using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; - using ModeEvent = scheduler::RefreshRateConfigEvent; - - struct Options { - // Whether to use content detection at all. - bool useContentDetection; - }; - - Scheduler(ICompositor&, ISchedulerCallback&, Options); + Scheduler(ICompositor&, ISchedulerCallback&, FeatureFlags); ~Scheduler(); - void createVsyncSchedule(bool supportKernelIdleTimer); + void createVsyncSchedule(FeatureFlags); void startTimers(); void run(); @@ -107,7 +96,6 @@ public: return std::move(future); } - using ConnectionHandle = scheduler::ConnectionHandle; ConnectionHandle createConnection(const char* connectionName, frametimeline::TokenManager*, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration, @@ -119,7 +107,7 @@ public: sp<EventThreadConnection> getEventConnection(ConnectionHandle); void onHotplugReceived(ConnectionHandle, PhysicalDisplayId, bool connected); - void onPrimaryDisplayModeChanged(ConnectionHandle, DisplayModePtr) EXCLUDES(mFeatureStateLock); + void onPrimaryDisplayModeChanged(ConnectionHandle, DisplayModePtr) EXCLUDES(mPolicyLock); void onNonPrimaryDisplayModeChanged(ConnectionHandle, DisplayModePtr); void onScreenAcquired(ConnectionHandle); void onScreenReleased(ConnectionHandle); @@ -152,8 +140,7 @@ public: // VsyncController detected that the vsync period changed, and false otherwise. void addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod, bool* periodFlushed); - void addPresentFence(const std::shared_ptr<FenceTime>&); - void setIgnorePresentFences(bool ignore); + void addPresentFence(std::shared_ptr<FenceTime>); // Layers are registered on creation, and unregistered when the weak reference expires. void registerLayer(Layer*); @@ -172,7 +159,7 @@ public: void setDisplayPowerState(bool normal); - scheduler::VSyncDispatch& getVsyncDispatch() { return *mVsyncSchedule.dispatch; } + VSyncDispatch& getVsyncDispatch() { return mVsyncSchedule->getDispatch(); } // Returns true if a given vsync timestamp is considered valid vsync // for a given uid @@ -211,7 +198,7 @@ public: std::optional<Fps> getFrameRateOverride(uid_t uid) const EXCLUDES(mRefreshRateConfigsLock, mFrameRateOverridesLock); - void setRefreshRateConfigs(std::shared_ptr<scheduler::RefreshRateConfigs> refreshRateConfigs) + void setRefreshRateConfigs(std::shared_ptr<RefreshRateConfigs> refreshRateConfigs) EXCLUDES(mRefreshRateConfigsLock) { // We need to stop the idle timer on the previous RefreshRateConfigs instance // and cleanup the scheduler's state before we switch to the other RefreshRateConfigs. @@ -220,8 +207,8 @@ public: if (mRefreshRateConfigs) mRefreshRateConfigs->stopIdleTimer(); } { - std::scoped_lock lock(mFeatureStateLock); - mFeatures = {}; + std::scoped_lock lock(mPolicyLock); + mPolicy = {}; } { std::scoped_lock lock(mRefreshRateConfigsLock); @@ -251,18 +238,10 @@ private: using FrameHint = ISchedulerCallback::FrameHint; - // In order to make sure that the features don't override themselves, we need a state machine - // to keep track which feature requested the config change. enum class ContentDetectionState { Off, On }; enum class TimerState { Reset, Expired }; enum class TouchState { Inactive, Active }; - struct VsyncSchedule { - std::unique_ptr<scheduler::VsyncController> controller; - std::unique_ptr<scheduler::VSyncTracker> tracker; - std::unique_ptr<scheduler::VSyncDispatch> dispatch; - }; - // Create a connection on the given EventThread. ConnectionHandle createConnection(std::unique_ptr<EventThread>); sp<EventThreadConnection> createConnectionInternal( @@ -284,19 +263,17 @@ private: // selection were initialized, prioritizes them, and calculates the DisplayModeId // for the suggested refresh rate. DisplayModePtr calculateRefreshRateModeId( - scheduler::RefreshRateConfigs::GlobalSignals* consideredSignals = nullptr) - REQUIRES(mFeatureStateLock); + RefreshRateConfigs::GlobalSignals* consideredSignals = nullptr) REQUIRES(mPolicyLock); - void dispatchCachedReportedMode() REQUIRES(mFeatureStateLock) EXCLUDES(mRefreshRateConfigsLock); - bool updateFrameRateOverrides(scheduler::RefreshRateConfigs::GlobalSignals consideredSignals, - Fps displayRefreshRate) REQUIRES(mFeatureStateLock) - EXCLUDES(mFrameRateOverridesLock); + void dispatchCachedReportedMode() REQUIRES(mPolicyLock) EXCLUDES(mRefreshRateConfigsLock); + bool updateFrameRateOverrides(RefreshRateConfigs::GlobalSignals, Fps displayRefreshRate) + REQUIRES(mPolicyLock) EXCLUDES(mFrameRateOverridesLock); impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const EXCLUDES(mRefreshRateConfigsLock); impl::EventThread::GetVsyncPeriodFunction makeGetVsyncPeriodFunction() const; - std::shared_ptr<scheduler::RefreshRateConfigs> holdRefreshRateConfigs() const + std::shared_ptr<RefreshRateConfigs> holdRefreshRateConfigs() const EXCLUDES(mRefreshRateConfigsLock) { std::scoped_lock lock(mRefreshRateConfigsLock); return mRefreshRateConfigs; @@ -322,66 +299,63 @@ private: std::atomic<nsecs_t> mLastResyncTime = 0; - const Options mOptions; - VsyncSchedule mVsyncSchedule; + const FeatureFlags mFeatures; + std::optional<VsyncSchedule> mVsyncSchedule; // Used to choose refresh rate if content detection is enabled. LayerHistory mLayerHistory; // Timer used to monitor touch events. - std::optional<scheduler::OneShotTimer> mTouchTimer; + std::optional<OneShotTimer> mTouchTimer; // Timer used to monitor display power mode. - std::optional<scheduler::OneShotTimer> mDisplayPowerTimer; + std::optional<OneShotTimer> mDisplayPowerTimer; ISchedulerCallback& mSchedulerCallback; - // In order to make sure that the features don't override themselves, we need a state machine - // to keep track which feature requested the config change. - mutable std::mutex mFeatureStateLock; + mutable std::mutex mPolicyLock; struct { + // Policy for choosing the display mode. + LayerHistory::Summary contentRequirements; TimerState idleTimer = TimerState::Reset; TouchState touch = TouchState::Inactive; TimerState displayPowerTimer = TimerState::Expired; + bool isDisplayPowerStateNormal = true; + // Chosen display mode. DisplayModePtr mode; - LayerHistory::Summary contentRequirements; - - bool isDisplayPowerStateNormal = true; - // Used to cache the last parameters of onPrimaryDisplayModeChanged struct ModeChangedParams { ConnectionHandle handle; DisplayModePtr mode; }; + // Parameters for latest dispatch of mode change event. std::optional<ModeChangedParams> cachedModeChangedParams; - } mFeatures GUARDED_BY(mFeatureStateLock); + } mPolicy GUARDED_BY(mPolicyLock); mutable std::mutex mRefreshRateConfigsLock; - std::shared_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs - GUARDED_BY(mRefreshRateConfigsLock); + std::shared_ptr<RefreshRateConfigs> mRefreshRateConfigs GUARDED_BY(mRefreshRateConfigsLock); std::mutex mVsyncTimelineLock; std::optional<hal::VsyncPeriodChangeTimeline> mLastVsyncPeriodChangeTimeline GUARDED_BY(mVsyncTimelineLock); static constexpr std::chrono::nanoseconds MAX_VSYNC_APPLIED_TIME = 200ms; - std::unique_ptr<PredictedVsyncTracer> mPredictedVsyncTracer; - // The frame rate override lists need their own mutex as they are being read // by SurfaceFlinger, Scheduler and EventThread (as a callback) to prevent deadlocks mutable std::mutex mFrameRateOverridesLock; // mappings between a UID and a preferred refresh rate that this app would // run at. - scheduler::RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesByContent + RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesByContent GUARDED_BY(mFrameRateOverridesLock); - scheduler::RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesFromBackdoor + RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesFromBackdoor GUARDED_BY(mFrameRateOverridesLock); // Keeps track of whether the screen is acquired for debug std::atomic<bool> mScreenAcquired = false; }; +} // namespace scheduler } // namespace android diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp index ee973f718a..1c9de1c452 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp @@ -47,7 +47,7 @@ VSyncReactor::VSyncReactor(std::unique_ptr<Clock> clock, VSyncTracker& tracker, VSyncReactor::~VSyncReactor() = default; -bool VSyncReactor::addPresentFence(const std::shared_ptr<android::FenceTime>& fence) { +bool VSyncReactor::addPresentFence(std::shared_ptr<FenceTime> fence) { if (!fence) { return false; } @@ -80,7 +80,7 @@ bool VSyncReactor::addPresentFence(const std::shared_ptr<android::FenceTime>& fe if (mPendingLimit == mUnfiredFences.size()) { mUnfiredFences.erase(mUnfiredFences.begin()); } - mUnfiredFences.push_back(fence); + mUnfiredFences.push_back(std::move(fence)); } else { timestampAccepted &= mTracker.addVsyncTimestamp(signalTime); } diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h index 449d4c3bee..a9d536be28 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.h +++ b/services/surfaceflinger/Scheduler/VSyncReactor.h @@ -37,7 +37,7 @@ public: bool supportKernelIdleTimer); ~VSyncReactor(); - bool addPresentFence(const std::shared_ptr<android::FenceTime>& fence) final; + bool addPresentFence(std::shared_ptr<FenceTime>) final; void setIgnorePresentFences(bool ignore) final; void startPeriodTransition(nsecs_t period) final; diff --git a/services/surfaceflinger/Scheduler/VsyncController.h b/services/surfaceflinger/Scheduler/VsyncController.h index 0f0df222f4..59f65372a9 100644 --- a/services/surfaceflinger/Scheduler/VsyncController.h +++ b/services/surfaceflinger/Scheduler/VsyncController.h @@ -17,19 +17,15 @@ #pragma once #include <cstddef> +#include <memory> +#include <ui/FenceTime.h> #include <utils/Mutex.h> #include <utils/RefBase.h> #include <utils/Timers.h> -#include <ui/FenceTime.h> - -#include <memory> - namespace android::scheduler { -class FenceTime; - class VsyncController { public: virtual ~VsyncController(); @@ -43,7 +39,7 @@ public: * an accurate prediction, * False otherwise */ - virtual bool addPresentFence(const std::shared_ptr<android::FenceTime>&) = 0; + virtual bool addPresentFence(std::shared_ptr<FenceTime>) = 0; /* * Adds a hw sync timestamp to the model. The controller will use the timestamp diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp new file mode 100644 index 0000000000..77d1223aeb --- /dev/null +++ b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp @@ -0,0 +1,113 @@ +/* + * Copyright 2021 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. + */ + +#include <scheduler/Fps.h> + +#include "VsyncSchedule.h" + +#include "Timer.h" +#include "VSyncDispatchTimerQueue.h" +#include "VSyncPredictor.h" +#include "VSyncReactor.h" + +#include "../TracedOrdinal.h" + +namespace android::scheduler { + +class VsyncSchedule::PredictedVsyncTracer { + // Invoked from the thread of the VsyncDispatch owned by this VsyncSchedule. + constexpr auto makeVsyncCallback() { + return [this](nsecs_t, nsecs_t, nsecs_t) { + mParity = !mParity; + schedule(); + }; + } + +public: + explicit PredictedVsyncTracer(VsyncDispatch& dispatch) + : mRegistration(dispatch, makeVsyncCallback(), __func__) { + schedule(); + } + +private: + void schedule() { mRegistration.schedule({0, 0, 0}); } + + TracedOrdinal<bool> mParity = {"VSYNC-predicted", 0}; + VSyncCallbackRegistration mRegistration; +}; + +VsyncSchedule::VsyncSchedule(FeatureFlags features) + : mTracker(createTracker()), + mDispatch(createDispatch(*mTracker)), + mController(createController(*mTracker, features)) { + if (features.test(Feature::kTracePredictedVsync)) { + mTracer = std::make_unique<PredictedVsyncTracer>(*mDispatch); + } +} + +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; + +void VsyncSchedule::dump(std::string& out) const { + out.append("VsyncController:\n"); + mController->dump(out); + + out.append("VsyncDispatch:\n"); + mDispatch->dump(out); +} + +VsyncSchedule::TrackerPtr VsyncSchedule::createTracker() { + // TODO(b/144707443): Tune constants. + constexpr nsecs_t kInitialPeriod = (60_Hz).getPeriodNsecs(); + constexpr size_t kHistorySize = 20; + constexpr size_t kMinSamplesForPrediction = 6; + constexpr uint32_t kDiscardOutlierPercent = 20; + + return std::make_unique<VSyncPredictor>(kInitialPeriod, kHistorySize, kMinSamplesForPrediction, + kDiscardOutlierPercent); +} + +VsyncSchedule::DispatchPtr VsyncSchedule::createDispatch(VsyncTracker& tracker) { + using namespace std::chrono_literals; + + // TODO(b/144707443): Tune constants. + constexpr std::chrono::nanoseconds kGroupDispatchWithin = 500us; + constexpr std::chrono::nanoseconds kSnapToSameVsyncWithin = 3ms; + + return std::make_unique<VSyncDispatchTimerQueue>(std::make_unique<Timer>(), tracker, + kGroupDispatchWithin.count(), + kSnapToSameVsyncWithin.count()); +} + +VsyncSchedule::ControllerPtr VsyncSchedule::createController(VsyncTracker& tracker, + FeatureFlags features) { + // TODO(b/144707443): Tune constants. + constexpr size_t kMaxPendingFences = 20; + const bool hasKernelIdleTimer = features.test(Feature::kKernelIdleTimer); + + auto reactor = std::make_unique<VSyncReactor>(std::make_unique<SystemClock>(), tracker, + kMaxPendingFences, hasKernelIdleTimer); + + reactor->setIgnorePresentFences(!features.test(Feature::kPresentFences)); + return reactor; +} + +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.h b/services/surfaceflinger/Scheduler/VsyncSchedule.h new file mode 100644 index 0000000000..0d9b114875 --- /dev/null +++ b/services/surfaceflinger/Scheduler/VsyncSchedule.h @@ -0,0 +1,75 @@ +/* + * Copyright 2021 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 <memory> +#include <string> + +#include <scheduler/Features.h> + +namespace android::scheduler { + +// TODO(b/185535769): Rename classes, and remove aliases. +class VSyncDispatch; +class VSyncTracker; + +class VsyncController; +using VsyncDispatch = VSyncDispatch; +using VsyncTracker = VSyncTracker; + +// Schedule that synchronizes to hardware VSYNC of a physical display. +class VsyncSchedule { +public: + explicit VsyncSchedule(FeatureFlags); + VsyncSchedule(VsyncSchedule&&); + ~VsyncSchedule(); + + // TODO(b/185535769): Hide behind API. + const VsyncTracker& getTracker() const { return *mTracker; } + VsyncTracker& getTracker() { return *mTracker; } + VsyncController& getController() { return *mController; } + + // TODO(b/185535769): Remove once VsyncSchedule owns all registrations. + VsyncDispatch& getDispatch() { return *mDispatch; } + + void dump(std::string&) const; + +private: + friend class TestableScheduler; + + using TrackerPtr = std::unique_ptr<VsyncTracker>; + using DispatchPtr = std::unique_ptr<VsyncDispatch>; + using ControllerPtr = std::unique_ptr<VsyncController>; + + // For tests. + VsyncSchedule(TrackerPtr, DispatchPtr, ControllerPtr); + + static TrackerPtr createTracker(); + static DispatchPtr createDispatch(VsyncTracker&); + static ControllerPtr createController(VsyncTracker&, FeatureFlags); + + class PredictedVsyncTracer; + using TracerPtr = std::unique_ptr<PredictedVsyncTracer>; + + // Effectively const except in move constructor. + TrackerPtr mTracker; + DispatchPtr mDispatch; + ControllerPtr mController; + TracerPtr mTracer; +}; + +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Features.h b/services/surfaceflinger/Scheduler/include/scheduler/Features.h new file mode 100644 index 0000000000..0e96678420 --- /dev/null +++ b/services/surfaceflinger/Scheduler/include/scheduler/Features.h @@ -0,0 +1,34 @@ +/* + * Copyright 2021 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 <ftl/Flags.h> + +#include <cstdint> + +namespace android::scheduler { + +enum class Feature : std::uint8_t { + kPresentFences = 0b1, + kKernelIdleTimer = 0b10, + kContentDetection = 0b100, + kTracePredictedVsync = 0b1000, +}; + +using FeatureFlags = Flags<Feature>; + +} // namespace android::scheduler diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e497d95306..3860901edb 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1200,7 +1200,7 @@ void SurfaceFlinger::updateInternalStateWithChangedMode() { mRefreshRateStats->setRefreshRate(refreshRate); updatePhaseConfiguration(refreshRate); - if (upcomingModeInfo.event != Scheduler::ModeEvent::None) { + if (upcomingModeInfo.event != DisplayModeEvent::None) { mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, upcomingModeInfo.mode); } } @@ -3099,7 +3099,7 @@ void SurfaceFlinger::updateCursorAsync() { mCompositionEngine->updateCursorAsync(refreshArgs); } -void SurfaceFlinger::changeRefreshRate(const RefreshRate& refreshRate, Scheduler::ModeEvent event) { +void SurfaceFlinger::changeRefreshRate(const RefreshRate& refreshRate, DisplayModeEvent event) { // If this is called from the main thread mStateLock must be locked before // Currently the only way to call this function from the main thread is from // Scheduler::chooseRefreshRateForContent @@ -3147,17 +3147,32 @@ void SurfaceFlinger::initScheduler(const sp<DisplayDevice>& display) { mVsyncConfiguration = getFactory().createVsyncConfiguration(currRefreshRate); mVsyncModulator = sp<VsyncModulator>::make(mVsyncConfiguration->getCurrentConfigs()); - const Scheduler::Options options = { - .useContentDetection = sysprop::use_content_detection_for_refresh_rate(false)}; + using Feature = scheduler::Feature; + scheduler::FeatureFlags features; - mScheduler = std::make_unique<Scheduler>(static_cast<ICompositor&>(*this), - static_cast<ISchedulerCallback&>(*this), options); + if (sysprop::use_content_detection_for_refresh_rate(false)) { + features |= Feature::kContentDetection; + } + if (base::GetBoolProperty("debug.sf.show_predicted_vsync"s, false)) { + features |= Feature::kTracePredictedVsync; + } + if (!base::GetBoolProperty("debug.sf.vsync_reactor_ignore_present_fences"s, false) && + !getHwComposer().hasCapability(hal::Capability::PRESENT_FENCE_IS_NOT_RELIABLE)) { + features |= Feature::kPresentFences; + } + + mScheduler = std::make_unique<scheduler::Scheduler>(static_cast<ICompositor&>(*this), + static_cast<ISchedulerCallback&>(*this), + features); { auto configs = display->holdRefreshRateConfigs(); - mScheduler->createVsyncSchedule(configs->supportsKernelIdleTimer()); + if (configs->supportsKernelIdleTimer()) { + features |= Feature::kKernelIdleTimer; + } + + mScheduler->createVsyncSchedule(features); mScheduler->setRefreshRateConfigs(std::move(configs)); } - setVsyncEnabled(false); mScheduler->startTimers(); @@ -3190,11 +3205,6 @@ void SurfaceFlinger::initScheduler(const sp<DisplayDevice>& display) { // classes from EventThread, and there should be no run-time binder cost // anyway since there are no connected apps at this point. mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, display->getActiveMode()); - static auto ignorePresentFences = - base::GetBoolProperty("debug.sf.vsync_reactor_ignore_present_fences"s, false); - mScheduler->setIgnorePresentFences( - ignorePresentFences || - getHwComposer().hasCapability(hal::Capability::PRESENT_FENCE_IS_NOT_RELIABLE)); } void SurfaceFlinger::updatePhaseConfiguration(const Fps& refreshRate) { @@ -3818,10 +3828,11 @@ bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin clientStateFlags |= setClientStateLocked(frameTimelineInfo, state, desiredPresentTime, isAutoTimestamp, postTime, permissions); if ((flags & eAnimation) && state.state.surface) { - if (const auto layer = fromHandle(state.state.surface).promote(); layer) { + if (const auto layer = fromHandle(state.state.surface).promote()) { + using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType; mScheduler->recordLayerHistory(layer.get(), isAutoTimestamp ? 0 : desiredPresentTime, - LayerHistory::LayerUpdateType::AnimationTX); + LayerUpdateType::AnimationTX); } } } @@ -6478,7 +6489,7 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( if (display->refreshRateConfigs().isModeAllowed(preferredDisplayMode->getId())) { ALOGV("switching to Scheduler preferred display mode %d", preferredDisplayMode->getId().value()); - setDesiredActiveMode({preferredDisplayMode, Scheduler::ModeEvent::Changed}); + setDesiredActiveMode({preferredDisplayMode, DisplayModeEvent::Changed}); } else { LOG_ALWAYS_FATAL("Desired display mode not allowed: %d", preferredDisplayMode->getId().value()); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 05c058b9af..eb934b6b16 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -165,7 +165,7 @@ class SurfaceFlinger : public BnSurfaceComposer, private IBinder::DeathRecipient, private HWC2::ComposerCallback, private ICompositor, - private ISchedulerCallback { + private scheduler::ISchedulerCallback { public: struct SkipInitializationTag {}; @@ -356,7 +356,6 @@ private: friend class TransactionApplicationTest; friend class TunnelModeEnabledReporterTest; - using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; using VsyncModulator = scheduler::VsyncModulator; using TransactionSchedule = scheduler::TransactionSchedule; using TraverseLayersFunction = std::function<void(const LayerVector::Visitor&)>; @@ -643,7 +642,7 @@ private: // Toggles hardware VSYNC by calling into HWC. void setVsyncEnabled(bool) override; // Initiates a refresh rate change to be applied on commit. - void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ModeEvent) override; + void changeRefreshRate(const RefreshRate&, DisplayModeEvent) override; // Called when kernel idle timer has expired. Used to update the refresh rate overlay. void kernelTimerChanged(bool expired) override; // Called when the frame rate override list changed to trigger an event. @@ -1261,7 +1260,7 @@ private: /* * Scheduler */ - std::unique_ptr<Scheduler> mScheduler; + std::unique_ptr<scheduler::Scheduler> mScheduler; scheduler::ConnectionHandle mAppConnectionHandle; scheduler::ConnectionHandle mSfConnectionHandle; diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h index e509cc9385..6153e8e354 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.h +++ b/services/surfaceflinger/SurfaceFlingerFactory.h @@ -42,16 +42,12 @@ class HWComposer; class IGraphicBufferConsumer; class IGraphicBufferProducer; class Layer; -class MessageQueue; -class Scheduler; class StartPropertySetThread; class SurfaceFlinger; class SurfaceInterceptor; class TimeStats; struct DisplayDeviceCreationArgs; -struct ICompositor; -struct ISchedulerCallback; struct LayerCreationArgs; namespace compositionengine { diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 8d2c078305..eb5f31e796 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -138,7 +138,7 @@ public: .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - constexpr ISchedulerCallback* kCallback = nullptr; + constexpr scheduler::ISchedulerCallback* kCallback = nullptr; constexpr bool kHasMultipleConfigs = true; mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), std::move(eventThread), std::move(sfEventThread), kCallback, diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp index d4cfbbbe0c..5a0033ea7e 100644 --- a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp @@ -29,7 +29,7 @@ using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjec class InitiateModeChangeTest : public DisplayTransactionTest { public: - using Event = scheduler::RefreshRateConfigEvent; + using Event = scheduler::DisplayModeEvent; void SetUp() override { injectFakeBufferQueueFactory(); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index de5e9dfb97..0a3437aab9 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -121,7 +121,7 @@ public: mock::VsyncController* mVsyncController = new mock::VsyncController; mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker; - mock::SchedulerCallback mSchedulerCallback; + scheduler::mock::SchedulerCallback mSchedulerCallback; mock::EventThread* mEventThread = new mock::EventThread; mock::EventThread* mSFEventThread = new mock::EventThread; diff --git a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp index cd2fc7426e..bb1f4328b5 100644 --- a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp +++ b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp @@ -17,6 +17,8 @@ #undef LOG_TAG #define LOG_TAG "FpsReporterTest" +#include <chrono> + #include <android/gui/BnFpsListener.h> #include <gmock/gmock.h> #include <gtest/gtest.h> @@ -36,6 +38,8 @@ namespace android { +using namespace std::chrono_literals; + using testing::_; using testing::DoAll; using testing::Mock; diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index 4993a2d8bc..00687ad4b6 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -38,9 +38,9 @@ using testing::_; using testing::Return; using testing::ReturnRef; -namespace android { +namespace android::scheduler { -namespace scheduler { +using MockLayer = android::mock::MockLayer; class LayerHistoryTest : public testing::Test { protected: @@ -93,12 +93,12 @@ protected: } } - auto createLayer() { return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger())); } + auto createLayer() { return sp<MockLayer>::make(mFlinger.flinger()); } auto createLayer(std::string name) { - return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger(), std::move(name))); + return sp<MockLayer>::make(mFlinger.flinger(), std::move(name)); } - void recordFramesAndExpect(const sp<mock::MockLayer>& layer, nsecs_t& time, Fps frameRate, + void recordFramesAndExpect(const sp<MockLayer>& layer, nsecs_t& time, Fps frameRate, Fps desiredRefreshRate, int numFrames) { LayerHistory::Summary summary; for (int i = 0; i < numFrames; i++) { @@ -768,8 +768,7 @@ INSTANTIATE_TEST_CASE_P(LeapYearTests, LayerHistoryTestParameterized, ::testing::Values(1s, 2s, 3s, 4s, 5s)); } // namespace -} // namespace scheduler -} // namespace android +} // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wextra" diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index e558f3b700..a6fd378d3d 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -28,12 +28,16 @@ #include "mock/MockLayer.h" #include "mock/MockSchedulerCallback.h" +namespace android::scheduler { + using testing::_; using testing::Return; -namespace android { namespace { +using MockEventThread = android::mock::EventThread; +using MockLayer = android::mock::MockLayer; + constexpr PhysicalDisplayId PHYSICAL_DISPLAY_ID = PhysicalDisplayId::fromPort(255u); class SchedulerTest : public testing::Test { @@ -64,21 +68,21 @@ protected: .setGroup(0) .build(); - std::shared_ptr<scheduler::RefreshRateConfigs> mConfigs = - std::make_shared<scheduler::RefreshRateConfigs>(DisplayModes{mode60}, mode60->getId()); + std::shared_ptr<RefreshRateConfigs> mConfigs = + std::make_shared<RefreshRateConfigs>(DisplayModes{mode60}, mode60->getId()); mock::SchedulerCallback mSchedulerCallback; TestableScheduler* mScheduler = new TestableScheduler{mConfigs, mSchedulerCallback}; - Scheduler::ConnectionHandle mConnectionHandle; - mock::EventThread* mEventThread; + ConnectionHandle mConnectionHandle; + MockEventThread* mEventThread; sp<MockEventThreadConnection> mEventThreadConnection; TestableSurfaceFlinger mFlinger; }; SchedulerTest::SchedulerTest() { - auto eventThread = std::make_unique<mock::EventThread>(); + auto eventThread = std::make_unique<MockEventThread>(); mEventThread = eventThread.get(); EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)).WillOnce(Return(0)); @@ -98,7 +102,7 @@ SchedulerTest::SchedulerTest() { } // namespace TEST_F(SchedulerTest, invalidConnectionHandle) { - Scheduler::ConnectionHandle handle; + ConnectionHandle handle; const sp<IDisplayEventConnection> connection = mScheduler->createDisplayEventConnection(handle); @@ -155,7 +159,7 @@ TEST_F(SchedulerTest, validConnectionHandle) { TEST_F(SchedulerTest, chooseRefreshRateForContentIsNoopWhenModeSwitchingIsNotSupported) { // The layer is registered at creation time and deregistered at destruction time. - sp<mock::MockLayer> layer = sp<mock::MockLayer>::make(mFlinger.flinger()); + sp<MockLayer> layer = sp<MockLayer>::make(mFlinger.flinger()); // recordLayerHistory should be a noop ASSERT_EQ(0u, mScheduler->getNumActiveLayers()); @@ -174,24 +178,22 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentIsNoopWhenModeSwitchingIsNotSup TEST_F(SchedulerTest, updateDisplayModes) { ASSERT_EQ(0u, mScheduler->layerHistorySize()); - sp<mock::MockLayer> layer = sp<mock::MockLayer>::make(mFlinger.flinger()); + sp<MockLayer> layer = sp<MockLayer>::make(mFlinger.flinger()); ASSERT_EQ(1u, mScheduler->layerHistorySize()); mScheduler->setRefreshRateConfigs( - std::make_shared<scheduler::RefreshRateConfigs>(DisplayModes{mode60, mode120}, - mode60->getId())); + std::make_shared<RefreshRateConfigs>(DisplayModes{mode60, mode120}, mode60->getId())); ASSERT_EQ(0u, mScheduler->getNumActiveLayers()); mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer); ASSERT_EQ(1u, mScheduler->getNumActiveLayers()); } -TEST_F(SchedulerTest, testDispatchCachedReportedMode) { - // If the optional fields are cleared, the function should return before - // onModeChange is called. - mScheduler->clearOptionalFieldsInFeatures(); - EXPECT_NO_FATAL_FAILURE(mScheduler->dispatchCachedReportedMode()); +TEST_F(SchedulerTest, dispatchCachedReportedMode) { + mScheduler->clearCachedReportedMode(); + EXPECT_CALL(*mEventThread, onModeChanged(_)).Times(0); + EXPECT_NO_FATAL_FAILURE(mScheduler->dispatchCachedReportedMode()); } TEST_F(SchedulerTest, onNonPrimaryDisplayModeChanged_invalidParameters) { @@ -203,7 +205,7 @@ TEST_F(SchedulerTest, onNonPrimaryDisplayModeChanged_invalidParameters) { // If the handle is incorrect, the function should return before // onModeChange is called. - Scheduler::ConnectionHandle invalidHandle = {.id = 123}; + ConnectionHandle invalidHandle = {.id = 123}; EXPECT_NO_FATAL_FAILURE(mScheduler->onNonPrimaryDisplayModeChanged(invalidHandle, mode)); EXPECT_CALL(*mEventThread, onModeChanged(_)).Times(0); } @@ -224,10 +226,9 @@ MATCHER(Is120Hz, "") { TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { mScheduler->setRefreshRateConfigs( - std::make_shared<scheduler::RefreshRateConfigs>(DisplayModes{mode60, mode120}, - mode60->getId())); + std::make_shared<RefreshRateConfigs>(DisplayModes{mode60, mode120}, mode60->getId())); - sp<mock::MockLayer> layer = sp<mock::MockLayer>::make(mFlinger.flinger()); + sp<MockLayer> layer = sp<MockLayer>::make(mFlinger.flinger()); mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer); @@ -241,4 +242,4 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { mScheduler->chooseRefreshRateForContent(); } -} // namespace android +} // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index eed62a70c3..fe5f9e0717 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -48,6 +48,8 @@ using android::Hwc2::IComposerClient; using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; +using scheduler::LayerHistory; + using FrameRate = Layer::FrameRate; using FrameRateCompatibility = Layer::FrameRateCompatibility; diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp index 69e0501bd6..ec7e8a7f82 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp @@ -17,6 +17,9 @@ #undef LOG_TAG #define LOG_TAG "LibSurfaceFlingerUnittests" +#include <chrono> +#include <thread> + #include "DisplayTransactionTestHelpers.h" #include <android/hardware/power/Boost.h> @@ -27,6 +30,8 @@ namespace { using android::hardware::power::Boost; TEST_F(DisplayTransactionTest, notifyPowerBoostNotifiesTouchEvent) { + using namespace std::chrono_literals; + mFlinger.scheduler()->replaceTouchTimer(100); std::this_thread::sleep_for(10ms); // wait for callback to be triggered EXPECT_TRUE(mFlinger.scheduler()->isTouchActive()); // Starting timer activates touch @@ -47,4 +52,4 @@ TEST_F(DisplayTransactionTest, notifyPowerBoostNotifiesTouchEvent) { } } // namespace -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index 9d1fc981aa..dabd2d2cc2 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -28,22 +28,20 @@ #include "mock/MockVSyncTracker.h" #include "mock/MockVsyncController.h" -namespace android { +namespace android::scheduler { class TestableScheduler : public Scheduler, private ICompositor { public: - TestableScheduler(std::shared_ptr<scheduler::RefreshRateConfigs> configs, - ISchedulerCallback& callback) + TestableScheduler(std::shared_ptr<RefreshRateConfigs> configs, ISchedulerCallback& callback) : TestableScheduler(std::make_unique<mock::VsyncController>(), std::make_unique<mock::VSyncTracker>(), std::move(configs), callback) {} - TestableScheduler(std::unique_ptr<scheduler::VsyncController> vsyncController, - std::unique_ptr<scheduler::VSyncTracker> vsyncTracker, - std::shared_ptr<scheduler::RefreshRateConfigs> configs, - ISchedulerCallback& callback) - : Scheduler(*this, callback, {.useContentDetection = true}) { - mVsyncSchedule = {std::move(vsyncController), std::move(vsyncTracker), nullptr}; + TestableScheduler(std::unique_ptr<VsyncController> controller, + std::unique_ptr<VSyncTracker> tracker, + std::shared_ptr<RefreshRateConfigs> configs, ISchedulerCallback& callback) + : Scheduler(*this, callback, Feature::kContentDetection) { + mVsyncSchedule.emplace(VsyncSchedule(std::move(tracker), nullptr, std::move(controller))); setRefreshRateConfigs(std::move(configs)); ON_CALL(*this, postMessage).WillByDefault([](sp<MessageHandler>&& handler) { @@ -86,33 +84,24 @@ public: } bool isTouchActive() { - std::lock_guard<std::mutex> lock(mFeatureStateLock); - return mFeatures.touch == Scheduler::TouchState::Active; + std::lock_guard<std::mutex> lock(mPolicyLock); + return mPolicy.touch == Scheduler::TouchState::Active; } void dispatchCachedReportedMode() { - std::lock_guard<std::mutex> lock(mFeatureStateLock); + std::lock_guard<std::mutex> lock(mPolicyLock); return Scheduler::dispatchCachedReportedMode(); } - void clearOptionalFieldsInFeatures() { - std::lock_guard<std::mutex> lock(mFeatureStateLock); - mFeatures.cachedModeChangedParams.reset(); + void clearCachedReportedMode() { + std::lock_guard<std::mutex> lock(mPolicyLock); + mPolicy.cachedModeChangedParams.reset(); } void onNonPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) { return Scheduler::onNonPrimaryDisplayModeChanged(handle, mode); } - ~TestableScheduler() { - // All these pointer and container clears help ensure that GMock does - // not report a leaked object, since the Scheduler instance may - // still be referenced by something despite our best efforts to destroy - // it after each test is done. - mVsyncSchedule.controller.reset(); - mConnections.clear(); - } - private: // ICompositor overrides: bool commit(nsecs_t, int64_t, nsecs_t) override { return false; } @@ -120,4 +109,4 @@ private: void sample() override {} }; -} // namespace android +} // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 4c5789e47f..4473e01c2b 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -169,12 +169,12 @@ public: } // namespace surfaceflinger::test -class TestableSurfaceFlinger final : private ISchedulerCallback { +class TestableSurfaceFlinger final : private scheduler::ISchedulerCallback { public: using HotplugEvent = SurfaceFlinger::HotplugEvent; SurfaceFlinger* flinger() { return mFlinger.get(); } - TestableScheduler* scheduler() { return mScheduler; } + scheduler::TestableScheduler* scheduler() { return mScheduler; } // Extend this as needed for accessing SurfaceFlinger private (and public) // functions. @@ -197,7 +197,8 @@ public: std::unique_ptr<scheduler::VSyncTracker> vsyncTracker, std::unique_ptr<EventThread> appEventThread, std::unique_ptr<EventThread> sfEventThread, - ISchedulerCallback* callback = nullptr, bool hasMultipleModes = false) { + scheduler::ISchedulerCallback* callback = nullptr, + bool hasMultipleModes = false) { DisplayModes modes{DisplayMode::Builder(0) .setId(DisplayModeId(0)) .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0)) @@ -224,17 +225,18 @@ public: std::make_unique<scheduler::RefreshRateStats>(*mFlinger->mTimeStats, currFps, /*powerMode=*/hal::PowerMode::OFF); - mScheduler = new TestableScheduler(std::move(vsyncController), std::move(vsyncTracker), - mRefreshRateConfigs, *(callback ?: this)); + mScheduler = new scheduler::TestableScheduler(std::move(vsyncController), + std::move(vsyncTracker), mRefreshRateConfigs, + *(callback ?: this)); mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread)); mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread)); resetScheduler(mScheduler); } - void resetScheduler(Scheduler* scheduler) { mFlinger->mScheduler.reset(scheduler); } + void resetScheduler(scheduler::Scheduler* scheduler) { mFlinger->mScheduler.reset(scheduler); } - TestableScheduler& mutableScheduler() const { return *mScheduler; } + scheduler::TestableScheduler& mutableScheduler() const { return *mScheduler; } using CreateBufferQueueFunction = surfaceflinger::test::Factory::CreateBufferQueueFunction; void setCreateBufferQueueFunction(CreateBufferQueueFunction f) { @@ -759,13 +761,13 @@ public: private: void scheduleComposite(FrameHint) override {} void setVsyncEnabled(bool) override {} - void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ModeEvent) override {} + void changeRefreshRate(const RefreshRate&, DisplayModeEvent) override {} void kernelTimerChanged(bool) override {} void triggerOnFrameRateOverridesChanged() {} surfaceflinger::test::Factory mFactory; sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization); - TestableScheduler* mScheduler = nullptr; + scheduler::TestableScheduler* mScheduler = nullptr; std::shared_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs; }; diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index ec19100c2b..16d4b59250 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -26,7 +26,7 @@ #include <log/log.h> #include <ui/MockFence.h> #include <utils/String8.h> -#include "TestableScheduler.h" + #include "TestableSurfaceFlinger.h" #include "mock/MockEventThread.h" #include "mock/MockVsyncController.h" @@ -85,11 +85,8 @@ public: std::move(eventThread), std::move(sfEventThread)); } - TestableScheduler* mScheduler; TestableSurfaceFlinger mFlinger; - std::unique_ptr<mock::EventThread> mEventThread = std::make_unique<mock::EventThread>(); - mock::VsyncController* mVsyncController = new mock::VsyncController(); mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker(); mock::MockFence* mFenceUnsignaled = new mock::MockFence(); diff --git a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h index e241dc903f..849e3083c4 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h +++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h @@ -20,25 +20,22 @@ #include "Scheduler/Scheduler.h" -namespace android::mock { +namespace android::scheduler::mock { struct SchedulerCallback final : ISchedulerCallback { MOCK_METHOD(void, scheduleComposite, (FrameHint), (override)); - MOCK_METHOD1(setVsyncEnabled, void(bool)); - MOCK_METHOD2(changeRefreshRate, - void(const scheduler::RefreshRateConfigs::RefreshRate&, - scheduler::RefreshRateConfigEvent)); - MOCK_METHOD1(kernelTimerChanged, void(bool)); - MOCK_METHOD0(triggerOnFrameRateOverridesChanged, void()); + MOCK_METHOD(void, setVsyncEnabled, (bool), (override)); + MOCK_METHOD(void, changeRefreshRate, (const RefreshRate&, DisplayModeEvent), (override)); + MOCK_METHOD(void, kernelTimerChanged, (bool), (override)); + MOCK_METHOD(void, triggerOnFrameRateOverridesChanged, (), (override)); }; struct NoOpSchedulerCallback final : ISchedulerCallback { void scheduleComposite(FrameHint) override {} void setVsyncEnabled(bool) override {} - void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&, - scheduler::RefreshRateConfigEvent) override {} + void changeRefreshRate(const RefreshRate&, DisplayModeEvent) override {} void kernelTimerChanged(bool) override {} void triggerOnFrameRateOverridesChanged() {} }; -} // namespace android::mock +} // namespace android::scheduler::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h b/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h index 94d99665ce..314f681545 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h +++ b/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h @@ -27,7 +27,7 @@ public: VsyncController(); ~VsyncController() override; - MOCK_METHOD1(addPresentFence, bool(const std::shared_ptr<FenceTime>&)); + MOCK_METHOD(bool, addPresentFence, (std::shared_ptr<FenceTime>), (override)); MOCK_METHOD3(addHwVsyncTimestamp, bool(nsecs_t, std::optional<nsecs_t>, bool*)); MOCK_METHOD1(startPeriodTransition, void(nsecs_t)); MOCK_METHOD1(setIgnorePresentFences, void(bool)); |