SF: Add ability to get basic geometry
For computing the layer visibility, CompositionEngine will need to get
basic geometry state for every layer, without getting everything. Add a
new request type for the basic geometry state, and modify the existing
code in computeVisibleRegions to use it rather than accessing directly
through the front-end layer pointer.
Test: atest libsurfaceflinger_unittest libcompositionengine_test
Test: go/wm-smoke
Bug: 121291683
Change-Id: Ie286fe1986a4c383ee390c1f646c7a8a5b8c14f4
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index db4f969..57cca69 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -39,9 +39,26 @@
// process.
virtual bool onPreComposition(nsecs_t refreshStartTime) = 0;
- // Latches the output-independent state. If includeGeometry is false, the
- // geometry state can be skipped.
- virtual void latchCompositionState(LayerFECompositionState&, bool includeGeometry) const = 0;
+ // Used with latchCompositionState()
+ enum class StateSubset {
+ // Gets the basic geometry (bounds, transparent region, visibility,
+ // transforms, alpha) for the layer, for computing visibility and
+ // coverage.
+ BasicGeometry,
+
+ // Gets the full geometry (crops, buffer transforms, metadata) and
+ // content (buffer or color) state for the layer.
+ GeometryAndContent,
+
+ // Gets the per frame content (buffer or color) state the layer.
+ Content,
+ };
+
+ // Latches the output-independent composition state for the layer. The
+ // StateSubset argument selects what portion of the state is actually needed
+ // by the CompositionEngine code, since computing everything may be
+ // expensive.
+ virtual void latchCompositionState(LayerFECompositionState&, StateSubset) const = 0;
// Latches the minimal bit of state for the cursor for a fast asynchronous
// update.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index b066cd1..530f49a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -40,6 +40,45 @@
// the next geometry change.
bool forceClientComposition{false};
+ // TODO(b/121291683): Reorganize and rename the contents of this structure
+
+ /*
+ * Visibility state
+ */
+ // the layer stack this layer belongs to
+ std::optional<uint32_t> layerStackId;
+
+ // If true, this layer should be only visible on the internal display
+ bool internalOnly{false};
+
+ // If false, this layer should not be considered visible
+ bool isVisible{true};
+
+ // True if the layer is completely opaque
+ bool isOpaque{true};
+
+ // If true, invalidates the entire visible region
+ bool contentDirty{false};
+
+ // The alpha value for this layer
+ float alpha{1.f};
+
+ // The transform from layer local coordinates to composition coordinates
+ ui::Transform geomLayerTransform;
+
+ // The inverse of the layer transform
+ ui::Transform geomInverseLayerTransform;
+
+ // The hint from the layer producer as to what portion of the layer is
+ // transparent.
+ Region transparentRegionHint;
+
+ // The blend mode for this layer
+ Hwc2::IComposerClient::BlendMode blendMode{Hwc2::IComposerClient::BlendMode::INVALID};
+
+ // The bounds of the layer in layer local coordinates
+ FloatRect geomLayerBounds;
+
/*
* Geometry state
*/
@@ -48,23 +87,9 @@
bool geomUsesSourceCrop{false};
bool geomBufferUsesDisplayInverseTransform{false};
uint32_t geomBufferTransform{0};
- ui::Transform geomLayerTransform;
- ui::Transform geomInverseLayerTransform;
Rect geomBufferSize;
Rect geomContentCrop;
Rect geomCrop;
- Region geomActiveTransparentRegion;
- FloatRect geomLayerBounds;
-
- /*
- * Presentation
- */
-
- // The blend mode for this layer
- Hwc2::IComposerClient::BlendMode blendMode{Hwc2::IComposerClient::BlendMode::INVALID};
-
- // The alpha value for this layer
- float alpha{1.f};
/*
* Extra metadata
@@ -113,9 +138,6 @@
mat4 colorTransform;
bool colorTransformIsIdentity{true};
- // True if the layer is completely opaque
- bool isOpaque{true};
-
// True if the layer has protected content
bool hasProtectedContent{false};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index a509ca8..43f44af 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -132,7 +132,7 @@
// A layer belongs to the output if its layerStackId matches. Additionally
// if the layer should only show in the internal (primary) display only and
// this output allows that.
- virtual bool belongsInOutput(uint32_t layerStackId, bool internalOnly) const = 0;
+ virtual bool belongsInOutput(std::optional<uint32_t> layerStackId, bool internalOnly) const = 0;
// Returns a pointer to the output layer corresponding to the given layer on
// this output, or nullptr if the layer does not have one
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index d826161..ece5b1c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -62,7 +62,7 @@
OutputCompositionState& editState() override;
Region getDirtyRegion(bool repaintEverything) const override;
- bool belongsInOutput(uint32_t, bool) const override;
+ bool belongsInOutput(std::optional<uint32_t>, bool) const override;
compositionengine::OutputLayer* getOutputLayerForLayer(
compositionengine::Layer*) const override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index e280295..3eada3c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -32,7 +32,8 @@
MOCK_METHOD1(onPreComposition, bool(nsecs_t));
- MOCK_CONST_METHOD2(latchCompositionState, void(LayerFECompositionState&, bool));
+ MOCK_CONST_METHOD2(latchCompositionState,
+ void(LayerFECompositionState&, compositionengine::LayerFE::StateSubset));
MOCK_CONST_METHOD1(latchCursorCompositionState, void(LayerFECompositionState&));
MOCK_METHOD1(prepareClientComposition,
std::optional<renderengine::LayerSettings>(
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 33925d5..2f24c15 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -59,7 +59,7 @@
MOCK_METHOD0(editState, OutputCompositionState&());
MOCK_CONST_METHOD1(getDirtyRegion, Region(bool));
- MOCK_CONST_METHOD2(belongsInOutput, bool(uint32_t, bool));
+ MOCK_CONST_METHOD2(belongsInOutput, bool(std::optional<uint32_t>, bool));
MOCK_CONST_METHOD1(getOutputLayerForLayer,
compositionengine::OutputLayer*(compositionengine::Layer*));
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
index 0dc4bf1..c5debf6 100644
--- a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
@@ -45,7 +45,7 @@
dumpVal(out, "geomBufferTransform", state.geomBufferTransform);
out.append("\n ");
- dumpVal(out, "geomActiveTransparentRegion", state.geomActiveTransparentRegion);
+ dumpVal(out, "transparentRegionHint", state.transparentRegionHint);
out.append(" ");
dumpVal(out, "geomLayerBounds", state.geomLayerBounds);
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 9f4f259..4dfdeba 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -212,10 +212,11 @@
return dirty;
}
-bool Output::belongsInOutput(uint32_t layerStackId, bool internalOnly) const {
+bool Output::belongsInOutput(std::optional<uint32_t> layerStackId, bool internalOnly) const {
// The layerStackId's must match, and also the layer must not be internal
// only when not on an internal output.
- return (layerStackId == mState.layerStackId) && (!internalOnly || mState.layerStackInternal);
+ return layerStackId && (*layerStackId == mState.layerStackId) &&
+ (!internalOnly || mState.layerStackInternal);
}
compositionengine::OutputLayer* Output::getOutputLayerForLayer(
@@ -281,7 +282,9 @@
void Output::updateLayerStateFromFE(const CompositionRefreshArgs& args) const {
for (auto& layer : mOutputLayersOrderedByZ) {
layer->getLayerFE().latchCompositionState(layer->getLayer().editState().frontEnd,
- args.updatingGeometryThisFrame);
+ args.updatingGeometryThisFrame
+ ? LayerFE::StateSubset::GeometryAndContent
+ : LayerFE::StateSubset::Content);
}
}
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 21f0ce8..3a0ebf8 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -102,7 +102,7 @@
// pixels in the buffer.
FloatRect activeCropFloat =
- reduce(layerState.geomLayerBounds, layerState.geomActiveTransparentRegion);
+ reduce(layerState.geomLayerBounds, layerState.transparentRegionHint);
const Rect& viewport = mOutput.getState().viewport;
const ui::Transform& layerTransform = layerState.geomLayerTransform;
@@ -209,7 +209,7 @@
// apply the layer's transform, followed by the display's global transform
// here we're guaranteed that the layer's transform preserves rects
- Region activeTransparentRegion = layerState.geomActiveTransparentRegion;
+ Region activeTransparentRegion = layerState.transparentRegionHint;
const ui::Transform& layerTransform = layerState.geomLayerTransform;
const ui::Transform& inverseLayerTransform = layerState.geomInverseLayerTransform;
const Rect& bufferSize = layerState.geomBufferSize;
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 2276dc3..65691ff 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -124,7 +124,7 @@
// set one specific value to something different.
mLayerState.frontEnd.geomUsesSourceCrop = true;
mLayerState.frontEnd.geomContentCrop = Rect{0, 0, 1920, 1080};
- mLayerState.frontEnd.geomActiveTransparentRegion = Region{};
+ mLayerState.frontEnd.transparentRegionHint = Region{};
mLayerState.frontEnd.geomLayerBounds = FloatRect{0.f, 0.f, 1920.f, 1080.f};
mLayerState.frontEnd.geomLayerTransform = ui::Transform{TR_IDENT};
mLayerState.frontEnd.geomBufferSize = Rect{0, 0, 1920, 1080};
@@ -231,7 +231,7 @@
// Set reasonable default values for a simple case. Each test will
// set one specific value to something different.
- mLayerState.frontEnd.geomActiveTransparentRegion = Region{};
+ mLayerState.frontEnd.transparentRegionHint = Region{};
mLayerState.frontEnd.geomLayerTransform = ui::Transform{TR_IDENT};
mLayerState.frontEnd.geomBufferSize = Rect{0, 0, 1920, 1080};
mLayerState.frontEnd.geomBufferUsesDisplayInverseTransform = false;
@@ -256,7 +256,7 @@
}
TEST_F(OutputLayerDisplayFrameTest, fullActiveTransparentRegionReturnsEmptyFrame) {
- mLayerState.frontEnd.geomActiveTransparentRegion = Region{Rect{0, 0, 1920, 1080}};
+ mLayerState.frontEnd.transparentRegionHint = Region{Rect{0, 0, 1920, 1080}};
const Rect expected{0, 0, 0, 0};
EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index b0e8e36..70d9871 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -356,6 +356,10 @@
// If the output accepts layerStack1 and internal-only layers....
mOutput.setLayerStackFilter(layerStack1, true);
+ // A layer with no layerStack does not belong to it, internal-only or not.
+ EXPECT_FALSE(mOutput.belongsInOutput(std::nullopt, false));
+ EXPECT_FALSE(mOutput.belongsInOutput(std::nullopt, true));
+
// Any layer with layerStack1 belongs to it, internal-only or not.
EXPECT_TRUE(mOutput.belongsInOutput(layerStack1, false));
EXPECT_TRUE(mOutput.belongsInOutput(layerStack1, true));
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 5e5302d..974488d 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -417,14 +417,43 @@
win.bottom -= roundedCornersCrop.top;
}
+void Layer::latchBasicGeometry(compositionengine::LayerFECompositionState& compositionState) const {
+ const auto& drawingState{getDrawingState()};
+ const uint32_t layerStack = getLayerStack();
+ const auto alpha = static_cast<float>(getAlpha());
+ const bool opaque = isOpaque(drawingState);
+ const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f;
+
+ auto blendMode = Hwc2::IComposerClient::BlendMode::NONE;
+ if (!opaque || alpha != 1.0f) {
+ blendMode = mPremultipliedAlpha ? Hwc2::IComposerClient::BlendMode::PREMULTIPLIED
+ : Hwc2::IComposerClient::BlendMode::COVERAGE;
+ }
+
+ // TODO(b/121291683): Instead of filling in a passed-in compositionState
+ // structure, switch to Layer owning the structure and have
+ // CompositionEngine be able to get a reference to it.
+
+ compositionState.layerStackId =
+ (layerStack != ~0u) ? std::make_optional(layerStack) : std::nullopt;
+ compositionState.internalOnly = getPrimaryDisplayOnly();
+ compositionState.isVisible = isVisible();
+ compositionState.isOpaque = opaque && !usesRoundedCorners && alpha == 1.f;
+
+ compositionState.contentDirty = contentDirty;
+ contentDirty = false;
+
+ compositionState.geomLayerBounds = mBounds;
+ compositionState.geomLayerTransform = getTransform();
+ compositionState.geomInverseLayerTransform = compositionState.geomLayerTransform.inverse();
+ compositionState.transparentRegionHint = getActiveTransparentRegion(drawingState);
+
+ compositionState.blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode);
+ compositionState.alpha = alpha;
+}
+
void Layer::latchGeometry(compositionengine::LayerFECompositionState& compositionState) const {
const auto& drawingState{getDrawingState()};
- auto alpha = static_cast<float>(getAlpha());
- auto blendMode = HWC2::BlendMode::None;
- if (!isOpaque(drawingState) || alpha != 1.0f) {
- blendMode =
- mPremultipliedAlpha ? HWC2::BlendMode::Premultiplied : HWC2::BlendMode::Coverage;
- }
int type = drawingState.metadata.getInt32(METADATA_WINDOW_TYPE, 0);
int appId = drawingState.metadata.getInt32(METADATA_OWNER_UID, 0);
@@ -439,20 +468,14 @@
}
}
- compositionState.geomLayerTransform = getTransform();
- compositionState.geomInverseLayerTransform = compositionState.geomLayerTransform.inverse();
compositionState.geomBufferSize = getBufferSize(drawingState);
compositionState.geomContentCrop = getContentCrop();
compositionState.geomCrop = getCrop(drawingState);
compositionState.geomBufferTransform = mCurrentTransform;
compositionState.geomBufferUsesDisplayInverseTransform = getTransformToDisplayInverse();
- compositionState.geomActiveTransparentRegion = getActiveTransparentRegion(drawingState);
- compositionState.geomLayerBounds = mBounds;
compositionState.geomUsesSourceCrop = usesSourceCrop();
compositionState.isSecure = isSecure();
- compositionState.blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode);
- compositionState.alpha = alpha;
compositionState.type = type;
compositionState.appId = appId;
}
@@ -498,12 +521,24 @@
}
void Layer::latchCompositionState(compositionengine::LayerFECompositionState& compositionState,
- bool includeGeometry) const {
- if (includeGeometry) {
- latchGeometry(compositionState);
- }
+ compositionengine::LayerFE::StateSubset subset) const {
+ using StateSubset = compositionengine::LayerFE::StateSubset;
- latchPerFrameState(compositionState);
+ switch (subset) {
+ case StateSubset::BasicGeometry:
+ latchBasicGeometry(compositionState);
+ break;
+
+ case StateSubset::GeometryAndContent:
+ latchBasicGeometry(compositionState);
+ latchGeometry(compositionState);
+ latchPerFrameState(compositionState);
+ break;
+
+ case StateSubset::Content:
+ latchPerFrameState(compositionState);
+ break;
+ }
}
const char* Layer::getDebugName() const {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 1486efe..02c78c9 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -471,7 +471,7 @@
*/
bool onPreComposition(nsecs_t) override;
void latchCompositionState(compositionengine::LayerFECompositionState&,
- bool includeGeometry) const override;
+ compositionengine::LayerFE::StateSubset subset) const override;
void latchCursorCompositionState(compositionengine::LayerFECompositionState&) const override;
std::optional<renderengine::LayerSettings> prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
@@ -479,6 +479,7 @@
const char* getDebugName() const override;
protected:
+ void latchBasicGeometry(compositionengine::LayerFECompositionState& outState) const;
void latchGeometry(compositionengine::LayerFECompositionState& outState) const;
virtual void latchPerFrameState(compositionengine::LayerFECompositionState& outState) const;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 3498419..6d853f9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2757,11 +2757,22 @@
return;
}
- // start with the whole surface at its current location
- const Layer::State& s(layer->getDrawingState());
+ // Note: Converts a wp<LayerFE> to a sp<LayerFE>
+ auto layerFE = compositionLayer->getLayerFE();
+ if (layerFE == nullptr) {
+ return;
+ }
+
+ // Request a snapshot of the subset of state relevant to visibility
+ // determination
+ layerFE->latchCompositionState(compositionLayer->editState().frontEnd,
+ compositionengine::LayerFE::StateSubset::BasicGeometry);
+
+ // Work with a read-only copy of the snapshot
+ const auto& layerFEState = compositionLayer->getState().frontEnd;
// only consider the layers on the given layer stack
- if (!display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) {
+ if (!display->belongsInOutput(layerFEState.layerStackId, layerFEState.internalOnly)) {
return;
}
@@ -2795,18 +2806,17 @@
Region transparentRegion;
// handle hidden surfaces by setting the visible region to empty
- if (CC_LIKELY(layer->isVisible())) {
- const bool translucent = !layer->isOpaque(s);
- Rect bounds(layer->getScreenBounds());
-
- visibleRegion.set(bounds);
- ui::Transform tr = layer->getTransform();
+ if (CC_LIKELY(layerFEState.isVisible)) {
+ // Get the visible region
+ visibleRegion.set(
+ Rect(layerFEState.geomLayerTransform.transform(layerFEState.geomLayerBounds)));
+ const ui::Transform& tr = layerFEState.geomLayerTransform;
if (!visibleRegion.isEmpty()) {
// Remove the transparent area from the visible region
- if (translucent) {
+ if (!layerFEState.isOpaque) {
if (tr.preserveRects()) {
// transform the transparent region
- transparentRegion = tr.transform(layer->getActiveTransparentRegion(s));
+ transparentRegion = tr.transform(layerFEState.transparentRegionHint);
} else {
// transformation too complex, can't do the
// transparent region optimization.
@@ -2816,9 +2826,8 @@
// compute the opaque region
const int32_t layerOrientation = tr.getOrientation();
- if (layer->getAlpha() == 1.0f && !translucent &&
- layer->getRoundedCornerState().radius == 0.0f &&
- ((layerOrientation & ui::Transform::ROT_INVALID) == false)) {
+ if (layerFEState.isOpaque &&
+ ((layerOrientation & ui::Transform::ROT_INVALID) == false)) {
// the opaque region is the layer's footprint
opaqueRegion = visibleRegion;
}
@@ -2848,12 +2857,11 @@
prevOutputLayer ? prevOutputLayer->getState().coveredRegion : kEmptyRegion;
// compute this layer's dirty region
- if (layer->contentDirty) {
+ if (layerFEState.contentDirty) {
// we need to invalidate the whole region
dirty = visibleRegion;
// as well, as the old visible region
dirty.orSelf(oldVisibleRegion);
- layer->contentDirty = false;
} else {
/* compute the exposed region:
* the exposed region consists of two components:
@@ -2892,8 +2900,6 @@
}
const auto displayId = displayDevice->getId();
- sp<compositionengine::LayerFE> layerFE = compositionLayer->getLayerFE();
- LOG_ALWAYS_FATAL_IF(layerFE.get() == nullptr);
outLayersSortedByZ.emplace_back(
display->getOrCreateOutputLayer(displayId, compositionLayer, layerFE));