Plumb new frameRateSelectionStrategy value
This new value will allow a parent layer to override the frame
rate specifications of all its descendants. This CL only plumbs the
value from Transaction to Layer.
Bug: 297418260
Test: atest CtsSurfaceControlTestsStaging
Test: atest libsurfaceflinger_unittest
Change-Id: Ibbda6ff6c143e931240178d89306822b4cce9669
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index e1afb52..27b1d8b 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -84,6 +84,7 @@
changeFrameRateStrategy(ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS),
defaultFrameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT),
frameRateCategory(ANATIVEWINDOW_FRAME_RATE_CATEGORY_DEFAULT),
+ frameRateSelectionStrategy(ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_SELF),
fixedTransformHint(ui::Transform::ROT_INVALID),
autoRefresh(false),
isTrustedOverlay(false),
@@ -160,6 +161,7 @@
SAFE_PARCEL(output.writeByte, changeFrameRateStrategy);
SAFE_PARCEL(output.writeByte, defaultFrameRateCompatibility);
SAFE_PARCEL(output.writeByte, frameRateCategory);
+ SAFE_PARCEL(output.writeByte, frameRateSelectionStrategy);
SAFE_PARCEL(output.writeUint32, fixedTransformHint);
SAFE_PARCEL(output.writeBool, autoRefresh);
SAFE_PARCEL(output.writeBool, dimmingEnabled);
@@ -293,6 +295,7 @@
SAFE_PARCEL(input.readByte, &changeFrameRateStrategy);
SAFE_PARCEL(input.readByte, &defaultFrameRateCompatibility);
SAFE_PARCEL(input.readByte, &frameRateCategory);
+ SAFE_PARCEL(input.readByte, &frameRateSelectionStrategy);
SAFE_PARCEL(input.readUint32, &tmpUint32);
fixedTransformHint = static_cast<ui::Transform::RotationFlags>(tmpUint32);
SAFE_PARCEL(input.readBool, &autoRefresh);
@@ -666,6 +669,10 @@
what |= eFrameRateCategoryChanged;
frameRateCategory = other.frameRateCategory;
}
+ if (other.what & eFrameRateSelectionStrategyChanged) {
+ what |= eFrameRateSelectionStrategyChanged;
+ frameRateSelectionStrategy = other.frameRateSelectionStrategy;
+ }
if (other.what & eFixedTransformHintChanged) {
what |= eFixedTransformHintChanged;
fixedTransformHint = other.fixedTransformHint;
@@ -777,6 +784,7 @@
CHECK_DIFF3(diff, eFrameRateChanged, other, frameRate, frameRateCompatibility,
changeFrameRateStrategy);
CHECK_DIFF(diff, eFrameRateCategoryChanged, other, frameRateCategory);
+ CHECK_DIFF(diff, eFrameRateSelectionStrategyChanged, other, frameRateSelectionStrategy);
CHECK_DIFF(diff, eFixedTransformHintChanged, other, fixedTransformHint);
CHECK_DIFF(diff, eAutoRefreshChanged, other, autoRefresh);
CHECK_DIFF(diff, eTrustedOverlayChanged, other, isTrustedOverlay);
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 4db960e..c2543d1 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -2104,6 +2104,19 @@
return *this;
}
+SurfaceComposerClient::Transaction&
+SurfaceComposerClient::Transaction::setFrameRateSelectionStrategy(const sp<SurfaceControl>& sc,
+ int8_t strategy) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eFrameRateSelectionStrategyChanged;
+ s->frameRateSelectionStrategy = strategy;
+ return *this;
+}
+
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFixedTransformHint(
const sp<SurfaceControl>& sc, int32_t fixedTransformHint) {
layer_state_t* s = getLayerState(sc);
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 8c36058..35fcccd 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -197,7 +197,7 @@
eInputInfoChanged = 0x40000000,
eCornerRadiusChanged = 0x80000000,
eDestinationFrameChanged = 0x1'00000000,
- /* unused = 0x2'00000000, */
+ eFrameRateSelectionStrategyChanged = 0x2'00000000,
eBackgroundColorChanged = 0x4'00000000,
eMetadataChanged = 0x8'00000000,
eColorSpaceAgnosticChanged = 0x10'00000000,
@@ -268,6 +268,7 @@
layer_state_t::eColorTransformChanged | layer_state_t::eCornerRadiusChanged |
layer_state_t::eFlagsChanged | layer_state_t::eTrustedOverlayChanged |
layer_state_t::eFrameRateChanged | layer_state_t::eFrameRateCategoryChanged |
+ layer_state_t::eFrameRateSelectionStrategyChanged |
layer_state_t::eFrameRateSelectionPriority | layer_state_t::eFixedTransformHintChanged;
// Changes affecting data sent to input.
@@ -361,6 +362,9 @@
// Frame rate category to suggest what frame rate range a surface should run.
int8_t frameRateCategory;
+ // Strategy of the layer for frame rate selection.
+ int8_t frameRateSelectionStrategy;
+
// Set by window manager indicating the layer and all its children are
// in a different orientation than the display. The hint suggests that
// the graphic producers should receive a transform hint as if the
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 6fef5d2..42e3c16 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -687,6 +687,8 @@
Transaction& setFrameRateCategory(const sp<SurfaceControl>& sc, int8_t category);
+ Transaction& setFrameRateSelectionStrategy(const sp<SurfaceControl>& sc, int8_t strategy);
+
// Set by window manager indicating the layer and all its children are
// in a different orientation than the display. The hint suggests that
// the graphic producers should receive a transform hint as if the
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index e158f01..b068f48 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -1096,6 +1096,26 @@
ANATIVEWINDOW_FRAME_RATE_CATEGORY_HIGH = 4
};
+/*
+ * Frame rate selection strategy values that can be used in
+ * Transaction::setFrameRateSelectionStrategy.
+ */
+enum {
+ /**
+ * Default value. The layer uses its own frame rate specifications, assuming it has any
+ * specifications, instead of its parent's.
+ */
+ ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_SELF = 0,
+
+ /**
+ * The layer's frame rate specifications will propagate to and override those of its descendant
+ * layers.
+ * The layer with this strategy has the ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_SELF
+ * behavior for itself.
+ */
+ ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN = 1,
+};
+
static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate,
int8_t compatibility, int8_t changeFrameRateStrategy) {
return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate,
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
index 7537a39..a5e9368 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
@@ -85,6 +85,7 @@
bool isTrustedOverlay;
gui::GameMode gameMode;
scheduler::LayerInfo::FrameRate frameRate;
+ scheduler::LayerInfo::FrameRateSelectionStrategy frameRateSelectionStrategy;
ui::Transform::RotationFlags fixedTransformHint;
std::optional<ui::Transform::RotationFlags> transformHint;
bool handleSkipScreenshotFlag = false;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index da84e44..4c9fb06 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -813,11 +813,23 @@
RequestedLayerState::Changes::Hierarchy) ||
snapshot.changes.any(RequestedLayerState::Changes::FrameRate |
RequestedLayerState::Changes::Hierarchy)) {
- snapshot.frameRate = requested.requestedFrameRate.isValid() ? requested.requestedFrameRate
- : parentSnapshot.frameRate;
+ bool shouldOverrideChildren = parentSnapshot.frameRateSelectionStrategy ==
+ scheduler::LayerInfo::FrameRateSelectionStrategy::OverrideChildren;
+ snapshot.frameRate = !requested.requestedFrameRate.isValid() || shouldOverrideChildren
+ ? parentSnapshot.frameRate
+ : requested.requestedFrameRate;
snapshot.changes |= RequestedLayerState::Changes::FrameRate;
}
+ 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 (forceUpdate || snapshot.clientChanges & layer_state_t::eFrameRateSelectionPriority) {
snapshot.frameRateSelectionPriority =
(requested.frameRateSelectionPriority == Layer::PRIORITY_UNSET)
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index 57ebee9..acec630 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -125,6 +125,8 @@
defaultFrameRateCompatibility =
static_cast<int8_t>(scheduler::LayerInfo::FrameRateCompatibility::Default);
frameRateCategory = static_cast<int8_t>(FrameRateCategory::Default);
+ frameRateSelectionStrategy =
+ static_cast<int8_t>(scheduler::LayerInfo::FrameRateSelectionStrategy::Self);
dataspace = ui::Dataspace::V0_SRGB;
gameMode = gui::GameMode::Unsupported;
requestedFrameRate = {};
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 2684000..31b5e28 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -192,6 +192,7 @@
mDrawingState.dropInputMode = gui::DropInputMode::NONE;
mDrawingState.dimmingEnabled = true;
mDrawingState.defaultFrameRateCompatibility = FrameRateCompatibility::Default;
+ mDrawingState.frameRateSelectionStrategy = FrameRateSelectionStrategy::Self;
if (args.flags & ISurfaceComposerClient::eNoColorFill) {
// Set an invalid color so there is no color fill.
@@ -1338,6 +1339,15 @@
return true;
}
+bool Layer::setFrameRateSelectionStrategy(FrameRateSelectionStrategy strategy) {
+ if (mDrawingState.frameRateSelectionStrategy == strategy) return false;
+ mDrawingState.frameRateSelectionStrategy = strategy;
+ mDrawingState.sequence++;
+ mDrawingState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
void Layer::setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info,
nsecs_t postTime) {
mDrawingState.postTime = postTime;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 0b0cef5..d5e2185 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -112,6 +112,7 @@
using FrameRate = scheduler::LayerInfo::FrameRate;
using FrameRateCompatibility = scheduler::LayerInfo::FrameRateCompatibility;
+ using FrameRateSelectionStrategy = scheduler::LayerInfo::FrameRateSelectionStrategy;
struct State {
int32_t z;
@@ -188,6 +189,8 @@
// The combined frame rate of parents / children of this layer
FrameRate frameRateForLayerTree;
+ FrameRateSelectionStrategy frameRateSelectionStrategy;
+
// Set by window manager indicating the layer and all its children are
// in a different orientation than the display. The hint suggests that
// the graphic producers should receive a transform hint as if the
@@ -782,6 +785,8 @@
bool setFrameRate(FrameRate::FrameRateVote);
bool setFrameRateCategory(FrameRateCategory);
+ bool setFrameRateSelectionStrategy(FrameRateSelectionStrategy);
+
virtual void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& /*info*/) {}
void setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info, nsecs_t postTime);
void setFrameTimelineVsyncForBufferlessTransaction(const FrameTimelineInfo& info,
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index 0784251..03844ef 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -490,6 +490,19 @@
}
}
+LayerInfo::FrameRateSelectionStrategy LayerInfo::convertFrameRateSelectionStrategy(
+ int8_t strategy) {
+ switch (strategy) {
+ case ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_SELF:
+ return FrameRateSelectionStrategy::Self;
+ case ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN:
+ return FrameRateSelectionStrategy::OverrideChildren;
+ default:
+ LOG_ALWAYS_FATAL("Invalid frame rate selection strategy value %d", strategy);
+ return FrameRateSelectionStrategy::Self;
+ }
+}
+
bool LayerInfo::FrameRate::isNoVote() const {
return vote.type == FrameRateCompatibility::NoVote;
}
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index 7fe407f..3b4d823 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -96,6 +96,13 @@
ftl_last = NoVote
};
+ enum class FrameRateSelectionStrategy {
+ Self,
+ OverrideChildren,
+
+ ftl_last = OverrideChildren
+ };
+
// Encapsulates the frame rate specifications of the layer. This information will be used
// when the display refresh rate is determined.
struct FrameRate {
@@ -139,11 +146,11 @@
static FrameRateCompatibility convertCompatibility(int8_t compatibility);
// Convert an ANATIVEWINDOW_CHANGE_FRAME_RATE_* value to a scheduler::Seamlessness.
- // Logs fatal if the compatibility value is invalid.
+ // Logs fatal if the strategy value is invalid.
static scheduler::Seamlessness convertChangeFrameRateStrategy(int8_t strategy);
// Convert an ANATIVEWINDOW_FRAME_RATE_CATEGORY_* value to a FrameRateCategory.
- // Logs fatal if the compatibility value is invalid.
+ // Logs fatal if the category value is invalid.
static FrameRateCategory convertCategory(int8_t category);
// True if the FrameRate has explicit frame rate specifications.
@@ -164,6 +171,10 @@
}
};
+ // Convert an ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_* value to FrameRateSelectionStrategy.
+ // Logs fatal if the strategy value is invalid.
+ static FrameRateSelectionStrategy convertFrameRateSelectionStrategy(int8_t strategy);
+
static void setTraceEnabled(bool enabled) { sTraceEnabled = enabled; }
LayerInfo(const std::string& name, uid_t ownerUid, LayerHistory::LayerVoteType defaultVote);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 6d4d186..10768a9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -5206,6 +5206,14 @@
flags |= eTraversalNeeded;
}
}
+ if (what & layer_state_t::eFrameRateSelectionStrategyChanged) {
+ const scheduler::LayerInfo::FrameRateSelectionStrategy strategy =
+ scheduler::LayerInfo::convertFrameRateSelectionStrategy(
+ s.frameRateSelectionStrategy);
+ if (layer->setFrameRateSelectionStrategy(strategy)) {
+ flags |= eTraversalNeeded;
+ }
+ }
if (what & layer_state_t::eFixedTransformHintChanged) {
if (layer->setFixedTransformHint(s.fixedTransformHint)) {
flags |= eTraversalNeeded | eTransformHintUpdateNeeded;
diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
index ff644ba..32821b7 100644
--- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
@@ -346,6 +346,18 @@
mLifecycleManager.applyTransactions(transactions);
}
+ void setFrameRateSelectionStrategy(uint32_t id, int8_t strategy) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what =
+ layer_state_t::eFrameRateSelectionStrategyChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.frameRateSelectionStrategy = strategy;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
void setRoundedCorners(uint32_t id, float radius) {
std::vector<TransactionState> transactions;
transactions.emplace_back();
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 1227b99..662f4bd 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -743,6 +743,50 @@
EXPECT_TRUE(getSnapshot({.id = 1221})->changes.test(RequestedLayerState::Changes::FrameRate));
}
+TEST_F(LayerSnapshotTest, frameRateSelectionStrategy) {
+ // ROOT
+ // ├── 1
+ // │ ├── 11
+ // │ │ └── 111
+ // │ ├── 12 (frame rate set to 244.f with strategy OverrideChildren)
+ // │ │ ├── 121
+ // │ │ └── 122 (frame rate set to 123.f but should be overridden by layer 12)
+ // │ │ └── 1221
+ // │ └── 13
+ // └── 2
+ setFrameRate(12, 244.f, 0, 0);
+ setFrameRate(122, 123.f, 0, 0);
+ setFrameRateSelectionStrategy(12, 1 /* OverrideChildren */);
+
+ 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::LayerInfo::FrameRateCompatibility::NoVote);
+ EXPECT_TRUE(getSnapshot({.id = 1})->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::OverrideChildren);
+ 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::OverrideChildren);
+ 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));
+}
+
TEST_F(LayerSnapshotTest, skipRoundCornersWhenProtected) {
setRoundedCorners(1, 42.f);
setRoundedCorners(2, 42.f);