diff options
23 files changed, 351 insertions, 152 deletions
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index 1fd07b01f4..791e7db75c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -138,6 +138,9 @@ public: // Gets the sequence number: a serial number that uniquely identifies a Layer virtual int32_t getSequence() const = 0; + + // Whether the layer should be rendered with rounded corners. + virtual bool hasRoundedCorners() const = 0; }; // TODO(b/121291683): Specialize std::hash<> for sp<T> so these and others can diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h index 3a843273b9..ead941d1f9 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h @@ -16,6 +16,7 @@ #pragma once +#include <cstdint> #include <optional> #include <string> @@ -90,8 +91,13 @@ public: // Writes the geometry state to the HWC, or does nothing if this layer does // not use the HWC. If includeGeometry is false, the geometry state can be // skipped. If skipLayer is true, then the alpha of the layer is forced to - // 0 so that HWC will ignore it. - virtual void writeStateToHWC(bool includeGeometry, bool skipLayer) = 0; + // 0 so that HWC will ignore it. z specifies the order to draw the layer in + // (starting with 0 for the back layer, and increasing for each following + // layer). zIsOverridden specifies whether the layer has been reordered. + // isPeekingThrough specifies whether this layer will be shown through a + // hole punch in a layer above it. + virtual void writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t z, + bool zIsOverridden, bool isPeekingThrough) = 0; // Updates the cursor position with the HWC virtual void writeCursorPositionToHWC() const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h index ae88e7839c..2488c66b6d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h @@ -16,6 +16,7 @@ #pragma once +#include <cstdint> #include <memory> #include <string> @@ -42,7 +43,8 @@ public: void updateCompositionState(bool includeGeometry, bool forceClientComposition, ui::Transform::RotationFlags) override; - void writeStateToHWC(bool includeGeometry, bool skipLayer) override; + void writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t z, bool zIsOverridden, + bool isPeekingThrough) override; void writeCursorPositionToHWC() const override; HWC2::Layer* getHwcLayer() const override; @@ -66,7 +68,8 @@ protected: private: Rect calculateInitialCrop() const; - void writeOutputDependentGeometryStateToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition); + void writeOutputDependentGeometryStateToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition, + uint32_t z); void writeOutputIndependentGeometryStateToHWC(HWC2::Layer*, const LayerFECompositionState&, bool skipLayer); void writeOutputDependentPerFrameStateToHWC(HWC2::Layer*); @@ -74,7 +77,8 @@ private: void writeSolidColorStateToHWC(HWC2::Layer*, const LayerFECompositionState&); void writeSidebandStateToHWC(HWC2::Layer*, const LayerFECompositionState&); void writeBufferStateToHWC(HWC2::Layer*, const LayerFECompositionState&); - void writeCompositionTypeToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition); + void writeCompositionTypeToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition, + bool isPeekingThrough); void detectDisallowedCompositionTypeChange(Hwc2::IComposerClient::Composition from, Hwc2::IComposerClient::Composition to) const; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h index c61ec5991b..356965cf48 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h @@ -46,6 +46,10 @@ class Layer; class HWComposer; +namespace compositionengine { +class OutputLayer; +} // namespace compositionengine + namespace compositionengine::impl { // Note that fields that affect HW composer state may need to be mirrored into @@ -84,9 +88,6 @@ struct OutputLayerCompositionState { // The dataspace for this layer ui::Dataspace dataspace{ui::Dataspace::UNKNOWN}; - // The Z order index of this layer on this output - uint32_t z{0}; - // Overrides the buffer, acquire fence, and display frame stored in LayerFECompositionState struct { std::shared_ptr<renderengine::ExternalTexture> buffer = nullptr; @@ -96,6 +97,12 @@ struct OutputLayerCompositionState { ProjectionSpace displaySpace; Region damageRegion = Region::INVALID_REGION; Region visibleRegion; + + // The OutputLayer pointed to by this field will be rearranged to draw + // behind the OutputLayer represented by this CompositionState and will + // be visible through it. Unowned - the OutputLayer's lifetime will + // outlast this.) + OutputLayer* peekThroughLayer = nullptr; } overrideInfo; /* diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h index 53f4a30fb8..1ee0e2f47c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h @@ -105,12 +105,32 @@ public: void dump(std::string& result) const; + // Whether this represents a single layer with a buffer and rounded corners. + // If it is, we may be able to draw it by placing it behind another + // CachedSet and punching a hole. + bool requiresHolePunch() const; + + // Add a layer that will be drawn behind this one. ::render() will render a + // hole in this CachedSet's buffer, allowing the supplied layer to peek + // through. Must be called before ::render(). + // Will do nothing if this CachedSet is not opaque where the hole punch + // layer is displayed. + // If isFirstLayer is true, this CachedSet can be considered opaque because + // nothing (besides the hole punch layer) will be drawn behind it. + void addHolePunchLayerIfFeasible(const CachedSet&, bool isFirstLayer); + + // Retrieve the layer that will be drawn behind this one. + OutputLayer* getHolePunchLayer() const; + private: CachedSet() = default; const NonBufferHash mFingerprint; std::chrono::steady_clock::time_point mLastUpdate = std::chrono::steady_clock::now(); std::vector<Layer> mLayers; + + // Unowned. + const LayerState* mHolePunchLayer = nullptr; Rect mBounds = Rect::EMPTY_RECT; Region mVisibleRegion; size_t mAge = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h index 2f2ad4c9b5..942592a9eb 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h @@ -36,7 +36,8 @@ class Predictor; class Flattener { public: - Flattener(Predictor& predictor) : mPredictor(predictor) {} + Flattener(Predictor& predictor, bool enableHolePunch = false) + : mEnableHolePunch(enableHolePunch), mPredictor(predictor) {} void setDisplaySize(ui::Size size) { mDisplaySize = size; } @@ -61,6 +62,7 @@ private: void buildCachedSets(std::chrono::steady_clock::time_point now); + const bool mEnableHolePunch; Predictor& mPredictor; ui::Size mDisplaySize; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h index f2f6c0b912..3391273679 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h @@ -53,20 +53,19 @@ enum class LayerStateField : uint32_t { Name = 1u << 1, DisplayFrame = 1u << 2, SourceCrop = 1u << 3, - ZOrder = 1u << 4, - BufferTransform = 1u << 5, - BlendMode = 1u << 6, - Alpha = 1u << 7, - LayerMetadata = 1u << 8, - VisibleRegion = 1u << 9, - Dataspace = 1u << 10, - PixelFormat = 1u << 11, - ColorTransform = 1u << 12, - SurfaceDamage = 1u << 13, - CompositionType = 1u << 14, - SidebandStream = 1u << 15, - Buffer = 1u << 16, - SolidColor = 1u << 17, + BufferTransform = 1u << 4, + BlendMode = 1u << 5, + Alpha = 1u << 6, + LayerMetadata = 1u << 7, + VisibleRegion = 1u << 8, + Dataspace = 1u << 9, + PixelFormat = 1u << 10, + ColorTransform = 1u << 11, + SurfaceDamage = 1u << 12, + CompositionType = 1u << 13, + SidebandStream = 1u << 14, + Buffer = 1u << 15, + SolidColor = 1u << 16, }; // clang-format on @@ -271,9 +270,6 @@ private: rect.top, rect.right, rect.bottom)}; }}; - OutputLayerState<uint32_t, LayerStateField::ZOrder> mZOrder{ - [](auto layer) { return layer->getState().z; }}; - using BufferTransformState = OutputLayerState<hardware::graphics::composer::hal::Transform, LayerStateField::BufferTransform>; BufferTransformState mBufferTransform{[](auto layer) { @@ -402,7 +398,7 @@ private: return std::vector<std::string>{stream.str()}; }}; - static const constexpr size_t kNumNonUniqueFields = 15; + static const constexpr size_t kNumNonUniqueFields = 14; std::array<StateInterface*, kNumNonUniqueFields> getNonUniqueFields() { std::array<const StateInterface*, kNumNonUniqueFields> constFields = @@ -417,10 +413,10 @@ private: std::array<const StateInterface*, kNumNonUniqueFields> getNonUniqueFields() const { return { - &mDisplayFrame, &mSourceCrop, &mZOrder, &mBufferTransform, - &mBlendMode, &mAlpha, &mLayerMetadata, &mVisibleRegion, - &mOutputDataspace, &mPixelFormat, &mColorTransform, &mCompositionType, - &mSidebandStream, &mBuffer, &mSolidColor, + &mDisplayFrame, &mSourceCrop, &mBufferTransform, &mBlendMode, + &mAlpha, &mLayerMetadata, &mVisibleRegion, &mOutputDataspace, + &mPixelFormat, &mColorTransform, &mCompositionType, &mSidebandStream, + &mBuffer, &mSolidColor, }; } }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h index e6d2b636a3..c2037a899e 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h @@ -41,7 +41,7 @@ namespace compositionengine::impl::planner { // as a more efficient representation of parts of the layer stack. class Planner { public: - Planner() : mFlattener(mPredictor) {} + Planner(); void setDisplaySize(ui::Size); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h index dde8999524..d215bda891 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h @@ -43,6 +43,7 @@ public: MOCK_CONST_METHOD0(getDebugName, const char*()); MOCK_CONST_METHOD0(getSequence, int32_t()); + MOCK_CONST_METHOD0(hasRoundedCorners, bool()); }; } // namespace android::compositionengine::mock diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h index 2454ff7188..358ed5a0b9 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h @@ -22,6 +22,7 @@ #include <compositionengine/OutputLayer.h> #include <compositionengine/impl/OutputLayerCompositionState.h> #include <gmock/gmock.h> +#include <cstdint> namespace android::compositionengine::mock { @@ -39,7 +40,7 @@ public: MOCK_METHOD0(editState, impl::OutputLayerCompositionState&()); MOCK_METHOD3(updateCompositionState, void(bool, bool, ui::Transform::RotationFlags)); - MOCK_METHOD2(writeStateToHWC, void(bool, bool)); + MOCK_METHOD5(writeStateToHWC, void(bool, bool, uint32_t, bool, bool)); MOCK_CONST_METHOD0(writeCursorPositionToHWC, void()); MOCK_CONST_METHOD0(getHwcLayer, HWC2::Layer*()); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index faa4b74c28..c809e1afad 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -455,12 +455,6 @@ void Output::collectVisibleLayers(const compositionengine::CompositionRefreshArg setReleasedLayers(refreshArgs); finalizePendingOutputLayers(); - - // Generate a simple Z-order values to each visible output layer - uint32_t zOrder = 0; - for (auto* outputLayer : getOutputLayersOrderedByZ()) { - outputLayer->editState().z = zOrder++; - } } void Output::ensureOutputLayerIfVisible(sp<compositionengine::LayerFE>& layerFE, @@ -713,20 +707,45 @@ void Output::writeCompositionState(const compositionengine::CompositionRefreshAr editState().earliestPresentTime = refreshArgs.earliestPresentTime; + OutputLayer* peekThroughLayer = nullptr; sp<GraphicBuffer> previousOverride = nullptr; + bool includeGeometry = refreshArgs.updatingGeometryThisFrame; + uint32_t z = 0; + bool overrideZ = false; for (auto* layer : getOutputLayersOrderedByZ()) { + if (layer == peekThroughLayer) { + // No longer needed, although it should not show up again, so + // resetting it is not truly needed either. + peekThroughLayer = nullptr; + + // peekThroughLayer was already drawn ahead of its z order. + continue; + } bool skipLayer = false; - if (layer->getState().overrideInfo.buffer != nullptr) { - if (previousOverride != nullptr && - layer->getState().overrideInfo.buffer->getBuffer() == previousOverride) { + const auto& overrideInfo = layer->getState().overrideInfo; + if (overrideInfo.buffer != nullptr) { + if (previousOverride && overrideInfo.buffer->getBuffer() == previousOverride) { ALOGV("Skipping redundant buffer"); skipLayer = true; + } else { + // First layer with the override buffer. + if (overrideInfo.peekThroughLayer) { + peekThroughLayer = overrideInfo.peekThroughLayer; + + // Draw peekThroughLayer first. + overrideZ = true; + includeGeometry = true; + constexpr bool isPeekingThrough = true; + peekThroughLayer->writeStateToHWC(includeGeometry, false, z++, overrideZ, + isPeekingThrough); + } + + previousOverride = overrideInfo.buffer->getBuffer(); } - previousOverride = layer->getState().overrideInfo.buffer->getBuffer(); } - const bool includeGeometry = refreshArgs.updatingGeometryThisFrame; - layer->writeStateToHWC(includeGeometry, skipLayer); + constexpr bool isPeekingThrough = false; + layer->writeStateToHWC(includeGeometry, skipLayer, z++, overrideZ, isPeekingThrough); } } diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 9ca8914deb..d3e2c253a9 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -21,6 +21,7 @@ #include <compositionengine/impl/OutputCompositionState.h> #include <compositionengine/impl/OutputLayer.h> #include <compositionengine/impl/OutputLayerCompositionState.h> +#include <cstdint> // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push @@ -312,7 +313,8 @@ void OutputLayer::updateCompositionState( } } -void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer) { +void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t z, + bool zIsOverridden, bool isPeekingThrough) { const auto& state = getState(); // Skip doing this if there is no HWC interface if (!state.hwc) { @@ -335,10 +337,11 @@ void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer) { // TODO(b/181172795): We now update geometry for all flattened layers. We should update it // only when the geometry actually changes - const bool isOverridden = state.overrideInfo.buffer != nullptr; + const bool isOverridden = + state.overrideInfo.buffer != nullptr || isPeekingThrough || zIsOverridden; const bool prevOverridden = state.hwc->stateOverridden; if (isOverridden || prevOverridden || skipLayer || includeGeometry) { - writeOutputDependentGeometryStateToHWC(hwcLayer.get(), requestedCompositionType); + writeOutputDependentGeometryStateToHWC(hwcLayer.get(), requestedCompositionType, z); writeOutputIndependentGeometryStateToHWC(hwcLayer.get(), *outputIndependentState, skipLayer); } @@ -346,7 +349,7 @@ void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer) { writeOutputDependentPerFrameStateToHWC(hwcLayer.get()); writeOutputIndependentPerFrameStateToHWC(hwcLayer.get(), *outputIndependentState); - writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType); + writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType, isPeekingThrough); // Always set the layer color after setting the composition type. writeSolidColorStateToHWC(hwcLayer.get(), *outputIndependentState); @@ -354,8 +357,9 @@ void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer) { editState().hwc->stateOverridden = isOverridden; } -void OutputLayer::writeOutputDependentGeometryStateToHWC( - HWC2::Layer* hwcLayer, hal::Composition requestedCompositionType) { +void OutputLayer::writeOutputDependentGeometryStateToHWC(HWC2::Layer* hwcLayer, + hal::Composition requestedCompositionType, + uint32_t z) { const auto& outputDependentState = getState(); Rect displayFrame = outputDependentState.displayFrame; @@ -382,9 +386,9 @@ void OutputLayer::writeOutputDependentGeometryStateToHWC( sourceCrop.bottom, to_string(error).c_str(), static_cast<int32_t>(error)); } - if (auto error = hwcLayer->setZOrder(outputDependentState.z); error != hal::Error::NONE) { - ALOGE("[%s] Failed to set Z %u: %s (%d)", getLayerFE().getDebugName(), - outputDependentState.z, to_string(error).c_str(), static_cast<int32_t>(error)); + if (auto error = hwcLayer->setZOrder(z); error != hal::Error::NONE) { + ALOGE("[%s] Failed to set Z %u: %s (%d)", getLayerFE().getDebugName(), z, + to_string(error).c_str(), static_cast<int32_t>(error)); } // Solid-color layers and overridden buffers should always use an identity transform. @@ -403,7 +407,10 @@ void OutputLayer::writeOutputDependentGeometryStateToHWC( void OutputLayer::writeOutputIndependentGeometryStateToHWC( HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState, bool skipLayer) { - const auto blendMode = getState().overrideInfo.buffer + // If there is a peekThroughLayer, then this layer has a hole in it. We need to use + // PREMULTIPLIED so it will peek through. + const auto& overrideInfo = getState().overrideInfo; + const auto blendMode = overrideInfo.buffer || overrideInfo.peekThroughLayer ? hardware::graphics::composer::hal::BlendMode::PREMULTIPLIED : outputIndependentState.blendMode; if (auto error = hwcLayer->setBlendMode(blendMode); error != hal::Error::NONE) { @@ -558,11 +565,13 @@ void OutputLayer::writeBufferStateToHWC(HWC2::Layer* hwcLayer, } void OutputLayer::writeCompositionTypeToHWC(HWC2::Layer* hwcLayer, - hal::Composition requestedCompositionType) { + hal::Composition requestedCompositionType, + bool isPeekingThrough) { auto& outputDependentState = editState(); // If we are forcing client composition, we need to tell the HWC - if (outputDependentState.forceClientComposition) { + if (outputDependentState.forceClientComposition || + (!isPeekingThrough && getLayerFE().hasRoundedCorners())) { requestedCompositionType = hal::Composition::CLIENT; } diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp index efd23dce98..b4c314c8d4 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp @@ -67,7 +67,6 @@ void OutputLayerCompositionState::dump(std::string& out) const { dumpVal(out, "sourceCrop", sourceCrop); dumpVal(out, "bufferTransform", toString(bufferTransform), bufferTransform); dumpVal(out, "dataspace", toString(dataspace), dataspace); - dumpVal(out, "z-index", z); dumpVal(out, "override buffer", overrideInfo.buffer.get()); dumpVal(out, "override acquire fence", overrideInfo.acquireFence.get()); dumpVal(out, "override display frame", overrideInfo.displayFrame); diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp index 9955e29f4a..b31e89e247 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp @@ -193,6 +193,23 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, std::transform(layerSettings.cbegin(), layerSettings.cend(), std::back_inserter(layerSettingsPointers), [](const renderengine::LayerSettings& settings) { return &settings; }); + renderengine::LayerSettings holePunchSettings; + if (mHolePunchLayer) { + auto clientCompositionList = + mHolePunchLayer->getOutputLayer()->getLayerFE().prepareClientCompositionList( + targetSettings); + // Assume that the final layer contains the buffer that we want to + // replace with a hole punch. + holePunchSettings = clientCompositionList.back(); + LOG_ALWAYS_FATAL_IF(!holePunchSettings.source.buffer.buffer, "Expected to have a buffer!"); + // This mimics Layer::prepareClearClientComposition + holePunchSettings.source.buffer.buffer = nullptr; + holePunchSettings.source.solidColor = half3(0.0f, 0.0f, 0.0f); + holePunchSettings.disableBlending = true; + holePunchSettings.alpha = 0.0f; + holePunchSettings.name = std::string("hole punch layer"); + layerSettingsPointers.push_back(&holePunchSettings); + } if (sDebugHighlighLayers) { highlight = { @@ -241,6 +258,56 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, } } +bool CachedSet::requiresHolePunch() const { + // In order for the hole punch to be beneficial, the layer must be updating + // regularly, meaning it should not have been merged with other layers. + if (getLayerCount() != 1) { + return false; + } + + // There is no benefit to a hole punch unless the layer has a buffer. + if (!mLayers[0].getBuffer()) { + return false; + } + + const auto& layerFE = mLayers[0].getState()->getOutputLayer()->getLayerFE(); + if (layerFE.getCompositionState()->forceClientComposition) { + return false; + } + + return layerFE.hasRoundedCorners(); +} + +namespace { +bool contains(const Rect& outer, const Rect& inner) { + return outer.left <= inner.left && outer.right >= inner.right && outer.top <= inner.top && + outer.bottom >= inner.bottom; +} +}; // namespace + +void CachedSet::addHolePunchLayerIfFeasible(const CachedSet& holePunchLayer, bool isFirstLayer) { + // Verify that this CachedSet is opaque where the hole punch layer + // will draw. + const Rect& holePunchBounds = holePunchLayer.getBounds(); + for (const auto& layer : mLayers) { + // The first layer is considered opaque because nothing is behind it. + // Note that isOpaque is always false for a layer with rounded + // corners, even if the interior is opaque. In theory, such a layer + // could be used for a hole punch, but this is unlikely to happen in + // practice. + const auto* outputLayer = layer.getState()->getOutputLayer(); + if (contains(outputLayer->getState().displayFrame, holePunchBounds) && + (isFirstLayer || outputLayer->getLayerFE().getCompositionState()->isOpaque)) { + mHolePunchLayer = holePunchLayer.getFirstLayer().getState(); + return; + } + } +} + +OutputLayer* CachedSet::getHolePunchLayer() const { + return mHolePunchLayer ? mHolePunchLayer->getOutputLayer() : nullptr; +} + void CachedSet::dump(std::string& result) const { const auto now = std::chrono::steady_clock::now(); @@ -248,6 +315,11 @@ void CachedSet::dump(std::string& result) const { std::chrono::duration_cast<std::chrono::milliseconds>(now - mLastUpdate); base::StringAppendF(&result, " + Fingerprint %016zx, last update %sago, age %zd\n", mFingerprint, durationString(lastUpdate).c_str(), mAge); + { + const auto b = mTexture ? mTexture->getBuffer().get() : nullptr; + base::StringAppendF(&result, " Override buffer: %p\n", b); + } + base::StringAppendF(&result, " HolePunchLayer: %p\n", mHolePunchLayer); if (mLayers.size() == 1) { base::StringAppendF(&result, " Layer [%s]\n", mLayers[0].getName().c_str()); diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp index 9c9649ccbe..13de622de0 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp @@ -209,6 +209,7 @@ bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers ALOGV("[%s] Found ready buffer", __func__); size_t skipCount = mNewCachedSet->getLayerCount(); while (skipCount != 0) { + auto* peekThroughLayer = mNewCachedSet->getHolePunchLayer(); const size_t layerCount = currentLayerIter->getLayerCount(); for (size_t i = 0; i < layerCount; ++i) { OutputLayer::CompositionState& state = @@ -221,6 +222,7 @@ bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers .displaySpace = mNewCachedSet->getOutputSpace(), .damageRegion = Region::INVALID_REGION, .visibleRegion = mNewCachedSet->getVisibleRegion(), + .peekThroughLayer = peekThroughLayer, }; ++incomingLayerIter; } @@ -244,6 +246,7 @@ bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers // Skip the incoming layers corresponding to this valid current layer const size_t layerCount = currentLayerIter->getLayerCount(); + auto* peekThroughLayer = currentLayerIter->getHolePunchLayer(); for (size_t i = 0; i < layerCount; ++i) { OutputLayer::CompositionState& state = (*incomingLayerIter)->getOutputLayer()->editState(); @@ -255,6 +258,7 @@ bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers .displaySpace = currentLayerIter->getOutputSpace(), .damageRegion = Region(), .visibleRegion = currentLayerIter->getVisibleRegion(), + .peekThroughLayer = peekThroughLayer, }; ++incomingLayerIter; } @@ -298,6 +302,11 @@ void Flattener::buildCachedSets(time_point now) { std::vector<Run> runs; bool isPartOfRun = false; + + // Keep track of the layer that follows a run. It's possible that we will + // render it with a hole-punch. + const CachedSet* holePunchLayer = nullptr; + for (auto currentSet = mLayers.cbegin(); currentSet != mLayers.cend(); ++currentSet) { if (now - currentSet->getLastUpdate() > kActiveLayerTimeout) { // Layer is inactive @@ -312,10 +321,20 @@ void Flattener::buildCachedSets(time_point now) { isPartOfRun = true; } } - } else { + } else if (isPartOfRun) { // Runs must be at least 2 sets long or there's nothing to combine - if (isPartOfRun && runs.back().start->getLayerCount() == runs.back().length) { + if (runs.back().start->getLayerCount() == runs.back().length) { runs.pop_back(); + } else { + // The prior run contained at least two sets. Currently, we'll + // only possibly merge a single run, so only keep track of a + // holePunchLayer if this is the first run. + if (runs.size() == 1) { + holePunchLayer = &(*currentSet); + } + + // TODO(b/185114532: Break out of the loop? We may find more runs, but we + // won't do anything with them. } isPartOfRun = false; @@ -341,6 +360,13 @@ void Flattener::buildCachedSets(time_point now) { mNewCachedSet->append(*currentSet); } + if (mEnableHolePunch && holePunchLayer && holePunchLayer->requiresHolePunch()) { + // Add the pip layer to mNewCachedSet, but in a special way - it should + // replace the buffer with a clear round rect. + mNewCachedSet->addHolePunchLayerIfFeasible(*holePunchLayer, + runs[0].start == mLayers.cbegin()); + } + // TODO(b/181192467): Actually compute new LayerState vector and corresponding hash for each run mPredictor.getPredictedPlan({}, 0); diff --git a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp index ab8599796f..8423a124cf 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp @@ -155,10 +155,9 @@ std::optional<std::string> LayerState::compare(const LayerState& other) const { bool operator==(const LayerState& lhs, const LayerState& rhs) { return lhs.mId == rhs.mId && lhs.mName == rhs.mName && lhs.mDisplayFrame == rhs.mDisplayFrame && - lhs.mSourceCrop == rhs.mSourceCrop && lhs.mZOrder == rhs.mZOrder && - lhs.mBufferTransform == rhs.mBufferTransform && lhs.mBlendMode == rhs.mBlendMode && - lhs.mAlpha == rhs.mAlpha && lhs.mLayerMetadata == rhs.mLayerMetadata && - lhs.mVisibleRegion == rhs.mVisibleRegion && + lhs.mSourceCrop == rhs.mSourceCrop && lhs.mBufferTransform == rhs.mBufferTransform && + lhs.mBlendMode == rhs.mBlendMode && lhs.mAlpha == rhs.mAlpha && + lhs.mLayerMetadata == rhs.mLayerMetadata && lhs.mVisibleRegion == rhs.mVisibleRegion && lhs.mOutputDataspace == rhs.mOutputDataspace && lhs.mPixelFormat == rhs.mPixelFormat && lhs.mColorTransform == rhs.mColorTransform && lhs.mCompositionType == rhs.mCompositionType && diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp index 3a2534b847..7d2bf06133 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp @@ -19,12 +19,17 @@ #undef LOG_TAG #define LOG_TAG "Planner" +#include <android-base/properties.h> #include <compositionengine/LayerFECompositionState.h> #include <compositionengine/impl/OutputLayerCompositionState.h> #include <compositionengine/impl/planner/Planner.h> namespace android::compositionengine::impl::planner { +Planner::Planner() + : mFlattener(mPredictor, + base::GetBoolProperty(std::string("debug.sf.enable_hole_punch_pip"), false)) {} + void Planner::setDisplaySize(ui::Size size) { mFlattener.setDisplaySize(size); } diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index 4c3f4940cc..5a92f26ff8 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -689,7 +689,6 @@ TEST_F(OutputLayerUpdateCompositionStateTest, clientCompositionForcedFromArgumen struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { static constexpr hal::Error kError = hal::Error::UNSUPPORTED; static constexpr FloatRect kSourceCrop{11.f, 12.f, 13.f, 14.f}; - static constexpr uint32_t kZOrder = 21u; static constexpr Hwc2::Transform kBufferTransform = static_cast<Hwc2::Transform>(31); static constexpr Hwc2::Transform kOverrideBufferTransform = static_cast<Hwc2::Transform>(0); static constexpr Hwc2::IComposerClient::BlendMode kBlendMode = @@ -735,7 +734,6 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { outputLayerState.displayFrame = kDisplayFrame; outputLayerState.sourceCrop = kSourceCrop; - outputLayerState.z = kZOrder; outputLayerState.bufferTransform = static_cast<Hwc2::Transform>(kBufferTransform); outputLayerState.outputSpaceVisibleRegion = kOutputSpaceVisibleRegion; outputLayerState.dataspace = kDataspace; @@ -785,7 +783,7 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { float alpha = kAlpha) { EXPECT_CALL(*mHwcLayer, setDisplayFrame(displayFrame)).WillOnce(Return(kError)); EXPECT_CALL(*mHwcLayer, setSourceCrop(sourceCrop)).WillOnce(Return(kError)); - EXPECT_CALL(*mHwcLayer, setZOrder(kZOrder)).WillOnce(Return(kError)); + EXPECT_CALL(*mHwcLayer, setZOrder(_)).WillOnce(Return(kError)); EXPECT_CALL(*mHwcLayer, setTransform(bufferTransform)).WillOnce(Return(kError)); EXPECT_CALL(*mHwcLayer, setBlendMode(blendMode)).WillOnce(Return(kError)); @@ -878,19 +876,22 @@ const std::vector<uint8_t> OutputLayerWriteStateToHWCTest::kLayerGenericMetadata TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoFECompositionState) { EXPECT_CALL(*mLayerFE, getCompositionState()).WillOnce(Return(nullptr)); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false); + mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoHWCState) { mOutputLayer.editState().hwc.reset(); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false); + mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoHWCLayer) { mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc(nullptr); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false); + mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, canSetAllState) { @@ -898,8 +899,10 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetAllState) { expectPerFrameCommonCalls(); expectNoSetCompositionTypeCall(); + EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false); + mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerTest, displayInstallOrientationBufferTransformSetTo90) { @@ -921,6 +924,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSolidColor) { mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR; expectPerFrameCommonCalls(); + EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); // Setting the composition type should happen before setting the color. We // check this in this test only by setting up an testing::InSeqeuence @@ -929,7 +933,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSolidColor) { expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::SOLID_COLOR); expectSetColorCall(); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false); + mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSideband) { @@ -939,7 +944,10 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSideband) { expectSetSidebandHandleCall(); expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::SIDEBAND); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false); + EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); + + mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForCursor) { @@ -949,7 +957,10 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForCursor) { expectSetHdrMetadataAndBufferCalls(); expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CURSOR); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false); + EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); + + mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForDevice) { @@ -959,7 +970,10 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForDevice) { expectSetHdrMetadataAndBufferCalls(); expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false); + EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); + + mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsNotSetIfUnchanged) { @@ -972,7 +986,10 @@ TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsNotSetIfUnchanged) { expectSetColorCall(); expectNoSetCompositionTypeCall(); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false); + EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); + + mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfColorTransformNotSupported) { @@ -982,7 +999,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfColorTransf expectSetColorCall(); expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CLIENT); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false); + mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfClientCompositionForced) { @@ -994,7 +1012,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfClientCompo expectSetColorCall(); expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CLIENT); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false); + mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, allStateIncludesMetadataIfPresent) { @@ -1007,7 +1026,10 @@ TEST_F(OutputLayerWriteStateToHWCTest, allStateIncludesMetadataIfPresent) { expectGenericLayerMetadataCalls(); expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false); + EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); + + mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, perFrameStateDoesNotIncludeMetadataIfPresent) { @@ -1018,7 +1040,10 @@ TEST_F(OutputLayerWriteStateToHWCTest, perFrameStateDoesNotIncludeMetadataIfPres expectSetHdrMetadataAndBufferCalls(); expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false); + EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); + + mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoIfPresent) { @@ -1032,7 +1057,10 @@ TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoIfPresent) { expectSetHdrMetadataAndBufferCalls(kOverrideBuffer->getBuffer(), kOverrideFence); expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); - mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false); + EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); + + mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } /* diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index e80100cc6e..7b71957021 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -30,6 +30,7 @@ #include <ui/Region.h> #include <cmath> +#include <cstdint> #include "CallOrderStateMachineHelper.h" #include "MockHWC2.h" @@ -783,15 +784,19 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, updatesLayerContentForAllLayers InjectedLayer layer2; InjectedLayer layer3; + uint32_t z = 0; EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180)); EXPECT_CALL(*layer1.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180)); EXPECT_CALL(*layer2.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180)); EXPECT_CALL(*layer3.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); injectOutputLayer(layer1); injectOutputLayer(layer2); @@ -813,15 +818,19 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, updatesLayerGeometryAndContentF InjectedLayer layer2; InjectedLayer layer3; + uint32_t z = 0; EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); EXPECT_CALL(*layer1.outputLayer, - writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); EXPECT_CALL(*layer2.outputLayer, - writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); EXPECT_CALL(*layer3.outputLayer, - writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); injectOutputLayer(layer1); injectOutputLayer(layer2); @@ -842,15 +851,19 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, forcesClientCompositionForAllLa InjectedLayer layer2; InjectedLayer layer3; + uint32_t z = 0; EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); EXPECT_CALL(*layer1.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); EXPECT_CALL(*layer2.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); EXPECT_CALL(*layer3.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); injectOutputLayer(layer1); injectOutputLayer(layer2); @@ -1144,11 +1157,6 @@ TEST_F(OutputCollectVisibleLayersTest, processesCandidateLayersReversedAndSetsOu EXPECT_CALL(mOutput, finalizePendingOutputLayers()); mOutput.collectVisibleLayers(mRefreshArgs, mCoverageState); - - // Ensure all output layers have been assigned a simple/flattened z-order. - EXPECT_EQ(0u, mLayer1.outputLayerState.z); - EXPECT_EQ(1u, mLayer2.outputLayerState.z); - EXPECT_EQ(2u, mLayer3.outputLayerState.z); } /* @@ -3501,7 +3509,8 @@ struct OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur EXPECT_CALL(mLayer.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); EXPECT_CALL(mLayer.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace)) .WillOnce(Return(std::vector<LayerFE::LayerSettings>{})); EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _, _)).WillOnce(Return(NO_ERROR)); @@ -4080,16 +4089,20 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBackgroundBlurRequests) InjectedLayer layer2; InjectedLayer layer3; + uint32_t z = 0; // Layer requesting blur, or below, should request client composition. EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); EXPECT_CALL(*layer1.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); EXPECT_CALL(*layer2.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0)); EXPECT_CALL(*layer3.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); layer2.layerFEState.backgroundBlurRadius = 10; @@ -4112,16 +4125,20 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBlurRegionRequests) { InjectedLayer layer2; InjectedLayer layer3; + uint32_t z = 0; // Layer requesting blur, or below, should request client composition. EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); EXPECT_CALL(*layer1.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); EXPECT_CALL(*layer2.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0)); EXPECT_CALL(*layer3.outputLayer, - writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false)); + writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); BlurRegion region; layer2.layerFEState.blurRegions.push_back(region); diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp index 83cc19b014..948c850735 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp @@ -41,8 +41,6 @@ const Rect sRectOne = Rect(10, 20, 30, 40); const Rect sRectTwo = Rect(40, 30, 20, 10); const FloatRect sFloatRectOne = FloatRect(100.f, 200.f, 300.f, 400.f); const FloatRect sFloatRectTwo = FloatRect(400.f, 300.f, 200.f, 100.f); -const constexpr int32_t sZOne = 100; -const constexpr int32_t sZTwo = 101; const constexpr float sAlphaOne = 0.25f; const constexpr float sAlphaTwo = 0.5f; const Region sRegionOne = Region(sRectOne); @@ -408,45 +406,6 @@ TEST_F(LayerStateTest, compareSourceCrop) { EXPECT_TRUE(otherLayerState->compare(*mLayerState)); } -TEST_F(LayerStateTest, updateZOrder) { - OutputLayerCompositionState outputLayerCompositionState; - outputLayerCompositionState.z = sZOne; - LayerFECompositionState layerFECompositionState; - setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState, - layerFECompositionState); - mLayerState = std::make_unique<LayerState>(&mOutputLayer); - - mock::OutputLayer newOutputLayer; - mock::LayerFE newLayerFE; - OutputLayerCompositionState outputLayerCompositionStateTwo; - outputLayerCompositionStateTwo.z = sZTwo; - setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo, - layerFECompositionState); - Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::ZOrder), updates); -} - -TEST_F(LayerStateTest, compareZOrder) { - OutputLayerCompositionState outputLayerCompositionState; - outputLayerCompositionState.z = sZOne; - LayerFECompositionState layerFECompositionState; - setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState, - layerFECompositionState); - mLayerState = std::make_unique<LayerState>(&mOutputLayer); - mock::OutputLayer newOutputLayer; - mock::LayerFE newLayerFE; - OutputLayerCompositionState outputLayerCompositionStateTwo; - outputLayerCompositionStateTwo.z = sZTwo; - setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo, - layerFECompositionState); - auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer); - - verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::ZOrder); - - EXPECT_TRUE(mLayerState->compare(*otherLayerState)); - EXPECT_TRUE(otherLayerState->compare(*mLayerState)); -} - TEST_F(LayerStateTest, updateBufferTransform) { OutputLayerCompositionState outputLayerCompositionState; outputLayerCompositionState.bufferTransform = Hwc2::Transform::FLIP_H; @@ -954,4 +913,4 @@ TEST_F(LayerStateTest, getNonBufferHash_filtersOutBuffers) { } } // namespace -} // namespace android::compositionengine::impl::planner
\ No newline at end of file +} // namespace android::compositionengine::impl::planner diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp index 43e119fc11..1492707ad2 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp @@ -31,8 +31,6 @@ const FloatRect sFloatRectOne = FloatRect(100.f, 200.f, 300.f, 400.f); const FloatRect sFloatRectTwo = FloatRect(400.f, 300.f, 200.f, 100.f); const Rect sRectOne = Rect(1, 2, 3, 4); const Rect sRectTwo = Rect(4, 3, 2, 1); -const constexpr int32_t sZOne = 100; -const constexpr int32_t sZTwo = 101; const constexpr float sAlphaOne = 0.25f; const constexpr float sAlphaTwo = 0.5f; const Region sRegionOne = Region(sRectOne); @@ -194,11 +192,11 @@ TEST_F(LayerStackTest, getApproximateMatch_doesNotMatchManyDifferences) { .displayFrame = sRectOne, .sourceCrop = sFloatRectOne, .dataspace = ui::Dataspace::SRGB, - .z = sZOne, }; LayerFECompositionState layerFECompositionStateOne; layerFECompositionStateOne.alpha = sAlphaOne; layerFECompositionStateOne.colorTransformIsIdentity = true; + layerFECompositionStateOne.blendMode = hal::BlendMode::NONE; setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne, layerFECompositionStateOne); LayerState layerStateOne(&outputLayerOne); @@ -210,12 +208,12 @@ TEST_F(LayerStackTest, getApproximateMatch_doesNotMatchManyDifferences) { .displayFrame = sRectTwo, .sourceCrop = sFloatRectTwo, .dataspace = ui::Dataspace::DISPLAY_P3, - .z = sZTwo, }; LayerFECompositionState layerFECompositionStateTwo; layerFECompositionStateTwo.alpha = sAlphaTwo; layerFECompositionStateTwo.colorTransformIsIdentity = false; layerFECompositionStateTwo.colorTransform = sMat4One; + layerFECompositionStateTwo.blendMode = hal::BlendMode::PREMULTIPLIED; setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo, layerFECompositionStateTwo); LayerState layerStateTwo(&outputLayerTwo); @@ -264,7 +262,6 @@ TEST_F(LayerStackTest, getApproximateMatch_alwaysMatchesClientComposition) { .displayFrame = sRectOne, .sourceCrop = sFloatRectOne, .dataspace = ui::Dataspace::SRGB, - .z = sZOne, }; LayerFECompositionState layerFECompositionStateOne; layerFECompositionStateOne.buffer = new GraphicBuffer(); @@ -282,7 +279,6 @@ TEST_F(LayerStackTest, getApproximateMatch_alwaysMatchesClientComposition) { .displayFrame = sRectTwo, .sourceCrop = sFloatRectTwo, .dataspace = ui::Dataspace::DISPLAY_P3, - .z = sZTwo, }; LayerFECompositionState layerFECompositionStateTwo; layerFECompositionStateTwo.buffer = new GraphicBuffer(); @@ -346,6 +342,32 @@ struct PredictionTest : public testing::Test { } }; +TEST_F(LayerStackTest, reorderingChangesNonBufferHash) { + mock::OutputLayer outputLayerOne; + mock::LayerFE layerFEOne; + OutputLayerCompositionState outputLayerCompositionStateOne{ + .sourceCrop = sFloatRectOne, + }; + LayerFECompositionState layerFECompositionStateOne; + setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne, + layerFECompositionStateOne); + LayerState layerStateOne(&outputLayerOne); + + mock::OutputLayer outputLayerTwo; + mock::LayerFE layerFETwo; + OutputLayerCompositionState outputLayerCompositionStateTwo{ + .sourceCrop = sFloatRectTwo, + }; + LayerFECompositionState layerFECompositionStateTwo; + setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo, + layerFECompositionStateTwo); + LayerState layerStateTwo(&outputLayerTwo); + + NonBufferHash hash = getNonBufferHash({&layerStateOne, &layerStateTwo}); + NonBufferHash hashReverse = getNonBufferHash({&layerStateTwo, &layerStateOne}); + EXPECT_NE(hash, hashReverse); +} + TEST_F(PredictionTest, constructPrediction) { Plan plan; plan.addLayerType(hal::Composition::DEVICE); @@ -525,4 +547,4 @@ TEST_F(PredictorTest, recordMissedPlan_skipsApproximateMatch) { } } // namespace -} // namespace android::compositionengine::impl::planner
\ No newline at end of file +} // namespace android::compositionengine::impl::planner diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index cf215adba2..4461420b46 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -531,7 +531,9 @@ void Layer::preparePerFrameCompositionState() { isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf; // Force client composition for special cases known only to the front-end. - if (isHdrY410() || usesRoundedCorners || drawShadows() || drawingState.blurRegions.size() > 0 || + // Rounded corners no longer force client composition, since we may use a + // hole punch so that the layer will appear to have rounded corners. + if (isHdrY410() || drawShadows() || drawingState.blurRegions.size() > 0 || compositionState->stretchEffect.hasEffect()) { compositionState->forceClientComposition = true; } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 9f3ea9ab39..688a2c3aff 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -600,6 +600,8 @@ public: // ignored. virtual RoundedCornerState getRoundedCornerState() const; + bool hasRoundedCorners() const override { return getRoundedCornerState().radius > .0f; } + virtual PixelFormat getPixelFormat() const { return PIXEL_FORMAT_NONE; } /** * Return whether this layer needs an input info. For most layer types |