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/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) {