diff options
12 files changed, 490 insertions, 275 deletions
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h index 6f689ad4be..90158c721d 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 @@ namespace android::compositionengine { 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 @@ struct CompositionRefreshArgs { // 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 @@ struct CompositionRefreshArgs { // 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 57cca69eb2..e5857694b9 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 @@ public: 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 80fce2cd5c..d374baa388 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 @@ public: 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 @@ public: 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 @@ protected: 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 2e595d6e23..b5d8325040 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -42,6 +42,8 @@ public: 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 6dde86d706..fa6cd27e1a 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -77,9 +77,17 @@ public: 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 @@ public: 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 8cf7f79513..286a20f5af 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -79,9 +79,20 @@ public: 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 590c596a6d..713266ff85 100644 --- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp +++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp @@ -72,8 +72,20 @@ nsecs_t CompositionEngine::getLastFrameRefreshTimestamp() const { } 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 49727dfed5..fe8fa21a8c 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -158,6 +158,39 @@ std::unique_ptr<compositionengine::OutputLayer> Display::createOutputLayer( 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 a9b1d5540b..83df628f25 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -40,6 +40,27 @@ Output::~Output() = default; 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 @@ void Output::setDisplayColorProfile(std::unique_ptr<compositionengine::DisplayCo 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 @@ compositionengine::OutputLayer* Output::getOutputLayerForLayer( 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 @@ Output::ReleasedLayers Output::takeReleasedLayers() { 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 @@ void Output::present(const compositionengine::CompositionRefreshArgs& refreshArg 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 6821ec1301..74b3adaa95 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -277,6 +277,79 @@ TEST_F(DisplayTest, createOutputLayerSetsHwcLayer) { } /* + * 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 1af67fb283..cc12608e87 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1710,6 +1710,7 @@ void SurfaceFlinger::handleMessageRefresh() { 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 @@ void SurfaceFlinger::handleMessageRefresh() { 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 @@ void SurfaceFlinger::handleMessageRefresh() { 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::computeLayerBounds() { } } -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 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) // 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::commitOffscreenLayers() { } } -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 aaa50f61a0..c9e46927c9 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -743,9 +743,6 @@ private: * 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 @@ private: std::shared_ptr<FenceTime>& presentFenceTime); void setCompositorTimingSnapped(const DisplayStatInfo& stats, nsecs_t compositeToPresentLatency); - void rebuildLayerStacks(); void postFrame(); |