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/Display/DisplayModeRequest.h b/services/surfaceflinger/Display/DisplayModeRequest.h
index ac25fe0..d07cdf5 100644
--- a/services/surfaceflinger/Display/DisplayModeRequest.h
+++ b/services/surfaceflinger/Display/DisplayModeRequest.h
@@ -18,19 +18,19 @@
#include <ftl/non_null.h>
-#include "DisplayHardware/DisplayMode.h"
+#include <scheduler/FrameRateMode.h>
namespace android::display {
struct DisplayModeRequest {
- ftl::NonNull<DisplayModePtr> modePtr;
+ scheduler::FrameRateMode mode;
// Whether to emit DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE.
bool emitEvent = false;
};
inline bool operator==(const DisplayModeRequest& lhs, const DisplayModeRequest& rhs) {
- return lhs.modePtr == rhs.modePtr && lhs.emitEvent == rhs.emitEvent;
+ return lhs.mode == rhs.mode && lhs.emitEvent == rhs.emitEvent;
}
} // namespace android::display
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index b40c6d1..269a5ea 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -68,6 +68,7 @@
mCompositionDisplay{args.compositionDisplay},
mActiveModeFPSTrace("ActiveModeFPS -" + to_string(getId())),
mActiveModeFPSHwcTrace("ActiveModeFPS_HWC -" + to_string(getId())),
+ mRenderFrameRateFPSTrace("RenderRateFPS -" + to_string(getId())),
mPhysicalOrientation(args.physicalOrientation),
mIsPrimary(args.isPrimary),
mRefreshRateSelector(std::move(args.refreshRateSelector)) {
@@ -195,35 +196,32 @@
return mPowerMode && *mPowerMode != hal::PowerMode::OFF;
}
-void DisplayDevice::setActiveMode(DisplayModeId modeId, const display::DisplaySnapshot& snapshot) {
- const auto fpsOpt = snapshot.displayModes().get(modeId).transform(
- [](const DisplayModePtr& mode) { return mode->getFps(); });
+void DisplayDevice::setActiveMode(DisplayModeId modeId, Fps displayFps, Fps renderFps) {
+ ATRACE_INT(mActiveModeFPSTrace.c_str(), displayFps.getIntValue());
+ ATRACE_INT(mRenderFrameRateFPSTrace.c_str(), renderFps.getIntValue());
- LOG_ALWAYS_FATAL_IF(!fpsOpt, "Unknown mode");
- const Fps fps = *fpsOpt;
-
- ATRACE_INT(mActiveModeFPSTrace.c_str(), fps.getIntValue());
-
- mRefreshRateSelector->setActiveModeId(modeId);
+ mRefreshRateSelector->setActiveMode(modeId, renderFps);
if (mRefreshRateOverlay) {
- mRefreshRateOverlay->changeRefreshRate(fps);
+ mRefreshRateOverlay->changeRefreshRate(displayFps);
}
}
status_t DisplayDevice::initiateModeChange(const ActiveModeInfo& info,
const hal::VsyncPeriodChangeConstraints& constraints,
hal::VsyncPeriodChangeTimeline* outTimeline) {
- if (!info.mode || info.mode->getPhysicalDisplayId() != getPhysicalId()) {
+ if (!info.modeOpt || info.modeOpt->modePtr->getPhysicalDisplayId() != getPhysicalId()) {
ALOGE("Trying to initiate a mode change to invalid mode %s on display %s",
- info.mode ? std::to_string(info.mode->getId().value()).c_str() : "null",
+ info.modeOpt ? std::to_string(info.modeOpt->modePtr->getId().value()).c_str()
+ : "null",
to_string(getId()).c_str());
return BAD_VALUE;
}
mUpcomingActiveMode = info;
- ATRACE_INT(mActiveModeFPSHwcTrace.c_str(), info.mode->getFps().getIntValue());
- return mHwComposer.setActiveModeWithConstraints(getPhysicalId(), info.mode->getHwcId(),
- constraints, outTimeline);
+ ATRACE_INT(mActiveModeFPSHwcTrace.c_str(), info.modeOpt->modePtr->getFps().getIntValue());
+ return mHwComposer.setActiveModeWithConstraints(getPhysicalId(),
+ info.modeOpt->modePtr->getHwcId(), constraints,
+ outTimeline);
}
nsecs_t DisplayDevice::getVsyncPeriodFromHWC() const {
@@ -238,7 +236,7 @@
return vsyncPeriod;
}
- return refreshRateSelector().getActiveModePtr()->getVsyncPeriod();
+ return refreshRateSelector().getActiveMode().modePtr->getVsyncPeriod();
}
ui::Dataspace DisplayDevice::getCompositionDataSpace() const {
@@ -422,7 +420,7 @@
mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(fpsRange, showSpinnner);
mRefreshRateOverlay->setLayerStack(getLayerStack());
mRefreshRateOverlay->setViewport(getSize());
- mRefreshRateOverlay->changeRefreshRate(getActiveMode().getFps());
+ mRefreshRateOverlay->changeRefreshRate(getActiveMode().modePtr->getFps());
}
bool DisplayDevice::onKernelTimerChanged(std::optional<DisplayModeId> desiredModeId,
@@ -445,13 +443,14 @@
}
}
-bool DisplayDevice::setDesiredActiveMode(const ActiveModeInfo& info) {
+auto DisplayDevice::setDesiredActiveMode(const ActiveModeInfo& info) -> DesiredActiveModeAction {
ATRACE_CALL();
- LOG_ALWAYS_FATAL_IF(!info.mode, "desired mode not provided");
- LOG_ALWAYS_FATAL_IF(getPhysicalId() != info.mode->getPhysicalDisplayId(), "DisplayId mismatch");
+ LOG_ALWAYS_FATAL_IF(!info.modeOpt, "desired mode not provided");
+ LOG_ALWAYS_FATAL_IF(getPhysicalId() != info.modeOpt->modePtr->getPhysicalDisplayId(),
+ "DisplayId mismatch");
- ALOGV("%s(%s)", __func__, to_string(*info.mode).c_str());
+ ALOGV("%s(%s)", __func__, to_string(*info.modeOpt->modePtr).c_str());
std::scoped_lock lock(mActiveModeLock);
if (mDesiredActiveModeChanged) {
@@ -459,18 +458,25 @@
const auto prevConfig = mDesiredActiveMode.event;
mDesiredActiveMode = info;
mDesiredActiveMode.event = mDesiredActiveMode.event | prevConfig;
- return false;
+ return DesiredActiveModeAction::None;
}
+ const auto& desiredMode = *info.modeOpt->modePtr;
+
// Check if we are already at the desired mode
- if (refreshRateSelector().getActiveModePtr()->getId() == info.mode->getId()) {
- return false;
+ if (refreshRateSelector().getActiveMode().modePtr->getId() == desiredMode.getId()) {
+ if (refreshRateSelector().getActiveMode() == info.modeOpt) {
+ return DesiredActiveModeAction::None;
+ }
+
+ setActiveMode(desiredMode.getId(), desiredMode.getFps(), info.modeOpt->fps);
+ return DesiredActiveModeAction::InitiateRenderRateSwitch;
}
// Initiate a mode change.
mDesiredActiveModeChanged = true;
mDesiredActiveMode = info;
- return true;
+ return DesiredActiveModeAction::InitiateDisplayModeSwitch;
}
std::optional<DisplayDevice::ActiveModeInfo> DisplayDevice::getDesiredActiveMode() const {
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 4b64aab..852a8a2 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -190,33 +190,38 @@
using Event = scheduler::DisplayModeEvent;
ActiveModeInfo() = default;
- ActiveModeInfo(DisplayModePtr mode, Event event) : mode(std::move(mode)), event(event) {}
+ ActiveModeInfo(scheduler::FrameRateMode mode, Event event)
+ : modeOpt(std::move(mode)), event(event) {}
explicit ActiveModeInfo(display::DisplayModeRequest&& request)
- : ActiveModeInfo(std::move(request.modePtr).take(),
+ : ActiveModeInfo(std::move(request.mode),
request.emitEvent ? Event::Changed : Event::None) {}
- DisplayModePtr mode;
+ ftl::Optional<scheduler::FrameRateMode> modeOpt;
Event event = Event::None;
bool operator!=(const ActiveModeInfo& other) const {
- return mode != other.mode || event != other.event;
+ return modeOpt != other.modeOpt || event != other.event;
}
};
- bool setDesiredActiveMode(const ActiveModeInfo&) EXCLUDES(mActiveModeLock);
+ enum class DesiredActiveModeAction {
+ None,
+ InitiateDisplayModeSwitch,
+ InitiateRenderRateSwitch
+ };
+ DesiredActiveModeAction setDesiredActiveMode(const ActiveModeInfo&) EXCLUDES(mActiveModeLock);
std::optional<ActiveModeInfo> getDesiredActiveMode() const EXCLUDES(mActiveModeLock);
void clearDesiredActiveModeState() EXCLUDES(mActiveModeLock);
ActiveModeInfo getUpcomingActiveMode() const REQUIRES(kMainThreadContext) {
return mUpcomingActiveMode;
}
- const DisplayMode& getActiveMode() const REQUIRES(kMainThreadContext) {
+ scheduler::FrameRateMode getActiveMode() const REQUIRES(kMainThreadContext) {
return mRefreshRateSelector->getActiveMode();
}
- // Precondition: DisplaySnapshot must contain a mode with DisplayModeId.
- void setActiveMode(DisplayModeId, const display::DisplaySnapshot&) REQUIRES(kMainThreadContext);
+ void setActiveMode(DisplayModeId, Fps displayFps, Fps renderFps);
status_t initiateModeChange(const ActiveModeInfo&,
const hal::VsyncPeriodChangeConstraints& constraints,
@@ -254,6 +259,7 @@
std::string mDisplayName;
std::string mActiveModeFPSTrace;
std::string mActiveModeFPSHwcTrace;
+ std::string mRenderFrameRateFPSTrace;
const ui::Rotation mPhysicalOrientation;
ui::Rotation mOrientation = ui::ROTATION_0;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index d53f0b1..0017af0 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -3597,7 +3597,7 @@
}
if (display) {
- const Fps refreshRate = display->refreshRateSelector().getActiveModePtr()->getFps();
+ const Fps refreshRate = display->refreshRateSelector().getActiveMode().fps;
const std::optional<Fps> renderRate =
mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
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
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 6961f7c..111b927 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1039,7 +1039,8 @@
const PhysicalDisplayId displayId = snapshot.displayId();
- info->activeDisplayModeId = display->refreshRateSelector().getActiveModePtr()->getId().value();
+ info->activeDisplayModeId =
+ display->refreshRateSelector().getActiveMode().modePtr->getId().value();
info->activeColorMode = display->getCompositionDisplay()->getState().colorMode;
info->hdrCapabilities = display->getHdrCapabilities();
@@ -1076,26 +1077,39 @@
void SurfaceFlinger::setDesiredActiveMode(display::DisplayModeRequest&& request) {
ATRACE_CALL();
- auto display = getDisplayDeviceLocked(request.modePtr->getPhysicalDisplayId());
+ auto display = getDisplayDeviceLocked(request.mode.modePtr->getPhysicalDisplayId());
if (!display) {
ALOGW("%s: display is no longer valid", __func__);
return;
}
- const Fps refreshRate = request.modePtr->getFps();
+ const Fps renderFps = request.mode.fps;
+ const Fps displayFps = request.mode.modePtr->getFps();
- if (display->setDesiredActiveMode(DisplayDevice::ActiveModeInfo(std::move(request)))) {
- scheduleComposite(FrameHint::kNone);
+ switch (display->setDesiredActiveMode(DisplayDevice::ActiveModeInfo(std::move(request)))) {
+ case DisplayDevice::DesiredActiveModeAction::InitiateDisplayModeSwitch:
+ scheduleComposite(FrameHint::kNone);
- // Start receiving vsync samples now, so that we can detect a period
- // switch.
- mScheduler->resyncToHardwareVsync(true, refreshRate);
- // As we called to set period, we will call to onRefreshRateChangeCompleted once
- // VsyncController model is locked.
- modulateVsync(&VsyncModulator::onRefreshRateChangeInitiated);
+ // Start receiving vsync samples now, so that we can detect a period
+ // switch.
+ mScheduler->resyncToHardwareVsync(true, displayFps);
+ // As we called to set period, we will call to onRefreshRateChangeCompleted once
+ // VsyncController model is locked.
+ modulateVsync(&VsyncModulator::onRefreshRateChangeInitiated);
- updatePhaseConfiguration(refreshRate);
- mScheduler->setModeChangePending(true);
+ updatePhaseConfiguration(renderFps);
+ mScheduler->setModeChangePending(true);
+ break;
+ case DisplayDevice::DesiredActiveModeAction::InitiateRenderRateSwitch:
+ mScheduler->setRenderRate(renderFps);
+ updatePhaseConfiguration(renderFps);
+ mRefreshRateStats->setRefreshRate(renderFps);
+
+ // TODO(b/259740021): send event to display manager about
+ // the render rate change
+ break;
+ case DisplayDevice::DesiredActiveModeAction::None:
+ break;
}
}
@@ -1157,18 +1171,19 @@
}
const auto upcomingModeInfo = display->getUpcomingActiveMode();
- if (!upcomingModeInfo.mode) {
+ if (!upcomingModeInfo.modeOpt) {
// There is no pending mode change. This can happen if the active
// display changed and the mode change happened on a different display.
return;
}
- if (display->getActiveMode().getResolution() != upcomingModeInfo.mode->getResolution()) {
+ if (display->getActiveMode().modePtr->getResolution() !=
+ upcomingModeInfo.modeOpt->modePtr->getResolution()) {
auto& state = mCurrentState.displays.editValueFor(display->getDisplayToken());
// We need to generate new sequenceId in order to recreate the display (and this
// way the framebuffer).
state.sequenceId = DisplayDeviceState{}.sequenceId;
- state.physical->activeMode = upcomingModeInfo.mode;
+ state.physical->activeMode = upcomingModeInfo.modeOpt->modePtr.get();
processDisplayChangesLocked();
// processDisplayChangesLocked will update all necessary components so we're done here.
@@ -1179,15 +1194,17 @@
.transform(&PhysicalDisplay::snapshotRef)
.transform(ftl::unit_fn([&](const display::DisplaySnapshot& snapshot) {
FTL_FAKE_GUARD(kMainThreadContext,
- display->setActiveMode(upcomingModeInfo.mode->getId(), snapshot));
+ display->setActiveMode(upcomingModeInfo.modeOpt->modePtr->getId(),
+ upcomingModeInfo.modeOpt->modePtr->getFps(),
+ upcomingModeInfo.modeOpt->fps));
}));
- const Fps refreshRate = upcomingModeInfo.mode->getFps();
+ const Fps refreshRate = upcomingModeInfo.modeOpt->fps;
mRefreshRateStats->setRefreshRate(refreshRate);
updatePhaseConfiguration(refreshRate);
if (upcomingModeInfo.event != scheduler::DisplayModeEvent::None) {
- mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, upcomingModeInfo.mode);
+ mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, *upcomingModeInfo.modeOpt);
}
}
@@ -1199,10 +1216,12 @@
}
void SurfaceFlinger::desiredActiveModeChangeDone(const sp<DisplayDevice>& display) {
- const auto refreshRate = display->getDesiredActiveMode()->mode->getFps();
+ const auto displayFps = display->getDesiredActiveMode()->modeOpt->modePtr->getFps();
+ const auto renderFps = display->getDesiredActiveMode()->modeOpt->fps;
clearDesiredActiveModeState(display);
- mScheduler->resyncToHardwareVsync(true, refreshRate);
- updatePhaseConfiguration(refreshRate);
+ mScheduler->resyncToHardwareVsync(true, displayFps);
+ mScheduler->setRenderRate(renderFps);
+ updatePhaseConfiguration(renderFps);
}
void SurfaceFlinger::setActiveModeInHwcIfNeeded() {
@@ -1233,13 +1252,10 @@
continue;
}
- const auto desiredModeId = desiredActiveMode->mode->getId();
- const auto refreshRateOpt =
- snapshot.displayModes()
- .get(desiredModeId)
- .transform([](const DisplayModePtr& mode) { return mode->getFps(); });
+ const auto desiredModeId = desiredActiveMode->modeOpt->modePtr->getId();
+ const auto displayModePtrOpt = snapshot.displayModes().get(desiredModeId);
- if (!refreshRateOpt) {
+ if (!displayModePtrOpt) {
ALOGW("Desired display mode is no longer supported. Mode ID = %d",
desiredModeId.value());
clearDesiredActiveModeState(display);
@@ -1247,9 +1263,10 @@
}
ALOGV("%s changing active mode to %d(%s) for display %s", __func__, desiredModeId.value(),
- to_string(*refreshRateOpt).c_str(), to_string(display->getId()).c_str());
+ to_string(displayModePtrOpt->get()->getFps()).c_str(),
+ to_string(display->getId()).c_str());
- if (display->getActiveMode().getId() == desiredModeId) {
+ if (display->getActiveMode() == desiredActiveMode->modeOpt) {
// we are already in the requested mode, there is nothing left to do
desiredActiveModeChangeDone(display);
continue;
@@ -1258,7 +1275,8 @@
// Desired active mode was set, it is different than the mode currently in use, however
// allowed modes might have changed by the time we process the refresh.
// Make sure the desired mode is still allowed
- const auto displayModeAllowed = display->refreshRateSelector().isModeAllowed(desiredModeId);
+ const auto displayModeAllowed =
+ display->refreshRateSelector().isModeAllowed(*desiredActiveMode->modeOpt);
if (!displayModeAllowed) {
clearDesiredActiveModeState(display);
continue;
@@ -1299,8 +1317,7 @@
const auto display = getDisplayDeviceLocked(*displayToUpdateImmediately);
const auto desiredActiveMode = display->getDesiredActiveMode();
- if (desiredActiveMode &&
- display->getActiveMode().getId() == desiredActiveMode->mode->getId()) {
+ if (desiredActiveMode && display->getActiveMode() == desiredActiveMode->modeOpt) {
desiredActiveModeChangeDone(display);
}
}
@@ -2069,7 +2086,7 @@
activeDisplay->getPowerMode() == hal::PowerMode::ON;
if (mPowerHintSessionEnabled) {
const auto& display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()).get();
- const Period vsyncPeriod = Period::fromNs(display->getActiveMode().getVsyncPeriod());
+ const Period vsyncPeriod = Period::fromNs(display->getActiveMode().fps.getPeriodNsecs());
mPowerAdvisor->setCommitStart(frameTime);
mPowerAdvisor->setExpectedPresentTime(mExpectedPresentTime);
@@ -2898,7 +2915,9 @@
.transform(&PhysicalDisplay::snapshotRef)
.transform(ftl::unit_fn([&](const display::DisplaySnapshot& snapshot) {
FTL_FAKE_GUARD(kMainThreadContext,
- display->setActiveMode(physical->activeMode->getId(), snapshot));
+ display->setActiveMode(physical->activeMode->getId(),
+ physical->activeMode->getFps(),
+ physical->activeMode->getFps()));
}));
}
@@ -3094,7 +3113,7 @@
void SurfaceFlinger::updateInternalDisplayVsyncLocked(const sp<DisplayDevice>& activeDisplay) {
mVsyncConfiguration->reset();
- const Fps refreshRate = activeDisplay->getActiveMode().getFps();
+ const Fps refreshRate = activeDisplay->getActiveMode().fps;
updatePhaseConfiguration(refreshRate);
mRefreshRateStats->setRefreshRate(refreshRate);
}
@@ -3376,12 +3395,12 @@
ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
for (auto& request : modeRequests) {
- const auto& modePtr = request.modePtr;
+ const auto& modePtr = request.mode.modePtr;
const auto display = getDisplayDeviceLocked(modePtr->getPhysicalDisplayId());
if (!display) continue;
- if (display->refreshRateSelector().isModeAllowed(modePtr->getId())) {
+ if (display->refreshRateSelector().isModeAllowed(request.mode)) {
setDesiredActiveMode(std::move(request));
} else {
ALOGV("%s: Mode %d is disallowed for display %s", __func__, modePtr->getId().value(),
@@ -3402,8 +3421,8 @@
void SurfaceFlinger::initScheduler(const sp<const DisplayDevice>& display) {
LOG_ALWAYS_FATAL_IF(mScheduler);
- const auto activeModePtr = display->refreshRateSelector().getActiveModePtr();
- const Fps activeRefreshRate = activeModePtr->getFps();
+ const auto activeMode = display->refreshRateSelector().getActiveMode();
+ const Fps activeRefreshRate = activeMode.fps;
mRefreshRateStats =
std::make_unique<scheduler::RefreshRateStats>(*mTimeStats, activeRefreshRate,
hal::PowerMode::OFF);
@@ -4673,7 +4692,7 @@
display->setPowerMode(mode);
- const auto refreshRate = display->refreshRateSelector().getActiveMode().getFps();
+ const auto refreshRate = display->refreshRateSelector().getActiveMode().modePtr->getFps();
if (!currentModeOpt || *currentModeOpt == hal::PowerMode::OFF) {
// Turn on the display
if (isInternalDisplay && (!activeDisplay || !activeDisplay->isPoweredOn())) {
@@ -5243,7 +5262,8 @@
if (const auto display = getDefaultDisplayDeviceLocked()) {
std::string fps, xDpi, yDpi;
- if (const auto activeModePtr = display->refreshRateSelector().getActiveModePtr()) {
+ if (const auto activeModePtr =
+ display->refreshRateSelector().getActiveMode().modePtr.get()) {
fps = to_string(activeModePtr->getFps());
const auto dpi = activeModePtr->getDpi();
@@ -5915,7 +5935,7 @@
if (!updateOverlay) return;
// Update the overlay on the main thread to avoid race conditions with
- // RefreshRateSelector::getActiveMode.
+ // RefreshRateSelector::getActiveMode
static_cast<void>(mScheduler->schedule([=] {
const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
if (!display) {
@@ -5926,7 +5946,8 @@
const auto desiredActiveMode = display->getDesiredActiveMode();
const std::optional<DisplayModeId> desiredModeId = desiredActiveMode
- ? std::make_optional(desiredActiveMode->mode->getId())
+ ? std::make_optional(desiredActiveMode->modeOpt->modePtr->getId())
+
: std::nullopt;
const bool timerExpired = mKernelIdleTimerEnabled && expired;
@@ -6620,11 +6641,11 @@
}
}
-std::optional<ftl::NonNull<DisplayModePtr>> SurfaceFlinger::getPreferredDisplayMode(
+ftl::Optional<scheduler::FrameRateMode> SurfaceFlinger::getPreferredDisplayMode(
PhysicalDisplayId displayId, DisplayModeId defaultModeId) const {
if (const auto schedulerMode = mScheduler->getPreferredDisplayMode();
- schedulerMode && schedulerMode->getPhysicalDisplayId() == displayId) {
- return ftl::as_non_null(schedulerMode);
+ schedulerMode && schedulerMode->modePtr->getPhysicalDisplayId() == displayId) {
+ return schedulerMode;
}
return mPhysicalDisplays.get(displayId)
@@ -6632,7 +6653,9 @@
.and_then([&](const display::DisplaySnapshot& snapshot) {
return snapshot.displayModes().get(defaultModeId);
})
- .transform(&ftl::as_non_null<const DisplayModePtr&>);
+ .transform([](const DisplayModePtr& modePtr) {
+ return scheduler::FrameRateMode{modePtr->getFps(), ftl::as_non_null(modePtr)};
+ });
}
status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal(
@@ -6667,11 +6690,11 @@
// TODO(b/140204874): Leave the event in until we do proper testing with all apps that might
// be depending in this callback.
- if (const auto activeModePtr = selector.getActiveModePtr(); displayId == mActiveDisplayId) {
- mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, activeModePtr);
+ if (const auto activeMode = selector.getActiveMode(); displayId == mActiveDisplayId) {
+ mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, activeMode);
toggleKernelIdleTimer();
} else {
- mScheduler->onNonPrimaryDisplayModeChanged(mAppConnectionHandle, activeModePtr);
+ mScheduler->onNonPrimaryDisplayModeChanged(mAppConnectionHandle, activeMode);
}
auto preferredModeOpt = getPreferredDisplayMode(displayId, currentPolicy.defaultMode);
@@ -6681,12 +6704,12 @@
}
auto preferredMode = std::move(*preferredModeOpt);
- const auto preferredModeId = preferredMode->getId();
+ const auto preferredModeId = preferredMode.modePtr->getId();
ALOGV("Switching to Scheduler preferred mode %d (%s)", preferredModeId.value(),
- to_string(preferredMode->getFps()).c_str());
+ to_string(preferredMode.fps).c_str());
- if (!selector.isModeAllowed(preferredModeId)) {
+ if (!selector.isModeAllowed(preferredMode)) {
ALOGE("%s: Preferred mode %d is disallowed", __func__, preferredModeId.value());
return INVALID_OPERATION;
}
@@ -6898,7 +6921,7 @@
refreshRate = *frameRateOverride;
} else if (!getHwComposer().isHeadless()) {
if (const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked())) {
- refreshRate = display->refreshRateSelector().getActiveModePtr()->getFps();
+ refreshRate = display->refreshRateSelector().getActiveMode().fps;
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 751d1e5..e3217a3 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -660,7 +660,7 @@
// Returns the preferred mode for PhysicalDisplayId if the Scheduler has selected one for that
// display. Falls back to the display's defaultModeId otherwise.
- std::optional<ftl::NonNull<DisplayModePtr>> getPreferredDisplayMode(
+ ftl::Optional<scheduler::FrameRateMode> getPreferredDisplayMode(
PhysicalDisplayId, DisplayModeId defaultModeId) const REQUIRES(mStateLock);
status_t setDesiredDisplayModeSpecsInternal(
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 577f84e..dbfce78 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -231,8 +231,7 @@
: Scheduler(*this, callback, Feature::kContentDetection) {
mVsyncSchedule.emplace(VsyncSchedule(std::move(tracker), nullptr, std::move(controller)));
- const auto displayId = FTL_FAKE_GUARD(kMainThreadContext,
- selectorPtr->getActiveMode().getPhysicalDisplayId());
+ const auto displayId = selectorPtr->getActiveMode().modePtr->getPhysicalDisplayId();
registerDisplay(displayId, std::move(selectorPtr));
}
@@ -273,7 +272,7 @@
mPolicy.cachedModeChangedParams.reset();
}
- void onNonPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) {
+ void onNonPrimaryDisplayModeChanged(ConnectionHandle handle, const FrameRateMode &mode) {
return Scheduler::onNonPrimaryDisplayModeChanged(handle, mode);
}
@@ -658,8 +657,7 @@
}
mRefreshRateSelector = std::make_shared<scheduler::RefreshRateSelector>(modes, kModeId60);
- const auto fps =
- FTL_FAKE_GUARD(kMainThreadContext, mRefreshRateSelector->getActiveMode().getFps());
+ const auto fps = mRefreshRateSelector->getActiveMode().modePtr->getFps();
mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(fps);
mFlinger->mVsyncModulator = sp<scheduler::VsyncModulator>::make(
mFlinger->mVsyncConfiguration->getCurrentConfigs());
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index 950e6d3..7959e52 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -381,7 +381,8 @@
mFdp.ConsumeFloatingPoint<float>())}});
refreshRateSelector.setPolicy(RefreshRateSelector::NoOverridePolicy{});
- refreshRateSelector.setActiveModeId(modeId);
+ refreshRateSelector.setActiveMode(modeId,
+ Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()));
}
RefreshRateSelector::isFractionalPairOrMultiple(Fps::fromValue(
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
index 88e32e1..2bc5b46 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
@@ -116,6 +116,8 @@
return true;
}
+ void setDivisor(unsigned) override {}
+
nsecs_t nextVSyncTime(nsecs_t timePoint) const {
if (timePoint % mPeriod == 0) {
return timePoint;
diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp
index 982b9ff..60ad7a3 100644
--- a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "LibSurfaceFlingerUnittests"
#include "DisplayTransactionTestHelpers.h"
+#include "mock/MockFrameRateMode.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -29,6 +30,7 @@
class InitiateModeChangeTest : public DisplayTransactionTest {
public:
+ using Action = DisplayDevice::DesiredActiveModeAction;
using Event = scheduler::DisplayModeEvent;
void SetUp() override {
@@ -56,31 +58,42 @@
static constexpr DisplayModeId kModeId90{1};
static constexpr DisplayModeId kModeId120{2};
- static inline const DisplayModePtr kMode60 = createDisplayMode(kModeId60, 60_Hz);
- static inline const DisplayModePtr kMode90 = createDisplayMode(kModeId90, 90_Hz);
- static inline const DisplayModePtr kMode120 = createDisplayMode(kModeId120, 120_Hz);
+ static inline const ftl::NonNull<DisplayModePtr> kMode60 =
+ ftl::as_non_null(createDisplayMode(kModeId60, 60_Hz));
+ static inline const ftl::NonNull<DisplayModePtr> kMode90 =
+ ftl::as_non_null(createDisplayMode(kModeId90, 90_Hz));
+ static inline const ftl::NonNull<DisplayModePtr> kMode120 =
+ ftl::as_non_null(createDisplayMode(kModeId120, 120_Hz));
};
TEST_F(InitiateModeChangeTest, setDesiredActiveMode_setCurrentMode) {
- EXPECT_FALSE(mDisplay->setDesiredActiveMode({kMode60, Event::None}));
+ EXPECT_EQ(Action::None,
+ mDisplay->setDesiredActiveMode(
+ {scheduler::FrameRateMode{60_Hz, kMode60}, Event::None}));
EXPECT_EQ(std::nullopt, mDisplay->getDesiredActiveMode());
}
TEST_F(InitiateModeChangeTest, setDesiredActiveMode_setNewMode) {
- EXPECT_TRUE(mDisplay->setDesiredActiveMode({kMode90, Event::None}));
+ EXPECT_EQ(Action::InitiateDisplayModeSwitch,
+ mDisplay->setDesiredActiveMode(
+ {scheduler::FrameRateMode{90_Hz, kMode90}, Event::None}));
ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
- EXPECT_EQ(kMode90, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, mDisplay->getDesiredActiveMode()->modeOpt);
EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
- // Setting another mode should be cached but return false
- EXPECT_FALSE(mDisplay->setDesiredActiveMode({kMode120, Event::None}));
+ // Setting another mode should be cached but return None
+ EXPECT_EQ(Action::None,
+ mDisplay->setDesiredActiveMode(
+ {scheduler::FrameRateMode{120_Hz, kMode120}, Event::None}));
ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
- EXPECT_EQ(kMode120, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, mDisplay->getDesiredActiveMode()->modeOpt);
EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
}
TEST_F(InitiateModeChangeTest, clearDesiredActiveModeState) {
- EXPECT_TRUE(mDisplay->setDesiredActiveMode({kMode90, Event::None}));
+ EXPECT_EQ(Action::InitiateDisplayModeSwitch,
+ mDisplay->setDesiredActiveMode(
+ {scheduler::FrameRateMode{90_Hz, kMode90}, Event::None}));
ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
mDisplay->clearDesiredActiveModeState();
@@ -88,9 +101,11 @@
}
TEST_F(InitiateModeChangeTest, initiateModeChange) NO_THREAD_SAFETY_ANALYSIS {
- EXPECT_TRUE(mDisplay->setDesiredActiveMode({kMode90, Event::None}));
+ EXPECT_EQ(Action::InitiateDisplayModeSwitch,
+ mDisplay->setDesiredActiveMode(
+ {scheduler::FrameRateMode{90_Hz, kMode90}, Event::None}));
ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
- EXPECT_EQ(kMode90, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, mDisplay->getDesiredActiveMode()->modeOpt);
EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
hal::VsyncPeriodChangeConstraints constraints{
@@ -101,18 +116,27 @@
EXPECT_EQ(OK,
mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints,
&timeline));
- EXPECT_EQ(kMode90, mDisplay->getUpcomingActiveMode().mode);
+ EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, *mDisplay->getUpcomingActiveMode().modeOpt);
EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event);
mDisplay->clearDesiredActiveModeState();
ASSERT_EQ(std::nullopt, mDisplay->getDesiredActiveMode());
}
+TEST_F(InitiateModeChangeTest, initiateRenderRateChange) {
+ EXPECT_EQ(Action::InitiateRenderRateSwitch,
+ mDisplay->setDesiredActiveMode(
+ {scheduler::FrameRateMode{30_Hz, kMode60}, Event::None}));
+ EXPECT_EQ(std::nullopt, mDisplay->getDesiredActiveMode());
+}
+
TEST_F(InitiateModeChangeTest, getUpcomingActiveMode_desiredActiveModeChanged)
NO_THREAD_SAFETY_ANALYSIS {
- EXPECT_TRUE(mDisplay->setDesiredActiveMode({kMode90, Event::None}));
+ EXPECT_EQ(Action::InitiateDisplayModeSwitch,
+ mDisplay->setDesiredActiveMode(
+ {scheduler::FrameRateMode{90_Hz, kMode90}, Event::None}));
ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
- EXPECT_EQ(kMode90, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, mDisplay->getDesiredActiveMode()->modeOpt);
EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
hal::VsyncPeriodChangeConstraints constraints{
@@ -123,21 +147,23 @@
EXPECT_EQ(OK,
mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints,
&timeline));
- EXPECT_EQ(kMode90, mDisplay->getUpcomingActiveMode().mode);
+ EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, *mDisplay->getUpcomingActiveMode().modeOpt);
EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event);
- EXPECT_FALSE(mDisplay->setDesiredActiveMode({kMode120, Event::None}));
+ EXPECT_EQ(Action::None,
+ mDisplay->setDesiredActiveMode(
+ {scheduler::FrameRateMode{120_Hz, kMode120}, Event::None}));
ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
- EXPECT_EQ(kMode120, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, mDisplay->getDesiredActiveMode()->modeOpt);
EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
- EXPECT_EQ(kMode90, mDisplay->getUpcomingActiveMode().mode);
+ EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, *mDisplay->getUpcomingActiveMode().modeOpt);
EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event);
EXPECT_EQ(OK,
mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints,
&timeline));
- EXPECT_EQ(kMode120, mDisplay->getUpcomingActiveMode().mode);
+ EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, *mDisplay->getUpcomingActiveMode().modeOpt);
EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event);
mDisplay->clearDesiredActiveModeState();
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
index 8757e63..fdf2ffe 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
@@ -31,6 +31,9 @@
#include "FpsOps.h"
#include "Scheduler/RefreshRateSelector.h"
#include "mock/DisplayHardware/MockDisplayMode.h"
+#include "mock/MockFrameRateMode.h"
+
+#include "libsurfaceflinger_unittest_main.h"
using namespace std::chrono_literals;
@@ -45,44 +48,41 @@
using mock::createDisplayMode;
-// Use a C style macro to keep the line numbers printed in gtest
-#define EXPECT_SCORED_FRAME_RATE(modePtr, fps, scored) \
- EXPECT_EQ((FrameRateMode{(fps), (modePtr)}), (scored).frameRateMode)
-
struct TestableRefreshRateSelector : RefreshRateSelector {
using RefreshRateSelector::FrameRateRanking;
using RefreshRateSelector::RefreshRateOrder;
using RefreshRateSelector::RefreshRateSelector;
- void setActiveModeId(DisplayModeId modeId) {
+ void setActiveMode(DisplayModeId modeId, Fps renderFrameRate) {
ftl::FakeGuard guard(kMainThreadContext);
- return RefreshRateSelector::setActiveModeId(modeId);
+ return RefreshRateSelector::setActiveMode(modeId, renderFrameRate);
}
const DisplayMode& getActiveMode() const {
- ftl::FakeGuard guard(kMainThreadContext);
- return RefreshRateSelector::getActiveMode();
+ std::lock_guard lock(mLock);
+ return *RefreshRateSelector::getActiveModeLocked().modePtr;
}
- DisplayModePtr getMinSupportedRefreshRate() const {
+ ftl::NonNull<DisplayModePtr> getMinSupportedRefreshRate() const {
std::lock_guard lock(mLock);
- return mMinRefreshRateModeIt->second;
+ return ftl::as_non_null(mMinRefreshRateModeIt->second);
}
- DisplayModePtr getMaxSupportedRefreshRate() const {
+ ftl::NonNull<DisplayModePtr> getMaxSupportedRefreshRate() const {
std::lock_guard lock(mLock);
- return mMaxRefreshRateModeIt->second;
+ return ftl::as_non_null(mMaxRefreshRateModeIt->second);
}
- DisplayModePtr getMinRefreshRateByPolicy() const {
+ ftl::NonNull<DisplayModePtr> getMinRefreshRateByPolicy() const {
std::lock_guard lock(mLock);
- return getMinRefreshRateByPolicyLocked();
+ return ftl::as_non_null(getMinRefreshRateByPolicyLocked());
}
- DisplayModePtr getMaxRefreshRateByPolicy() const {
+ ftl::NonNull<DisplayModePtr> getMaxRefreshRateByPolicy() const {
std::lock_guard lock(mLock);
- return getMaxRefreshRateByPolicyLocked(getActiveModeItLocked()->second->getGroup());
+ return ftl::as_non_null(
+ getMaxRefreshRateByPolicyLocked(getActiveModeLocked().modePtr->getGroup()));
}
FrameRateRanking rankRefreshRates(std::optional<int> anchorGroupOpt,
@@ -112,8 +112,8 @@
return std::make_pair(ranking, consideredSignals);
}
- DisplayModePtr getBestFrameRateMode(const std::vector<LayerRequirement>& layers = {},
- GlobalSignals signals = {}) const {
+ ftl::NonNull<DisplayModePtr> getBestFrameRateMode(
+ const std::vector<LayerRequirement>& layers = {}, GlobalSignals signals = {}) const {
return getRankedFrameRates(layers, signals).ranking.front().frameRateMode.modePtr;
}
@@ -154,25 +154,42 @@
static constexpr DisplayModeId kModeId60Frac{10};
static constexpr DisplayModeId kModeId35{11};
- static inline const DisplayModePtr kMode60 = createDisplayMode(kModeId60, 60_Hz);
- static inline const DisplayModePtr kMode60Frac = createDisplayMode(kModeId60Frac, 59.94_Hz);
- static inline const DisplayModePtr kMode90 = createDisplayMode(kModeId90, 90_Hz);
- static inline const DisplayModePtr kMode90_G1 = createDisplayMode(kModeId90, 90_Hz, 1);
- static inline const DisplayModePtr kMode90_4K =
- createDisplayMode(kModeId90, 90_Hz, 0, {3840, 2160});
- static inline const DisplayModePtr kMode72 = createDisplayMode(kModeId72, 72_Hz);
- static inline const DisplayModePtr kMode72_G1 = createDisplayMode(kModeId72, 72_Hz, 1);
- static inline const DisplayModePtr kMode120 = createDisplayMode(kModeId120, 120_Hz);
- static inline const DisplayModePtr kMode120_G1 = createDisplayMode(kModeId120, 120_Hz, 1);
- static inline const DisplayModePtr kMode30 = createDisplayMode(kModeId30, 30_Hz);
- static inline const DisplayModePtr kMode30_G1 = createDisplayMode(kModeId30, 30_Hz, 1);
- static inline const DisplayModePtr kMode30Frac = createDisplayMode(kModeId30Frac, 29.97_Hz);
- static inline const DisplayModePtr kMode25 = createDisplayMode(kModeId25, 25_Hz);
- static inline const DisplayModePtr kMode25_G1 = createDisplayMode(kModeId25, 25_Hz, 1);
- static inline const DisplayModePtr kMode35 = createDisplayMode(kModeId35, 35_Hz);
- static inline const DisplayModePtr kMode50 = createDisplayMode(kModeId50, 50_Hz);
- static inline const DisplayModePtr kMode24 = createDisplayMode(kModeId24, 24_Hz);
- static inline const DisplayModePtr kMode24Frac = createDisplayMode(kModeId24Frac, 23.976_Hz);
+ static inline const ftl::NonNull<DisplayModePtr> kMode60 =
+ ftl::as_non_null(createDisplayMode(kModeId60, 60_Hz));
+ static inline const ftl::NonNull<DisplayModePtr> kMode60Frac =
+ ftl::as_non_null(createDisplayMode(kModeId60Frac, 59.94_Hz));
+ static inline const ftl::NonNull<DisplayModePtr> kMode90 =
+ ftl::as_non_null(createDisplayMode(kModeId90, 90_Hz));
+ static inline const ftl::NonNull<DisplayModePtr> kMode90_G1 =
+ ftl::as_non_null(createDisplayMode(kModeId90, 90_Hz, 1));
+ static inline const ftl::NonNull<DisplayModePtr> kMode90_4K =
+ ftl::as_non_null(createDisplayMode(kModeId90, 90_Hz, 0, {3840, 2160}));
+ static inline const ftl::NonNull<DisplayModePtr> kMode72 =
+ ftl::as_non_null(createDisplayMode(kModeId72, 72_Hz));
+ static inline const ftl::NonNull<DisplayModePtr> kMode72_G1 =
+ ftl::as_non_null(createDisplayMode(kModeId72, 72_Hz, 1));
+ static inline const ftl::NonNull<DisplayModePtr> kMode120 =
+ ftl::as_non_null(createDisplayMode(kModeId120, 120_Hz));
+ static inline const ftl::NonNull<DisplayModePtr> kMode120_G1 =
+ ftl::as_non_null(createDisplayMode(kModeId120, 120_Hz, 1));
+ static inline const ftl::NonNull<DisplayModePtr> kMode30 =
+ ftl::as_non_null(createDisplayMode(kModeId30, 30_Hz));
+ static inline const ftl::NonNull<DisplayModePtr> kMode30_G1 =
+ ftl::as_non_null(createDisplayMode(kModeId30, 30_Hz, 1));
+ static inline const ftl::NonNull<DisplayModePtr> kMode30Frac =
+ ftl::as_non_null(createDisplayMode(kModeId30Frac, 29.97_Hz));
+ static inline const ftl::NonNull<DisplayModePtr> kMode25 =
+ ftl::as_non_null(createDisplayMode(kModeId25, 25_Hz));
+ static inline const ftl::NonNull<DisplayModePtr> kMode25_G1 =
+ ftl::as_non_null(createDisplayMode(kModeId25, 25_Hz, 1));
+ static inline const ftl::NonNull<DisplayModePtr> kMode35 =
+ ftl::as_non_null(createDisplayMode(kModeId35, 35_Hz));
+ static inline const ftl::NonNull<DisplayModePtr> kMode50 =
+ ftl::as_non_null(createDisplayMode(kModeId50, 50_Hz));
+ static inline const ftl::NonNull<DisplayModePtr> kMode24 =
+ ftl::as_non_null(createDisplayMode(kModeId24, 24_Hz));
+ static inline const ftl::NonNull<DisplayModePtr> kMode24Frac =
+ ftl::as_non_null(createDisplayMode(kModeId24Frac, 23.976_Hz));
// Test configurations.
static inline const DisplayModes kModes_60 = makeModes(kMode60);
@@ -298,7 +315,7 @@
EXPECT_EQ(SetPolicyResult::Changed,
selector.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}}));
- selector.setActiveModeId(kModeId90);
+ selector.setActiveMode(kModeId90, 90_Hz);
const auto minRate90 = selector.getMinRefreshRateByPolicy();
const auto performanceRate90 = selector.getMaxRefreshRateByPolicy();
@@ -322,7 +339,7 @@
EXPECT_EQ(SetPolicyResult::Changed,
selector.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}}));
- selector.setActiveModeId(kModeId90);
+ selector.setActiveMode(kModeId90, 90_Hz);
const auto minRate90 = selector.getMinRefreshRateByPolicy();
const auto performanceRate90 = selector.getMaxRefreshRateByPolicy();
@@ -358,7 +375,7 @@
EXPECT_EQ(mode.getId(), kModeId60);
}
- selector.setActiveModeId(kModeId90);
+ selector.setActiveMode(kModeId90, 90_Hz);
{
const auto& mode = selector.getActiveMode();
EXPECT_EQ(mode.getId(), kModeId90);
@@ -1805,7 +1822,7 @@
policy.allowGroupSwitching = true;
EXPECT_EQ(SetPolicyResult::Changed, selector.setPolicy(policy));
- selector.setActiveModeId(kModeId90);
+ selector.setActiveMode(kModeId90, 90_Hz);
// Verify that we won't do a seamless switch if we request the same mode as the default
std::vector<LayerRequirement> layers = {{.weight = 1.f}};
@@ -1826,7 +1843,7 @@
policy.allowGroupSwitching = true;
EXPECT_EQ(SetPolicyResult::Changed, selector.setPolicy(policy));
- selector.setActiveModeId(kModeId90);
+ selector.setActiveMode(kModeId90, 90_Hz);
// Verify that if the active mode is in another group and there are no layers with
// Seamlessness::SeamedAndSeamless, we should switch back to the default group.
@@ -1850,7 +1867,7 @@
policy.allowGroupSwitching = true;
EXPECT_EQ(SetPolicyResult::Changed, selector.setPolicy(policy));
- selector.setActiveModeId(kModeId90);
+ selector.setActiveMode(kModeId90, 90_Hz);
// If there's a layer with Seamlessness::SeamedAndSeamless, another layer with
// Seamlessness::OnlySeamless can't change the mode group.
@@ -1879,7 +1896,7 @@
policy.allowGroupSwitching = true;
EXPECT_EQ(SetPolicyResult::Changed, selector.setPolicy(policy));
- selector.setActiveModeId(kModeId90);
+ selector.setActiveMode(kModeId90, 90_Hz);
// If there's a focused layer with Seamlessness::SeamedAndSeamless, another layer with
// Seamlessness::Default can't change the mode group back to the group of the default
@@ -1912,7 +1929,7 @@
policy.allowGroupSwitching = true;
EXPECT_EQ(SetPolicyResult::Changed, selector.setPolicy(policy));
- selector.setActiveModeId(kModeId90);
+ selector.setActiveMode(kModeId90, 90_Hz);
// Layer with Seamlessness::Default can change the mode group if there's an
// unfocused layer with Seamlessness::SeamedAndSeamless. For example, this happens
@@ -1953,7 +1970,7 @@
EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers)->getId());
- selector.setActiveModeId(kModeId120);
+ selector.setActiveMode(kModeId120, 120_Hz);
EXPECT_EQ(kModeId120, selector.getBestFrameRateMode(layers)->getId());
}
@@ -1984,7 +2001,7 @@
auto& seamedLayer = layers[0];
seamedLayer.desiredRefreshRate = 30_Hz;
seamedLayer.name = "30Hz ExplicitDefault";
- selector.setActiveModeId(kModeId30);
+ selector.setActiveMode(kModeId30, 30_Hz);
EXPECT_EQ(kModeId25, selector.getBestFrameRateMode(layers)->getId());
}
@@ -2102,7 +2119,7 @@
EXPECT_EQ(kModeId90, selector.getBestFrameRateMode({}, {.touch = true, .idle = true})->getId());
// Idle should be higher precedence than other layer frame rate considerations.
- selector.setActiveModeId(kModeId90);
+ selector.setActiveMode(kModeId90, 90_Hz);
{
constexpr bool kTouchActive = false;
@@ -2142,7 +2159,7 @@
struct Expectation {
Fps fps;
- DisplayModePtr mode;
+ ftl::NonNull<DisplayModePtr> mode;
};
const std::initializer_list<Expectation> knownFrameRatesExpectations = {
@@ -2185,33 +2202,39 @@
explicitExactOrMultipleLayer.desiredRefreshRate = 60_Hz;
if (GetParam() == Config::FrameRateOverride::Disabled) {
- EXPECT_SCORED_FRAME_RATE(kMode30, 30_Hz, selector.getBestScoredFrameRate(layers));
- EXPECT_SCORED_FRAME_RATE(kMode30, 30_Hz,
- selector.getBestScoredFrameRate(layers, {.touch = true}));
+ EXPECT_FRAME_RATE_MODE(kMode30, 30_Hz,
+ selector.getBestScoredFrameRate(layers).frameRateMode);
+ EXPECT_FRAME_RATE_MODE(kMode30, 30_Hz,
+ selector.getBestScoredFrameRate(layers, {.touch = true})
+ .frameRateMode);
} else {
- EXPECT_SCORED_FRAME_RATE(kMode60, 60_Hz, selector.getBestScoredFrameRate(layers));
- EXPECT_SCORED_FRAME_RATE(kMode120, 120_Hz,
- selector.getBestScoredFrameRate(layers, {.touch = true}));
+ EXPECT_FRAME_RATE_MODE(kMode60, 60_Hz,
+ selector.getBestScoredFrameRate(layers).frameRateMode);
+ EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz,
+ selector.getBestScoredFrameRate(layers, {.touch = true})
+ .frameRateMode);
}
explicitExactOrMultipleLayer.desiredRefreshRate = 120_Hz;
explicitExactLayer.desiredRefreshRate = 60_Hz;
if (GetParam() == Config::FrameRateOverride::Disabled) {
- EXPECT_SCORED_FRAME_RATE(kMode60, 60_Hz, selector.getBestScoredFrameRate(layers));
+ EXPECT_FRAME_RATE_MODE(kMode60, 60_Hz,
+ selector.getBestScoredFrameRate(layers).frameRateMode);
} else {
- EXPECT_SCORED_FRAME_RATE(kMode120, 120_Hz, selector.getBestScoredFrameRate(layers));
+ EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz,
+ selector.getBestScoredFrameRate(layers).frameRateMode);
}
explicitExactLayer.desiredRefreshRate = 72_Hz;
- EXPECT_SCORED_FRAME_RATE(kMode72, 72_Hz, selector.getBestScoredFrameRate(layers));
+ EXPECT_FRAME_RATE_MODE(kMode72, 72_Hz, selector.getBestScoredFrameRate(layers).frameRateMode);
explicitExactLayer.desiredRefreshRate = 90_Hz;
- EXPECT_SCORED_FRAME_RATE(kMode90, 90_Hz, selector.getBestScoredFrameRate(layers));
+ EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, selector.getBestScoredFrameRate(layers).frameRateMode);
explicitExactLayer.desiredRefreshRate = 120_Hz;
- EXPECT_SCORED_FRAME_RATE(kMode120, 120_Hz, selector.getBestScoredFrameRate(layers));
+ EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, selector.getBestScoredFrameRate(layers).frameRateMode);
}
TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_ReadsCache) {
@@ -2295,6 +2318,10 @@
// b/190578904
TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withCloseRefreshRates) {
+ if (g_noSlowTests) {
+ GTEST_SKIP();
+ }
+
const int kMinRefreshRate = RefreshRateSelector::kMinSupportedFrameRate.getIntValue();
constexpr int kMaxRefreshRate = 240;
@@ -2409,23 +2436,23 @@
Fps displayRefreshRate = selector.getActiveMode().getFps();
EXPECT_EQ(1, RefreshRateSelector::getFrameRateDivisor(displayRefreshRate, frameRate));
- selector.setActiveModeId(kModeId60);
+ selector.setActiveMode(kModeId60, 60_Hz);
displayRefreshRate = selector.getActiveMode().getFps();
EXPECT_EQ(2, RefreshRateSelector::getFrameRateDivisor(displayRefreshRate, frameRate));
- selector.setActiveModeId(kModeId72);
+ selector.setActiveMode(kModeId72, 72_Hz);
displayRefreshRate = selector.getActiveMode().getFps();
EXPECT_EQ(0, RefreshRateSelector::getFrameRateDivisor(displayRefreshRate, frameRate));
- selector.setActiveModeId(kModeId90);
+ selector.setActiveMode(kModeId90, 90_Hz);
displayRefreshRate = selector.getActiveMode().getFps();
EXPECT_EQ(3, RefreshRateSelector::getFrameRateDivisor(displayRefreshRate, frameRate));
- selector.setActiveModeId(kModeId120);
+ selector.setActiveMode(kModeId120, 120_Hz);
displayRefreshRate = selector.getActiveMode().getFps();
EXPECT_EQ(4, RefreshRateSelector::getFrameRateDivisor(displayRefreshRate, frameRate));
- selector.setActiveModeId(kModeId90);
+ selector.setActiveMode(kModeId90, 90_Hz);
displayRefreshRate = selector.getActiveMode().getFps();
EXPECT_EQ(4, RefreshRateSelector::getFrameRateDivisor(displayRefreshRate, 22.5_Hz));
@@ -2808,7 +2835,7 @@
constexpr FpsRanges kAppRequest = {/*physical*/ k0_120Hz,
/*render*/ k0_120Hz};
- EXPECT_SCORED_FRAME_RATE(kMode120, 120_Hz, selector.getBestScoredFrameRate());
+ EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, selector.getBestScoredFrameRate().frameRateMode);
{
constexpr FpsRanges kPrimary = {/*physical*/ k0_120Hz,
/*render*/ k0_120Hz};
@@ -2819,7 +2846,7 @@
/*appRequestRanges*/
kAppRequest}));
}
- EXPECT_SCORED_FRAME_RATE(kMode120, 120_Hz, selector.getBestScoredFrameRate());
+ EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, selector.getBestScoredFrameRate().frameRateMode);
{
constexpr FpsRanges kPrimary = {/*physical*/ k0_60Hz,
@@ -2831,7 +2858,7 @@
/*appRequestRanges*/
kAppRequest}));
}
- EXPECT_SCORED_FRAME_RATE(kMode60, 60_Hz, selector.getBestScoredFrameRate());
+ EXPECT_FRAME_RATE_MODE(kMode60, 60_Hz, selector.getBestScoredFrameRate().frameRateMode);
{
constexpr FpsRanges kPrimary = {/*physical*/ k0_120Hz,
@@ -2843,7 +2870,7 @@
/*appRequestRanges*/
kAppRequest}));
}
- EXPECT_SCORED_FRAME_RATE(kMode60, 60_Hz, selector.getBestScoredFrameRate());
+ EXPECT_FRAME_RATE_MODE(kMode60, 60_Hz, selector.getBestScoredFrameRate().frameRateMode);
}
TEST_P(RefreshRateSelectorTest, renderFrameRates_60_120) {
@@ -2858,17 +2885,20 @@
layer.name = "30Hz ExplicitDefault";
layer.desiredRefreshRate = 30_Hz;
layer.vote = LayerVoteType::ExplicitDefault;
- EXPECT_SCORED_FRAME_RATE(kMode60, expectedRenderRate, selector.getBestScoredFrameRate(layers));
+ EXPECT_FRAME_RATE_MODE(kMode60, expectedRenderRate,
+ selector.getBestScoredFrameRate(layers).frameRateMode);
layer.name = "30Hz Heuristic";
layer.desiredRefreshRate = 30_Hz;
layer.vote = LayerVoteType::Heuristic;
- EXPECT_SCORED_FRAME_RATE(kMode60, expectedRenderRate, selector.getBestScoredFrameRate(layers));
+ EXPECT_FRAME_RATE_MODE(kMode60, expectedRenderRate,
+ selector.getBestScoredFrameRate(layers).frameRateMode);
layer.name = "30Hz ExplicitExactOrMultiple";
layer.desiredRefreshRate = 30_Hz;
layer.vote = LayerVoteType::ExplicitExactOrMultiple;
- EXPECT_SCORED_FRAME_RATE(kMode60, expectedRenderRate, selector.getBestScoredFrameRate(layers));
+ EXPECT_FRAME_RATE_MODE(kMode60, expectedRenderRate,
+ selector.getBestScoredFrameRate(layers).frameRateMode);
}
TEST_P(RefreshRateSelectorTest, idleWhenLowestRefreshRateIsNotDivisor) {
@@ -2897,7 +2927,7 @@
EXPECT_EQ(kModeId90, selector.getBestFrameRateMode({}, {.touch = true, .idle = true})->getId());
// Idle should be higher precedence than other layer frame rate considerations.
- selector.setActiveModeId(kModeId90);
+ selector.setActiveMode(kModeId90, 90_Hz);
{
constexpr bool kTouchActive = false;
EXPECT_EQ(kModeId35, getIdleDisplayModeId(LayerVoteType::NoVote, kTouchActive));
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 8e333a3..3ee53c9 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -58,22 +58,22 @@
SchedulerTest();
static constexpr PhysicalDisplayId kDisplayId1 = PhysicalDisplayId::fromPort(255u);
- static inline const DisplayModePtr kDisplay1Mode60 =
- createDisplayMode(kDisplayId1, DisplayModeId(0), 60_Hz);
- static inline const DisplayModePtr kDisplay1Mode120 =
- createDisplayMode(kDisplayId1, DisplayModeId(1), 120_Hz);
+ static inline const ftl::NonNull<DisplayModePtr> kDisplay1Mode60 =
+ ftl::as_non_null(createDisplayMode(kDisplayId1, DisplayModeId(0), 60_Hz));
+ static inline const ftl::NonNull<DisplayModePtr> kDisplay1Mode120 =
+ ftl::as_non_null(createDisplayMode(kDisplayId1, DisplayModeId(1), 120_Hz));
static inline const DisplayModes kDisplay1Modes = makeModes(kDisplay1Mode60, kDisplay1Mode120);
static constexpr PhysicalDisplayId kDisplayId2 = PhysicalDisplayId::fromPort(254u);
- static inline const DisplayModePtr kDisplay2Mode60 =
- createDisplayMode(kDisplayId2, DisplayModeId(0), 60_Hz);
- static inline const DisplayModePtr kDisplay2Mode120 =
- createDisplayMode(kDisplayId2, DisplayModeId(1), 120_Hz);
+ static inline const ftl::NonNull<DisplayModePtr> kDisplay2Mode60 =
+ ftl::as_non_null(createDisplayMode(kDisplayId2, DisplayModeId(0), 60_Hz));
+ static inline const ftl::NonNull<DisplayModePtr> kDisplay2Mode120 =
+ ftl::as_non_null(createDisplayMode(kDisplayId2, DisplayModeId(1), 120_Hz));
static inline const DisplayModes kDisplay2Modes = makeModes(kDisplay2Mode60, kDisplay2Mode120);
static constexpr PhysicalDisplayId kDisplayId3 = PhysicalDisplayId::fromPort(253u);
- static inline const DisplayModePtr kDisplay3Mode60 =
- createDisplayMode(kDisplayId3, DisplayModeId(0), 60_Hz);
+ static inline const ftl::NonNull<DisplayModePtr> kDisplay3Mode60 =
+ ftl::as_non_null(createDisplayMode(kDisplayId3, DisplayModeId(0), 60_Hz));
static inline const DisplayModes kDisplay3Modes = makeModes(kDisplay3Mode60);
std::shared_ptr<RefreshRateSelector> mSelector =
@@ -217,7 +217,9 @@
// If the handle is incorrect, the function should return before
// onModeChange is called.
ConnectionHandle invalidHandle = {.id = 123};
- EXPECT_NO_FATAL_FAILURE(mScheduler->onNonPrimaryDisplayModeChanged(invalidHandle, mode));
+ EXPECT_NO_FATAL_FAILURE(
+ mScheduler->onNonPrimaryDisplayModeChanged(invalidHandle,
+ {90_Hz, ftl::as_non_null(mode)}));
EXPECT_CALL(*mEventThread, onModeChanged(_)).Times(0);
}
@@ -232,7 +234,7 @@
}
MATCHER(Is120Hz, "") {
- return isApproxEqual(arg.front().modePtr->getFps(), 120_Hz);
+ return isApproxEqual(arg.front().mode.fps, 120_Hz);
}
TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) {
@@ -277,7 +279,7 @@
auto choice = modeChoices.get(kDisplayId1);
ASSERT_TRUE(choice);
- EXPECT_EQ(choice->get(), DisplayModeChoice(kDisplay1Mode60, globalSignals));
+ EXPECT_EQ(choice->get(), DisplayModeChoice({60_Hz, kDisplay1Mode60}, globalSignals));
globalSignals = {.idle = false};
mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals);
@@ -287,7 +289,7 @@
choice = modeChoices.get(kDisplayId1);
ASSERT_TRUE(choice);
- EXPECT_EQ(choice->get(), DisplayModeChoice(kDisplay1Mode120, globalSignals));
+ EXPECT_EQ(choice->get(), DisplayModeChoice({120_Hz, kDisplay1Mode120}, globalSignals));
globalSignals = {.touch = true};
mScheduler->replaceTouchTimer(10);
@@ -298,7 +300,7 @@
choice = modeChoices.get(kDisplayId1);
ASSERT_TRUE(choice);
- EXPECT_EQ(choice->get(), DisplayModeChoice(kDisplay1Mode120, globalSignals));
+ EXPECT_EQ(choice->get(), DisplayModeChoice({120_Hz, kDisplay1Mode120}, globalSignals));
mScheduler->unregisterDisplay(kDisplayId1);
EXPECT_FALSE(mScheduler->hasRefreshRateSelectors());
@@ -319,8 +321,11 @@
const GlobalSignals globalSignals = {.idle = true};
expectedChoices =
ftl::init::map<const PhysicalDisplayId&,
- DisplayModeChoice>(kDisplayId1, kDisplay1Mode60,
- globalSignals)(kDisplayId2, kDisplay2Mode60,
+ DisplayModeChoice>(kDisplayId1,
+ FrameRateMode{60_Hz, kDisplay1Mode60},
+ globalSignals)(kDisplayId2,
+ FrameRateMode{60_Hz,
+ kDisplay2Mode60},
globalSignals);
std::vector<RefreshRateSelector::LayerRequirement> layers = {{.weight = 1.f},
@@ -335,8 +340,11 @@
const GlobalSignals globalSignals = {.idle = false};
expectedChoices =
ftl::init::map<const PhysicalDisplayId&,
- DisplayModeChoice>(kDisplayId1, kDisplay1Mode120,
- globalSignals)(kDisplayId2, kDisplay2Mode120,
+ DisplayModeChoice>(kDisplayId1,
+ FrameRateMode{120_Hz, kDisplay1Mode120},
+ globalSignals)(kDisplayId2,
+ FrameRateMode{120_Hz,
+ kDisplay2Mode120},
globalSignals);
mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals);
@@ -351,8 +359,11 @@
expectedChoices =
ftl::init::map<const PhysicalDisplayId&,
- DisplayModeChoice>(kDisplayId1, kDisplay1Mode120,
- globalSignals)(kDisplayId2, kDisplay2Mode120,
+ DisplayModeChoice>(kDisplayId1,
+ FrameRateMode{120_Hz, kDisplay1Mode120},
+ globalSignals)(kDisplayId2,
+ FrameRateMode{120_Hz,
+ kDisplay2Mode120},
globalSignals);
const auto actualChoices = mScheduler->chooseDisplayModes();
@@ -369,13 +380,15 @@
mScheduler->replaceTouchTimer(10);
mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals);
- expectedChoices =
- ftl::init::map<const PhysicalDisplayId&,
- DisplayModeChoice>(kDisplayId1, kDisplay1Mode60,
- globalSignals)(kDisplayId2, kDisplay2Mode60,
- globalSignals)(kDisplayId3,
- kDisplay3Mode60,
- globalSignals);
+ expectedChoices = ftl::init::map<
+ const PhysicalDisplayId&,
+ DisplayModeChoice>(kDisplayId1, FrameRateMode{60_Hz, kDisplay1Mode60},
+ globalSignals)(kDisplayId2,
+ FrameRateMode{60_Hz, kDisplay2Mode60},
+ globalSignals)(kDisplayId3,
+ FrameRateMode{60_Hz,
+ kDisplay3Mode60},
+ globalSignals);
const auto actualChoices = mScheduler->chooseDisplayModes();
EXPECT_EQ(expectedChoices, actualChoices);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
index 05d0ebf..b81693a 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
@@ -116,7 +116,7 @@
ftl::FakeGuard guard(kMainThreadContext);
ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getActiveMode().getId(), kModeId60);
+ ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60);
mFlinger.onActiveDisplayChanged(mDisplay);
@@ -125,8 +125,8 @@
120));
ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kModeId90);
- ASSERT_EQ(mDisplay->getActiveMode().getId(), kModeId60);
+ ASSERT_EQ(mDisplay->getDesiredActiveMode()->modeOpt->modePtr->getId(), kModeId90);
+ ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60);
// Verify that next commit will call setActiveConfigWithConstraints in HWC
const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
@@ -139,7 +139,7 @@
Mock::VerifyAndClearExpectations(mComposer);
ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getActiveMode().getId(), kModeId60);
+ ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60);
// Verify that the next commit will complete the mode change and send
// a onModeChanged event to the framework.
@@ -149,7 +149,7 @@
Mock::VerifyAndClearExpectations(mAppEventThread);
ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getActiveMode().getId(), kModeId90);
+ ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId90);
}
TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithoutRefreshRequired) {
@@ -164,8 +164,8 @@
120));
ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kModeId90);
- ASSERT_EQ(mDisplay->getActiveMode().getId(), kModeId60);
+ ASSERT_EQ(mDisplay->getDesiredActiveMode()->modeOpt->modePtr->getId(), kModeId90);
+ ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60);
// Verify that next commit will call setActiveConfigWithConstraints in HWC
// and complete the mode change.
@@ -180,7 +180,7 @@
mFlinger.commit();
ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getActiveMode().getId(), kModeId90);
+ ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId90);
}
TEST_F(DisplayModeSwitchingTest, twoConsecutiveSetDesiredDisplayModeSpecs) {
@@ -190,7 +190,7 @@
// is still being processed the later call will be respected.
ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getActiveMode().getId(), kModeId60);
+ ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60);
mFlinger.onActiveDisplayChanged(mDisplay);
@@ -211,7 +211,7 @@
180));
ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kModeId120);
+ ASSERT_EQ(mDisplay->getDesiredActiveMode()->modeOpt->modePtr->getId(), kModeId120);
EXPECT_CALL(*mComposer,
setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID,
@@ -221,19 +221,19 @@
mFlinger.commit();
ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kModeId120);
+ ASSERT_EQ(mDisplay->getDesiredActiveMode()->modeOpt->modePtr->getId(), kModeId120);
mFlinger.commit();
ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getActiveMode().getId(), kModeId120);
+ ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId120);
}
TEST_F(DisplayModeSwitchingTest, changeResolution_OnActiveDisplay_WithoutRefreshRequired) {
ftl::FakeGuard guard(kMainThreadContext);
ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getActiveMode().getId(), kModeId60);
+ ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60);
mFlinger.onActiveDisplayChanged(mDisplay);
@@ -242,8 +242,8 @@
120));
ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kModeId90_4K);
- ASSERT_EQ(mDisplay->getActiveMode().getId(), kModeId60);
+ ASSERT_EQ(mDisplay->getDesiredActiveMode()->modeOpt->modePtr->getId(), kModeId90_4K);
+ ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60);
// Verify that next commit will call setActiveConfigWithConstraints in HWC
// and complete the mode change.
@@ -278,7 +278,7 @@
mDisplay = mFlinger.getDisplay(displayToken);
ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
- ASSERT_EQ(mDisplay->getActiveMode().getId(), kModeId90_4K);
+ ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId90_4K);
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
index 0384568..c0796df 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
@@ -288,7 +288,7 @@
if constexpr (Case::Display::CONNECTION_TYPE::value) {
ftl::FakeGuard guard(kMainThreadContext);
- EXPECT_EQ(Case::Display::HWC_ACTIVE_CONFIG_ID, device->getActiveMode().getHwcId());
+ EXPECT_EQ(Case::Display::HWC_ACTIVE_CONFIG_ID, device->getActiveMode().modePtr->getHwcId());
}
}
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index 3f8fe0d..54c10c5 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -44,8 +44,7 @@
: Scheduler(*this, callback, Feature::kContentDetection) {
mVsyncSchedule.emplace(VsyncSchedule(std::move(tracker), nullptr, std::move(controller)));
- const auto displayId = FTL_FAKE_GUARD(kMainThreadContext,
- selectorPtr->getActiveMode().getPhysicalDisplayId());
+ const auto displayId = selectorPtr->getActiveMode().modePtr->getPhysicalDisplayId();
registerDisplay(displayId, std::move(selectorPtr));
ON_CALL(*this, postMessage).WillByDefault([](sp<MessageHandler>&& handler) {
@@ -147,7 +146,7 @@
mPolicy.cachedModeChangedParams.reset();
}
- void onNonPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) {
+ void onNonPrimaryDisplayModeChanged(ConnectionHandle handle, const FrameRateMode& mode) {
Scheduler::onNonPrimaryDisplayModeChanged(handle, mode);
}
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index c15b3c8..e29dd67 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -221,7 +221,7 @@
selectorPtr = std::make_shared<scheduler::RefreshRateSelector>(modes, kModeId60);
}
- const auto fps = FTL_FAKE_GUARD(kMainThreadContext, selectorPtr->getActiveMode().getFps());
+ const auto fps = selectorPtr->getActiveMode().fps;
mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(fps);
mFlinger->mVsyncModulator = sp<scheduler::VsyncModulator>::make(
mFlinger->mVsyncConfiguration->getCurrentConfigs());
@@ -857,23 +857,24 @@
const auto activeMode = modes.get(activeModeId);
LOG_ALWAYS_FATAL_IF(!activeMode);
+ const auto fps = activeMode->get()->getFps();
state.physical = {.id = physicalId,
.hwcDisplayId = *mHwcDisplayId,
.activeMode = activeMode->get()};
- const auto it = mFlinger.mutablePhysicalDisplays()
- .emplace_or_replace(physicalId, mDisplayToken, physicalId,
- *mConnectionType, std::move(modes),
- ui::ColorModes(), std::nullopt)
- .first;
+ mFlinger.mutablePhysicalDisplays().emplace_or_replace(physicalId, mDisplayToken,
+ physicalId, *mConnectionType,
+ std::move(modes),
+ ui::ColorModes(),
+ std::nullopt);
if (mFlinger.scheduler()) {
mFlinger.scheduler()->registerDisplay(physicalId,
display->holdRefreshRateSelector());
}
- display->setActiveMode(activeModeId, it->second.snapshot());
+ display->setActiveMode(activeModeId, fps, fps);
}
mFlinger.mutableCurrentState().displays.add(mDisplayToken, state);
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
index 2da266b..47c2dee 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
@@ -54,6 +54,7 @@
void resetModel() final {}
bool needsMoreSamples() const final { return false; }
bool isVSyncInPhase(nsecs_t, Fps) const final { return false; }
+ void setDivisor(unsigned) final {}
void dump(std::string&) const final {}
private:
@@ -91,6 +92,7 @@
void resetModel() final {}
bool needsMoreSamples() const final { return false; }
bool isVSyncInPhase(nsecs_t, Fps) const final { return false; }
+ void setDivisor(unsigned) final {}
void dump(std::string&) const final {}
private:
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index f660753..2b86e94 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -55,6 +55,7 @@
MOCK_METHOD0(resetModel, void());
MOCK_CONST_METHOD0(needsMoreSamples, bool());
MOCK_CONST_METHOD2(isVSyncInPhase, bool(nsecs_t, Fps));
+ MOCK_METHOD(void, setDivisor, (unsigned), (override));
MOCK_CONST_METHOD1(dump, void(std::string&));
nsecs_t nextVSyncTime(nsecs_t timePoint) const {
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index 74d2b7d..3095e8a 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -532,6 +532,26 @@
EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
}
+TEST_F(VSyncPredictorTest, setDivisorIsRespected) {
+ auto last = mNow;
+ for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
+ EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod));
+ mNow += mPeriod;
+ last = mNow;
+ tracker.addVsyncTimestamp(mNow);
+ }
+
+ tracker.setDivisor(3);
+
+ EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
+ EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 100), Eq(mNow + mPeriod));
+ EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 1100), Eq(mNow + 4 * mPeriod));
+ EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 2100), Eq(mNow + 4 * mPeriod));
+ EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 3100), Eq(mNow + 4 * mPeriod));
+ EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 4100), Eq(mNow + 7 * mPeriod));
+ EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 5100), Eq(mNow + 7 * mPeriod));
+}
+
} // namespace android::scheduler
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index a35ff96..8bd689a 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -50,6 +50,7 @@
MOCK_METHOD0(resetModel, void());
MOCK_CONST_METHOD0(needsMoreSamples, bool());
MOCK_CONST_METHOD2(isVSyncInPhase, bool(nsecs_t, Fps));
+ MOCK_METHOD(void, setDivisor, (unsigned), (override));
MOCK_CONST_METHOD1(dump, void(std::string&));
};
diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameRateMode.h b/services/surfaceflinger/tests/unittests/mock/MockFrameRateMode.h
new file mode 100644
index 0000000..ef9cd9b
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameRateMode.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2022 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 <scheduler/FrameRateMode.h>
+
+// Use a C style macro to keep the line numbers printed in gtest
+#define EXPECT_FRAME_RATE_MODE(modePtr, fps, mode) \
+ EXPECT_EQ((scheduler::FrameRateMode{(fps), (modePtr)}), (mode))
diff --git a/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h b/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h
index 5b0c1f3..6893154 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h
@@ -34,6 +34,7 @@
MOCK_METHOD0(resetModel, void());
MOCK_CONST_METHOD0(needsMoreSamples, bool());
MOCK_CONST_METHOD2(isVSyncInPhase, bool(nsecs_t, Fps));
+ MOCK_METHOD(void, setDivisor, (unsigned), (override));
MOCK_CONST_METHOD1(dump, void(std::string&));
};