SurfaceFlinger: add support for FrameRateCompatibilityType
Bug: 147516364
Test: adb shell /data/nativetest64/SurfaceFlinger_test/SurfaceFlinger_test --gtest_filter='SetFrameRateTest.*'
Test: adb shell /data/nativetest64/libsurfaceflinger_unittest/libsurfaceflinger_unittest --gtest_filter=*RefreshRateConfigs*
Test: adb shell /data/nativetest64/libsurfaceflinger_unittest/libsurfaceflinger_unittest --gtest_filter=*LayerHistory*
Change-Id: I49272804e25f04e1d7a148a0008551cbc5428011
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 6423893..61386f4 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -125,21 +125,16 @@
return isDue || !isPlausible;
}
-bool BufferQueueLayer::setFrameRate(float frameRate) {
+bool BufferQueueLayer::setFrameRate(FrameRate frameRate) {
float oldFrameRate = 0.f;
status_t result = mConsumer->getFrameRate(&oldFrameRate);
- bool frameRateChanged = result < 0 || frameRate != oldFrameRate;
- mConsumer->setFrameRate(frameRate);
+ bool frameRateChanged = result < 0 || frameRate.rate != oldFrameRate;
+ mConsumer->setFrameRate(frameRate.rate);
return frameRateChanged;
}
-std::optional<float> BufferQueueLayer::getFrameRate() const {
- const auto frameRate = mLatchedFrameRate.load();
- if (frameRate > 0.f || frameRate == FRAME_RATE_NO_VOTE) {
- return frameRate;
- }
-
- return {};
+Layer::FrameRate BufferQueueLayer::getFrameRate() const {
+ return FrameRate(mLatchedFrameRate, Layer::FrameRateCompatibility::Default);
}
// -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 2bd1e3d..598bc6b 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -56,8 +56,8 @@
bool shouldPresentNow(nsecs_t expectedPresentTime) const override;
- bool setFrameRate(float frameRate) override;
- std::optional<float> getFrameRate() const override;
+ bool setFrameRate(FrameRate frameRate) override;
+ FrameRate getFrameRate() const override;
// -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index cedab59..cf1e8b0 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -117,7 +117,6 @@
mCurrentState.frameRateSelectionPriority = PRIORITY_UNSET;
mCurrentState.metadata = args.metadata;
mCurrentState.shadowRadius = 0.f;
- mCurrentState.frameRate = 0.f;
// drawing state & current state are identical
mDrawingState = mCurrentState;
@@ -1245,7 +1244,7 @@
return true;
}
-bool Layer::setFrameRate(float frameRate) {
+bool Layer::setFrameRate(FrameRate frameRate) {
if (mCurrentState.frameRate == frameRate) {
return false;
}
@@ -1257,11 +1256,8 @@
return true;
}
-std::optional<float> Layer::getFrameRate() const {
- const auto frameRate = getDrawingState().frameRate;
- if (frameRate > 0.f || frameRate == FRAME_RATE_NO_VOTE) return frameRate;
-
- return {};
+Layer::FrameRate Layer::getFrameRate() const {
+ return getDrawingState().frameRate;
}
void Layer::deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index da3df8f..c20e04a 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -136,6 +136,34 @@
float radius = 0.0f;
};
+ // FrameRateCompatibility specifies how we should interpret the frame rate associated with
+ // the layer.
+ enum class FrameRateCompatibility {
+ Default, // Layer didn't specify any specific handling strategy
+
+ 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.
+
+ NoVote, // Layer doesn't have any requirements for the refresh rate and
+ // should not be considered when the display refresh rate is determined.
+ };
+
+ // Encapsulates the frame rate and compatibility of the layer. This information will be used
+ // when the display refresh rate is determined.
+ struct FrameRate {
+ float rate;
+ FrameRateCompatibility type;
+
+ FrameRate() : rate(0), type(FrameRateCompatibility::Default) {}
+ FrameRate(float rate, FrameRateCompatibility type) : rate(rate), type(type) {}
+
+ bool operator==(const FrameRate& other) const {
+ return rate == other.rate && type == other.type;
+ }
+
+ bool operator!=(const FrameRate& other) const { return !(*this == other); }
+ };
+
struct State {
Geometry active_legacy;
Geometry requested_legacy;
@@ -227,7 +255,7 @@
// Priority of the layer assigned by Window Manager.
int32_t frameRateSelectionPriority;
- float frameRate;
+ FrameRate frameRate;
};
explicit Layer(const LayerCreationArgs& args);
@@ -754,9 +782,8 @@
*/
Rect getCroppedBufferSize(const Layer::State& s) const;
- constexpr static auto FRAME_RATE_NO_VOTE = -1.0f;
- virtual bool setFrameRate(float frameRate);
- virtual std::optional<float> getFrameRate() const;
+ virtual bool setFrameRate(FrameRate frameRate);
+ virtual FrameRate getFrameRate() const;
protected:
// constant
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index d3d9d3a..59c2bbd 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -155,7 +155,7 @@
Mutex::Autolock _l(mFlinger.mStateLock);
mLayer = mClient->getLayerUser(mIBinder);
- mLayer->setFrameRate(Layer::FRAME_RATE_NO_VOTE);
+ mLayer->setFrameRate(Layer::FrameRate(0, Layer::FrameRateCompatibility::NoVote));
// setting Layer's Z requires resorting layersSortedByZ
ssize_t idx = mFlinger.mCurrentState.layersSortedByZ.indexOf(mLayer);
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index b976523..9aada11 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -39,7 +39,7 @@
namespace {
bool isLayerActive(const Layer& layer, const LayerInfo& info, nsecs_t threshold) {
- if (layer.getFrameRate().has_value()) {
+ if (layer.getFrameRate().rate > 0) {
return layer.isVisible();
}
return layer.isVisible() && info.getLastUpdatedTime() >= threshold;
@@ -126,18 +126,27 @@
// Only use the layer if the reference still exists.
if (layer || CC_UNLIKELY(mTraceEnabled)) {
// Check if frame rate was set on layer.
- auto frameRate = layer->getFrameRate();
- if (frameRate.has_value() && frameRate.value() > 0.f) {
- summary.push_back(
- {layer->getName(), LayerVoteType::Explicit, *frameRate, /* weight */ 1.0f});
+ const auto frameRate = layer->getFrameRate();
+ if (frameRate.rate > 0.f) {
+ const auto voteType = [&]() {
+ switch (frameRate.type) {
+ case Layer::FrameRateCompatibility::Default:
+ return LayerVoteType::ExplicitDefault;
+ case Layer::FrameRateCompatibility::ExactOrMultiple:
+ return LayerVoteType::ExplicitExactOrMultiple;
+ case Layer::FrameRateCompatibility::NoVote:
+ return LayerVoteType::NoVote;
+ }
+ }();
+ summary.push_back({layer->getName(), voteType, frameRate.rate, /* weight */ 1.0f});
} else if (recent) {
- frameRate = info->getRefreshRate(now);
- summary.push_back({layer->getName(), LayerVoteType::Heuristic, *frameRate,
+ summary.push_back({layer->getName(), LayerVoteType::Heuristic,
+ info->getRefreshRate(now),
/* weight */ 1.0f});
}
if (CC_UNLIKELY(mTraceEnabled)) {
- trace(weakLayer, round<int>(*frameRate));
+ trace(weakLayer, round<int>(frameRate.rate));
}
}
}
diff --git a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
index a6d2c74..ce085f4 100644
--- a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
@@ -40,7 +40,7 @@
namespace {
bool isLayerActive(const Layer& layer, const LayerInfoV2& info, nsecs_t threshold) {
- if (layer.getFrameRate().has_value()) {
+ if (layer.getFrameRate().rate > 0) {
return layer.isVisible();
}
return layer.isVisible() && info.getLastUpdatedTime() >= threshold;
@@ -63,13 +63,17 @@
const auto& name = layer->getName();
const auto noVoteTag = "LFPS NoVote " + name;
const auto heuristicVoteTag = "LFPS Heuristic " + name;
- const auto explicitVoteTag = "LFPS Explicit " + name;
+ const auto explicitDefaultVoteTag = "LFPS ExplicitDefault" + name;
+ const auto explicitExactOrMultipleVoteTag = "LFPS ExplicitExactOrMultiple" + name;
const auto minVoteTag = "LFPS Min " + name;
const auto maxVoteTag = "LFPS Max " + name;
ATRACE_INT(noVoteTag.c_str(), type == LayerHistory::LayerVoteType::NoVote ? 1 : 0);
ATRACE_INT(heuristicVoteTag.c_str(), type == LayerHistory::LayerVoteType::Heuristic ? fps : 0);
- ATRACE_INT(explicitVoteTag.c_str(), type == LayerHistory::LayerVoteType::Explicit ? fps : 0);
+ ATRACE_INT(explicitDefaultVoteTag.c_str(),
+ type == LayerHistory::LayerVoteType::ExplicitDefault ? fps : 0);
+ ATRACE_INT(explicitExactOrMultipleVoteTag.c_str(),
+ type == LayerHistory::LayerVoteType::ExplicitExactOrMultiple ? fps : 0);
ATRACE_INT(minVoteTag.c_str(), type == LayerHistory::LayerVoteType::Min ? 1 : 0);
ATRACE_INT(maxVoteTag.c_str(), type == LayerHistory::LayerVoteType::Max ? 1 : 0);
@@ -160,12 +164,18 @@
i++;
// Set layer vote if set
const auto frameRate = layer->getFrameRate();
- if (frameRate.has_value()) {
- if (*frameRate == Layer::FRAME_RATE_NO_VOTE) {
- info->setLayerVote(LayerVoteType::NoVote, 0.f);
- } else {
- info->setLayerVote(LayerVoteType::Explicit, *frameRate);
+ const auto voteType = [&]() {
+ switch (frameRate.type) {
+ case Layer::FrameRateCompatibility::Default:
+ return LayerVoteType::ExplicitDefault;
+ case Layer::FrameRateCompatibility::ExactOrMultiple:
+ return LayerVoteType::ExplicitExactOrMultiple;
+ case Layer::FrameRateCompatibility::NoVote:
+ return LayerVoteType::NoVote;
}
+ }();
+ if (frameRate.rate > 0 || voteType == LayerVoteType::NoVote) {
+ info->setLayerVote(voteType, frameRate.rate);
} else {
info->resetLayerVote();
}
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index d2af912..c73e825 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -37,7 +37,8 @@
int explicitContentFramerate = 0;
for (const auto& layer : layers) {
const auto desiredRefreshRateRound = round<int>(layer.desiredRefreshRate);
- if (layer.vote == LayerVoteType::Explicit) {
+ if (layer.vote == LayerVoteType::ExplicitDefault ||
+ layer.vote == LayerVoteType::ExplicitExactOrMultiple) {
if (desiredRefreshRateRound > explicitContentFramerate) {
explicitContentFramerate = desiredRefreshRateRound;
}
@@ -94,7 +95,8 @@
int noVoteLayers = 0;
int minVoteLayers = 0;
int maxVoteLayers = 0;
- int explicitVoteLayers = 0;
+ int explicitDefaultVoteLayers = 0;
+ int explicitExactOrMultipleVoteLayers = 0;
for (const auto& layer : layers) {
if (layer.vote == LayerVoteType::NoVote)
noVoteLayers++;
@@ -102,8 +104,10 @@
minVoteLayers++;
else if (layer.vote == LayerVoteType::Max)
maxVoteLayers++;
- else if (layer.vote == LayerVoteType::Explicit)
- explicitVoteLayers++;
+ else if (layer.vote == LayerVoteType::ExplicitDefault)
+ explicitDefaultVoteLayers++;
+ else if (layer.vote == LayerVoteType::ExplicitExactOrMultiple)
+ explicitExactOrMultipleVoteLayers++;
}
// Only if all layers want Min we should return Min
@@ -112,7 +116,7 @@
}
// If we have some Max layers and no Explicit we should return Max
- if (maxVoteLayers > 0 && explicitVoteLayers == 0) {
+ if (maxVoteLayers > 0 && explicitDefaultVoteLayers + explicitExactOrMultipleVoteLayers == 0) {
return *mAvailableRefreshRates.back();
}
@@ -131,9 +135,22 @@
continue;
}
- // If we have Explicit layers, ignore the Hueristic ones
- if (explicitVoteLayers > 0 && layer.vote == LayerVoteType::Heuristic) {
- continue;
+ // Adjust the weight in case we have explicit layers. The priority is:
+ // - ExplicitExactOrMultiple
+ // - ExplicitDefault
+ // - Heuristic
+ auto weight = layer.weight;
+ if (explicitExactOrMultipleVoteLayers + explicitDefaultVoteLayers > 0) {
+ if (layer.vote == LayerVoteType::Heuristic) {
+ weight /= 2.f;
+ }
+ }
+
+ if (explicitExactOrMultipleVoteLayers > 0) {
+ if (layer.vote == LayerVoteType::Heuristic ||
+ layer.vote == LayerVoteType::ExplicitDefault) {
+ weight /= 2.f;
+ }
}
for (auto& [refreshRate, overallScore] : scores) {
@@ -152,10 +169,10 @@
static constexpr size_t MAX_FRAMES_TO_FIT = 10; // Stop calculating when score < 0.1
if (displayFramesRem == 0) {
// Layer desired refresh rate matches the display rate.
- layerScore = layer.weight * 1.0f;
+ layerScore = weight * 1.0f;
} else if (displayFramesQuot == 0) {
// Layer desired refresh rate is higher the display rate.
- layerScore = layer.weight *
+ layerScore = weight *
(static_cast<float>(layerPeriod) / static_cast<float>(displayPeriod)) *
(1.0f / (MAX_FRAMES_TO_FIT + 1));
} else {
@@ -168,11 +185,11 @@
iter++;
}
- layerScore = layer.weight * (1.0f / iter);
+ layerScore = weight * (1.0f / iter);
}
- ALOGV("%s (weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(),
- layer.weight, 1e9f / layerPeriod, refreshRate->name.c_str(), layerScore);
+ ALOGV("%s (weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(), weight,
+ 1e9f / layerPeriod, refreshRate->name.c_str(), layerScore);
overallScore += layerScore;
}
}
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index c762efd..fc95959 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -96,11 +96,14 @@
// Describes the different options the layer voted for refresh rate
enum class LayerVoteType {
- NoVote, // Doesn't care about the refresh rate
- Min, // Minimal refresh rate available
- Max, // Maximal refresh rate available
- Heuristic, // Specific refresh rate that was calculated by platform using a heuristic
- Explicit, // Specific refresh rate that was provided by the app
+ NoVote, // Doesn't care about the refresh rate
+ Min, // Minimal refresh rate available
+ Max, // Maximal refresh rate available
+ 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
};
// Captures the layer requirements for a refresh rate. This will be used to determine the
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 258ce0a..52fb6f3 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -408,7 +408,8 @@
"SurfaceView - "
"com.google.android.youtube/"
"com.google.android.apps.youtube.app.WatchWhileActivity#0") {
- layer->setFrameRate(vote);
+ layer->setFrameRate(
+ Layer::FrameRate(vote, Layer::FrameRateCompatibility::ExactOrMultiple));
}
}
}
@@ -562,7 +563,8 @@
bool Scheduler::layerHistoryHasClientSpecifiedFrameRate() {
for (const auto& layer : mFeatures.contentRequirements) {
- if (layer.vote == scheduler::RefreshRateConfigs::LayerVoteType::Explicit) {
+ if (layer.vote == scheduler::RefreshRateConfigs::LayerVoteType::ExplicitDefault ||
+ layer.vote == scheduler::RefreshRateConfigs::LayerVoteType::ExplicitExactOrMultiple) {
return true;
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a066d4b..61e5e66 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3548,7 +3548,9 @@
}
}
if (what & layer_state_t::eFrameRateChanged) {
- if (layer->setFrameRate(s.frameRate)) flags |= eTraversalNeeded;
+ if (layer->setFrameRate(
+ Layer::FrameRate(s.frameRate, Layer::FrameRateCompatibility::Default)))
+ flags |= eTraversalNeeded;
}
// This has to happen after we reparent children because when we reparent to null we remove
// child layers from current state and remove its relative z. If the children are reparented in
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index 68b7a74..18e9941 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -84,7 +84,7 @@
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer, getFrameSelectionPriority()).WillRepeatedly(Return(1));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -113,7 +113,7 @@
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer, getFrameSelectionPriority()).WillRepeatedly(Return(1));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -137,15 +137,15 @@
EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer1, getFrameSelectionPriority()).WillRepeatedly(Return(1));
- EXPECT_CALL(*layer1, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer1, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer2, getFrameSelectionPriority()).WillRepeatedly(Return(1));
- EXPECT_CALL(*layer2, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer2, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer3, getFrameSelectionPriority()).WillRepeatedly(Return(1));
- EXPECT_CALL(*layer3, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer3, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
nsecs_t time = mTime;
EXPECT_EQ(3, layerCount());
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
index a5dcf11..959c256 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
@@ -90,7 +90,7 @@
TEST_F(LayerHistoryTestV2, oneLayer) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -121,7 +121,7 @@
TEST_F(LayerHistoryTestV2, oneInvisibleLayer) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -145,7 +145,7 @@
TEST_F(LayerHistoryTestV2, explicitTimestamp) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -166,7 +166,7 @@
TEST_F(LayerHistoryTestV2, oneLayerNoVote) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::NoVote);
@@ -193,7 +193,7 @@
TEST_F(LayerHistoryTestV2, oneLayerMinVote) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Min);
@@ -221,7 +221,7 @@
TEST_F(LayerHistoryTestV2, oneLayerMaxVote) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Max);
@@ -249,7 +249,9 @@
TEST_F(LayerHistoryTestV2, oneLayerExplicitVote) {
auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(73.4f));
+ EXPECT_CALL(*layer, getFrameRate())
+ .WillRepeatedly(
+ Return(Layer::FrameRate(73.4f, Layer::FrameRateCompatibility::Default)));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -261,7 +263,39 @@
}
ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Explicit, history().summarize(time)[0].vote);
+ EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, history().summarize(time)[0].vote);
+ EXPECT_FLOAT_EQ(73.4f, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer became inactive
+ setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
+ time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+ ASSERT_TRUE(history().summarize(time).empty());
+ // TODO: activeLayerCount() should be 0 but it is 1 since getFrameRate() returns a value > 0
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, oneLayerExplicitExactVote) {
+ auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRate())
+ .WillRepeatedly(Return(
+ Layer::FrameRate(73.4f, Layer::FrameRateCompatibility::ExactOrMultiple)));
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ nsecs_t time = systemTime();
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer.get(), time, time);
+ time += HI_FPS_PERIOD;
+ }
+
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
+ history().summarize(time)[0].vote);
EXPECT_FLOAT_EQ(73.4f, history().summarize(time)[0].desiredRefreshRate);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
@@ -281,13 +315,13 @@
auto layer3 = createLayer();
EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer1, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer1, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer2, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer2, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer3, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer3, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
nsecs_t time = systemTime();
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index cd9f2b1..841c624 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -432,6 +432,77 @@
EXPECT_EQ(expected72Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
}
+TEST_F(RefreshRateConfigsTest,
+ twoDeviceConfigs_getRefreshRateForContentV2_30_60_90_120_DifferentTypes) {
+ std::vector<RefreshRateConfigs::InputConfig> configs{
+ {{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30},
+ {HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
+ {HWC_CONFIG_ID_72, HWC_GROUP_ID_0, VSYNC_72},
+ {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90},
+ {HWC_CONFIG_ID_120, HWC_GROUP_ID_0, VSYNC_120}}};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ RefreshRate expected30Config = {HWC_CONFIG_ID_30, VSYNC_30, HWC_GROUP_ID_0, "30fps", 30};
+ RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
+ RefreshRate expected72Config = {HWC_CONFIG_ID_72, VSYNC_72, HWC_GROUP_ID_0, "72fps", 72};
+ RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90};
+ RefreshRate expected120Config = {HWC_CONFIG_ID_120, VSYNC_120, HWC_GROUP_ID_0, "120fps", 120};
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+ LayerRequirement{.weight = 1.0f}};
+ auto& lr1 = layers[0];
+ auto& lr2 = layers[1];
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitDefault;
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.vote = LayerVoteType::ExplicitDefault;
+ EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitDefault;
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::ExplicitDefault;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::ExplicitDefault;
+ EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitDefault;
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+}
+
TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_30_60) {
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
@@ -535,7 +606,7 @@
EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
lr1.vote = LayerVoteType::Min;
- lr2.vote = LayerVoteType::Explicit;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 24.0f;
EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
@@ -545,7 +616,7 @@
EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
lr1.vote = LayerVoteType::Max;
- lr2.vote = LayerVoteType::Explicit;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 60.0f;
EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
@@ -557,7 +628,7 @@
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 30.0f;
- lr2.vote = LayerVoteType::Explicit;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 45.0f;
EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
}
@@ -576,7 +647,7 @@
auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
auto& lr = layers[0];
- lr.vote = LayerVoteType::Explicit;
+ lr.vote = LayerVoteType::ExplicitExactOrMultiple;
for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) {
lr.desiredRefreshRate = fps;
const auto& refreshRate = refreshRateConfigs->getRefreshRateForContentV2(layers);
@@ -602,13 +673,13 @@
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 60.0f;
- lr2.vote = LayerVoteType::Explicit;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 90.0f;
EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(layers));
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 90.0f;
- lr2.vote = LayerVoteType::Explicit;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 60.0f;
EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(layers));
}
@@ -630,13 +701,13 @@
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 60.0f;
- lr2.vote = LayerVoteType::Explicit;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 90.0f;
EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 90.0f;
- lr2.vote = LayerVoteType::Explicit;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 60.0f;
EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
}
@@ -665,7 +736,7 @@
auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
auto& lr = layers[0];
- lr.vote = LayerVoteType::Explicit;
+ lr.vote = LayerVoteType::ExplicitExactOrMultiple;
for (float fps = 75.0f; fps < 100.0f; fps += 0.1f) {
lr.desiredRefreshRate = fps;
const auto& refreshRate = refreshRateConfigs->getRefreshRateForContentV2(layers);
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
index 494e73d..e2f6abd 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -31,7 +31,7 @@
MOCK_METHOD0(getFrameSelectionPriority, int32_t());
MOCK_CONST_METHOD0(isVisible, bool());
MOCK_METHOD0(createClone, sp<Layer>());
- MOCK_CONST_METHOD0(getFrameRate, std::optional<float>());
+ MOCK_CONST_METHOD0(getFrameRate, FrameRate());
};
} // namespace android::mock