SF: Move OutputLayer creation to computeVisibleRegions
This moves part of rebuildLayerStacks to computeVisibleRegions. In
particular it eliminates a second loop over all front-end layers to
identify the ones that are visible on an output. The first loop
computes the visibility, and can immediately create the output layers.
This is a bit of nontrivial restructuring prior to moving the code to
CompositionEngine, since that will also break things up a bit.
Test: atest libsurfaceflinger_unittest libcompositionengine_test
Bug: 121291683
Change-Id: I8a498195f9b5f976e7a69de717818b57494e2f2b
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 50440e8..49a6800 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2085,6 +2085,12 @@
ATRACE_NAME("rebuildLayerStacks VR Dirty");
invalidateHwcGeometry();
+ std::vector<sp<compositionengine::LayerFE>> layersWithQueuedFrames;
+ layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size());
+ for (sp<Layer> layer : mLayersWithQueuedFrames) {
+ layersWithQueuedFrames.push_back(layer);
+ }
+
for (const auto& pair : mDisplays) {
const auto& displayDevice = pair.second;
auto display = displayDevice->getCompositionDisplay();
@@ -2092,59 +2098,44 @@
Region opaqueRegion;
Region dirtyRegion;
compositionengine::Output::OutputLayers layersSortedByZ;
- compositionengine::Output::ReleasedLayers releasedLayers;
const ui::Transform& tr = displayState.transform;
const Rect bounds = displayState.bounds;
- if (displayState.isEnabled) {
- computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion);
-
- mDrawingState.traverseInZOrder([&](Layer* layer) {
- auto compositionLayer = layer->getCompositionLayer();
- if (compositionLayer == nullptr) {
- return;
- }
-
- const auto displayId = displayDevice->getId();
- sp<compositionengine::LayerFE> layerFE = compositionLayer->getLayerFE();
- LOG_ALWAYS_FATAL_IF(layerFE.get() == nullptr);
-
- bool needsOutputLayer = false;
-
- if (display->belongsInOutput(layer->getLayerStack(),
- layer->getPrimaryDisplayOnly())) {
- Region drawRegion(tr.transform(
- layer->visibleNonTransparentRegion));
- drawRegion.andSelf(bounds);
- if (!drawRegion.isEmpty()) {
- needsOutputLayer = true;
- }
- }
-
- if (needsOutputLayer) {
- layersSortedByZ.emplace_back(
- display->getOrCreateOutputLayer(displayId, compositionLayer,
- layerFE));
- auto& outputLayerState = layersSortedByZ.back()->editState();
- outputLayerState.visibleRegion =
- tr.transform(layer->visibleRegion.intersect(displayState.viewport));
- } else if (displayId) {
- // For layers that are being removed from a HWC display,
- // and that have queued frames, add them to a a list of
- // released layers so we can properly set a fence.
- bool hasExistingOutputLayer =
- display->getOutputLayerForLayer(compositionLayer.get()) != nullptr;
- bool hasQueuedFrames = std::find(mLayersWithQueuedFrames.cbegin(),
- mLayersWithQueuedFrames.cend(),
- layer) != mLayersWithQueuedFrames.cend();
-
- if (hasExistingOutputLayer && hasQueuedFrames) {
- releasedLayers.push_back(layer);
- }
- }
- });
+ if (!displayState.isEnabled) {
+ continue;
}
+ computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion, layersSortedByZ);
+
+ // computeVisibleRegions walks the layers in reverse-Z order. Reverse
+ // to get a back-to-front ordering.
+ std::reverse(layersSortedByZ.begin(), layersSortedByZ.end());
+
display->setOutputLayersOrderedByZ(std::move(layersSortedByZ));
+
+ compositionengine::Output::ReleasedLayers releasedLayers;
+ if (displayDevice->getId() && !layersWithQueuedFrames.empty()) {
+ // For layers that are being removed from a HWC display,
+ // and that have queued frames, add them to a a list of
+ // released layers so we can properly set a fence.
+
+ // Any non-null entries in the current list of layers are layers
+ // that are no longer going to be visible
+ for (auto& layer : display->getOutputLayersOrderedByZ()) {
+ if (!layer) {
+ continue;
+ }
+
+ sp<compositionengine::LayerFE> layerFE(&layer->getLayerFE());
+ const bool hasQueuedFrames =
+ std::find(layersWithQueuedFrames.cbegin(),
+ layersWithQueuedFrames.cend(),
+ layerFE) != layersWithQueuedFrames.cend();
+
+ if (hasQueuedFrames) {
+ releasedLayers.emplace_back(layerFE);
+ }
+ }
+ }
display->setReleasedLayers(std::move(releasedLayers));
Region undefinedRegion{bounds};
@@ -2744,8 +2735,10 @@
}
}
-void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
- Region& outDirtyRegion, Region& outOpaqueRegion) {
+void SurfaceFlinger::computeVisibleRegions(
+ const sp<const DisplayDevice>& displayDevice, Region& outDirtyRegion,
+ Region& outOpaqueRegion,
+ std::vector<std::unique_ptr<compositionengine::OutputLayer>>& outLayersSortedByZ) {
ATRACE_CALL();
ALOGV("computeVisibleRegions");
@@ -2758,6 +2751,11 @@
outDirtyRegion.clear();
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
+ auto compositionLayer = layer->getCompositionLayer();
+ if (compositionLayer == nullptr) {
+ return;
+ }
+
// start with the whole surface at its current location
const Layer::State& s(layer->getDrawingState());
@@ -2880,6 +2878,25 @@
layer->setCoveredRegion(coveredRegion);
layer->setVisibleNonTransparentRegion(
visibleRegion.subtract(transparentRegion));
+
+ // Setup an output layer for this output if the layer is
+ // visible on this output
+ const auto& displayState = display->getState();
+ Region drawRegion(displayState.transform.transform(layer->visibleNonTransparentRegion));
+ drawRegion.andSelf(displayState.bounds);
+ if (drawRegion.isEmpty()) {
+ return;
+ }
+
+ 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));
+ auto& outputLayerState = outLayersSortedByZ.back()->editState();
+ outputLayerState.visibleRegion = displayState.transform.transform(
+ layer->visibleRegion.intersect(displayState.viewport));
});
outOpaqueRegion = aboveOpaqueLayers;