From fa247b1870da660a722551d6eb944dab1c8f0b53 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 11 Feb 2020 08:58:26 -0800 Subject: Rename ColorLayer to EffectLayer to handle both shadows and color fill We want the ability for a layer to render shadows without any content. This new layer type will be able to combine effects as needed. Test: presubmit tests (no functional changes) Test: go/wm-smoke Change-Id: I8663d126a23263a3d7dc799d39a9cf44b3b6e4a0 --- services/surfaceflinger/EffectLayer.cpp | 132 ++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 services/surfaceflinger/EffectLayer.cpp (limited to 'services/surfaceflinger/EffectLayer.cpp') diff --git a/services/surfaceflinger/EffectLayer.cpp b/services/surfaceflinger/EffectLayer.cpp new file mode 100644 index 0000000000..e928c57929 --- /dev/null +++ b/services/surfaceflinger/EffectLayer.cpp @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" + +// #define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "EffectLayer" + +#include "EffectLayer.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "DisplayDevice.h" +#include "SurfaceFlinger.h" + +namespace android { +// --------------------------------------------------------------------------- + +EffectLayer::EffectLayer(const LayerCreationArgs& args) + : Layer(args), + mCompositionState{mFlinger->getCompositionEngine().createLayerFECompositionState()} {} + +EffectLayer::~EffectLayer() = default; + +std::optional EffectLayer::prepareClientComposition( + compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) { + auto result = Layer::prepareClientComposition(targetSettings); + if (!result) { + return result; + } + result->source.solidColor = getColor().rgb; + return result; +} + +bool EffectLayer::isVisible() const { + return !isHiddenByPolicy() && getAlpha() > 0.0_hf; +} + +bool EffectLayer::setColor(const half3& color) { + if (mCurrentState.color.r == color.r && mCurrentState.color.g == color.g && + mCurrentState.color.b == color.b) { + return false; + } + + mCurrentState.sequence++; + mCurrentState.color.r = color.r; + mCurrentState.color.g = color.g; + mCurrentState.color.b = color.b; + mCurrentState.modified = true; + setTransactionFlags(eTransactionNeeded); + return true; +} + +bool EffectLayer::setDataspace(ui::Dataspace dataspace) { + if (mCurrentState.dataspace == dataspace) { + return false; + } + + mCurrentState.sequence++; + mCurrentState.dataspace = dataspace; + mCurrentState.modified = true; + setTransactionFlags(eTransactionNeeded); + return true; +} + +void EffectLayer::preparePerFrameCompositionState() { + Layer::preparePerFrameCompositionState(); + + auto* compositionState = editCompositionState(); + compositionState->color = getColor(); + compositionState->compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR; +} + +sp EffectLayer::getCompositionEngineLayerFE() const { + return asLayerFE(); +} + +compositionengine::LayerFECompositionState* EffectLayer::editCompositionState() { + return mCompositionState.get(); +} + +const compositionengine::LayerFECompositionState* EffectLayer::getCompositionState() const { + return mCompositionState.get(); +} + +bool EffectLayer::isOpaque(const Layer::State& s) const { + // Consider the layer to be opaque if its opaque flag is set or its effective + // alpha (considering the alpha of its parents as well) is 1.0; + return (s.flags & layer_state_t::eLayerOpaque) != 0 || getAlpha() == 1.0_hf; +} + +ui::Dataspace EffectLayer::getDataSpace() const { + return mDrawingState.dataspace; +} + +sp EffectLayer::createClone() { + sp layer = mFlinger->getFactory().createEffectLayer( + LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0, + LayerMetadata())); + layer->setInitialValuesForClone(this); + return layer; +} + +} // namespace android + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wconversion" -- cgit v1.2.3-59-g8ed1b From b87d94f61ddf784947cb6fd2d0569d8e568c1822 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 13 Feb 2020 09:17:36 -0800 Subject: Retrieve a list of composition settings from front end layer Replace prepareClientComposition and prepareShadowClientComposition calls with one that provides a list of composition settings in z-order to handle layers that renders shadows wihtout any content. If the EffectLayer is called with an invalid color, skip the color fill. Test: atest libcompositionengine_test Test: LayerTransactionTest.SetFlagsSecureEUidSystem Test: go/wm-smoke Change-Id: Iad16931341fc2e58247f4439a322c0ad1e8750f8 --- services/surfaceflinger/BufferLayer.cpp | 156 ++++++------ services/surfaceflinger/BufferLayer.h | 5 +- .../include/compositionengine/LayerFE.h | 40 ++- .../include/compositionengine/mock/LayerFE.h | 6 +- .../CompositionEngine/src/Output.cpp | 47 ++-- .../CompositionEngine/tests/OutputTest.cpp | 274 ++++++++++++++------- services/surfaceflinger/EffectLayer.cpp | 36 ++- services/surfaceflinger/EffectLayer.h | 9 +- services/surfaceflinger/Layer.cpp | 46 +++- services/surfaceflinger/Layer.h | 14 +- services/surfaceflinger/SurfaceFlinger.cpp | 21 +- .../tests/LayerRenderTypeTransaction_test.cpp | 16 +- 12 files changed, 430 insertions(+), 240 deletions(-) (limited to 'services/surfaceflinger/EffectLayer.cpp') diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index f4f45be49f..5a955f777b 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -180,95 +180,91 @@ std::optional BufferLayer::prepareCli } bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) || (isSecure() && !targetSettings.isSecure); - const State& s(getDrawingState()); compositionengine::LayerFE::LayerSettings& layer = *result; - if (!blackOutLayer) { - layer.source.buffer.buffer = mBufferInfo.mBuffer; - layer.source.buffer.isOpaque = isOpaque(s); - layer.source.buffer.fence = mBufferInfo.mFence; - layer.source.buffer.textureName = mTextureName; - layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha(); - layer.source.buffer.isY410BT2020 = isHdrY410(); - bool hasSmpte2086 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::SMPTE2086; - bool hasCta861_3 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::CTA861_3; - layer.source.buffer.maxMasteringLuminance = hasSmpte2086 - ? mBufferInfo.mHdrMetadata.smpte2086.maxLuminance - : defaultMaxMasteringLuminance; - layer.source.buffer.maxContentLuminance = hasCta861_3 - ? mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel - : defaultMaxContentLuminance; - layer.frameNumber = mCurrentFrameNumber; - layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0; - - // TODO: we could be more subtle with isFixedSize() - const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || isFixedSize(); - - // Query the texture matrix given our current filtering mode. - float textureMatrix[16]; - getDrawingTransformMatrix(useFiltering, textureMatrix); - - if (getTransformToDisplayInverse()) { - /* - * the code below applies the primary display's inverse transform to - * the texture transform - */ - uint32_t transform = DisplayDevice::getPrimaryDisplayRotationFlags(); - mat4 tr = inverseOrientation(transform); - - /** - * TODO(b/36727915): This is basically a hack. - * - * Ensure that regardless of the parent transformation, - * this buffer is always transformed from native display - * orientation to display orientation. For example, in the case - * of a camera where the buffer remains in native orientation, - * we want the pixels to always be upright. - */ - sp p = mDrawingParent.promote(); - if (p != nullptr) { - const auto parentTransform = p->getTransform(); - tr = tr * inverseOrientation(parentTransform.getOrientation()); - } - - // and finally apply it to the original texture matrix - const mat4 texTransform(mat4(static_cast(textureMatrix)) * tr); - memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix)); - } + if (blackOutLayer) { + prepareClearClientComposition(layer, true /* blackout */); + return layer; + } - const Rect win{getBounds()}; - float bufferWidth = getBufferSize(s).getWidth(); - float bufferHeight = getBufferSize(s).getHeight(); + const State& s(getDrawingState()); + layer.source.buffer.buffer = mBufferInfo.mBuffer; + layer.source.buffer.isOpaque = isOpaque(s); + layer.source.buffer.fence = mBufferInfo.mFence; + layer.source.buffer.textureName = mTextureName; + layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha(); + layer.source.buffer.isY410BT2020 = isHdrY410(); + bool hasSmpte2086 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::SMPTE2086; + bool hasCta861_3 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::CTA861_3; + layer.source.buffer.maxMasteringLuminance = hasSmpte2086 + ? mBufferInfo.mHdrMetadata.smpte2086.maxLuminance + : defaultMaxMasteringLuminance; + layer.source.buffer.maxContentLuminance = hasCta861_3 + ? mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel + : defaultMaxContentLuminance; + layer.frameNumber = mCurrentFrameNumber; + layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0; + + // TODO: we could be more subtle with isFixedSize() + const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || isFixedSize(); + + // Query the texture matrix given our current filtering mode. + float textureMatrix[16]; + getDrawingTransformMatrix(useFiltering, textureMatrix); - // BufferStateLayers can have a "buffer size" of [0, 0, -1, -1] when no display frame has - // been set and there is no parent layer bounds. In that case, the scale is meaningless so - // ignore them. - if (!getBufferSize(s).isValid()) { - bufferWidth = float(win.right) - float(win.left); - bufferHeight = float(win.bottom) - float(win.top); + if (getTransformToDisplayInverse()) { + /* + * the code below applies the primary display's inverse transform to + * the texture transform + */ + uint32_t transform = DisplayDevice::getPrimaryDisplayRotationFlags(); + mat4 tr = inverseOrientation(transform); + + /** + * TODO(b/36727915): This is basically a hack. + * + * Ensure that regardless of the parent transformation, + * this buffer is always transformed from native display + * orientation to display orientation. For example, in the case + * of a camera where the buffer remains in native orientation, + * we want the pixels to always be upright. + */ + sp p = mDrawingParent.promote(); + if (p != nullptr) { + const auto parentTransform = p->getTransform(); + tr = tr * inverseOrientation(parentTransform.getOrientation()); } - const float scaleHeight = (float(win.bottom) - float(win.top)) / bufferHeight; - const float scaleWidth = (float(win.right) - float(win.left)) / bufferWidth; - const float translateY = float(win.top) / bufferHeight; - const float translateX = float(win.left) / bufferWidth; + // and finally apply it to the original texture matrix + const mat4 texTransform(mat4(static_cast(textureMatrix)) * tr); + memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix)); + } - // Flip y-coordinates because GLConsumer expects OpenGL convention. - mat4 tr = mat4::translate(vec4(.5, .5, 0, 1)) * mat4::scale(vec4(1, -1, 1, 1)) * - mat4::translate(vec4(-.5, -.5, 0, 1)) * - mat4::translate(vec4(translateX, translateY, 0, 1)) * - mat4::scale(vec4(scaleWidth, scaleHeight, 1.0, 1.0)); + const Rect win{getBounds()}; + float bufferWidth = getBufferSize(s).getWidth(); + float bufferHeight = getBufferSize(s).getHeight(); - layer.source.buffer.useTextureFiltering = useFiltering; - layer.source.buffer.textureTransform = mat4(static_cast(textureMatrix)) * tr; - } else { - // If layer is blacked out, force alpha to 1 so that we draw a black color - // layer. - layer.source.buffer.buffer = nullptr; - layer.alpha = 1.0; - layer.frameNumber = 0; - layer.bufferId = 0; + // BufferStateLayers can have a "buffer size" of [0, 0, -1, -1] when no display frame has + // been set and there is no parent layer bounds. In that case, the scale is meaningless so + // ignore them. + if (!getBufferSize(s).isValid()) { + bufferWidth = float(win.right) - float(win.left); + bufferHeight = float(win.bottom) - float(win.top); } + const float scaleHeight = (float(win.bottom) - float(win.top)) / bufferHeight; + const float scaleWidth = (float(win.right) - float(win.left)) / bufferWidth; + const float translateY = float(win.top) / bufferHeight; + const float translateX = float(win.left) / bufferWidth; + + // Flip y-coordinates because GLConsumer expects OpenGL convention. + mat4 tr = mat4::translate(vec4(.5, .5, 0, 1)) * mat4::scale(vec4(1, -1, 1, 1)) * + mat4::translate(vec4(-.5, -.5, 0, 1)) * + mat4::translate(vec4(translateX, translateY, 0, 1)) * + mat4::scale(vec4(scaleWidth, scaleHeight, 1.0, 1.0)); + + layer.source.buffer.useTextureFiltering = useFiltering; + layer.source.buffer.textureTransform = mat4(static_cast(textureMatrix)) * tr; + return layer; } diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index 4085b52449..0487e380ec 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -173,14 +173,15 @@ protected: BufferInfo mBufferInfo; virtual void gatherBufferInfo() = 0; + std::optional prepareClientComposition( + compositionengine::LayerFE::ClientCompositionTargetSettings&) override; + /* * compositionengine::LayerFE overrides */ const compositionengine::LayerFECompositionState* getCompositionState() const override; bool onPreComposition(nsecs_t) override; void preparePerFrameCompositionState() override; - std::optional prepareClientComposition( - compositionengine::LayerFE::ClientCompositionTargetSettings&) override; // Loads the corresponding system property once per process static bool latchUnsignaledBuffers(); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index 912dffd029..6cc90cb3ee 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -97,6 +97,21 @@ public: // Modified by each call to prepareClientComposition to indicate the // region of the target buffer that should be cleared. Region& clearRegion; + + // Viewport of the target being rendered to. This is used to determine + // the shadow light position. + const Rect& viewport; + + // Dataspace of the output so we can optimize how to render the shadow + // by avoiding unnecessary color space conversions. + const ui::Dataspace dataspace; + + // True if the region excluding the shadow is visible. + const bool realContentIsVisible; + + // If set to true, change the layer settings to render a clear output. + // This may be requested by the HWC + const bool clearContent; }; // A superset of LayerSettings required by RenderEngine to compose a layer @@ -109,18 +124,12 @@ public: uint64_t frameNumber = 0; }; - // Returns the LayerSettings to pass to RenderEngine::drawLayers, or - // nullopt_t if the layer does not render - virtual std::optional prepareClientComposition( + // Returns the z-ordered list of LayerSettings to pass to RenderEngine::drawLayers. The list + // may contain shadows casted by the layer or the content of the layer itself. If the layer + // does not render then an empty list will be returned. + virtual std::vector prepareClientCompositionList( ClientCompositionTargetSettings&) = 0; - // Returns the LayerSettings used to draw shadows around a layer. It is passed - // to RenderEngine::drawLayers. Returns nullopt_t if the layer does not render - // shadows. - virtual std::optional prepareShadowClientComposition( - const LayerSettings& layerSettings, const Rect& displayViewport, - ui::Dataspace outputDataspace) = 0; - // Called after the layer is displayed to update the presentation fence virtual void onLayerDisplayed(const sp&) = 0; @@ -142,7 +151,10 @@ static inline bool operator==(const LayerFE::ClientCompositionTargetSettings& lh lhs.useIdentityTransform == rhs.useIdentityTransform && lhs.needsFiltering == rhs.needsFiltering && lhs.isSecure == rhs.isSecure && lhs.supportsProtectedContent == rhs.supportsProtectedContent && - lhs.clearRegion.hasSameRects(rhs.clearRegion); + lhs.clearRegion.hasSameRects(rhs.clearRegion) && lhs.viewport == rhs.viewport && + lhs.dataspace == rhs.dataspace && + lhs.realContentIsVisible == rhs.realContentIsVisible && + lhs.clearContent == rhs.clearContent; } static inline bool operator==(const LayerFE::LayerSettings& lhs, @@ -164,6 +176,12 @@ static inline void PrintTo(const LayerFE::ClientCompositionTargetSettings& setti *os << "\n .supportsProtectedContent = " << settings.supportsProtectedContent; *os << "\n .clearRegion = "; PrintTo(settings.clearRegion, os); + *os << "\n .viewport = "; + PrintTo(settings.viewport, os); + *os << "\n .dataspace = "; + PrintTo(settings.dataspace, os); + *os << "\n .realContentIsVisible = " << settings.realContentIsVisible; + *os << "\n .clearContent = " << settings.clearContent; *os << "\n}"; } diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h index 5c2ad15268..45891a7ff6 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h @@ -35,11 +35,9 @@ public: MOCK_METHOD1(onPreComposition, bool(nsecs_t)); MOCK_METHOD1(prepareCompositionState, void(compositionengine::LayerFE::StateSubset)); - MOCK_METHOD1(prepareClientComposition, - std::optional( + MOCK_METHOD1(prepareClientCompositionList, + std::vector( compositionengine::LayerFE::ClientCompositionTargetSettings&)); - MOCK_METHOD3(prepareShadowClientComposition, - std::optional(const LayerSettings&, const Rect&, ui::Dataspace)); MOCK_METHOD1(onLayerDisplayed, void(const sp&)); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index a389bf3805..e792f45bb7 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -963,11 +963,16 @@ std::vector Output::generateClientCompositionRequests( // rectangle, as by definition the layer must blend with whatever is // underneath. We also skip the first layer as the buffer target is // guaranteed to start out cleared. - bool clearClientComposition = + const bool clearClientComposition = layerState.clearClientTarget && layerFEState->isOpaque && !firstLayer; ALOGV(" Composition type: client %d clear %d", clientComposition, clearClientComposition); + // If the layer casts a shadow but the content casting the shadow is occluded, skip + // composing the non-shadow content and only draw the shadows. + const bool realContentIsVisible = clientComposition && + !layerState.visibleRegion.subtract(layerState.shadowRegion).isEmpty(); + if (clientComposition || clearClientComposition) { compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{ clip, @@ -976,35 +981,21 @@ std::vector Output::generateClientCompositionRequests( outputState.isSecure, supportsProtectedContent, clientComposition ? clearRegion : dummyRegion, + outputState.viewport, + outputDataspace, + realContentIsVisible, + !clientComposition, /* clearContent */ }; - if (std::optional result = - layerFE.prepareClientComposition(targetSettings)) { - if (!clientComposition) { - LayerFE::LayerSettings& layerSettings = *result; - layerSettings.source.buffer.buffer = nullptr; - layerSettings.source.solidColor = half3(0.0, 0.0, 0.0); - layerSettings.alpha = half(0.0); - layerSettings.disableBlending = true; - layerSettings.frameNumber = 0; - } else { - std::optional shadowLayer = - layerFE.prepareShadowClientComposition(*result, outputState.viewport, - outputDataspace); - if (shadowLayer) { - clientCompositionLayers.push_back(*shadowLayer); - } - } - - // If the layer casts a shadow but the content casting the shadow is occluded, skip - // composing the non-shadow content and only draw the shadows. - const bool skipNonShadowContentComposition = clientComposition && - layerState.visibleRegion.subtract(layerState.shadowRegion).isEmpty(); - - if (!skipNonShadowContentComposition) { - layer->editState().clientCompositionTimestamp = systemTime(); - clientCompositionLayers.push_back(*result); - } + std::vector results = + layerFE.prepareClientCompositionList(targetSettings); + if (realContentIsVisible && !results.empty()) { + layer->editState().clientCompositionTimestamp = systemTime(); } + + clientCompositionLayers.insert(clientCompositionLayers.end(), + std::make_move_iterator(results.begin()), + std::make_move_iterator(results.end())); + results.clear(); } firstLayer = false; diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 2b450467ed..be0e9e4bc8 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -3425,19 +3425,13 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, gathersClientCompositi LayerFE::LayerSettings mShadowSettings; mShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f}; - EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(_)).WillOnce(Return(std::nullopt)); - EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(_)) - .WillOnce(Return(mLayers[1].mLayerSettings)); - EXPECT_CALL(mLayers[1].mLayerFE, - prepareShadowClientComposition(mLayers[1].mLayerSettings, kDisplayViewport, - kDisplayDataspace)) - .WillOnce(Return(std::nullopt)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_)) - .WillOnce(Return(mLayers[2].mLayerSettings)); - EXPECT_CALL(mLayers[2].mLayerFE, - prepareShadowClientComposition(mLayers[2].mLayerSettings, kDisplayViewport, - kDisplayDataspace)) - .WillOnce(Return(mShadowSettings)); + EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(_)) + .WillOnce(Return(std::vector())); + EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(_)) + .WillOnce(Return(std::vector({mLayers[1].mLayerSettings}))); + EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(_)) + .WillOnce(Return(std::vector( + {mShadowSettings, mLayers[2].mLayerSettings}))); Region accumClearRegion(Rect(10, 11, 12, 13)); auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */, @@ -3469,10 +3463,8 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, mLayers[1].mLayerFEState.isOpaque = true; mLayers[2].mLayerFEState.isOpaque = true; - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_)) - .WillOnce(Return(mLayers[2].mLayerSettings)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareShadowClientComposition(_, _, _)) - .WillOnce(Return(std::nullopt)); + EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(_)) + .WillOnce(Return(std::vector({mLayers[2].mLayerSettings}))); Region accumClearRegion(Rect(10, 11, 12, 13)); auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */, @@ -3497,10 +3489,8 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, mLayers[1].mLayerFEState.isOpaque = false; mLayers[2].mLayerFEState.isOpaque = false; - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_)) - .WillOnce(Return(mLayers[2].mLayerSettings)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareShadowClientComposition(_, _, _)) - .WillOnce(Return(std::nullopt)); + EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(_)) + .WillOnce(Return(std::vector({mLayers[2].mLayerSettings}))); Region accumClearRegion(Rect(10, 11, 12, 13)); auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */, @@ -3529,25 +3519,51 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, clearsHWCLayersIfOpaqu mLayers[0].mLayerFEState.isOpaque = true; mLayers[1].mLayerFEState.isOpaque = true; mLayers[2].mLayerFEState.isOpaque = true; + Region accumClearRegion(Rect(10, 11, 12, 13)); + Region dummyRegion; + + compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{ + Region(kDisplayFrame), + false, /* identity transform */ + false, /* needs filtering */ + false, /* secure */ + false, /* supports protected content */ + dummyRegion, /* clear region */ + kDisplayViewport, + kDisplayDataspace, + false /* realContentIsVisible */, + true /* clearContent */, + }; + compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{ + Region(kDisplayFrame), + false, /* identity transform */ + false, /* needs filtering */ + false, /* secure */ + false, /* supports protected content */ + accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, + }; - EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(_)) - .WillOnce(Return(mLayers[1].mLayerSettings)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_)) - .WillOnce(Return(mLayers[2].mLayerSettings)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareShadowClientComposition(_, _, _)) - .WillOnce(Return(std::nullopt)); + LayerFE::LayerSettings mBlackoutSettings = mLayers[1].mLayerSettings; + mBlackoutSettings.source.buffer.buffer = nullptr; + mBlackoutSettings.source.solidColor = {0.1f, 0.1f, 0.1f}; + mBlackoutSettings.alpha = 0.f; + mBlackoutSettings.disableBlending = true; + + EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) + .WillOnce(Return(std::vector({mBlackoutSettings}))); + EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) + .WillOnce(Return(std::vector({mLayers[2].mLayerSettings}))); - Region accumClearRegion(Rect(10, 11, 12, 13)); auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */, accumClearRegion, kDisplayDataspace); ASSERT_EQ(2u, requests.size()); // The second layer is expected to be rendered as alpha=0 black with no blending - EXPECT_EQ(mLayers[1].mLayerSettings.geometry.boundaries, requests[0].geometry.boundaries); - EXPECT_FALSE(requests[0].source.buffer.buffer); - EXPECT_EQ((half3{0.f, 0.f, 0.f}), requests[0].source.solidColor); - EXPECT_EQ(0.f, static_cast(requests[0].alpha)); - EXPECT_EQ(true, requests[0].disableBlending); + EXPECT_EQ(mBlackoutSettings, requests[0]); EXPECT_EQ(mLayers[2].mLayerSettings, requests[1]); @@ -3569,6 +3585,10 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* secure */ false, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{ Region(Rect(0, 0, 30, 30)), @@ -3577,6 +3597,10 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* secure */ false, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{ Region(Rect(0, 0, 40, 201)), @@ -3585,14 +3609,18 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* secure */ false, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; - EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings)))) - .WillOnce(Return(std::nullopt)); - EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings)))) - .WillOnce(Return(std::nullopt)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings)))) - .WillOnce(Return(std::nullopt)); + EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) + .WillOnce(Return(std::vector())); + EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) + .WillOnce(Return(std::vector())); + EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) + .WillOnce(Return(std::vector())); static_cast( mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */, @@ -3613,6 +3641,10 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* secure */ false, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{ Region(kDisplayFrame), @@ -3621,6 +3653,10 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* secure */ false, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{ Region(kDisplayFrame), @@ -3629,14 +3665,18 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* secure */ false, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; - EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings)))) - .WillOnce(Return(std::nullopt)); - EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings)))) - .WillOnce(Return(std::nullopt)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings)))) - .WillOnce(Return(std::nullopt)); + EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) + .WillOnce(Return(std::vector())); + EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) + .WillOnce(Return(std::vector())); + EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) + .WillOnce(Return(std::vector())); static_cast( mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */, @@ -3657,6 +3697,11 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* secure */ false, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, + }; compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{ Region(kDisplayFrame), @@ -3665,6 +3710,10 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* secure */ false, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{ Region(kDisplayFrame), @@ -3673,14 +3722,18 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* secure */ false, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; - EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings)))) - .WillOnce(Return(std::nullopt)); - EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings)))) - .WillOnce(Return(std::nullopt)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings)))) - .WillOnce(Return(std::nullopt)); + EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) + .WillOnce(Return(std::vector())); + EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) + .WillOnce(Return(std::vector())); + EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) + .WillOnce(Return(std::vector())); static_cast( mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */, @@ -3700,6 +3753,10 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, true, /* secure */ false, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{ Region(kDisplayFrame), @@ -3708,6 +3765,10 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, true, /* secure */ false, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{ Region(kDisplayFrame), @@ -3716,14 +3777,18 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, true, /* secure */ false, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; - EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings)))) - .WillOnce(Return(std::nullopt)); - EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings)))) - .WillOnce(Return(std::nullopt)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings)))) - .WillOnce(Return(std::nullopt)); + EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) + .WillOnce(Return(std::vector())); + EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) + .WillOnce(Return(std::vector())); + EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) + .WillOnce(Return(std::vector())); static_cast( mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */, @@ -3741,6 +3806,10 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* secure */ true, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{ Region(kDisplayFrame), @@ -3749,6 +3818,10 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* secure */ true, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{ Region(kDisplayFrame), @@ -3757,14 +3830,18 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* secure */ true, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; - EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings)))) - .WillOnce(Return(std::nullopt)); - EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings)))) - .WillOnce(Return(std::nullopt)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings)))) - .WillOnce(Return(std::nullopt)); + EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) + .WillOnce(Return(std::vector())); + EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) + .WillOnce(Return(std::vector())); + EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) + .WillOnce(Return(std::vector())); static_cast(mOutput.generateClientCompositionRequests(true /* supportsProtectedContent */, accumClearRegion, @@ -3847,16 +3924,16 @@ TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenReq true, /* secure */ true, /* supports protected content */ accumClearRegion, + kPortraitViewport, + kOutputDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; EXPECT_CALL(leftLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true)); EXPECT_CALL(leftLayer.mOutputLayer, needsFiltering()).WillRepeatedly(Return(false)); - EXPECT_CALL(leftLayer.mLayerFE, prepareClientComposition(Eq(ByRef(leftLayerSettings)))) - .WillOnce(Return(leftLayer.mLayerSettings)); - EXPECT_CALL(leftLayer.mLayerFE, - prepareShadowClientComposition(leftLayer.mLayerSettings, kPortraitViewport, - kOutputDataspace)) - .WillOnce(Return(std::nullopt)); + EXPECT_CALL(leftLayer.mLayerFE, prepareClientCompositionList(Eq(ByRef(leftLayerSettings)))) + .WillOnce(Return(std::vector({leftLayer.mLayerSettings}))); compositionengine::LayerFE::ClientCompositionTargetSettings rightLayerSettings{ Region(Rect(1000, 0, 2000, 1000)), @@ -3865,16 +3942,16 @@ TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenReq true, /* secure */ true, /* supports protected content */ accumClearRegion, + kPortraitViewport, + kOutputDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; EXPECT_CALL(rightLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true)); EXPECT_CALL(rightLayer.mOutputLayer, needsFiltering()).WillRepeatedly(Return(false)); - EXPECT_CALL(rightLayer.mLayerFE, prepareClientComposition(Eq(ByRef(rightLayerSettings)))) - .WillOnce(Return(rightLayer.mLayerSettings)); - EXPECT_CALL(rightLayer.mLayerFE, - prepareShadowClientComposition(rightLayer.mLayerSettings, kPortraitViewport, - kOutputDataspace)) - .WillOnce(Return(std::nullopt)); + EXPECT_CALL(rightLayer.mLayerFE, prepareClientCompositionList(Eq(ByRef(rightLayerSettings)))) + .WillOnce(Return(std::vector({rightLayer.mLayerSettings}))); constexpr bool supportsProtectedContent = true; auto requests = mOutput.generateClientCompositionRequests(supportsProtectedContent, @@ -3891,6 +3968,20 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, const Region kShadowRegion = Region(kContentWithShadow).subtract(kContent); const Region kPartialShadowRegion = Region(kContentWithShadow).subtract(Rect(40, 40, 60, 80)); + Region accumClearRegion(Rect(10, 11, 12, 13)); + compositionengine::LayerFE::ClientCompositionTargetSettings layer2Settings{ + Region(Rect(60, 40, 70, 80)).merge(Rect(40, 80, 70, 90)), /* visible region */ + false, /* identity transform */ + false, /* needs filtering */ + false, /* secure */ + false, /* supports protected content */ + accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + false /* realContentIsVisible */, + false /* clearContent */, + }; + LayerFE::LayerSettings mShadowSettings; mShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f}; @@ -3899,14 +3990,9 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, EXPECT_CALL(mLayers[0].mOutputLayer, requiresClientComposition()).WillOnce(Return(false)); EXPECT_CALL(mLayers[1].mOutputLayer, requiresClientComposition()).WillOnce(Return(false)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_)) - .WillOnce(Return(mLayers[2].mLayerSettings)); - EXPECT_CALL(mLayers[2].mLayerFE, - prepareShadowClientComposition(mLayers[2].mLayerSettings, kDisplayViewport, - kDisplayDataspace)) - .WillOnce(Return(mShadowSettings)); + EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2Settings)))) + .WillOnce(Return(std::vector({mShadowSettings}))); - Region accumClearRegion(Rect(10, 11, 12, 13)); auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */, accumClearRegion, kDisplayDataspace); ASSERT_EQ(1u, requests.size()); @@ -3928,16 +4014,26 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, mLayers[2].mOutputLayerState.visibleRegion = kPartialContentWithPartialShadowRegion; mLayers[2].mOutputLayerState.shadowRegion = kShadowRegion; + Region accumClearRegion(Rect(10, 11, 12, 13)); + compositionengine::LayerFE::ClientCompositionTargetSettings layer2Settings{ + Region(Rect(50, 40, 70, 80)).merge(Rect(40, 80, 70, 90)), /* visible region */ + false, /* identity transform */ + false, /* needs filtering */ + false, /* secure */ + false, /* supports protected content */ + accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, + }; + EXPECT_CALL(mLayers[0].mOutputLayer, requiresClientComposition()).WillOnce(Return(false)); EXPECT_CALL(mLayers[1].mOutputLayer, requiresClientComposition()).WillOnce(Return(false)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_)) - .WillOnce(Return(mLayers[2].mLayerSettings)); - EXPECT_CALL(mLayers[2].mLayerFE, - prepareShadowClientComposition(mLayers[2].mLayerSettings, kDisplayViewport, - kDisplayDataspace)) - .WillOnce(Return(mShadowSettings)); + EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2Settings)))) + .WillOnce(Return(std::vector( + {mShadowSettings, mLayers[2].mLayerSettings}))); - Region accumClearRegion(Rect(10, 11, 12, 13)); auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */, accumClearRegion, kDisplayDataspace); ASSERT_EQ(2u, requests.size()); diff --git a/services/surfaceflinger/EffectLayer.cpp b/services/surfaceflinger/EffectLayer.cpp index e928c57929..9d45e333d8 100644 --- a/services/surfaceflinger/EffectLayer.cpp +++ b/services/surfaceflinger/EffectLayer.cpp @@ -47,18 +47,35 @@ EffectLayer::EffectLayer(const LayerCreationArgs& args) EffectLayer::~EffectLayer() = default; -std::optional EffectLayer::prepareClientComposition( +std::vector EffectLayer::prepareClientCompositionList( compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) { - auto result = Layer::prepareClientComposition(targetSettings); - if (!result) { - return result; + std::vector results; + std::optional layerSettings = + prepareClientComposition(targetSettings); + // Nothing to render. + if (!layerSettings) { + return {}; } - result->source.solidColor = getColor().rgb; - return result; + + std::optional shadowSettings = + prepareShadowClientComposition(*layerSettings, targetSettings.viewport, + targetSettings.dataspace); + if (shadowSettings) { + results.push_back(*shadowSettings); + } + + // If fill bounds are occluded or the fill color is invalid skip the fill settings. + if (targetSettings.realContentIsVisible && fillsColor()) { + // Set color for color fill settings. + layerSettings->source.solidColor = getColor().rgb; + results.push_back(*layerSettings); + } + + return results; } bool EffectLayer::isVisible() const { - return !isHiddenByPolicy() && getAlpha() > 0.0_hf; + return !isHiddenByPolicy() && getAlpha() > 0.0_hf && hasSomethingToDraw(); } bool EffectLayer::setColor(const half3& color) { @@ -126,6 +143,11 @@ sp EffectLayer::createClone() { return layer; } +bool EffectLayer::fillsColor() const { + return mDrawingState.color.r >= 0.0_hf && mDrawingState.color.g >= 0.0_hf && + mDrawingState.color.b >= 0.0_hf; +} + } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/EffectLayer.h b/services/surfaceflinger/EffectLayer.h index 8694283760..33758b6378 100644 --- a/services/surfaceflinger/EffectLayer.h +++ b/services/surfaceflinger/EffectLayer.h @@ -52,12 +52,17 @@ protected: */ const compositionengine::LayerFECompositionState* getCompositionState() const override; void preparePerFrameCompositionState() override; - std::optional prepareClientComposition( - compositionengine::LayerFE::ClientCompositionTargetSettings&) override; + std::vector prepareClientCompositionList( + compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) override; std::unique_ptr mCompositionState; sp createClone() override; + +private: + // Returns true if there is a valid color to fill. + bool fillsColor() const; + bool hasSomethingToDraw() const { return fillsColor() || drawShadows(); } }; } // namespace android diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 8eb5c22fa8..5073a9231b 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -492,13 +492,12 @@ void Layer::preparePerFrameCompositionState() { compositionState->hasProtectedContent = isProtected(); const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f; - const bool drawsShadows = mEffectiveShadowRadius != 0.f; compositionState->isOpaque = isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf; // Force client composition for special cases known only to the front-end. - if (isHdrY410() || usesRoundedCorners || drawsShadows) { + if (isHdrY410() || usesRoundedCorners || drawShadows()) { compositionState->forceClientComposition = true; } } @@ -653,6 +652,49 @@ std::optional Layer::prepareShadowCli return shadowLayer; } +void Layer::prepareClearClientComposition(LayerFE::LayerSettings& layerSettings, + bool blackout) const { + layerSettings.source.buffer.buffer = nullptr; + layerSettings.source.solidColor = half3(0.0, 0.0, 0.0); + layerSettings.disableBlending = true; + layerSettings.frameNumber = 0; + + // If layer is blacked out, force alpha to 1 so that we draw a black color layer. + layerSettings.alpha = blackout ? 1.0f : 0.0f; +} + +std::vector Layer::prepareClientCompositionList( + compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) { + std::optional layerSettings = + prepareClientComposition(targetSettings); + // Nothing to render. + if (!layerSettings) { + return {}; + } + + // HWC requests to clear this layer. + if (targetSettings.clearContent) { + prepareClearClientComposition(*layerSettings, false /* blackout */); + return {*layerSettings}; + } + + std::optional shadowSettings = + prepareShadowClientComposition(*layerSettings, targetSettings.viewport, + targetSettings.dataspace); + // There are no shadows to render. + if (!shadowSettings) { + return {*layerSettings}; + } + + // If the layer casts a shadow but the content casting the shadow is occluded, skip + // composing the non-shadow content and only draw the shadows. + if (targetSettings.realContentIsVisible) { + return {*shadowSettings, *layerSettings}; + } + + return {*shadowSettings}; +} + Hwc2::IComposerClient::Composition Layer::getCompositionType( const sp& display) const { const auto outputLayer = findOutputLayerForDisplay(display); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index a249726739..1689881c8d 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -552,6 +552,14 @@ protected: void updateClonedRelatives(const std::map, sp>& clonedLayersMap); void addChildToDrawing(const sp& layer); void updateClonedInputInfo(const std::map, sp>& clonedLayersMap); + virtual std::optional prepareClientComposition( + compositionengine::LayerFE::ClientCompositionTargetSettings&); + virtual std::optional prepareShadowClientComposition( + const LayerFE::LayerSettings& layerSettings, const Rect& displayViewport, + ui::Dataspace outputDataspace); + // Modifies the passed in layer settings to clear the contents. If the blackout flag is set, + // the settings clears the content with a solid black fill. + void prepareClearClientComposition(LayerFE::LayerSettings& layerSettings, bool blackout) const; public: /* @@ -560,11 +568,8 @@ public: const compositionengine::LayerFECompositionState* getCompositionState() const override; bool onPreComposition(nsecs_t) override; void prepareCompositionState(compositionengine::LayerFE::StateSubset subset) override; - std::optional prepareClientComposition( + std::vector prepareClientCompositionList( compositionengine::LayerFE::ClientCompositionTargetSettings&) override; - std::optional prepareShadowClientComposition( - const LayerFE::LayerSettings& layerSettings, const Rect& displayViewport, - ui::Dataspace outputDataspace) override; void onLayerDisplayed(const sp& releaseFence) override; const char* getDebugName() const override; @@ -704,6 +709,7 @@ public: half getAlpha() const; half4 getColor() const; int32_t getBackgroundBlurRadius() const; + bool drawShadows() const { return mEffectiveShadowRadius > 0.f; }; // Returns how rounded corners should be drawn for this layer. // This will traverse the hierarchy until it reaches its root, finding topmost rounded diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 55166c0ab3..ff4a6529fa 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5545,17 +5545,18 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, renderArea.isSecure(), supportProtectedContent, clearRegion, + displayViewport, + clientCompositionDisplay.outputDataspace, + true, /* realContentIsVisible */ + false, /* clearContent */ }; - auto result = layer->prepareClientComposition(targetSettings); - if (result) { - std::optional shadowLayer = - layer->prepareShadowClientComposition(*result, displayViewport, - clientCompositionDisplay.outputDataspace); - if (shadowLayer) { - clientCompositionLayers.push_back(*shadowLayer); - } - clientCompositionLayers.push_back(*result); - } + std::vector results = + layer->prepareClientCompositionList(targetSettings); + clientCompositionLayers.insert(clientCompositionLayers.end(), + std::make_move_iterator(results.begin()), + std::make_move_iterator(results.end())); + results.clear(); + }); std::vector clientCompositionLayerPointers; diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp index 6c8eb27bd0..83e5060830 100644 --- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp @@ -747,12 +747,26 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorClamped) { ISurfaceComposerClient::eFXSurfaceEffect)); Transaction() .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)) - .setColor(colorLayer, half3(2.0f, -1.0f, 0.0f)) + .setColor(colorLayer, half3(2.0f, 0.0f, 0.0f)) .apply(); getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); } +// An invalid color will not render a color and the layer will not be visible. +TEST_P(LayerRenderTypeTransactionTest, SetInvalidColor) { + sp colorLayer; + ASSERT_NO_FATAL_FAILURE(colorLayer = + createLayer("test", 0 /* buffer width */, 0 /* buffer height */, + ISurfaceComposerClient::eFXSurfaceEffect)); + Transaction() + .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)) + .setColor(colorLayer, half3(1.0f, -1.0f, 0.5f)) + .apply(); + + getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK); +} + TEST_P(LayerRenderTypeTransactionTest, SetColorWithAlpha) { sp bufferLayer; sp colorLayer; -- cgit v1.2.3-59-g8ed1b From b83097dd02257962bb94ffcf323671e476c3560c Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Tue, 18 Feb 2020 19:49:27 -0800 Subject: Enable effect layers with blur Change-Id: Ia13f0b6d816aa918433297567735482dc5b3502e Test: launch apps Bug: 149792636 Fixes: 148804546 --- services/surfaceflinger/EffectLayer.cpp | 6 ++++++ services/surfaceflinger/EffectLayer.h | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'services/surfaceflinger/EffectLayer.cpp') diff --git a/services/surfaceflinger/EffectLayer.cpp b/services/surfaceflinger/EffectLayer.cpp index 9d45e333d8..44d4d756e0 100644 --- a/services/surfaceflinger/EffectLayer.cpp +++ b/services/surfaceflinger/EffectLayer.cpp @@ -69,6 +69,8 @@ std::vector EffectLayer::prepareClien // Set color for color fill settings. layerSettings->source.solidColor = getColor().rgb; results.push_back(*layerSettings); + } else if (hasBlur()) { + results.push_back(*layerSettings); } return results; @@ -148,6 +150,10 @@ bool EffectLayer::fillsColor() const { mDrawingState.color.b >= 0.0_hf; } +bool EffectLayer::hasBlur() const { + return getBackgroundBlurRadius() > 0; +} + } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/EffectLayer.h b/services/surfaceflinger/EffectLayer.h index 33758b6378..1dcb633251 100644 --- a/services/surfaceflinger/EffectLayer.h +++ b/services/surfaceflinger/EffectLayer.h @@ -62,7 +62,9 @@ protected: private: // Returns true if there is a valid color to fill. bool fillsColor() const; - bool hasSomethingToDraw() const { return fillsColor() || drawShadows(); } + // Returns true if this layer has a blur value. + bool hasBlur() const; + bool hasSomethingToDraw() const { return fillsColor() || drawShadows() || hasBlur(); } }; } // namespace android -- cgit v1.2.3-59-g8ed1b