Add MRR guard logic to SF scheduler
Uses a flag to guard the new dVRR scheduler features
from MRR devices. This is to easily allow development on
dVRR devices and MRR devices separately.
Bug: 330224639
Test: atest libsurfaceflinger_unittest
Test: atest CtsSurfaceControlTestsStaging
Test: dumpsys and observe no category or GTE
Change-Id: I8be520b5630c1a8fbde5f0fb2265e803e46983a8
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index b8d5e76..974c837 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -40,14 +40,15 @@
namespace {
-bool isLayerActive(const LayerInfo& info, nsecs_t threshold) {
+bool isLayerActive(const LayerInfo& info, nsecs_t threshold, bool isVrrDevice) {
if (FlagManager::getInstance().misc1() && !info.isVisible()) {
return false;
}
// Layers with an explicit frame rate or frame rate category are kept active,
// but ignore NoVote.
- if (info.getSetFrameRateVote().isValid() && !info.getSetFrameRateVote().isNoVote()) {
+ const auto frameRate = info.getSetFrameRateVote();
+ if (frameRate.isValid() && !frameRate.isNoVote() && frameRate.isVoteValidForMrr(isVrrDevice)) {
return true;
}
@@ -194,7 +195,7 @@
std::lock_guard lock(mLock);
- partitionLayers(now);
+ partitionLayers(now, selector.isVrrDevice());
for (const auto& [key, value] : mActiveLayerInfos) {
auto& info = value.second;
@@ -236,7 +237,7 @@
return summary;
}
-void LayerHistory::partitionLayers(nsecs_t now) {
+void LayerHistory::partitionLayers(nsecs_t now, bool isVrrDevice) {
ATRACE_CALL();
const nsecs_t threshold = getActiveLayerThreshold(now);
@@ -244,7 +245,7 @@
LayerInfos::iterator it = mInactiveLayerInfos.begin();
while (it != mInactiveLayerInfos.end()) {
auto& [layerUnsafe, info] = it->second;
- if (isLayerActive(*info, threshold)) {
+ if (isLayerActive(*info, threshold, isVrrDevice)) {
// move this to the active map
mActiveLayerInfos.insert({it->first, std::move(it->second)});
@@ -262,7 +263,7 @@
it = mActiveLayerInfos.begin();
while (it != mActiveLayerInfos.end()) {
auto& [layerUnsafe, info] = it->second;
- if (isLayerActive(*info, threshold)) {
+ if (isLayerActive(*info, threshold, isVrrDevice)) {
// Set layer vote if set
const auto frameRate = info->getSetFrameRateVote();
@@ -305,7 +306,7 @@
trace(*info, gameFrameRateOverrideVoteType,
gameModeFrameRateOverride.getIntValue());
}
- } else if (frameRate.isValid()) {
+ } else if (frameRate.isValid() && frameRate.isVoteValidForMrr(isVrrDevice)) {
info->setLayerVote({setFrameRateVoteType, frameRate.vote.rate,
frameRate.vote.seamlessness, frameRate.category});
if (CC_UNLIKELY(mTraceEnabled)) {
@@ -321,14 +322,30 @@
gameDefaultFrameRateOverride.getIntValue());
}
} else {
+ if (frameRate.isValid() && !frameRate.isVoteValidForMrr(isVrrDevice)) {
+ ATRACE_FORMAT_INSTANT("Reset layer to ignore explicit vote on MRR %s: %s "
+ "%s %s",
+ info->getName().c_str(),
+ ftl::enum_string(frameRate.vote.type).c_str(),
+ to_string(frameRate.vote.rate).c_str(),
+ ftl::enum_string(frameRate.category).c_str());
+ }
info->resetLayerVote();
}
} else {
- if (frameRate.isValid()) {
+ if (frameRate.isValid() && frameRate.isVoteValidForMrr(isVrrDevice)) {
const auto type = info->isVisible() ? voteType : LayerVoteType::NoVote;
info->setLayerVote({type, frameRate.vote.rate, frameRate.vote.seamlessness,
frameRate.category});
} else {
+ if (!frameRate.isVoteValidForMrr(isVrrDevice)) {
+ ATRACE_FORMAT_INSTANT("Reset layer to ignore explicit vote on MRR %s: %s "
+ "%s %s",
+ info->getName().c_str(),
+ ftl::enum_string(frameRate.vote.type).c_str(),
+ to_string(frameRate.vote.rate).c_str(),
+ ftl::enum_string(frameRate.category).c_str());
+ }
info->resetLayerVote();
}
}
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index a6f1b56..c09f148 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -111,9 +111,12 @@
std::string dumpGameFrameRateOverridesLocked() const REQUIRES(mLock);
// Iterates over layers maps moving all active layers to mActiveLayerInfos and all inactive
- // layers to mInactiveLayerInfos.
+ // layers to mInactiveLayerInfos. Layer's active state is determined by multiple factors
+ // such as update activity, visibility, and frame rate vote.
// worst case time complexity is O(2 * inactive + active)
- void partitionLayers(nsecs_t now) REQUIRES(mLock);
+ // now: the current time (system time) when calling the method
+ // isVrrDevice: true if the device has DisplayMode with VrrConfig specified.
+ void partitionLayers(nsecs_t now, bool isVrrDevice) REQUIRES(mLock);
enum class LayerStatus {
NotFound,
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index 9745452..1bc4ac2 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -566,6 +566,18 @@
return isNoVote() || vote.rate.isValid() || category != FrameRateCategory::Default;
}
+bool LayerInfo::FrameRate::isVoteValidForMrr(bool isVrrDevice) const {
+ if (isVrrDevice || FlagManager::getInstance().frame_rate_category_mrr()) {
+ return true;
+ }
+
+ if (category == FrameRateCategory::Default && vote.type != FrameRateCompatibility::Gte) {
+ return true;
+ }
+
+ return false;
+}
+
std::ostream& operator<<(std::ostream& stream, const LayerInfo::FrameRate& rate) {
return stream << "{rate=" << rate.vote.rate << " type=" << ftl::enum_string(rate.vote.type)
<< " seamlessness=" << ftl::enum_string(rate.vote.seamlessness) << '}';
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index 326e444..40903ed 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -146,6 +146,10 @@
// selection.
bool isNoVote() const;
+ // Checks whether the given FrameRate's vote specifications is valid for MRR devices
+ // given the current flagging.
+ bool isVoteValidForMrr(bool isVrrDevice) const;
+
private:
static Seamlessness getSeamlessness(Fps rate, Seamlessness seamlessness) {
if (!rate.isValid()) {
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index ad59f1a..ae646a0 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -1216,6 +1216,8 @@
LOG_ALWAYS_FATAL_IF(!activeModeOpt);
mActiveModeOpt.emplace(FrameRateMode{renderFrameRate, ftl::as_non_null(activeModeOpt->get())});
+ mIsVrrDevice = FlagManager::getInstance().vrr_config() &&
+ activeModeOpt->get()->getVrrConfig().has_value();
}
RefreshRateSelector::RefreshRateSelector(DisplayModes modes, DisplayModeId activeModeId,
@@ -1429,7 +1431,8 @@
}
return str;
};
- ALOGV("%s render rates: %s", rangeName, stringifyModes().c_str());
+ ALOGV("%s render rates: %s, isVrrDevice? %d", rangeName, stringifyModes().c_str(),
+ mIsVrrDevice);
return frameRateModes;
};
@@ -1438,6 +1441,11 @@
mAppRequestFrameRates = filterRefreshRates(policy->appRequestRanges, "app request");
}
+bool RefreshRateSelector::isVrrDevice() const {
+ std::lock_guard lock(mLock);
+ return mIsVrrDevice;
+}
+
Fps RefreshRateSelector::findClosestKnownFrameRate(Fps frameRate) const {
using namespace fps_approx_ops;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
index 6051e89..a6b0236 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
@@ -406,6 +406,8 @@
std::chrono::milliseconds getIdleTimerTimeout();
+ bool isVrrDevice() const;
+
private:
friend struct TestableRefreshRateSelector;
@@ -513,6 +515,9 @@
std::vector<FrameRateMode> mPrimaryFrameRates GUARDED_BY(mLock);
std::vector<FrameRateMode> mAppRequestFrameRates GUARDED_BY(mLock);
+ // Caches whether the device is VRR-compatible based on the active display mode.
+ bool mIsVrrDevice GUARDED_BY(mLock) = false;
+
Policy mDisplayManagerPolicy GUARDED_BY(mLock);
std::optional<Policy> mOverridePolicy GUARDED_BY(mLock);