summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/gui/LayerState.cpp10
-rw-r--r--libs/gui/SurfaceComposerClient.cpp5
-rw-r--r--libs/gui/include/gui/LayerState.h13
-rw-r--r--libs/nativewindow/include/apex/window.h13
-rw-r--r--services/surfaceflinger/Layer.cpp9
-rw-r--r--services/surfaceflinger/Layer.h2
-rw-r--r--services/surfaceflinger/Scheduler/LayerHistory.cpp3
-rw-r--r--services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp88
-rw-r--r--services/surfaceflinger/Scheduler/RefreshRateConfigs.h20
-rw-r--r--services/surfaceflinger/Scheduler/Scheduler.cpp10
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp6
-rw-r--r--services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp176
-rw-r--r--services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp15
13 files changed, 308 insertions, 62 deletions
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 63be3edf94..e5e10a0014 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "LayerState"
+#include <apex/window.h>
#include <inttypes.h>
#include <binder/Parcel.h>
@@ -620,7 +621,8 @@ status_t InputWindowCommands::read(const Parcel& input) {
return NO_ERROR;
}
-bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* inFunctionName) {
+bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* inFunctionName,
+ bool privileged) {
const char* functionName = inFunctionName != nullptr ? inFunctionName : "call";
int floatClassification = std::fpclassify(frameRate);
if (frameRate < 0 || floatClassification == FP_INFINITE || floatClassification == FP_NAN) {
@@ -629,8 +631,10 @@ bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* inFunc
}
if (compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT &&
- compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE) {
- ALOGE("%s failed - invalid compatibility value %d", functionName, compatibility);
+ compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE &&
+ (!privileged || compatibility != ANATIVEWINDOW_FRAME_RATE_EXACT)) {
+ ALOGE("%s failed - invalid compatibility value %d privileged: %s", functionName,
+ compatibility, privileged ? "yes" : "no");
return false;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 4a372bba1e..78f655a71b 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1518,7 +1518,10 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame
mStatus = BAD_INDEX;
return *this;
}
- if (!ValidateFrameRate(frameRate, compatibility, "Transaction::setFrameRate")) {
+ // Allow privileged values as well here, those will be ignored by SF if
+ // the caller is not privileged
+ if (!ValidateFrameRate(frameRate, compatibility, "Transaction::setFrameRate",
+ /*privileged=*/true)) {
mStatus = BAD_VALUE;
return *this;
}
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 4a291aeb02..83a9d3356e 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -309,11 +309,14 @@ static inline int compare_type(const DisplayState& lhs, const DisplayState& rhs)
return compare_type(lhs.token, rhs.token);
}
-// Returns true if the frameRate and compatibility are valid values, false
-// othwerise. If either of the params are invalid, an error log is printed, and
-// functionName is added to the log to indicate which function call failed.
-// functionName can be null.
-bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* functionName);
+// Returns true if the frameRate is valid.
+//
+// @param frameRate the frame rate in Hz
+// @param compatibility a ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_*
+// @param functionName calling function or nullptr. Used for logging
+// @param privileged whether caller has unscoped surfaceflinger access
+bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* functionName,
+ bool privileged = false);
struct CaptureArgs {
const static int32_t UNSET_UID = -1;
diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h
index 2d1354cdf1..0923438eec 100644
--- a/libs/nativewindow/include/apex/window.h
+++ b/libs/nativewindow/include/apex/window.h
@@ -39,6 +39,19 @@ enum ANativeWindowPerform {
// clang-format on
};
+/*
+ * Internal extension of compatibility value for ANativeWindow_setFrameRate. */
+enum ANativeWindow_FrameRateCompatibilityInternal {
+ /**
+ * This surface belongs to an app on the High Refresh Rate Deny list, and needs the display
+ * to operate at the exact frame rate.
+ *
+ * This is used internally by the platform and should not be used by apps.
+ * @hide
+ */
+ ANATIVEWINDOW_FRAME_RATE_EXACT = 100,
+};
+
/**
* Prototype of the function that an ANativeWindow implementation would call
* when ANativeWindow_cancelBuffer is called.
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 24d1b52a49..66ce3f1a44 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1441,11 +1441,14 @@ void Layer::updateTreeHasFrameRateVote() {
layer->mCurrentState.frameRate.type == FrameRateCompatibility::Default;
const auto layerVotedWithNoVote =
layer->mCurrentState.frameRate.type == FrameRateCompatibility::NoVote;
+ const auto layerVotedWithExactCompatibility =
+ layer->mCurrentState.frameRate.type == FrameRateCompatibility::Exact;
// We do not count layers that are ExactOrMultiple for the same reason
// we are allowing touch boost for those layers. See
// RefreshRateConfigs::getBestRefreshRate for more details.
- if (layerVotedWithDefaultCompatibility || layerVotedWithNoVote) {
+ if (layerVotedWithDefaultCompatibility || layerVotedWithNoVote ||
+ layerVotedWithExactCompatibility) {
layersWithVote++;
}
@@ -1662,6 +1665,8 @@ std::string Layer::frameRateCompatibilityString(Layer::FrameRateCompatibility co
return "ExactOrMultiple";
case FrameRateCompatibility::NoVote:
return "NoVote";
+ case FrameRateCompatibility::Exact:
+ return "Exact";
}
}
@@ -2763,6 +2768,8 @@ Layer::FrameRateCompatibility Layer::FrameRate::convertCompatibility(int8_t comp
return FrameRateCompatibility::Default;
case ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE:
return FrameRateCompatibility::ExactOrMultiple;
+ case ANATIVEWINDOW_FRAME_RATE_EXACT:
+ return FrameRateCompatibility::Exact;
default:
LOG_ALWAYS_FATAL("Invalid frame rate compatibility value %d", compatibility);
return FrameRateCompatibility::Default;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index f78b5f31e9..359340eb64 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -145,6 +145,8 @@ public:
enum class FrameRateCompatibility {
Default, // Layer didn't specify any specific handling strategy
+ Exact, // Layer needs the exact frame rate.
+
ExactOrMultiple, // Layer needs the exact frame rate (or a multiple of it) to present the
// content properly. Any other value will result in a pull down.
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 170933d9b3..7ef531df63 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -71,6 +71,7 @@ void trace(const wp<Layer>& weak, const LayerInfo& info, LayerHistory::LayerVote
traceType(LayerHistory::LayerVoteType::Heuristic, fps);
traceType(LayerHistory::LayerVoteType::ExplicitDefault, fps);
traceType(LayerHistory::LayerVoteType::ExplicitExactOrMultiple, fps);
+ traceType(LayerHistory::LayerVoteType::ExplicitExact, fps);
traceType(LayerHistory::LayerVoteType::Min, 1);
traceType(LayerHistory::LayerVoteType::Max, 1);
@@ -172,6 +173,8 @@ void LayerHistory::partitionLayers(nsecs_t now) {
return LayerVoteType::ExplicitExactOrMultiple;
case Layer::FrameRateCompatibility::NoVote:
return LayerVoteType::NoVote;
+ case Layer::FrameRateCompatibility::Exact:
+ return LayerVoteType::ExplicitExact;
}
}();
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 0f1e26750e..81ffe0f20e 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -83,6 +83,8 @@ std::string RefreshRateConfigs::layerVoteTypeString(LayerVoteType vote) {
return "ExplicitDefault";
case LayerVoteType::ExplicitExactOrMultiple:
return "ExplicitExactOrMultiple";
+ case LayerVoteType::ExplicitExact:
+ return "ExplicitExact";
}
}
@@ -165,6 +167,18 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye
return (1.0f / iter) * seamlessness;
}
+ if (layer.vote == LayerVoteType::ExplicitExact) {
+ const int divider = getFrameRateDivider(refreshRate.getFps(), layer.desiredRefreshRate);
+ if (mSupportsFrameRateOverride) {
+ // Since we support frame rate override, allow refresh rates which are
+ // multiples of the layer's request, as those apps would be throttled
+ // down to run at the desired refresh rate.
+ return divider > 0;
+ }
+
+ return divider == 1;
+ }
+
return 0;
}
@@ -199,21 +213,34 @@ RefreshRate RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequir
int maxVoteLayers = 0;
int explicitDefaultVoteLayers = 0;
int explicitExactOrMultipleVoteLayers = 0;
+ int explicitExact = 0;
float maxExplicitWeight = 0;
int seamedLayers = 0;
for (const auto& layer : layers) {
- if (layer.vote == LayerVoteType::NoVote) {
- noVoteLayers++;
- } else if (layer.vote == LayerVoteType::Min) {
- minVoteLayers++;
- } else if (layer.vote == LayerVoteType::Max) {
- maxVoteLayers++;
- } else if (layer.vote == LayerVoteType::ExplicitDefault) {
- explicitDefaultVoteLayers++;
- maxExplicitWeight = std::max(maxExplicitWeight, layer.weight);
- } else if (layer.vote == LayerVoteType::ExplicitExactOrMultiple) {
- explicitExactOrMultipleVoteLayers++;
- maxExplicitWeight = std::max(maxExplicitWeight, layer.weight);
+ switch (layer.vote) {
+ case LayerVoteType::NoVote:
+ noVoteLayers++;
+ break;
+ case LayerVoteType::Min:
+ minVoteLayers++;
+ break;
+ case LayerVoteType::Max:
+ maxVoteLayers++;
+ break;
+ case LayerVoteType::ExplicitDefault:
+ explicitDefaultVoteLayers++;
+ maxExplicitWeight = std::max(maxExplicitWeight, layer.weight);
+ break;
+ case LayerVoteType::ExplicitExactOrMultiple:
+ explicitExactOrMultipleVoteLayers++;
+ maxExplicitWeight = std::max(maxExplicitWeight, layer.weight);
+ break;
+ case LayerVoteType::ExplicitExact:
+ explicitExact++;
+ maxExplicitWeight = std::max(maxExplicitWeight, layer.weight);
+ break;
+ case LayerVoteType::Heuristic:
+ break;
}
if (layer.seamlessness == Seamlessness::SeamedAndSeamless) {
@@ -221,8 +248,8 @@ RefreshRate RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequir
}
}
- const bool hasExplicitVoteLayers =
- explicitDefaultVoteLayers > 0 || explicitExactOrMultipleVoteLayers > 0;
+ const bool hasExplicitVoteLayers = explicitDefaultVoteLayers > 0 ||
+ explicitExactOrMultipleVoteLayers > 0 || explicitExact > 0;
// Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've
// selected a refresh rate to see if we should apply touch boost.
@@ -318,7 +345,9 @@ RefreshRate RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequir
bool inPrimaryRange = scores[i].refreshRate->inPolicy(policy->primaryRange.min,
policy->primaryRange.max);
if ((primaryRangeIsSingleRate || !inPrimaryRange) &&
- !(layer.focused && layer.vote == LayerVoteType::ExplicitDefault)) {
+ !(layer.focused &&
+ (layer.vote == LayerVoteType::ExplicitDefault ||
+ layer.vote == LayerVoteType::ExplicitExact))) {
// Only focused layers with ExplicitDefault frame rate settings are allowed to score
// refresh rates outside the primary range.
continue;
@@ -358,7 +387,8 @@ RefreshRate RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequir
// actually increase the refresh rate over the normal selection.
const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked();
- if (globalSignals.touch && explicitDefaultVoteLayers == 0 &&
+ bool touchBoostForExplicitExact = explicitExact == 0 || mSupportsFrameRateOverride;
+ if (globalSignals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact &&
bestRefreshRate->fps.lessThanWithMargin(touchRefreshRate.fps)) {
setTouchConsidered();
ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str());
@@ -412,7 +442,7 @@ std::vector<RefreshRateScore> initializeScoresForAllRefreshRates(
}
RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverrides(
- const std::vector<LayerRequirement>& layers, Fps displayFrameRate) const {
+ const std::vector<LayerRequirement>& layers, Fps displayFrameRate, bool touch) const {
ATRACE_CALL();
if (!mSupportsFrameRateOverride) return {};
@@ -423,6 +453,17 @@ RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverr
groupLayersByUid(layers);
UidToFrameRateOverride frameRateOverrides;
for (const auto& [uid, layersWithSameUid] : layersByUid) {
+ // Layers with ExplicitExactOrMultiple expect touch boost
+ const bool hasExplicitExactOrMultiple =
+ std::any_of(layersWithSameUid.cbegin(), layersWithSameUid.cend(),
+ [](const auto& layer) {
+ return layer->vote == LayerVoteType::ExplicitExactOrMultiple;
+ });
+
+ if (touch && hasExplicitExactOrMultiple) {
+ continue;
+ }
+
for (auto& score : scores) {
score.score = 0;
}
@@ -433,7 +474,8 @@ RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverr
}
LOG_ALWAYS_FATAL_IF(layer->vote != LayerVoteType::ExplicitDefault &&
- layer->vote != LayerVoteType::ExplicitExactOrMultiple);
+ layer->vote != LayerVoteType::ExplicitExactOrMultiple &&
+ layer->vote != LayerVoteType::ExplicitExact);
for (RefreshRateScore& score : scores) {
const auto layerScore = calculateLayerScoreLocked(*layer, *score.refreshRate,
/*isSeamlessSwitch*/ true);
@@ -559,8 +601,10 @@ void RefreshRateConfigs::setCurrentConfigId(DisplayModeId configId) {
mCurrentRefreshRate = mRefreshRates.at(configId).get();
}
-RefreshRateConfigs::RefreshRateConfigs(const DisplayModes& configs, DisplayModeId currentConfigId)
- : mKnownFrameRates(constructKnownFrameRates(configs)) {
+RefreshRateConfigs::RefreshRateConfigs(const DisplayModes& configs, DisplayModeId currentConfigId,
+ bool enableFrameRateOverride)
+ : mKnownFrameRates(constructKnownFrameRates(configs)),
+ mEnableFrameRateOverride(enableFrameRateOverride) {
updateDisplayConfigs(configs, currentConfigId);
}
@@ -589,7 +633,7 @@ void RefreshRateConfigs::updateDisplayConfigs(const DisplayModes& configs,
mMaxSupportedRefreshRate = sortedConfigs.back();
mSupportsFrameRateOverride = false;
- if (android::sysprop::enable_frame_rate_override(true)) {
+ if (mEnableFrameRateOverride) {
for (const auto& config1 : sortedConfigs) {
for (const auto& config2 : sortedConfigs) {
if (getFrameRateDivider(config1->getFps(), config2->getFps()) >= 2) {
@@ -826,4 +870,4 @@ void RefreshRateConfigs::dump(std::string& result) const {
} // namespace android::scheduler
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wextra" \ No newline at end of file
+#pragma clang diagnostic pop // ignored "-Wextra"
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index ef193ca787..36fbbad4d8 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -208,8 +208,11 @@ public:
Heuristic, // Specific refresh rate that was calculated by platform using a heuristic
ExplicitDefault, // Specific refresh rate that was provided by the app with Default
// compatibility
- ExplicitExactOrMultiple // Specific refresh rate that was provided by the app with
- // ExactOrMultiple compatibility
+ ExplicitExactOrMultiple, // Specific refresh rate that was provided by the app with
+ // ExactOrMultiple compatibility
+ ExplicitExact, // Specific refresh rate that was provided by the app with
+ // Exact compatibility
+
};
// Captures the layer requirements for a refresh rate. This will be used to determine the
@@ -295,7 +298,8 @@ public:
// Returns a known frame rate that is the closest to frameRate
Fps findClosestKnownFrameRate(Fps frameRate) const;
- RefreshRateConfigs(const DisplayModes& configs, DisplayModeId currentConfigId);
+ RefreshRateConfigs(const DisplayModes& configs, DisplayModeId currentConfigId,
+ bool enableFrameRateOverride = false);
void updateDisplayConfigs(const DisplayModes& configs, DisplayModeId currentConfig)
EXCLUDES(mLock);
@@ -324,10 +328,15 @@ public:
// Returns a divider for the current refresh rate
int getRefreshRateDivider(Fps frameRate) const EXCLUDES(mLock);
- // Returns the frame rate override for each uid
using UidToFrameRateOverride = std::map<uid_t, Fps>;
+ // Returns the frame rate override for each uid.
+ //
+ // @param layers list of visible layers
+ // @param displayFrameRate the display frame rate
+ // @param touch whether touch timer is active (i.e. user touched the screen recently)
UidToFrameRateOverride getFrameRateOverrides(const std::vector<LayerRequirement>& layers,
- Fps displayFrameRate) const EXCLUDES(mLock);
+ Fps displayFrameRate, bool touch) const
+ EXCLUDES(mLock);
void dump(std::string& result) const EXCLUDES(mLock);
@@ -407,6 +416,7 @@ private:
// from based on the closest value.
const std::vector<Fps> mKnownFrameRates;
+ const bool mEnableFrameRateOverride;
bool mSupportsFrameRateOverride;
};
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 588b83d774..d8612098ec 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -763,17 +763,11 @@ bool Scheduler::updateFrameRateOverrides(
return false;
}
- if (consideredSignals.touch) {
- std::lock_guard lock(mFrameRateOverridesMutex);
- const bool changed = !mFrameRateOverridesByContent.empty();
- mFrameRateOverridesByContent.clear();
- return changed;
- }
-
if (!consideredSignals.idle) {
const auto frameRateOverrides =
mRefreshRateConfigs.getFrameRateOverrides(mFeatures.contentRequirements,
- displayRefreshRate);
+ displayRefreshRate,
+ consideredSignals.touch);
std::lock_guard lock(mFrameRateOverridesMutex);
if (!std::equal(mFrameRateOverridesByContent.begin(), mFrameRateOverridesByContent.end(),
frameRateOverrides.begin(), frameRateOverrides.end(),
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 0a51659681..c1fabf8322 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2920,7 +2920,9 @@ void SurfaceFlinger::initScheduler(PhysicalDisplayId primaryDisplayId) {
auto currentConfig = getHwComposer().getActiveMode(primaryDisplayId)->getId();
const auto modes = getHwComposer().getModes(primaryDisplayId);
- mRefreshRateConfigs = std::make_unique<scheduler::RefreshRateConfigs>(modes, currentConfig);
+ mRefreshRateConfigs = std::make_unique<
+ scheduler::RefreshRateConfigs>(modes, currentConfig,
+ android::sysprop::enable_frame_rate_override(true));
const auto& currRefreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(currentConfig);
mRefreshRateStats =
std::make_unique<scheduler::RefreshRateStats>(*mTimeStats, currRefreshRate.getFps(),
@@ -3873,7 +3875,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(
}
if (what & layer_state_t::eFrameRateChanged) {
if (ValidateFrameRate(s.frameRate, s.frameRateCompatibility,
- "SurfaceFlinger::setClientStateLocked") &&
+ "SurfaceFlinger::setClientStateLocked", privileged) &&
layer->setFrameRate(Layer::FrameRate(Fps(s.frameRate),
Layer::FrameRate::convertCompatibility(
s.frameRateCompatibility),
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 0a747ab7e3..738ded18ac 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -1506,6 +1506,89 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_KnownFrameRate) {
}
}
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExact) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+ LayerRequirement{.weight = 0.5f}};
+ auto& explicitExactLayer = layers[0];
+ auto& explicitExactOrMultipleLayer = layers[1];
+
+ explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple;
+ explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple";
+ explicitExactOrMultipleLayer.desiredRefreshRate = Fps(60);
+
+ explicitExactLayer.vote = LayerVoteType::ExplicitExact;
+ explicitExactLayer.name = "ExplicitExact";
+ explicitExactLayer.desiredRefreshRate = Fps(30);
+
+ EXPECT_EQ(mExpected30Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected30Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+
+ explicitExactOrMultipleLayer.desiredRefreshRate = Fps(120);
+ explicitExactLayer.desiredRefreshRate = Fps(60);
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ explicitExactLayer.desiredRefreshRate = Fps(72);
+ EXPECT_EQ(mExpected72Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ explicitExactLayer.desiredRefreshRate = Fps(90);
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ explicitExactLayer.desiredRefreshRate = Fps(120);
+ EXPECT_EQ(mExpected120Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExactEnableFrameRateOverride) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60,
+ /*enableFrameRateOverride=*/true);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+ LayerRequirement{.weight = 0.5f}};
+ auto& explicitExactLayer = layers[0];
+ auto& explicitExactOrMultipleLayer = layers[1];
+
+ explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple;
+ explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple";
+ explicitExactOrMultipleLayer.desiredRefreshRate = Fps(60);
+
+ explicitExactLayer.vote = LayerVoteType::ExplicitExact;
+ explicitExactLayer.name = "ExplicitExact";
+ explicitExactLayer.desiredRefreshRate = Fps(30);
+
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected120Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+
+ explicitExactOrMultipleLayer.desiredRefreshRate = Fps(120);
+ explicitExactLayer.desiredRefreshRate = Fps(60);
+ EXPECT_EQ(mExpected120Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ explicitExactLayer.desiredRefreshRate = Fps(72);
+ EXPECT_EQ(mExpected72Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ explicitExactLayer.desiredRefreshRate = Fps(90);
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ explicitExactLayer.desiredRefreshRate = Fps(120);
+ EXPECT_EQ(mExpected120Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
TEST_F(RefreshRateConfigsTest, testComparisonOperator) {
EXPECT_TRUE(mExpected60Config < mExpected90Config);
EXPECT_FALSE(mExpected60Config < mExpected60Config);
@@ -1537,7 +1620,7 @@ TEST_F(RefreshRateConfigsTest, testKernelIdleTimerAction) {
EXPECT_EQ(KernelIdleTimerAction::TurnOff, refreshRateConfigs->getIdleTimerAction());
}
-TEST_F(RefreshRateConfigsTest, RefreshRateDividerForUid) {
+TEST_F(RefreshRateConfigsTest, getRefreshRateDivider) {
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
/*currentConfigId=*/HWC_CONFIG_ID_30);
@@ -1562,57 +1645,66 @@ TEST_F(RefreshRateConfigsTest, RefreshRateDividerForUid) {
EXPECT_EQ(4, refreshRateConfigs->getRefreshRateDivider(Fps(22.6f)));
}
-TEST_F(RefreshRateConfigsTest, populatePreferredFrameRate_noLayers) {
+TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_noLayers) {
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device, /*currentConfigId=*/
HWC_CONFIG_ID_120);
auto layers = std::vector<LayerRequirement>{};
- ASSERT_TRUE(refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f)).empty());
+ ASSERT_TRUE(refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false)
+ .empty());
}
TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_60on120) {
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device, /*currentConfigId=*/
- HWC_CONFIG_ID_120);
+ HWC_CONFIG_ID_120,
+ /*enableFrameRateOverride=*/true);
auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
layers[0].name = "Test layer";
layers[0].ownerUid = 1234;
layers[0].desiredRefreshRate = Fps(60.0f);
layers[0].vote = LayerVoteType::ExplicitDefault;
- auto frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f));
+ auto frameRateOverrides =
+ refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
ASSERT_EQ(1, frameRateOverrides.size());
ASSERT_EQ(1, frameRateOverrides.count(1234));
ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
layers[0].vote = LayerVoteType::ExplicitExactOrMultiple;
- frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f));
+ frameRateOverrides =
+ refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
ASSERT_EQ(1, frameRateOverrides.size());
ASSERT_EQ(1, frameRateOverrides.count(1234));
ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
layers[0].vote = LayerVoteType::NoVote;
- frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f));
+ frameRateOverrides =
+ refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
ASSERT_TRUE(frameRateOverrides.empty());
layers[0].vote = LayerVoteType::Min;
- frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f));
+ frameRateOverrides =
+ refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
ASSERT_TRUE(frameRateOverrides.empty());
layers[0].vote = LayerVoteType::Max;
- frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f));
+ frameRateOverrides =
+ refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
ASSERT_TRUE(frameRateOverrides.empty());
layers[0].vote = LayerVoteType::Heuristic;
- frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f));
+ frameRateOverrides =
+ refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
ASSERT_TRUE(frameRateOverrides.empty());
}
-TEST_F(RefreshRateConfigsTest, populatePreferredFrameRate_twoUids) {
+TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_twoUids) {
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device, /*currentConfigId=*/
- HWC_CONFIG_ID_120);
+ HWC_CONFIG_ID_120,
+ /*enableFrameRateOverride=*/true);
auto layers = std::vector<LayerRequirement>{
LayerRequirement{.ownerUid = 1234, .weight = 1.0f},
@@ -1626,7 +1718,8 @@ TEST_F(RefreshRateConfigsTest, populatePreferredFrameRate_twoUids) {
layers[1].name = "Test layer 5678";
layers[1].desiredRefreshRate = Fps(30.0f);
layers[1].vote = LayerVoteType::ExplicitDefault;
- auto frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f));
+ auto frameRateOverrides =
+ refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
ASSERT_EQ(2, frameRateOverrides.size());
ASSERT_EQ(1, frameRateOverrides.count(1234));
@@ -1635,13 +1728,66 @@ TEST_F(RefreshRateConfigsTest, populatePreferredFrameRate_twoUids) {
ASSERT_EQ(30.0f, frameRateOverrides.at(5678).getValue());
layers[1].vote = LayerVoteType::Heuristic;
- frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f));
+ frameRateOverrides =
+ refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
ASSERT_EQ(1, frameRateOverrides.size());
ASSERT_EQ(1, frameRateOverrides.count(1234));
ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
layers[1].ownerUid = 1234;
- frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f));
+ frameRateOverrides =
+ refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+ ASSERT_TRUE(frameRateOverrides.empty());
+}
+
+TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_touch) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device, /*currentConfigId=*/
+ HWC_CONFIG_ID_120,
+ /*enableFrameRateOverride=*/true);
+
+ auto layers = std::vector<LayerRequirement>{
+ LayerRequirement{.ownerUid = 1234, .weight = 1.0f},
+ };
+
+ layers[0].name = "Test layer";
+ layers[0].desiredRefreshRate = Fps(60.0f);
+ layers[0].vote = LayerVoteType::ExplicitDefault;
+
+ auto frameRateOverrides =
+ refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+ ASSERT_EQ(1, frameRateOverrides.size());
+ ASSERT_EQ(1, frameRateOverrides.count(1234));
+ ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+
+ frameRateOverrides =
+ refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/true);
+ ASSERT_EQ(1, frameRateOverrides.size());
+ ASSERT_EQ(1, frameRateOverrides.count(1234));
+ ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+
+ layers[0].vote = LayerVoteType::ExplicitExact;
+ frameRateOverrides =
+ refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+ ASSERT_EQ(1, frameRateOverrides.size());
+ ASSERT_EQ(1, frameRateOverrides.count(1234));
+ ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+
+ frameRateOverrides =
+ refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/true);
+ ASSERT_EQ(1, frameRateOverrides.size());
+ ASSERT_EQ(1, frameRateOverrides.count(1234));
+ ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+
+ layers[0].vote = LayerVoteType::ExplicitExactOrMultiple;
+ frameRateOverrides =
+ refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+ ASSERT_EQ(1, frameRateOverrides.size());
+ ASSERT_EQ(1, frameRateOverrides.count(1234));
+ ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+
+ frameRateOverrides =
+ refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/true);
ASSERT_TRUE(frameRateOverrides.empty());
}
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index c8f4cb4c19..e060df2420 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -473,5 +473,20 @@ INSTANTIATE_TEST_SUITE_P(PerLayerType, SetFrameRateTest,
std::make_shared<EffectLayerFactory>()),
PrintToStringParamName);
+TEST_F(SetFrameRateTest, ValidateFrameRate) {
+ EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, ""));
+ EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, ""));
+ EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, ""));
+ EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, "", /*privileged=*/true));
+
+ EXPECT_FALSE(ValidateFrameRate(-1, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, ""));
+ EXPECT_FALSE(
+ ValidateFrameRate(1.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, ""));
+ EXPECT_FALSE(
+ ValidateFrameRate(0.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, ""));
+
+ EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, ""));
+}
+
} // namespace
} // namespace android