Merge "SF: Move/Refactor rebuildLayerStacks and computeVisibleRegions"
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
index 6f689ad..90158c7 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
@@ -18,6 +18,7 @@
#include <chrono>
#include <optional>
+#include <vector>
#include <compositionengine/Display.h>
#include <compositionengine/Layer.h>
@@ -28,6 +29,7 @@
using Layers = std::vector<std::shared_ptr<compositionengine::Layer>>;
using Outputs = std::vector<std::shared_ptr<compositionengine::Output>>;
+using RawLayers = std::vector<compositionengine::Layer*>;
/**
* A parameter object for refreshing a set of outputs
@@ -41,6 +43,9 @@
// front.
Layers layers;
+ // All the layers that have queued updates.
+ RawLayers layersWithQueuedFrames;
+
// If true, forces the entire display to be considered dirty and repainted
bool repaintEverything{false};
@@ -53,6 +58,9 @@
// Forces a color mode on the outputs being refreshed
ui::ColorMode forceOutputColorMode{ui::ColorMode::NATIVE};
+ // If true, the complete output geometry needs to be recomputed this frame
+ bool updatingOutputGeometryThisFrame{false};
+
// If true, there was a geometry update this frame
bool updatingGeometryThisFrame{false};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index 57cca69..e585769 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -17,6 +17,7 @@
#pragma once
#include <optional>
+#include <unordered_set>
#include <renderengine/LayerSettings.h>
#include <utils/RefBase.h>
@@ -99,5 +100,13 @@
virtual const char* getDebugName() const = 0;
};
+// TODO(b/121291683): Specialize std::hash<> for sp<T> so these and others can
+// be removed.
+struct LayerFESpHash {
+ size_t operator()(const sp<LayerFE>& p) const { return std::hash<LayerFE*>()(p.get()); }
+};
+
+using LayerFESet = std::unordered_set<sp<LayerFE>, LayerFESpHash>;
+
} // namespace compositionengine
} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 80fce2c..d374baa 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -21,6 +21,7 @@
#include <string>
#include <unordered_map>
+#include <compositionengine/LayerFE.h>
#include <renderengine/LayerSettings.h>
#include <ui/Fence.h>
#include <ui/GraphicTypes.h>
@@ -71,6 +72,22 @@
ui::Dataspace colorSpaceAgnosticDataspace{ui::Dataspace::UNKNOWN};
};
+ // Use internally to incrementally compute visibility/coverage
+ struct CoverageState {
+ explicit CoverageState(LayerFESet& latchedLayers) : latchedLayers(latchedLayers) {}
+
+ // The set of layers that had been latched for the coverage calls, to
+ // avoid duplicate requests to obtain the same front-end layer state.
+ LayerFESet& latchedLayers;
+
+ // The region of the output which is covered by layers
+ Region aboveCoveredLayers;
+ // The region of the output which is opaquely covered by layers
+ Region aboveOpaqueLayers;
+ // The region of the output which should be considered dirty
+ Region dirtyRegion;
+ };
+
virtual ~Output();
// Returns true if the output is valid. This is meant to be checked post-
@@ -164,7 +181,7 @@
virtual ReleasedLayers takeReleasedLayers() = 0;
// Prepare the output, updating the OutputLayers used in the output
- virtual void prepare(CompositionRefreshArgs&) = 0;
+ virtual void prepare(const CompositionRefreshArgs&, LayerFESet&) = 0;
// Presents the output, finalizing all composition details
virtual void present(const CompositionRefreshArgs&) = 0;
@@ -176,6 +193,13 @@
virtual void setDisplayColorProfile(std::unique_ptr<DisplayColorProfile>) = 0;
virtual void setRenderSurface(std::unique_ptr<RenderSurface>) = 0;
+ virtual void rebuildLayerStacks(const compositionengine::CompositionRefreshArgs&,
+ LayerFESet&) = 0;
+ virtual void collectVisibleLayers(const CompositionRefreshArgs&, CoverageState&) = 0;
+ virtual std::unique_ptr<OutputLayer> getOutputLayerIfVisible(
+ std::shared_ptr<compositionengine::Layer>, CoverageState&) = 0;
+ virtual void setReleasedLayers(const compositionengine::CompositionRefreshArgs&) = 0;
+
virtual void updateAndWriteCompositionState(const CompositionRefreshArgs&) = 0;
virtual void setColorTransform(const CompositionRefreshArgs&) = 0;
virtual void updateColorProfile(const CompositionRefreshArgs&) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 2e595d6..b5d8325 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -42,6 +42,8 @@
void dump(std::string&) const override;
std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(
const std::shared_ptr<Layer>&, const sp<LayerFE>&) const override;
+ using compositionengine::impl::Output::setReleasedLayers;
+ void setReleasedLayers(const compositionengine::CompositionRefreshArgs&) override;
void setColorTransform(const compositionengine::CompositionRefreshArgs&) override;
void setColorProfile(const ColorProfile&) override;
void chooseCompositionStrategy() override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 6dde86d..fa6cd27 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -77,9 +77,17 @@
void setReleasedLayers(ReleasedLayers&&) override;
ReleasedLayers takeReleasedLayers() override;
- void prepare(compositionengine::CompositionRefreshArgs&) override;
+ void prepare(const compositionengine::CompositionRefreshArgs&, LayerFESet&) override;
void present(const compositionengine::CompositionRefreshArgs&) override;
+ void rebuildLayerStacks(const compositionengine::CompositionRefreshArgs&, LayerFESet&) override;
+ void collectVisibleLayers(const compositionengine::CompositionRefreshArgs&,
+ compositionengine::Output::CoverageState&) override;
+ std::unique_ptr<compositionengine::OutputLayer> getOutputLayerIfVisible(
+ std::shared_ptr<compositionengine::Layer>,
+ compositionengine::Output::CoverageState&) override;
+ void setReleasedLayers(const compositionengine::CompositionRefreshArgs&) override;
+
void updateLayerStateFromFE(const CompositionRefreshArgs&) const override;
void updateAndWriteCompositionState(const compositionengine::CompositionRefreshArgs&) override;
void updateColorProfile(const compositionengine::CompositionRefreshArgs&) override;
@@ -91,11 +99,14 @@
void postFramebuffer() override;
// Testing
+ const ReleasedLayers& getReleasedLayersForTest() const;
void setDisplayColorProfileForTest(std::unique_ptr<compositionengine::DisplayColorProfile>);
void setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface>);
protected:
const CompositionEngine& getCompositionEngine() const;
+ std::unique_ptr<compositionengine::OutputLayer> takeOutputLayerForLayer(
+ compositionengine::Layer*);
void chooseCompositionStrategy() override;
bool getSkipColorTransform() const override;
compositionengine::Output::FrameFences presentAndGetFrameFences() override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 8cf7f79..286a20f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -79,9 +79,20 @@
MOCK_METHOD1(setReleasedLayers, void(ReleasedLayers&&));
MOCK_METHOD0(takeReleasedLayers, ReleasedLayers());
- MOCK_METHOD1(prepare, void(compositionengine::CompositionRefreshArgs&));
+ MOCK_METHOD2(prepare, void(const compositionengine::CompositionRefreshArgs&, LayerFESet&));
MOCK_METHOD1(present, void(const compositionengine::CompositionRefreshArgs&));
+ MOCK_METHOD2(rebuildLayerStacks,
+ void(const compositionengine::CompositionRefreshArgs&, LayerFESet&));
+ MOCK_METHOD2(collectVisibleLayers,
+ void(const compositionengine::CompositionRefreshArgs&,
+ compositionengine::Output::CoverageState&));
+ MOCK_METHOD2(getOutputLayerIfVisible,
+ std::unique_ptr<compositionengine::OutputLayer>(
+ std::shared_ptr<compositionengine::Layer>,
+ compositionengine::Output::CoverageState&));
+ MOCK_METHOD1(setReleasedLayers, void(const compositionengine::CompositionRefreshArgs&));
+
MOCK_CONST_METHOD1(updateLayerStateFromFE, void(const CompositionRefreshArgs&));
MOCK_METHOD1(updateAndWriteCompositionState, void(const CompositionRefreshArgs&));
MOCK_METHOD1(updateColorProfile, void(const compositionengine::CompositionRefreshArgs&));
diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
index 590c596..713266f 100644
--- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
@@ -72,8 +72,20 @@
}
void CompositionEngine::present(CompositionRefreshArgs& args) {
- for (const auto& output : args.outputs) {
- output->prepare(args);
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ preComposition(args);
+
+ {
+ // latchedLayers is used to track the set of front-end layer state that
+ // has been latched across all outputs for the prepare step, and is not
+ // needed for anything else.
+ LayerFESet latchedLayers;
+
+ for (const auto& output : args.outputs) {
+ output->prepare(args, latchedLayers);
+ }
}
updateLayerStateFromFE(args);
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 49727df..fe8fa21 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -158,6 +158,39 @@
return result;
}
+void Display::setReleasedLayers(const compositionengine::CompositionRefreshArgs& refreshArgs) {
+ Output::setReleasedLayers(refreshArgs);
+
+ if (!mId || refreshArgs.layersWithQueuedFrames.empty()) {
+ return;
+ }
+
+ // 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.
+ compositionengine::Output::ReleasedLayers releasedLayers;
+
+ // Any non-null entries in the current list of layers are layers that are no
+ // longer going to be visible
+ for (auto& layer : getOutputLayersOrderedByZ()) {
+ if (!layer) {
+ continue;
+ }
+
+ sp<compositionengine::LayerFE> layerFE(&layer->getLayerFE());
+ const bool hasQueuedFrames =
+ std::find(refreshArgs.layersWithQueuedFrames.cbegin(),
+ refreshArgs.layersWithQueuedFrames.cend(),
+ &layer->getLayer()) != refreshArgs.layersWithQueuedFrames.cend();
+
+ if (hasQueuedFrames) {
+ releasedLayers.emplace_back(layerFE);
+ }
+ }
+
+ setReleasedLayers(std::move(releasedLayers));
+}
+
void Display::chooseCompositionStrategy() {
ATRACE_CALL();
ALOGV(__FUNCTION__);
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index a9b1d55..83df628 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -40,6 +40,27 @@
namespace impl {
+namespace {
+
+template <typename T>
+class Reversed {
+public:
+ explicit Reversed(const T& container) : mContainer(container) {}
+ auto begin() { return mContainer.rbegin(); }
+ auto end() { return mContainer.rend(); }
+
+private:
+ const T& mContainer;
+};
+
+// Helper for enumerating over a container in reverse order
+template <typename T>
+Reversed<T> reversed(const T& c) {
+ return Reversed<T>(c);
+}
+
+} // namespace
+
Output::Output(const CompositionEngine& compositionEngine)
: mCompositionEngine(compositionEngine) {}
@@ -176,6 +197,10 @@
mDisplayColorProfile = std::move(mode);
}
+const Output::ReleasedLayers& Output::getReleasedLayersForTest() const {
+ return mReleasedLayers;
+}
+
void Output::setDisplayColorProfileForTest(
std::unique_ptr<compositionengine::DisplayColorProfile> mode) {
mDisplayColorProfile = std::move(mode);
@@ -238,15 +263,24 @@
return nullptr;
}
-std::unique_ptr<compositionengine::OutputLayer> Output::getOrCreateOutputLayer(
- std::shared_ptr<compositionengine::Layer> layer, sp<compositionengine::LayerFE> layerFE) {
+std::unique_ptr<compositionengine::OutputLayer> Output::takeOutputLayerForLayer(
+ compositionengine::Layer* layer) {
+ // Removes the outputLayer from mOutputLayersorderedByZ and transfers ownership to the caller.
for (auto& outputLayer : mOutputLayersOrderedByZ) {
- if (outputLayer && &outputLayer->getLayer() == layer.get()) {
+ if (outputLayer && &outputLayer->getLayer() == layer) {
return std::move(outputLayer);
}
}
+ return nullptr;
+}
- return createOutputLayer(layer, layerFE);
+std::unique_ptr<compositionengine::OutputLayer> Output::getOrCreateOutputLayer(
+ std::shared_ptr<compositionengine::Layer> layer, sp<compositionengine::LayerFE> layerFE) {
+ auto result = takeOutputLayerForLayer(layer.get());
+ if (!result) {
+ result = createOutputLayer(layer, layerFE);
+ }
+ return result;
}
std::unique_ptr<compositionengine::OutputLayer> Output::createOutputLayer(
@@ -271,19 +305,18 @@
return std::move(mReleasedLayers);
}
-void Output::prepare(compositionengine::CompositionRefreshArgs& refreshArgs) {
- if (CC_LIKELY(!refreshArgs.updatingGeometryThisFrame)) {
- return;
- }
+void Output::prepare(const compositionengine::CompositionRefreshArgs& refreshArgs,
+ LayerFESet& geomSnapshots) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
- uint32_t zOrder = 0;
- for (auto& layer : mOutputLayersOrderedByZ) {
- // Assign a simple Z order sequence to each visible layer.
- layer->editState().z = zOrder++;
- }
+ rebuildLayerStacks(refreshArgs, geomSnapshots);
}
void Output::present(const compositionengine::CompositionRefreshArgs& refreshArgs) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
updateColorProfile(refreshArgs);
updateAndWriteCompositionState(refreshArgs);
setColorTransform(refreshArgs);
@@ -294,6 +327,249 @@
postFramebuffer();
}
+void Output::rebuildLayerStacks(const compositionengine::CompositionRefreshArgs& refreshArgs,
+ LayerFESet& layerFESet) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ // Do nothing if this output is not enabled or there is no need to perform this update
+ if (!mState.isEnabled || CC_LIKELY(!refreshArgs.updatingOutputGeometryThisFrame)) {
+ return;
+ }
+
+ // Process the layers to determine visibility and coverage
+ compositionengine::Output::CoverageState coverage{layerFESet};
+ collectVisibleLayers(refreshArgs, coverage);
+
+ // Compute the resulting coverage for this output, and store it for later
+ const ui::Transform& tr = mState.transform;
+ Region undefinedRegion{mState.bounds};
+ undefinedRegion.subtractSelf(tr.transform(coverage.aboveOpaqueLayers));
+
+ mState.undefinedRegion = undefinedRegion;
+ mState.dirtyRegion.orSelf(coverage.dirtyRegion);
+}
+
+void Output::collectVisibleLayers(const compositionengine::CompositionRefreshArgs& refreshArgs,
+ compositionengine::Output::CoverageState& coverage) {
+ // We build up a list of all layers that are going to be visible in the new
+ // frame.
+ compositionengine::Output::OutputLayers newLayersSortedByZ;
+
+ // Evaluate the layers from front to back to determine what is visible. This
+ // also incrementally calculates the coverage information for each layer as
+ // well as the entire output.
+ for (auto& layer : reversed(refreshArgs.layers)) {
+ // Incrementally process the coverage for each layer, obtaining an
+ // optional outputLayer if the layer is visible.
+ auto outputLayer = getOutputLayerIfVisible(layer, coverage);
+ if (outputLayer) {
+ newLayersSortedByZ.emplace_back(std::move(outputLayer));
+ }
+
+ // TODO(b/121291683): Stop early if the output is completely covered and
+ // no more layers could even be visible underneath the ones on top.
+ }
+
+ // Since we walked the layers in reverse order, we need to reverse
+ // newLayersSortedByZ to get the back-to-front ordered list of layers.
+ std::reverse(newLayersSortedByZ.begin(), newLayersSortedByZ.end());
+
+ // Generate a simple Z-order values to each visible output layer
+ uint32_t zOrder = 0;
+ for (auto& outputLayer : newLayersSortedByZ) {
+ outputLayer->editState().z = zOrder++;
+ }
+
+ setReleasedLayers(refreshArgs);
+
+ mOutputLayersOrderedByZ = std::move(newLayersSortedByZ);
+}
+
+std::unique_ptr<compositionengine::OutputLayer> Output::getOutputLayerIfVisible(
+ std::shared_ptr<compositionengine::Layer> layer,
+ compositionengine::Output::CoverageState& coverage) {
+ // Note: Converts a wp<LayerFE> to a sp<LayerFE>
+ auto layerFE = layer->getLayerFE();
+ if (layerFE == nullptr) {
+ return nullptr;
+ }
+
+ // Ensure we have a snapshot of the basic geometry layer state. Limit the
+ // snapshots to once per frame for each candidate layer, as layers may
+ // appear on multiple outputs.
+ if (!coverage.latchedLayers.count(layerFE)) {
+ coverage.latchedLayers.insert(layerFE);
+ layerFE->latchCompositionState(layer->editState().frontEnd,
+ compositionengine::LayerFE::StateSubset::BasicGeometry);
+ }
+
+ // Obtain a read-only reference to the front-end layer state
+ const auto& layerFEState = layer->getState().frontEnd;
+
+ // Only consider the layers on the given layer stack
+ if (!belongsInOutput(layer.get())) {
+ return nullptr;
+ }
+
+ /*
+ * opaqueRegion: area of a surface that is fully opaque.
+ */
+ Region opaqueRegion;
+
+ /*
+ * visibleRegion: area of a surface that is visible on screen and not fully
+ * transparent. This is essentially the layer's footprint minus the opaque
+ * regions above it. Areas covered by a translucent surface are considered
+ * visible.
+ */
+ Region visibleRegion;
+
+ /*
+ * coveredRegion: area of a surface that is covered by all visible regions
+ * above it (which includes the translucent areas).
+ */
+ Region coveredRegion;
+
+ /*
+ * transparentRegion: area of a surface that is hinted to be completely
+ * transparent. This is only used to tell when the layer has no visible non-
+ * transparent regions and can be removed from the layer list. It does not
+ * affect the visibleRegion of this layer or any layers beneath it. The hint
+ * may not be correct if apps don't respect the SurfaceView restrictions
+ * (which, sadly, some don't).
+ */
+ Region transparentRegion;
+
+ // handle hidden surfaces by setting the visible region to empty
+ if (CC_UNLIKELY(!layerFEState.isVisible)) {
+ return nullptr;
+ }
+
+ const ui::Transform& tr = layerFEState.geomLayerTransform;
+
+ // Get the visible region
+ // TODO(b/121291683): Is it worth creating helper methods on LayerFEState
+ // for computations like this?
+ visibleRegion.set(Rect(tr.transform(layerFEState.geomLayerBounds)));
+
+ if (visibleRegion.isEmpty()) {
+ return nullptr;
+ }
+
+ // Remove the transparent area from the visible region
+ if (!layerFEState.isOpaque) {
+ if (tr.preserveRects()) {
+ // transform the transparent region
+ transparentRegion = tr.transform(layerFEState.transparentRegionHint);
+ } else {
+ // transformation too complex, can't do the
+ // transparent region optimization.
+ transparentRegion.clear();
+ }
+ }
+
+ // compute the opaque region
+ const int32_t layerOrientation = tr.getOrientation();
+ if (layerFEState.isOpaque && ((layerOrientation & ui::Transform::ROT_INVALID) == 0)) {
+ // If we one of the simple category of transforms (0/90/180/270 rotation
+ // + any flip), then the opaque region is the layer's footprint.
+ // Otherwise we don't try and compute the opaque region since there may
+ // be errors at the edges, and we treat the entire layer as
+ // translucent.
+ opaqueRegion = visibleRegion;
+ }
+
+ // Clip the covered region to the visible region
+ coveredRegion = coverage.aboveCoveredLayers.intersect(visibleRegion);
+
+ // Update accumAboveCoveredLayers for next (lower) layer
+ coverage.aboveCoveredLayers.orSelf(visibleRegion);
+
+ // subtract the opaque region covered by the layers above us
+ visibleRegion.subtractSelf(coverage.aboveOpaqueLayers);
+
+ if (visibleRegion.isEmpty()) {
+ return nullptr;
+ }
+
+ // Get coverage information for the layer as previously displayed,
+ // also taking over ownership from mOutputLayersorderedByZ.
+ auto prevOutputLayer = takeOutputLayerForLayer(layer.get());
+
+ // Get coverage information for the layer as previously displayed
+ // TODO(b/121291683): Define kEmptyRegion as a constant in Region.h
+ const Region kEmptyRegion;
+ const Region& oldVisibleRegion =
+ prevOutputLayer ? prevOutputLayer->getState().visibleRegion : kEmptyRegion;
+ const Region& oldCoveredRegion =
+ prevOutputLayer ? prevOutputLayer->getState().coveredRegion : kEmptyRegion;
+
+ // compute this layer's dirty region
+ Region dirty;
+ if (layerFEState.contentDirty) {
+ // we need to invalidate the whole region
+ dirty = visibleRegion;
+ // as well, as the old visible region
+ dirty.orSelf(oldVisibleRegion);
+ } else {
+ /* compute the exposed region:
+ * the exposed region consists of two components:
+ * 1) what's VISIBLE now and was COVERED before
+ * 2) what's EXPOSED now less what was EXPOSED before
+ *
+ * note that (1) is conservative, we start with the whole visible region
+ * but only keep what used to be covered by something -- which mean it
+ * may have been exposed.
+ *
+ * (2) handles areas that were not covered by anything but got exposed
+ * because of a resize.
+ *
+ */
+ const Region newExposed = visibleRegion - coveredRegion;
+ const Region oldExposed = oldVisibleRegion - oldCoveredRegion;
+ dirty = (visibleRegion & oldCoveredRegion) | (newExposed - oldExposed);
+ }
+ dirty.subtractSelf(coverage.aboveOpaqueLayers);
+
+ // accumulate to the screen dirty region
+ coverage.dirtyRegion.orSelf(dirty);
+
+ // Update accumAboveOpaqueLayers for next (lower) layer
+ coverage.aboveOpaqueLayers.orSelf(opaqueRegion);
+
+ // Compute the visible non-transparent region
+ Region visibleNonTransparentRegion = visibleRegion.subtract(transparentRegion);
+
+ // Peform the final check to see if this layer is visible on this output
+ // TODO(b/121291683): Why does this not use visibleRegion? (see outputSpaceVisibleRegion below)
+ Region drawRegion(mState.transform.transform(visibleNonTransparentRegion));
+ drawRegion.andSelf(mState.bounds);
+ if (drawRegion.isEmpty()) {
+ return nullptr;
+ }
+
+ // The layer is visible. Either reuse the existing outputLayer if we have
+ // one, or create a new one if we do not.
+ std::unique_ptr<compositionengine::OutputLayer> result =
+ prevOutputLayer ? std::move(prevOutputLayer) : createOutputLayer(layer, layerFE);
+
+ // Store the layer coverage information into the layer state as some of it
+ // is useful later.
+ auto& outputLayerState = result->editState();
+ outputLayerState.visibleRegion = visibleRegion;
+ outputLayerState.visibleNonTransparentRegion = visibleNonTransparentRegion;
+ outputLayerState.coveredRegion = coveredRegion;
+ outputLayerState.outputSpaceVisibleRegion =
+ mState.transform.transform(outputLayerState.visibleRegion.intersect(mState.viewport));
+
+ return result;
+}
+
+void Output::setReleasedLayers(const compositionengine::CompositionRefreshArgs&) {
+ // The base class does nothing with this call.
+}
+
void Output::updateLayerStateFromFE(const CompositionRefreshArgs& args) const {
for (auto& layer : mOutputLayersOrderedByZ) {
layer->getLayerFE().latchCompositionState(layer->getLayer().editState().frontEnd,
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 6821ec1..74b3ada 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -277,6 +277,79 @@
}
/*
+ * Display::setReleasedLayers()
+ */
+
+TEST_F(DisplayTest, setReleasedLayersDoesNothingIfNotHwcDisplay) {
+ std::shared_ptr<impl::Display> nonHwcDisplay{
+ impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())};
+
+ sp<mock::LayerFE> layerXLayerFE = new StrictMock<mock::LayerFE>();
+ mock::Layer layerXLayer;
+
+ {
+ Output::ReleasedLayers releasedLayers;
+ releasedLayers.emplace_back(layerXLayerFE);
+ nonHwcDisplay->setReleasedLayers(std::move(releasedLayers));
+ }
+
+ CompositionRefreshArgs refreshArgs;
+ refreshArgs.layersWithQueuedFrames.push_back(&layerXLayer);
+
+ nonHwcDisplay->setReleasedLayers(refreshArgs);
+
+ const auto& releasedLayers = nonHwcDisplay->getReleasedLayersForTest();
+ ASSERT_EQ(1, releasedLayers.size());
+}
+
+TEST_F(DisplayTest, setReleasedLayersDoesNothingIfNoLayersWithQueuedFrames) {
+ sp<mock::LayerFE> layerXLayerFE = new StrictMock<mock::LayerFE>();
+
+ {
+ Output::ReleasedLayers releasedLayers;
+ releasedLayers.emplace_back(layerXLayerFE);
+ mDisplay.setReleasedLayers(std::move(releasedLayers));
+ }
+
+ CompositionRefreshArgs refreshArgs;
+ mDisplay.setReleasedLayers(refreshArgs);
+
+ const auto& releasedLayers = mDisplay.getReleasedLayersForTest();
+ ASSERT_EQ(1, releasedLayers.size());
+}
+
+TEST_F(DisplayTest, setReleasedLayers) {
+ sp<mock::LayerFE> layer1LayerFE = new StrictMock<mock::LayerFE>();
+ sp<mock::LayerFE> layer2LayerFE = new StrictMock<mock::LayerFE>();
+ sp<mock::LayerFE> layer3LayerFE = new StrictMock<mock::LayerFE>();
+ sp<mock::LayerFE> layerXLayerFE = new StrictMock<mock::LayerFE>();
+ mock::Layer layer1Layer;
+ mock::Layer layer2Layer;
+ mock::Layer layer3Layer;
+ mock::Layer layerXLayer;
+
+ EXPECT_CALL(*mLayer1, getLayer()).WillRepeatedly(ReturnRef(layer1Layer));
+ EXPECT_CALL(*mLayer1, getLayerFE()).WillRepeatedly(ReturnRef(*layer1LayerFE.get()));
+ EXPECT_CALL(*mLayer2, getLayer()).WillRepeatedly(ReturnRef(layer2Layer));
+ EXPECT_CALL(*mLayer2, getLayerFE()).WillRepeatedly(ReturnRef(*layer2LayerFE.get()));
+ EXPECT_CALL(*mLayer3, getLayer()).WillRepeatedly(ReturnRef(layer3Layer));
+ EXPECT_CALL(*mLayer3, getLayerFE()).WillRepeatedly(ReturnRef(*layer3LayerFE.get()));
+
+ CompositionRefreshArgs refreshArgs;
+ refreshArgs.layersWithQueuedFrames.push_back(&layer1Layer);
+ refreshArgs.layersWithQueuedFrames.push_back(&layer2Layer);
+ refreshArgs.layersWithQueuedFrames.push_back(&layerXLayer);
+ refreshArgs.layersWithQueuedFrames.push_back(nullptr);
+
+ mDisplay.setReleasedLayers(refreshArgs);
+
+ const auto& releasedLayers = mDisplay.getReleasedLayersForTest();
+ ASSERT_EQ(2, releasedLayers.size());
+ ASSERT_EQ(layer1LayerFE.get(), releasedLayers[0].promote().get());
+ ASSERT_EQ(layer2LayerFE.get(), releasedLayers[1].promote().get());
+}
+
+/*
* Display::chooseCompositionStrategy()
*/
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 1af67fb..cc12608 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1710,6 +1710,7 @@
mRefreshPending = false;
compositionengine::CompositionRefreshArgs refreshArgs;
+ refreshArgs.outputs.reserve(mDisplays.size());
for (const auto& [_, display] : mDisplays) {
refreshArgs.outputs.push_back(display->getCompositionDisplay());
}
@@ -1717,13 +1718,21 @@
auto compositionLayer = layer->getCompositionLayer();
if (compositionLayer) refreshArgs.layers.push_back(compositionLayer);
});
+ refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size());
+ for (sp<Layer> layer : mLayersWithQueuedFrames) {
+ auto compositionLayer = layer->getCompositionLayer();
+ if (compositionLayer) refreshArgs.layersWithQueuedFrames.push_back(compositionLayer.get());
+ }
+
refreshArgs.repaintEverything = mRepaintEverything.exchange(false);
refreshArgs.outputColorSetting = useColorManagement
? mDisplayColorSetting
: compositionengine::OutputColorSetting::kUnmanaged;
refreshArgs.colorSpaceAgnosticDataspace = mColorSpaceAgnosticDataspace;
refreshArgs.forceOutputColorMode = mForceColorMode;
- refreshArgs.updatingGeometryThisFrame = mGeometryInvalid;
+
+ refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty;
+ refreshArgs.updatingGeometryThisFrame = mGeometryInvalid || mVisibleRegionsDirty;
if (CC_UNLIKELY(mDrawingState.colorMatrixChanged)) {
refreshArgs.colorTransformMatrix = mDrawingState.colorMatrix;
@@ -1737,13 +1746,10 @@
std::chrono::milliseconds(mDebugRegion > 1 ? mDebugRegion : 0);
}
- mCompositionEngine->preComposition(refreshArgs);
- rebuildLayerStacks();
- refreshArgs.updatingGeometryThisFrame = mGeometryInvalid; // Can be set by rebuildLayerStacks()
- mCompositionEngine->present(refreshArgs);
-
mGeometryInvalid = false;
+ mCompositionEngine->present(refreshArgs);
+
postFrame();
postComposition();
@@ -2005,77 +2011,6 @@
}
}
-void SurfaceFlinger::rebuildLayerStacks() {
- ATRACE_CALL();
- ALOGV("rebuildLayerStacks");
-
- // rebuild the visible layer list per screen
- if (CC_UNLIKELY(mVisibleRegionsDirty)) {
- 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();
- const auto& displayState = display->getState();
- Region opaqueRegion;
- Region dirtyRegion;
- compositionengine::Output::OutputLayers layersSortedByZ;
- const ui::Transform& tr = displayState.transform;
- const Rect bounds = displayState.bounds;
- 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};
- undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
-
- display->editState().undefinedRegion = undefinedRegion;
- display->editState().dirtyRegion.orSelf(dirtyRegion);
- }
- }
-}
-
void SurfaceFlinger::postFrame()
{
// |mStateLock| not needed as we are on the main thread
@@ -2435,7 +2370,7 @@
// display is used to calculate the hint, otherwise we use the
// default display.
//
- // NOTE: we do this here, rather than in rebuildLayerStacks() so that
+ // NOTE: we do this here, rather than when presenting the display so that
// the hint is set before we acquire a buffer from the surface texture.
//
// NOTE: layer transactions have taken place already, so we use their
@@ -2715,181 +2650,6 @@
}
}
-void SurfaceFlinger::computeVisibleRegions(
- const sp<const DisplayDevice>& displayDevice, Region& outDirtyRegion,
- Region& outOpaqueRegion,
- std::vector<std::unique_ptr<compositionengine::OutputLayer>>& outLayersSortedByZ) {
- ATRACE_CALL();
- ALOGV("computeVisibleRegions");
-
- auto display = displayDevice->getCompositionDisplay();
-
- Region aboveOpaqueLayers;
- Region aboveCoveredLayers;
- Region dirty;
-
- outDirtyRegion.clear();
-
- mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
- auto compositionLayer = layer->getCompositionLayer();
- if (compositionLayer == nullptr) {
- return;
- }
-
- // 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(compositionLayer.get())) {
- return;
- }
-
- /*
- * opaqueRegion: area of a surface that is fully opaque.
- */
- Region opaqueRegion;
-
- /*
- * visibleRegion: area of a surface that is visible on screen
- * and not fully transparent. This is essentially the layer's
- * footprint minus the opaque regions above it.
- * Areas covered by a translucent surface are considered visible.
- */
- Region visibleRegion;
-
- /*
- * coveredRegion: area of a surface that is covered by all
- * visible regions above it (which includes the translucent areas).
- */
- Region coveredRegion;
-
- /*
- * transparentRegion: area of a surface that is hinted to be completely
- * transparent. This is only used to tell when the layer has no visible
- * non-transparent regions and can be removed from the layer list. It
- * does not affect the visibleRegion of this layer or any layers
- * beneath it. The hint may not be correct if apps don't respect the
- * SurfaceView restrictions (which, sadly, some don't).
- */
- Region transparentRegion;
-
- // handle hidden surfaces by setting the visible region to empty
- 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 (!layerFEState.isOpaque) {
- if (tr.preserveRects()) {
- // transform the transparent region
- transparentRegion = tr.transform(layerFEState.transparentRegionHint);
- } else {
- // transformation too complex, can't do the
- // transparent region optimization.
- transparentRegion.clear();
- }
- }
-
- // compute the opaque region
- const int32_t layerOrientation = tr.getOrientation();
- if (layerFEState.isOpaque &&
- ((layerOrientation & ui::Transform::ROT_INVALID) == false)) {
- // the opaque region is the layer's footprint
- opaqueRegion = visibleRegion;
- }
- }
- }
-
- if (visibleRegion.isEmpty()) {
- return;
- }
-
- // Clip the covered region to the visible region
- coveredRegion = aboveCoveredLayers.intersect(visibleRegion);
-
- // Update aboveCoveredLayers for next (lower) layer
- aboveCoveredLayers.orSelf(visibleRegion);
-
- // subtract the opaque region covered by the layers above us
- visibleRegion.subtractSelf(aboveOpaqueLayers);
-
- // Get coverage information for the layer as previously displayed
- auto prevOutputLayer = display->getOutputLayerForLayer(compositionLayer.get());
- // TODO(b/121291683): Define this as a constant in Region.h
- const Region kEmptyRegion;
- const Region& oldVisibleRegion =
- prevOutputLayer ? prevOutputLayer->getState().visibleRegion : kEmptyRegion;
- const Region& oldCoveredRegion =
- prevOutputLayer ? prevOutputLayer->getState().coveredRegion : kEmptyRegion;
-
- // compute this layer's dirty region
- if (layerFEState.contentDirty) {
- // we need to invalidate the whole region
- dirty = visibleRegion;
- // as well, as the old visible region
- dirty.orSelf(oldVisibleRegion);
- } else {
- /* compute the exposed region:
- * the exposed region consists of two components:
- * 1) what's VISIBLE now and was COVERED before
- * 2) what's EXPOSED now less what was EXPOSED before
- *
- * note that (1) is conservative, we start with the whole
- * visible region but only keep what used to be covered by
- * something -- which mean it may have been exposed.
- *
- * (2) handles areas that were not covered by anything but got
- * exposed because of a resize.
- */
- const Region newExposed = visibleRegion - coveredRegion;
- const Region oldExposed = oldVisibleRegion - oldCoveredRegion;
- dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed);
- }
- dirty.subtractSelf(aboveOpaqueLayers);
-
- // accumulate to the screen dirty region
- outDirtyRegion.orSelf(dirty);
-
- // Update aboveOpaqueLayers for next (lower) layer
- aboveOpaqueLayers.orSelf(opaqueRegion);
-
- // Compute the visible non-transparent region
- Region visibleNonTransparentRegion = 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(visibleNonTransparentRegion));
- drawRegion.andSelf(displayState.bounds);
- if (drawRegion.isEmpty()) {
- return;
- }
-
- outLayersSortedByZ.emplace_back(display->getOrCreateOutputLayer(compositionLayer, layerFE));
- auto& outputLayerState = outLayersSortedByZ.back()->editState();
- outputLayerState.visibleRegion = std::move(visibleRegion);
- outputLayerState.visibleNonTransparentRegion = std::move(visibleNonTransparentRegion);
- outputLayerState.coveredRegion = std::move(coveredRegion);
- outputLayerState.outputSpaceVisibleRegion = displayState.transform.transform(
- outputLayerState.visibleRegion.intersect(displayState.viewport));
- });
-
- outOpaqueRegion = aboveOpaqueLayers;
-}
-
void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) {
for (const auto& [token, displayDevice] : mDisplays) {
auto display = displayDevice->getCompositionDisplay();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index aaa50f6..c9e4692 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -743,9 +743,6 @@
* Compositing
*/
void invalidateHwcGeometry();
- void computeVisibleRegions(
- const sp<const DisplayDevice>& display, Region& dirtyRegion, Region& opaqueRegion,
- std::vector<std::unique_ptr<compositionengine::OutputLayer>>& outputLayers);
void postComposition();
void getCompositorTiming(CompositorTiming* compositorTiming);
@@ -753,7 +750,6 @@
std::shared_ptr<FenceTime>& presentFenceTime);
void setCompositorTimingSnapped(const DisplayStatInfo& stats,
nsecs_t compositeToPresentLatency);
- void rebuildLayerStacks();
void postFrame();