SF: add render frame rate to the scheduler
Schedule SF at the rate of the render frame rate instead of
the display refresh rate.
Test: SF unit tests
Bug: 257072060
Change-Id: Idaf9be5f25373d38c0ef6440f9f401dc90de7a91
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index fd1a733..4be1ac7 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -213,7 +213,7 @@
std::vector<FrameRateMode> frameRateModes;
frameRateModes.reserve(ratesMap.size());
for (const auto& [key, mode] : ratesMap) {
- frameRateModes.emplace_back(FrameRateMode{key.fps, mode->second});
+ frameRateModes.emplace_back(FrameRateMode{key.fps, ftl::as_non_null(mode->second)});
}
// We always want that the lowest frame rate will be corresponding to the
@@ -409,7 +409,7 @@
ATRACE_CALL();
ALOGV("%s: %zu layers", __func__, layers.size());
- const auto& activeMode = *getActiveModeItLocked()->second;
+ const auto& activeMode = *getActiveModeLocked().modePtr;
// Keep the display at max frame rate for the duration of powering on the display.
if (signals.powerOnImminent) {
@@ -842,7 +842,7 @@
const DisplayModePtr& current = desiredActiveModeId
? mDisplayModes.get(*desiredActiveModeId)->get()
- : getActiveModeItLocked()->second;
+ : getActiveModeLocked().modePtr.get();
const DisplayModePtr& min = mMinRefreshRateModeIt->second;
if (current == min) {
@@ -854,11 +854,11 @@
}
const DisplayModePtr& RefreshRateSelector::getMinRefreshRateByPolicyLocked() const {
- const auto& activeMode = *getActiveModeItLocked()->second;
+ const auto& activeMode = *getActiveModeLocked().modePtr;
for (const FrameRateMode& mode : mPrimaryFrameRates) {
if (activeMode.getGroup() == mode.modePtr->getGroup()) {
- return mode.modePtr;
+ return mode.modePtr.get();
}
}
@@ -866,12 +866,12 @@
to_string(activeMode).c_str());
// Default to the lowest refresh rate.
- return mPrimaryFrameRates.front().modePtr;
+ return mPrimaryFrameRates.front().modePtr.get();
}
const DisplayModePtr& RefreshRateSelector::getMaxRefreshRateByPolicyLocked(int anchorGroup) const {
- const DisplayModePtr* maxByAnchor = &mPrimaryFrameRates.back().modePtr;
- const DisplayModePtr* max = &mPrimaryFrameRates.back().modePtr;
+ const ftl::NonNull<DisplayModePtr>* maxByAnchor = &mPrimaryFrameRates.back().modePtr;
+ const ftl::NonNull<DisplayModePtr>* max = &mPrimaryFrameRates.back().modePtr;
bool maxByAnchorFound = false;
for (auto it = mPrimaryFrameRates.rbegin(); it != mPrimaryFrameRates.rend(); ++it) {
@@ -888,13 +888,13 @@
}
if (maxByAnchorFound) {
- return *maxByAnchor;
+ return maxByAnchor->get();
}
ALOGE("Can't find max refresh rate by policy with the same group %d", anchorGroup);
// Default to the highest refresh rate.
- return *max;
+ return max->get();
}
auto RefreshRateSelector::rankFrameRates(std::optional<int> anchorGroupOpt,
@@ -946,31 +946,26 @@
return rankFrameRates(kNoAnchorGroup, refreshRateOrder, preferredDisplayModeOpt);
}
-DisplayModePtr RefreshRateSelector::getActiveModePtr() const {
+FrameRateMode RefreshRateSelector::getActiveMode() const {
std::lock_guard lock(mLock);
- return getActiveModeItLocked()->second;
+ return getActiveModeLocked();
}
-const DisplayMode& RefreshRateSelector::getActiveMode() const {
- // Reads from kMainThreadContext do not require mLock.
- ftl::FakeGuard guard(mLock);
- return *mActiveModeIt->second;
+const FrameRateMode& RefreshRateSelector::getActiveModeLocked() const {
+ return *mActiveModeOpt;
}
-DisplayModeIterator RefreshRateSelector::getActiveModeItLocked() const {
- // Reads under mLock do not require kMainThreadContext.
- return FTL_FAKE_GUARD(kMainThreadContext, mActiveModeIt);
-}
-
-void RefreshRateSelector::setActiveModeId(DisplayModeId modeId) {
+void RefreshRateSelector::setActiveMode(DisplayModeId modeId, Fps renderFrameRate) {
std::lock_guard lock(mLock);
// Invalidate the cached invocation to getRankedFrameRates. This forces
// the refresh rate to be recomputed on the next call to getRankedFrameRates.
mGetRankedFrameRatesCache.reset();
- mActiveModeIt = mDisplayModes.find(modeId);
- LOG_ALWAYS_FATAL_IF(mActiveModeIt == mDisplayModes.end());
+ const auto activeModeOpt = mDisplayModes.get(modeId);
+ LOG_ALWAYS_FATAL_IF(!activeModeOpt);
+
+ mActiveModeOpt.emplace(FrameRateMode{renderFrameRate, ftl::as_non_null(activeModeOpt->get())});
}
RefreshRateSelector::RefreshRateSelector(DisplayModes modes, DisplayModeId activeModeId,
@@ -1007,8 +1002,10 @@
mGetRankedFrameRatesCache.reset();
mDisplayModes = std::move(modes);
- mActiveModeIt = mDisplayModes.find(activeModeId);
- LOG_ALWAYS_FATAL_IF(mActiveModeIt == mDisplayModes.end());
+ const auto activeModeOpt = mDisplayModes.get(activeModeId);
+ LOG_ALWAYS_FATAL_IF(!activeModeOpt);
+ mActiveModeOpt =
+ FrameRateMode{activeModeOpt->get()->getFps(), ftl::as_non_null(activeModeOpt->get())};
const auto sortedModes = sortByRefreshRate(mDisplayModes);
mMinRefreshRateModeIt = sortedModes.front();
@@ -1064,6 +1061,7 @@
auto RefreshRateSelector::setPolicy(const PolicyVariant& policy) -> SetPolicyResult {
Policy oldPolicy;
+ PhysicalDisplayId displayId;
{
std::lock_guard lock(mLock);
oldPolicy = *getCurrentPolicyLocked();
@@ -1103,9 +1101,10 @@
return SetPolicyResult::Unchanged;
}
constructAvailableRefreshRates();
+
+ displayId = getActiveModeLocked().modePtr->getPhysicalDisplayId();
}
- const auto displayId = getActiveMode().getPhysicalDisplayId();
const unsigned numModeChanges = std::exchange(mNumModeSwitchesInPolicy, 0u);
ALOGI("Display %s policy changed\n"
@@ -1132,12 +1131,10 @@
return mDisplayManagerPolicy;
}
-bool RefreshRateSelector::isModeAllowed(DisplayModeId modeId) const {
+bool RefreshRateSelector::isModeAllowed(const FrameRateMode& mode) const {
std::lock_guard lock(mLock);
- return std::any_of(mAppRequestFrameRates.begin(), mAppRequestFrameRates.end(),
- [modeId](const FrameRateMode& frameRateMode) {
- return frameRateMode.modePtr->getId() == modeId;
- });
+ return std::find(mAppRequestFrameRates.begin(), mAppRequestFrameRates.end(), mode) !=
+ mAppRequestFrameRates.end();
}
void RefreshRateSelector::constructAvailableRefreshRates() {
@@ -1211,7 +1208,7 @@
}
const DisplayModePtr& maxByPolicy =
- getMaxRefreshRateByPolicyLocked(getActiveModeItLocked()->second->getGroup());
+ getMaxRefreshRateByPolicyLocked(getActiveModeLocked().modePtr->getGroup());
if (minByPolicy == maxByPolicy) {
// Turn on the timer when the min of the primary range is below the device min.
if (const Policy* currentPolicy = getCurrentPolicyLocked();
@@ -1257,8 +1254,8 @@
std::lock_guard lock(mLock);
- const auto activeModeId = getActiveModeItLocked()->first;
- dumper.dump("activeModeId"sv, std::to_string(activeModeId.value()));
+ const auto activeMode = getActiveModeLocked();
+ dumper.dump("activeMode"sv, to_string(activeMode));
dumper.dump("displayModes"sv);
{
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
index 89ebeea..1ed16c6 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
@@ -133,7 +133,7 @@
Policy getDisplayManagerPolicy() const EXCLUDES(mLock);
// Returns true if mode is allowed by the current policy.
- bool isModeAllowed(DisplayModeId) const EXCLUDES(mLock);
+ bool isModeAllowed(const FrameRateMode&) const EXCLUDES(mLock);
// Describes the different options the layer voted for refresh rate
enum class LayerVoteType {
@@ -243,11 +243,10 @@
std::optional<Fps> onKernelTimerChanged(std::optional<DisplayModeId> desiredActiveModeId,
bool timerExpired) const EXCLUDES(mLock);
- void setActiveModeId(DisplayModeId) EXCLUDES(mLock) REQUIRES(kMainThreadContext);
+ void setActiveMode(DisplayModeId, Fps renderFrameRate) EXCLUDES(mLock);
- // See mActiveModeIt for thread safety.
- DisplayModePtr getActiveModePtr() const EXCLUDES(mLock);
- const DisplayMode& getActiveMode() const REQUIRES(kMainThreadContext);
+ // See mActiveModeOpt for thread safety.
+ FrameRateMode getActiveMode() const EXCLUDES(mLock);
// Returns a known frame rate that is the closest to frameRate
Fps findClosestKnownFrameRate(Fps frameRate) const;
@@ -399,8 +398,8 @@
void constructAvailableRefreshRates() REQUIRES(mLock);
- // See mActiveModeIt for thread safety.
- DisplayModeIterator getActiveModeItLocked() const REQUIRES(mLock);
+ // See mActiveModeOpt for thread safety.
+ const FrameRateMode& getActiveModeLocked() const REQUIRES(mLock);
RankedFrameRates getRankedFrameRatesLocked(const std::vector<LayerRequirement>& layers,
GlobalSignals signals) const REQUIRES(mLock);
@@ -478,9 +477,7 @@
// when FrameRateOverride::AppOverrideNativeRefreshRates is in use.
ftl::SmallMap<Fps, ftl::Unit, 8, FpsApproxEqual> mAppOverrideNativeRefreshRates;
- // Written under mLock exclusively from kMainThreadContext, so reads from kMainThreadContext
- // need not be under mLock.
- DisplayModeIterator mActiveModeIt GUARDED_BY(mLock) GUARDED_BY(kMainThreadContext);
+ ftl::Optional<FrameRateMode> mActiveModeOpt GUARDED_BY(mLock);
DisplayModeIterator mMinRefreshRateModeIt GUARDED_BY(mLock);
DisplayModeIterator mMaxRefreshRateModeIt GUARDED_BY(mLock);
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 0c541f9..7f8f600 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -174,7 +174,7 @@
impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction() const {
return [this](uid_t uid) {
- const Fps refreshRate = leaderSelectorPtr()->getActiveModePtr()->getFps();
+ const Fps refreshRate = leaderSelectorPtr()->getActiveMode().fps;
const nsecs_t currentPeriod = mVsyncSchedule->period().ns() ?: refreshRate.getPeriodNsecs();
const auto frameRate = getFrameRateOverride(uid);
@@ -282,7 +282,7 @@
thread->onFrameRateOverridesChanged(displayId, std::move(overrides));
}
-void Scheduler::onPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) {
+void Scheduler::onPrimaryDisplayModeChanged(ConnectionHandle handle, const FrameRateMode& mode) {
{
std::lock_guard<std::mutex> lock(mPolicyLock);
// Cache the last reported modes for primary display.
@@ -297,7 +297,7 @@
void Scheduler::dispatchCachedReportedMode() {
// Check optional fields first.
- if (!mPolicy.mode) {
+ if (!mPolicy.modeOpt) {
ALOGW("No mode ID found, not dispatching cached mode.");
return;
}
@@ -309,28 +309,28 @@
// If the mode is not the current mode, this means that a
// 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 (leaderSelectorPtr()->getActiveModePtr() != mPolicy.mode) {
+ if (leaderSelectorPtr()->getActiveMode() != mPolicy.modeOpt) {
return;
}
// If there is no change from cached mode, there is no need to dispatch an event
- if (mPolicy.mode == mPolicy.cachedModeChangedParams->mode) {
+ if (*mPolicy.modeOpt == mPolicy.cachedModeChangedParams->mode) {
return;
}
- mPolicy.cachedModeChangedParams->mode = mPolicy.mode;
+ mPolicy.cachedModeChangedParams->mode = *mPolicy.modeOpt;
onNonPrimaryDisplayModeChanged(mPolicy.cachedModeChangedParams->handle,
mPolicy.cachedModeChangedParams->mode);
}
-void Scheduler::onNonPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) {
+void Scheduler::onNonPrimaryDisplayModeChanged(ConnectionHandle handle, const FrameRateMode& mode) {
android::EventThread* thread;
{
std::lock_guard<std::mutex> lock(mConnectionsLock);
RETURN_IF_INVALID_HANDLE(handle);
thread = mConnections[handle].thread.get();
}
- thread->onModeChanged(mode);
+ thread->onModeChanged(mode.modePtr.get());
}
size_t Scheduler::getEventThreadConnectionCount(ConnectionHandle handle) {
@@ -395,6 +395,24 @@
setVsyncPeriod(refreshRate.getPeriodNsecs());
}
+void Scheduler::setRenderRate(Fps renderFrameRate) {
+ const auto mode = leaderSelectorPtr()->getActiveMode();
+
+ using fps_approx_ops::operator!=;
+ LOG_ALWAYS_FATAL_IF(renderFrameRate != mode.fps,
+ "Mismatch in render frame rates. Selector: %s, Scheduler: %s",
+ to_string(mode.fps).c_str(), to_string(renderFrameRate).c_str());
+
+ ALOGV("%s %s (%s)", __func__, to_string(mode.fps).c_str(),
+ to_string(mode.modePtr->getFps()).c_str());
+
+ const auto divisor = RefreshRateSelector::getFrameRateDivisor(mode.modePtr->getFps(), mode.fps);
+ LOG_ALWAYS_FATAL_IF(divisor == 0, "%s <> %s -- not divisors", to_string(mode.fps).c_str(),
+ to_string(mode.fps).c_str());
+
+ mVsyncSchedule->getTracker().setDivisor(static_cast<unsigned>(divisor));
+}
+
void Scheduler::resync() {
static constexpr nsecs_t kIgnoreDelay = ms2ns(750);
@@ -402,7 +420,7 @@
const nsecs_t last = mLastResyncTime.exchange(now);
if (now - last > kIgnoreDelay) {
- const auto refreshRate = leaderSelectorPtr()->getActiveModePtr()->getFps();
+ const auto refreshRate = leaderSelectorPtr()->getActiveMode().modePtr->getFps();
resyncToHardwareVsync(false, refreshRate);
}
}
@@ -517,7 +535,7 @@
// TODO(145561154): cleanup the kernel idle timer implementation and the refresh rate
// magic number
- const Fps refreshRate = leaderSelectorPtr()->getActiveModePtr()->getFps();
+ const Fps refreshRate = leaderSelectorPtr()->getActiveMode().modePtr->getFps();
constexpr Fps FPS_THRESHOLD_FOR_KERNEL_TIMER = 65_Hz;
using namespace fps_approx_ops;
@@ -657,7 +675,7 @@
currentState = std::forward<T>(newState);
DisplayModeChoiceMap modeChoices;
- DisplayModePtr modePtr;
+ ftl::Optional<FrameRateMode> modeOpt;
{
std::scoped_lock lock(mDisplayLock);
ftl::FakeGuard guard(kMainThreadContext);
@@ -666,10 +684,10 @@
// TODO(b/240743786): The leader display's mode must change for any DisplayModeRequest
// to go through. Fix this by tracking per-display Scheduler::Policy and timers.
- std::tie(modePtr, consideredSignals) =
+ std::tie(modeOpt, consideredSignals) =
modeChoices.get(*mLeaderDisplayId)
.transform([](const DisplayModeChoice& choice) {
- return std::make_pair(choice.modePtr, choice.consideredSignals);
+ return std::make_pair(choice.mode, choice.consideredSignals);
})
.value();
}
@@ -677,15 +695,14 @@
modeRequests.reserve(modeChoices.size());
for (auto& [id, choice] : modeChoices) {
modeRequests.emplace_back(
- display::DisplayModeRequest{.modePtr =
- ftl::as_non_null(std::move(choice.modePtr)),
+ display::DisplayModeRequest{.mode = std::move(choice.mode),
.emitEvent = !choice.consideredSignals.idle});
}
- frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, modePtr->getFps());
+ frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, modeOpt->fps);
- if (mPolicy.mode != modePtr) {
- mPolicy.mode = modePtr;
+ if (mPolicy.modeOpt != modeOpt) {
+ mPolicy.modeOpt = modeOpt;
refreshRateChanged = true;
} else {
// We don't need to change the display mode, but we might need to send an event
@@ -725,12 +742,11 @@
const auto globalSignals = makeGlobalSignals();
for (const auto& [id, selectorPtr] : mRefreshRateSelectors) {
- auto rankedRefreshRates =
+ auto rankedFrameRates =
selectorPtr->getRankedFrameRates(mPolicy.contentRequirements, globalSignals);
- for (const auto& [frameRateMode, score] : rankedRefreshRates.ranking) {
- const auto& modePtr = frameRateMode.modePtr;
- const auto [it, inserted] = refreshRateTallies.try_emplace(modePtr->getFps(), score);
+ for (const auto& [frameRateMode, score] : rankedFrameRates.ranking) {
+ const auto [it, inserted] = refreshRateTallies.try_emplace(frameRateMode.fps, score);
if (!inserted) {
auto& tally = it->second;
@@ -739,7 +755,7 @@
}
}
- perDisplayRanking.push_back(std::move(rankedRefreshRates));
+ perDisplayRanking.push_back(std::move(rankedFrameRates));
}
auto maxScoreIt = refreshRateTallies.cbegin();
@@ -773,17 +789,15 @@
for (auto& [ranking, signals] : perDisplayRanking) {
if (!chosenFps) {
const auto& [frameRateMode, _] = ranking.front();
- const auto& modePtr = frameRateMode.modePtr;
- modeChoices.try_emplace(modePtr->getPhysicalDisplayId(),
- DisplayModeChoice{modePtr, signals});
+ modeChoices.try_emplace(frameRateMode.modePtr->getPhysicalDisplayId(),
+ DisplayModeChoice{frameRateMode, signals});
continue;
}
for (auto& [frameRateMode, _] : ranking) {
- const auto& modePtr = frameRateMode.modePtr;
- if (modePtr->getFps() == *chosenFps) {
- modeChoices.try_emplace(modePtr->getPhysicalDisplayId(),
- DisplayModeChoice{modePtr, signals});
+ if (frameRateMode.fps == *chosenFps) {
+ modeChoices.try_emplace(frameRateMode.modePtr->getPhysicalDisplayId(),
+ DisplayModeChoice{frameRateMode, signals});
break;
}
}
@@ -801,18 +815,18 @@
.powerOnImminent = powerOnImminent};
}
-DisplayModePtr Scheduler::getPreferredDisplayMode() {
+ftl::Optional<FrameRateMode> Scheduler::getPreferredDisplayMode() {
std::lock_guard<std::mutex> lock(mPolicyLock);
// Make sure the stored mode is up to date.
- if (mPolicy.mode) {
+ if (mPolicy.modeOpt) {
const auto ranking =
leaderSelectorPtr()
->getRankedFrameRates(mPolicy.contentRequirements, makeGlobalSignals())
.ranking;
- mPolicy.mode = ranking.front().frameRateMode.modePtr;
+ mPolicy.modeOpt = ranking.front().frameRateMode;
}
- return mPolicy.mode;
+ return mPolicy.modeOpt;
}
void Scheduler::onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index fb23071..cf2ffb8 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -149,8 +149,8 @@
sp<EventThreadConnection> getEventConnection(ConnectionHandle);
void onHotplugReceived(ConnectionHandle, PhysicalDisplayId, bool connected);
- void onPrimaryDisplayModeChanged(ConnectionHandle, DisplayModePtr) EXCLUDES(mPolicyLock);
- void onNonPrimaryDisplayModeChanged(ConnectionHandle, DisplayModePtr);
+ void onPrimaryDisplayModeChanged(ConnectionHandle, const FrameRateMode&) EXCLUDES(mPolicyLock);
+ void onNonPrimaryDisplayModeChanged(ConnectionHandle, const FrameRateMode&);
void onScreenAcquired(ConnectionHandle);
void onScreenReleased(ConnectionHandle);
@@ -161,6 +161,9 @@
void setDuration(ConnectionHandle, std::chrono::nanoseconds workDuration,
std::chrono::nanoseconds readyDuration);
+ // Sets the render rate for the scheduler to run at.
+ void setRenderRate(Fps);
+
void enableHardwareVsync();
void disableHardwareVsync(bool makeUnavailable);
@@ -207,7 +210,7 @@
void dumpVsync(std::string&) const;
// Get the appropriate refresh for current conditions.
- DisplayModePtr getPreferredDisplayMode();
+ ftl::Optional<FrameRateMode> getPreferredDisplayMode();
// Notifies the scheduler about a refresh rate timeline change.
void onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline);
@@ -235,7 +238,7 @@
std::optional<Fps> getFrameRateOverride(uid_t) const EXCLUDES(mDisplayLock);
nsecs_t getLeaderVsyncPeriod() const EXCLUDES(mDisplayLock) {
- return leaderSelectorPtr()->getActiveModePtr()->getFps().getPeriodNsecs();
+ return leaderSelectorPtr()->getActiveMode().fps.getPeriodNsecs();
}
// Returns the framerate of the layer with the given sequence ID
@@ -283,19 +286,19 @@
GlobalSignals applyPolicy(S Policy::*, T&&) EXCLUDES(mPolicyLock);
struct DisplayModeChoice {
- DisplayModeChoice(DisplayModePtr modePtr, GlobalSignals consideredSignals)
- : modePtr(std::move(modePtr)), consideredSignals(consideredSignals) {}
+ DisplayModeChoice(FrameRateMode mode, GlobalSignals consideredSignals)
+ : mode(std::move(mode)), consideredSignals(consideredSignals) {}
- DisplayModePtr modePtr;
+ FrameRateMode mode;
GlobalSignals consideredSignals;
bool operator==(const DisplayModeChoice& other) const {
- return modePtr == other.modePtr && consideredSignals == other.consideredSignals;
+ return mode == other.mode && consideredSignals == other.consideredSignals;
}
// For tests.
friend std::ostream& operator<<(std::ostream& stream, const DisplayModeChoice& choice) {
- return stream << '{' << to_string(*choice.modePtr) << " considering "
+ return stream << '{' << to_string(*choice.mode.modePtr) << " considering "
<< choice.consideredSignals.toString().c_str() << '}';
}
};
@@ -382,11 +385,11 @@
hal::PowerMode displayPowerMode = hal::PowerMode::ON;
// Chosen display mode.
- DisplayModePtr mode;
+ ftl::Optional<FrameRateMode> modeOpt;
struct ModeChangedParams {
ConnectionHandle handle;
- DisplayModePtr mode;
+ FrameRateMode mode;
};
// Parameters for latest dispatch of mode change event.
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 0ad4236..ed4d25e 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -253,7 +253,13 @@
nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const {
std::lock_guard lock(mMutex);
- return nextAnticipatedVSyncTimeFromLocked(timePoint);
+
+ // TODO(b/246164114): This implementation is not efficient at all. Refactor.
+ nsecs_t nextVsync = nextAnticipatedVSyncTimeFromLocked(timePoint);
+ while (!isVSyncInPhaseLocked(nextVsync, mDivisor)) {
+ nextVsync = nextAnticipatedVSyncTimeFromLocked(nextVsync + 1);
+ }
+ return nextVsync;
}
/*
@@ -265,6 +271,13 @@
* isVSyncInPhase(50.0, 30) = true
*/
bool VSyncPredictor::isVSyncInPhase(nsecs_t timePoint, Fps frameRate) const {
+ std::lock_guard lock(mMutex);
+ const auto divisor =
+ RefreshRateSelector::getFrameRateDivisor(Fps::fromPeriodNsecs(mIdealPeriod), frameRate);
+ return isVSyncInPhaseLocked(timePoint, static_cast<unsigned>(divisor));
+}
+
+bool VSyncPredictor::isVSyncInPhaseLocked(nsecs_t timePoint, unsigned divisor) const {
struct VsyncError {
nsecs_t vsyncTimestamp;
float error;
@@ -272,9 +285,6 @@
bool operator<(const VsyncError& other) const { return error < other.error; }
};
- std::lock_guard lock(mMutex);
- const auto divisor =
- RefreshRateSelector::getFrameRateDivisor(Fps::fromPeriodNsecs(mIdealPeriod), frameRate);
if (divisor <= 1 || timePoint == 0) {
return true;
}
@@ -312,6 +322,12 @@
return std::abs(minVsyncError->vsyncTimestamp - timePoint) < period / 2;
}
+void VSyncPredictor::setDivisor(unsigned divisor) {
+ ALOGV("%s: %d", __func__, divisor);
+ std::lock_guard lock(mMutex);
+ mDivisor = divisor;
+}
+
VSyncPredictor::Model VSyncPredictor::getVSyncPredictionModel() const {
std::lock_guard lock(mMutex);
const auto model = VSyncPredictor::getVSyncPredictionModelLocked();
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h
index 3181102..4a3ba67 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.h
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h
@@ -67,6 +67,8 @@
bool isVSyncInPhase(nsecs_t timePoint, Fps frameRate) const final EXCLUDES(mMutex);
+ void setDivisor(unsigned divisor) final EXCLUDES(mMutex);
+
void dump(std::string& result) const final EXCLUDES(mMutex);
private:
@@ -89,6 +91,8 @@
nsecs_t nextAnticipatedVSyncTimeFromLocked(nsecs_t timePoint) const REQUIRES(mMutex);
+ bool isVSyncInPhaseLocked(nsecs_t timePoint, unsigned divisor) const REQUIRES(mMutex);
+
nsecs_t mIdealPeriod GUARDED_BY(mMutex);
std::optional<nsecs_t> mKnownTimestamp GUARDED_BY(mMutex);
@@ -100,6 +104,8 @@
size_t mLastTimestampIndex GUARDED_BY(mMutex) = 0;
std::vector<nsecs_t> mTimestamps GUARDED_BY(mMutex);
+
+ unsigned mDivisor GUARDED_BY(mMutex) = 1;
};
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VSyncTracker.h b/services/surfaceflinger/Scheduler/VSyncTracker.h
index 76315d2..8d1629f 100644
--- a/services/surfaceflinger/Scheduler/VSyncTracker.h
+++ b/services/surfaceflinger/Scheduler/VSyncTracker.h
@@ -79,6 +79,17 @@
*/
virtual bool isVSyncInPhase(nsecs_t timePoint, Fps frameRate) const = 0;
+ /*
+ * Sets a divisor on the rate (which is a multiplier of the period).
+ * The tracker will continue to track the vsync timeline and expect it
+ * to match the current period, however, nextAnticipatedVSyncTimeFrom will
+ * return vsyncs according to the divisor set. Setting a divisor is useful
+ * when a display is running at 120Hz but the render frame rate is 60Hz.
+ *
+ * \param [in] divisor The rate divisor the tracker should operate at.
+ */
+ virtual void setDivisor(unsigned divisor) = 0;
+
virtual void dump(std::string& result) const = 0;
protected:
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/FrameRateMode.h b/services/surfaceflinger/Scheduler/include/scheduler/FrameRateMode.h
index 670ab45..db38ebe 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/FrameRateMode.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/FrameRateMode.h
@@ -16,6 +16,7 @@
#pragma once
+#include <ftl/non_null.h>
#include <scheduler/Fps.h>
// TODO(b/241285191): Pull this to <ui/DisplayMode.h>
@@ -25,7 +26,7 @@
struct FrameRateMode {
Fps fps; // The render frame rate, which is a divisor of modePtr->getFps().
- DisplayModePtr modePtr;
+ ftl::NonNull<DisplayModePtr> modePtr;
bool operator==(const FrameRateMode& other) const {
return isApproxEqual(fps, other.fps) && modePtr == other.modePtr;
@@ -35,10 +36,7 @@
};
inline std::string to_string(const FrameRateMode& mode) {
- if (mode.modePtr) {
- return to_string(mode.fps) + " (" + to_string(mode.modePtr->getFps()) + ")";
- }
- return "{invalid}";
+ return to_string(mode.fps) + " (" + to_string(mode.modePtr->getFps()) + ")";
}
-} // namespace android::scheduler
\ No newline at end of file
+} // namespace android::scheduler