Logic for selection strategy "DoNotPropagate"
This logic is for the new FrameRateSelectionStrategy::DoNotPropagate.
The default behavior ("Self") is to propagate parent vote to children
that has no votes, but if a layer has "DoNotPropagate", it will not
propagate its vote to children.
Bug: 309687765
Test: atest libsurfaceflinger_unittest
Test: atest CtsSurfaceControlTestsStaging
Change-Id: I284b639f2b1902c5e9d3dcd08ceaf3f76b73451e
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index b068f48..0583812 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -1103,7 +1103,12 @@
enum {
/**
* Default value. The layer uses its own frame rate specifications, assuming it has any
- * specifications, instead of its parent's.
+ * specifications, instead of its parent's. If it does not have its own frame rate
+ * specifications, it will try to use its parent's.
+ *
+ * However, FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN on an ancestor layer
+ * supersedes this behavior, meaning that this layer will inherit the frame rate specifications
+ * of that ancestor layer.
*/
ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_SELF = 0,
@@ -1114,6 +1119,14 @@
* behavior for itself.
*/
ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN = 1,
+
+ /**
+ * The layer's frame rate specifications will never propagate to its descendant
+ * layers.
+ * FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN on an ancestor layer supersedes
+ * this behavior.
+ */
+ ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_DO_NOT_PROPAGATE = 2,
};
static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate,
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index 743cbf3..a57cd0a 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -814,9 +814,12 @@
RequestedLayerState::Changes::Hierarchy) ||
snapshot.changes.any(RequestedLayerState::Changes::FrameRate |
RequestedLayerState::Changes::Hierarchy)) {
- bool shouldOverrideChildren = parentSnapshot.frameRateSelectionStrategy ==
+ const bool shouldOverrideChildren = parentSnapshot.frameRateSelectionStrategy ==
scheduler::LayerInfo::FrameRateSelectionStrategy::OverrideChildren;
- if (!requested.requestedFrameRate.isValid() || shouldOverrideChildren) {
+ const bool propagationAllowed = parentSnapshot.frameRateSelectionStrategy !=
+ scheduler::LayerInfo::FrameRateSelectionStrategy::DoNotPropagate;
+ if ((!requested.requestedFrameRate.isValid() && propagationAllowed) ||
+ shouldOverrideChildren) {
snapshot.inheritedFrameRate = parentSnapshot.inheritedFrameRate;
} else {
snapshot.inheritedFrameRate = requested.requestedFrameRate;
@@ -828,12 +831,15 @@
}
if (forceUpdate || snapshot.clientChanges & layer_state_t::eFrameRateSelectionStrategyChanged) {
- const auto strategy = scheduler::LayerInfo::convertFrameRateSelectionStrategy(
- requested.frameRateSelectionStrategy);
- snapshot.frameRateSelectionStrategy =
- strategy == scheduler::LayerInfo::FrameRateSelectionStrategy::Self
- ? parentSnapshot.frameRateSelectionStrategy
- : strategy;
+ if (parentSnapshot.frameRateSelectionStrategy ==
+ scheduler::LayerInfo::FrameRateSelectionStrategy::OverrideChildren) {
+ snapshot.frameRateSelectionStrategy =
+ scheduler::LayerInfo::FrameRateSelectionStrategy::OverrideChildren;
+ } else {
+ const auto strategy = scheduler::LayerInfo::convertFrameRateSelectionStrategy(
+ requested.frameRateSelectionStrategy);
+ snapshot.frameRateSelectionStrategy = strategy;
+ }
}
if (forceUpdate || snapshot.clientChanges & layer_state_t::eFrameRateSelectionPriority) {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f587e9d..602dae0 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1273,14 +1273,15 @@
auto now = systemTime();
*transactionNeeded |= setFrameRateForLayerTreeLegacy(frameRate, now);
- // The frame rate is propagated to the children
+ // The frame rate is propagated to the children by default, but some properties may override it.
bool childrenHaveFrameRate = false;
+ const bool overrideChildrenFrameRate = overrideChildren || shouldOverrideChildrenFrameRate();
+ const bool canPropagateFrameRate = shouldPropagateFrameRate() || overrideChildrenFrameRate;
for (const sp<Layer>& child : mCurrentChildren) {
childrenHaveFrameRate |=
- child->propagateFrameRateForLayerTree(frameRate,
- overrideChildren ||
- shouldOverrideChildrenFrameRate(),
- transactionNeeded);
+ child->propagateFrameRateForLayerTree(canPropagateFrameRate ? frameRate
+ : FrameRate(),
+ overrideChildrenFrameRate, transactionNeeded);
}
// If we don't have a valid frame rate specification, but the children do, we set this
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 28168c3..790dfb5 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -1178,6 +1178,11 @@
FrameRateSelectionStrategy::OverrideChildren;
}
+ bool shouldPropagateFrameRate() const {
+ return getDrawingState().frameRateSelectionStrategy !=
+ FrameRateSelectionStrategy::DoNotPropagate;
+ }
+
// Cached properties computed from drawing state
// Effective transform taking into account parent transforms and any parent scaling, which is
// a transform from the current layer coordinate space to display(screen) coordinate space.
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index bf3a7bc..db0aebf 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -530,6 +530,8 @@
return FrameRateSelectionStrategy::Self;
case ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN:
return FrameRateSelectionStrategy::OverrideChildren;
+ case ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_DO_NOT_PROPAGATE:
+ return FrameRateSelectionStrategy::DoNotPropagate;
default:
LOG_ALWAYS_FATAL("Invalid frame rate selection strategy value %d", strategy);
return FrameRateSelectionStrategy::Self;
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index d24fc33..c7b53fc 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -83,8 +83,9 @@
enum class FrameRateSelectionStrategy {
Self,
OverrideChildren,
+ DoNotPropagate,
- ftl_last = OverrideChildren
+ ftl_last = DoNotPropagate
};
// Encapsulates the frame rate specifications of the layer. This information will be used
diff --git a/services/surfaceflinger/tests/unittests/FrameRateSelectionStrategyTest.cpp b/services/surfaceflinger/tests/unittests/FrameRateSelectionStrategyTest.cpp
index 20ea0c0..d791c4a 100644
--- a/services/surfaceflinger/tests/unittests/FrameRateSelectionStrategyTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameRateSelectionStrategyTest.cpp
@@ -49,6 +49,7 @@
const FrameRate FRAME_RATE_VOTE1 = FrameRate(11_Hz, FrameRateCompatibility::Default);
const FrameRate FRAME_RATE_VOTE2 = FrameRate(22_Hz, FrameRateCompatibility::Default);
const FrameRate FRAME_RATE_VOTE3 = FrameRate(33_Hz, FrameRateCompatibility::Default);
+ const FrameRate FRAME_RATE_DEFAULT = FrameRate(Fps(), FrameRateCompatibility::Default);
const FrameRate FRAME_RATE_TREE = FrameRate(Fps(), FrameRateCompatibility::NoVote);
FrameRateSelectionStrategyTest();
@@ -102,7 +103,7 @@
layer->getDrawingState().frameRateSelectionStrategy);
}
-TEST_P(FrameRateSelectionStrategyTest, SetChildAndGetParent) {
+TEST_P(FrameRateSelectionStrategyTest, SetChildOverrideChildren) {
EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
const auto& layerFactory = GetParam();
@@ -126,7 +127,7 @@
child2->getDrawingState().frameRateSelectionStrategy);
}
-TEST_P(FrameRateSelectionStrategyTest, SetParentAndGet) {
+TEST_P(FrameRateSelectionStrategyTest, SetParentOverrideChildren) {
EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
const auto& layerFactory = GetParam();
@@ -137,7 +138,6 @@
addChild(layer2, layer3);
layer1->setFrameRate(FRAME_RATE_VOTE1.vote);
- layer1->setFrameRate(FRAME_RATE_VOTE1.vote);
layer1->setFrameRateSelectionStrategy(FrameRateSelectionStrategy::OverrideChildren);
layer2->setFrameRate(FRAME_RATE_VOTE2.vote);
layer2->setFrameRateSelectionStrategy(FrameRateSelectionStrategy::OverrideChildren);
@@ -168,5 +168,57 @@
layer3->getDrawingState().frameRateSelectionStrategy);
}
+TEST_P(FrameRateSelectionStrategyTest, OverrideChildrenAndDoNotPropagate) {
+ EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
+
+ const auto& layerFactory = GetParam();
+ auto layer1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto layer2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto layer3 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ addChild(layer1, layer2);
+ addChild(layer2, layer3);
+
+ layer1->setFrameRate(FRAME_RATE_VOTE1.vote);
+ layer2->setFrameRate(FRAME_RATE_VOTE2.vote);
+ layer2->setFrameRateSelectionStrategy(FrameRateSelectionStrategy::DoNotPropagate);
+ commitTransaction();
+
+ EXPECT_EQ(FRAME_RATE_VOTE1, layer1->getFrameRateForLayerTree());
+ EXPECT_EQ(FrameRateSelectionStrategy::Self,
+ layer1->getDrawingState().frameRateSelectionStrategy);
+ EXPECT_EQ(FRAME_RATE_VOTE2, layer2->getFrameRateForLayerTree());
+ EXPECT_EQ(FrameRateSelectionStrategy::DoNotPropagate,
+ layer2->getDrawingState().frameRateSelectionStrategy);
+ EXPECT_EQ(FRAME_RATE_DEFAULT, layer3->getFrameRateForLayerTree());
+ EXPECT_EQ(FrameRateSelectionStrategy::Self,
+ layer3->getDrawingState().frameRateSelectionStrategy);
+
+ layer1->setFrameRateSelectionStrategy(FrameRateSelectionStrategy::OverrideChildren);
+ commitTransaction();
+
+ EXPECT_EQ(FRAME_RATE_VOTE1, layer1->getFrameRateForLayerTree());
+ EXPECT_EQ(FrameRateSelectionStrategy::OverrideChildren,
+ layer1->getDrawingState().frameRateSelectionStrategy);
+ EXPECT_EQ(FRAME_RATE_VOTE1, layer2->getFrameRateForLayerTree());
+ EXPECT_EQ(FrameRateSelectionStrategy::DoNotPropagate,
+ layer2->getDrawingState().frameRateSelectionStrategy);
+ EXPECT_EQ(FRAME_RATE_VOTE1, layer3->getFrameRateForLayerTree());
+ EXPECT_EQ(FrameRateSelectionStrategy::Self,
+ layer3->getDrawingState().frameRateSelectionStrategy);
+
+ layer1->setFrameRate(FRAME_RATE_DEFAULT.vote);
+ commitTransaction();
+
+ EXPECT_EQ(FRAME_RATE_TREE, layer1->getFrameRateForLayerTree());
+ EXPECT_EQ(FrameRateSelectionStrategy::OverrideChildren,
+ layer1->getDrawingState().frameRateSelectionStrategy);
+ EXPECT_EQ(FRAME_RATE_VOTE2, layer2->getFrameRateForLayerTree());
+ EXPECT_EQ(FrameRateSelectionStrategy::DoNotPropagate,
+ layer2->getDrawingState().frameRateSelectionStrategy);
+ EXPECT_EQ(FRAME_RATE_VOTE2, layer3->getFrameRateForLayerTree());
+ EXPECT_EQ(FrameRateSelectionStrategy::Self,
+ layer3->getDrawingState().frameRateSelectionStrategy);
+}
+
} // namespace
} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 16143e3..40d6ad3 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -928,6 +928,94 @@
EXPECT_TRUE(getSnapshot({.id = 1221})->changes.test(RequestedLayerState::Changes::FrameRate));
}
+TEST_F(LayerSnapshotTest, frameRateSelectionStrategyWithOverrideChildrenAndDoNotPropagate) {
+ // ROOT
+ // ├── 1
+ // │ ├── 11 (frame rate set to 11.f with strategy DoNotPropagate)
+ // │ │ └── 111 (frame rate is not inherited)
+ // │ ├── 12 (frame rate set to 244.f)
+ // │ │ ├── 121
+ // │ │ └── 122 (strategy OverrideChildren and inherits frame rate 244.f)
+ // │ │ └── 1221 (frame rate set to 123.f but should be overridden by layer 122)
+ // │ └── 13
+ // └── 2
+ setFrameRate(11, 11.f, 0, 0);
+ setFrameRateSelectionStrategy(11, 2 /* DoNotPropagate */);
+ setFrameRate(12, 244.f, 0, 0);
+ setFrameRateSelectionStrategy(122, 1 /* OverrideChildren */);
+ setFrameRate(1221, 123.f, 0, 0);
+
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ // verify parent 1 gets no vote
+ EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.vote.rate.isValid());
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.type,
+ scheduler::FrameRateCompatibility::NoVote);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRateSelectionStrategy,
+ scheduler::LayerInfo::FrameRateSelectionStrategy::Self);
+ EXPECT_TRUE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.rate.getValue(), 11.f);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRateSelectionStrategy,
+ scheduler::LayerInfo::FrameRateSelectionStrategy::DoNotPropagate);
+ EXPECT_TRUE(getSnapshot({.id = 11})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+ // verify layer 11 does does not propagate its framerate to 111.
+ EXPECT_FALSE(getSnapshot({.id = 111})->frameRate.vote.rate.isValid());
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRateSelectionStrategy,
+ scheduler::LayerInfo::FrameRateSelectionStrategy::Self);
+ EXPECT_TRUE(getSnapshot({.id = 111})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+ // verify layer 12 and all descendants (121, 122, 1221) get the requested vote
+ EXPECT_EQ(getSnapshot({.id = 12})->frameRate.vote.rate.getValue(), 244.f);
+ EXPECT_EQ(getSnapshot({.id = 12})->frameRateSelectionStrategy,
+ scheduler::LayerInfo::FrameRateSelectionStrategy::Self);
+ EXPECT_TRUE(getSnapshot({.id = 12})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+ EXPECT_EQ(getSnapshot({.id = 121})->frameRate.vote.rate.getValue(), 244.f);
+ EXPECT_EQ(getSnapshot({.id = 121})->frameRateSelectionStrategy,
+ scheduler::LayerInfo::FrameRateSelectionStrategy::Self);
+ EXPECT_TRUE(getSnapshot({.id = 121})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+ EXPECT_EQ(getSnapshot({.id = 122})->frameRate.vote.rate.getValue(), 244.f);
+ EXPECT_EQ(getSnapshot({.id = 122})->frameRateSelectionStrategy,
+ scheduler::LayerInfo::FrameRateSelectionStrategy::OverrideChildren);
+ EXPECT_TRUE(getSnapshot({.id = 122})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+ EXPECT_EQ(getSnapshot({.id = 1221})->frameRate.vote.rate.getValue(), 244.f);
+ EXPECT_EQ(getSnapshot({.id = 1221})->frameRateSelectionStrategy,
+ scheduler::LayerInfo::FrameRateSelectionStrategy::OverrideChildren);
+ EXPECT_TRUE(getSnapshot({.id = 1221})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+ // ROOT
+ // ├── 1 (frame rate set to 1.f with strategy OverrideChildren)
+ // │ ├── 11 (frame rate set to 11.f with strategy DoNotPropagate, but overridden by 1)
+ // │ │ └── 111 (frame rate inherited from 11 due to override from 1)
+ // ⋮ ⋮
+ setFrameRate(1, 1.f, 0, 0);
+ setFrameRateSelectionStrategy(1, 1 /* OverrideChildren */);
+ setFrameRate(11, 11.f, 0, 0);
+ setFrameRateSelectionStrategy(11, 2 /* DoNotPropagate */);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.rate.getValue(), 1.f);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.type,
+ scheduler::FrameRateCompatibility::Default);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRateSelectionStrategy,
+ scheduler::LayerInfo::FrameRateSelectionStrategy::OverrideChildren);
+ EXPECT_TRUE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.rate.getValue(), 1.f);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRateSelectionStrategy,
+ scheduler::LayerInfo::FrameRateSelectionStrategy::OverrideChildren);
+ EXPECT_TRUE(getSnapshot({.id = 11})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+ // verify layer 11 does does not propagate its framerate to 111.
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.rate.getValue(), 1.f);
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRateSelectionStrategy,
+ scheduler::LayerInfo::FrameRateSelectionStrategy::OverrideChildren);
+ EXPECT_TRUE(getSnapshot({.id = 111})->changes.test(RequestedLayerState::Changes::FrameRate));
+}
+
TEST_F(LayerSnapshotTest, skipRoundCornersWhenProtected) {
setRoundedCorners(1, 42.f);
setRoundedCorners(2, 42.f);