diff options
author | 2024-01-10 10:17:00 +0000 | |
---|---|---|
committer | 2024-07-04 09:17:37 +0000 | |
commit | dcc9d9b5cf697d238cbdca93a99a7a3aa48281fe (patch) | |
tree | 79722303a0656bfa6ae05b215967c60ef9ef7bbf | |
parent | 5b85b9733a6f74e080085feb0faa41519de62704 (diff) |
Edge extension effect: shader reimplementation
X-axis activity transitions require the translation of the surfaces
involved. As this movement would create unwanted see-through, we would
have added side windows anchored to the moving activities, and textured
them by clamping their parents.
We are replacing the additional windows with the extension of the
surfaces, and filling the area without buffer with a shader.
See go/edge-extension-sksl for more info.
Bug: 322036393
Test: LayerSnapshotTest
Flag: EXEMPT (calls will be protected by wm shell with com.android.window.flags.edge_extension_shader)
Change-Id: I3682efd16a1b311d67a522bb85960f100948b2ea
19 files changed, 413 insertions, 31 deletions
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 3745805aa3..307ae3990e 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -177,6 +177,7 @@ status_t layer_state_t::write(Parcel& output) const } SAFE_PARCEL(output.write, stretchEffect); + SAFE_PARCEL(output.writeParcelable, edgeExtensionParameters); SAFE_PARCEL(output.write, bufferCrop); SAFE_PARCEL(output.write, destinationFrame); SAFE_PARCEL(output.writeInt32, static_cast<uint32_t>(trustedOverlay)); @@ -306,6 +307,7 @@ status_t layer_state_t::read(const Parcel& input) } SAFE_PARCEL(input.read, stretchEffect); + SAFE_PARCEL(input.readParcelable, &edgeExtensionParameters); SAFE_PARCEL(input.read, bufferCrop); SAFE_PARCEL(input.read, destinationFrame); uint32_t trustedOverlayInt; @@ -682,6 +684,10 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eStretchChanged; stretchEffect = other.stretchEffect; } + if (other.what & eEdgeExtensionChanged) { + what |= eEdgeExtensionChanged; + edgeExtensionParameters = other.edgeExtensionParameters; + } if (other.what & eBufferCropChanged) { what |= eBufferCropChanged; bufferCrop = other.bufferCrop; @@ -783,6 +789,7 @@ uint64_t layer_state_t::diff(const layer_state_t& other) const { CHECK_DIFF(diff, eAutoRefreshChanged, other, autoRefresh); CHECK_DIFF(diff, eTrustedOverlayChanged, other, trustedOverlay); CHECK_DIFF(diff, eStretchChanged, other, stretchEffect); + CHECK_DIFF(diff, eEdgeExtensionChanged, other, edgeExtensionParameters); CHECK_DIFF(diff, eBufferCropChanged, other, bufferCrop); CHECK_DIFF(diff, eDestinationFrameChanged, other, destinationFrame); if (other.what & eProducerDisconnect) diff |= eProducerDisconnect; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 902684cf03..88d3a7cb1d 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -22,6 +22,7 @@ #include <android/gui/BnWindowInfosReportedListener.h> #include <android/gui/DisplayState.h> +#include <android/gui/EdgeExtensionParameters.h> #include <android/gui/ISurfaceComposerClient.h> #include <android/gui/IWindowInfosListener.h> #include <android/gui/TrustedPresentationThresholds.h> @@ -2330,6 +2331,19 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setStret return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setEdgeExtensionEffect( + const sp<SurfaceControl>& sc, const gui::EdgeExtensionParameters& effect) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + + s->what |= layer_state_t::eEdgeExtensionChanged; + s->edgeExtensionParameters = effect; + return *this; +} + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBufferCrop( const sp<SurfaceControl>& sc, const Rect& bufferCrop) { layer_state_t* s = getLayerState(sc); diff --git a/libs/gui/aidl/android/gui/EdgeExtensionParameters.aidl b/libs/gui/aidl/android/gui/EdgeExtensionParameters.aidl new file mode 100644 index 0000000000..44f4259f74 --- /dev/null +++ b/libs/gui/aidl/android/gui/EdgeExtensionParameters.aidl @@ -0,0 +1,27 @@ +/* + * Copyright 2024 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. + */ + +package android.gui; + + +/** @hide */ +parcelable EdgeExtensionParameters { + // These represent the translation of the window as requested by the animation + boolean extendRight; + boolean extendLeft; + boolean extendTop; + boolean extendBottom; +}
\ No newline at end of file diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 5f2f8dc013..3fb1894585 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -29,6 +29,7 @@ #include <math/mat4.h> #include <android/gui/DropInputMode.h> +#include <android/gui/EdgeExtensionParameters.h> #include <android/gui/FocusRequest.h> #include <android/gui/TrustedOverlay.h> @@ -218,6 +219,7 @@ struct layer_state_t { eTrustedOverlayChanged = 0x4000'00000000, eDropInputModeChanged = 0x8000'00000000, eExtendedRangeBrightnessChanged = 0x10000'00000000, + eEdgeExtensionChanged = 0x20000'00000000, }; layer_state_t(); @@ -241,7 +243,7 @@ struct layer_state_t { layer_state_t::eCropChanged | layer_state_t::eDestinationFrameChanged | layer_state_t::eMatrixChanged | layer_state_t::ePositionChanged | layer_state_t::eTransformToDisplayInverseChanged | - layer_state_t::eTransparentRegionChanged; + layer_state_t::eTransparentRegionChanged | layer_state_t::eEdgeExtensionChanged; // Buffer and related updates. static constexpr uint64_t BUFFER_CHANGES = layer_state_t::eApiChanged | @@ -393,6 +395,9 @@ struct layer_state_t { // Stretch effect to be applied to this layer StretchEffect stretchEffect; + // Edge extension effect to be applied to this layer + gui::EdgeExtensionParameters edgeExtensionParameters; + Rect bufferCrop; Rect destinationFrame; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 88c0c53e12..a10283b371 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -35,6 +35,7 @@ #include <ui/BlurRegion.h> #include <ui/ConfigStoreTypes.h> #include <ui/DisplayedFrameStats.h> +#include <ui/EdgeExtensionEffect.h> #include <ui/FrameStats.h> #include <ui/GraphicTypes.h> #include <ui/PixelFormat.h> @@ -744,6 +745,17 @@ public: Transaction& setStretchEffect(const sp<SurfaceControl>& sc, const StretchEffect& stretchEffect); + /** + * Provides the edge extension effect configured on a container that the + * surface is rendered within. + * @param sc target surface the edge extension should be applied to + * @param effect the corresponding EdgeExtensionParameters to be applied + * to the surface. + * @return The transaction being constructed + */ + Transaction& setEdgeExtensionEffect(const sp<SurfaceControl>& sc, + const gui::EdgeExtensionParameters& effect); + Transaction& setBufferCrop(const sp<SurfaceControl>& sc, const Rect& bufferCrop); Transaction& setDestinationFrame(const sp<SurfaceControl>& sc, const Rect& destinationFrame); diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index 4a04467308..ecf98c6696 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -105,6 +105,7 @@ filegroup { "skia/filters/LinearEffect.cpp", "skia/filters/MouriMap.cpp", "skia/filters/StretchShaderFactory.cpp", + "skia/filters/EdgeExtensionShaderFactory.cpp", ], } diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h index 8ac0af47c6..859ae8b6e2 100644 --- a/libs/renderengine/include/renderengine/LayerSettings.h +++ b/libs/renderengine/include/renderengine/LayerSettings.h @@ -31,6 +31,7 @@ #include <ui/ShadowSettings.h> #include <ui/StretchEffect.h> #include <ui/Transform.h> +#include "ui/EdgeExtensionEffect.h" #include <iosfwd> @@ -134,6 +135,7 @@ struct LayerSettings { mat4 blurRegionTransform = mat4(); StretchEffect stretchEffect; + EdgeExtensionEffect edgeExtensionEffect; // Name associated with the layer for debugging purposes. std::string name; @@ -183,7 +185,9 @@ static inline bool operator==(const LayerSettings& lhs, const LayerSettings& rhs lhs.skipContentDraw == rhs.skipContentDraw && lhs.shadow == rhs.shadow && lhs.backgroundBlurRadius == rhs.backgroundBlurRadius && lhs.blurRegionTransform == rhs.blurRegionTransform && - lhs.stretchEffect == rhs.stretchEffect && lhs.whitePointNits == rhs.whitePointNits; + lhs.stretchEffect == rhs.stretchEffect && + lhs.edgeExtensionEffect == rhs.edgeExtensionEffect && + lhs.whitePointNits == rhs.whitePointNits; } static inline void PrintTo(const Buffer& settings, ::std::ostream* os) { @@ -254,6 +258,10 @@ static inline void PrintTo(const StretchEffect& effect, ::std::ostream* os) { *os << "\n}"; } +static inline void PrintTo(const EdgeExtensionEffect& effect, ::std::ostream* os) { + *os << effect; +} + static inline void PrintTo(const LayerSettings& settings, ::std::ostream* os) { *os << "LayerSettings for '" << settings.name.c_str() << "' {"; *os << "\n .geometry = "; @@ -285,6 +293,10 @@ static inline void PrintTo(const LayerSettings& settings, ::std::ostream* os) { *os << "\n .stretchEffect = "; PrintTo(settings.stretchEffect, os); } + + if (settings.edgeExtensionEffect.hasEffect()) { + *os << "\n .edgeExtensionEffect = " << settings.edgeExtensionEffect; + } *os << "\n .whitePointNits = " << settings.whitePointNits; *os << "\n}"; } diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp index 5f37125d16..a609f2d2b3 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaRenderEngine.cpp @@ -507,16 +507,24 @@ sk_sp<SkShader> SkiaRenderEngine::createRuntimeEffectShader( const RuntimeEffectShaderParameters& parameters) { // The given surface will be stretched by HWUI via matrix transformation // which gets similar results for most surfaces - // Determine later on if we need to leverage the stertch shader within + // Determine later on if we need to leverage the stretch shader within // surface flinger const auto& stretchEffect = parameters.layer.stretchEffect; const auto& targetBuffer = parameters.layer.source.buffer.buffer; + const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr; + auto shader = parameters.shader; - if (stretchEffect.hasEffect()) { - const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr; - if (graphicBuffer && shader) { + if (graphicBuffer && parameters.shader) { + if (stretchEffect.hasEffect()) { shader = mStretchShaderFactory.createSkShader(shader, stretchEffect); } + // The given surface requires to be filled outside of its buffer bounds if the edge + // extension is required + const auto& edgeExtensionEffect = parameters.layer.edgeExtensionEffect; + if (edgeExtensionEffect.hasEffect()) { + shader = mEdgeExtensionShaderFactory.createSkShader(shader, parameters.layer, + parameters.imageBounds); + } } if (parameters.requiresLinearEffect) { @@ -566,8 +574,6 @@ sk_sp<SkShader> SkiaRenderEngine::createRuntimeEffectShader( parameters.layerDimmingRatio, 1.f)); } - const auto targetBuffer = parameters.layer.source.buffer.buffer; - const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr; const auto hardwareBuffer = graphicBuffer ? graphicBuffer->toAHardwareBuffer() : nullptr; return createLinearEffectShader(shader, effect, runtimeEffect, std::move(colorTransform), parameters.display.maxLuminance, @@ -1039,18 +1045,20 @@ void SkiaRenderEngine::drawLayersInternal( toSkColorSpace(layerDataspace))); } - paint.setShader(createRuntimeEffectShader( - RuntimeEffectShaderParameters{.shader = shader, - .layer = layer, - .display = display, - .undoPremultipliedAlpha = !item.isOpaque && - item.usePremultipliedAlpha, - .requiresLinearEffect = requiresLinearEffect, - .layerDimmingRatio = dimInLinearSpace - ? layerDimmingRatio - : 1.f, - .outputDataSpace = display.outputDataspace, - .fakeOutputDataspace = fakeDataspace})); + SkRect imageBounds; + matrix.mapRect(&imageBounds, SkRect::Make(image->bounds())); + + paint.setShader(createRuntimeEffectShader(RuntimeEffectShaderParameters{ + .shader = shader, + .layer = layer, + .display = display, + .undoPremultipliedAlpha = !item.isOpaque && item.usePremultipliedAlpha, + .requiresLinearEffect = requiresLinearEffect, + .layerDimmingRatio = dimInLinearSpace ? layerDimmingRatio : 1.f, + .outputDataSpace = display.outputDataspace, + .fakeOutputDataspace = fakeDataspace, + .imageBounds = imageBounds, + })); // Turn on dithering when dimming beyond this (arbitrary) threshold... static constexpr float kDimmingThreshold = 0.9f; @@ -1118,7 +1126,8 @@ void SkiaRenderEngine::drawLayersInternal( .requiresLinearEffect = requiresLinearEffect, .layerDimmingRatio = layerDimmingRatio, .outputDataSpace = display.outputDataspace, - .fakeOutputDataspace = fakeDataspace})); + .fakeOutputDataspace = fakeDataspace, + .imageBounds = SkRect::MakeEmpty()})); } if (layer.disableBlending) { diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h index c8f9241257..224a1cad92 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.h +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -38,6 +38,7 @@ #include "compat/SkiaGpuContext.h" #include "debug/SkiaCapture.h" #include "filters/BlurFilter.h" +#include "filters/EdgeExtensionShaderFactory.h" #include "filters/LinearEffect.h" #include "filters/StretchShaderFactory.h" @@ -156,6 +157,7 @@ private: float layerDimmingRatio; const ui::Dataspace outputDataSpace; const ui::Dataspace fakeOutputDataspace; + const SkRect& imageBounds; }; sk_sp<SkShader> createRuntimeEffectShader(const RuntimeEffectShaderParameters&); @@ -175,6 +177,7 @@ private: AutoBackendTexture::CleanupManager mTextureCleanupMgr GUARDED_BY(mRenderingMutex); StretchShaderFactory mStretchShaderFactory; + EdgeExtensionShaderFactory mEdgeExtensionShaderFactory; sp<Fence> mLastDrawFence; BlurFilter* mBlurFilter = nullptr; diff --git a/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.cpp b/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.cpp new file mode 100644 index 0000000000..1dbcc29190 --- /dev/null +++ b/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2024 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. + */ + +#include "EdgeExtensionShaderFactory.h" +#include <SkPoint.h> +#include <SkRuntimeEffect.h> +#include <SkStream.h> +#include <SkString.h> +#include "log/log_main.h" + +namespace android::renderengine::skia { + +static const SkString edgeShader = SkString(R"( + uniform shader uContentTexture; + uniform vec2 uImgSize; + + // TODO(b/214232209) oobTolerance is temporary and will be removed when the scrollbar will be + // hidden during the animation + const float oobTolerance = 15; + const int blurRadius = 3; + const float blurArea = float((2 * blurRadius + 1) * (2 * blurRadius + 1)); + + vec4 boxBlur(vec2 p) { + vec4 sumColors = vec4(0); + + for (int i = -blurRadius; i <= blurRadius; i++) { + for (int j = -blurRadius; j <= blurRadius; j++) { + sumColors += uContentTexture.eval(p + vec2(i, j)); + } + } + return sumColors / blurArea; + } + + vec4 main(vec2 coord) { + vec2 nearestTexturePoint = clamp(coord, vec2(0, 0), uImgSize); + if (coord == nearestTexturePoint) { + return uContentTexture.eval(coord); + } else { + vec2 samplePoint = nearestTexturePoint + oobTolerance * normalize( + nearestTexturePoint - coord); + return boxBlur(samplePoint); + } + } +)"); + +sk_sp<SkShader> EdgeExtensionShaderFactory::createSkShader(const sk_sp<SkShader>& inputShader, + const LayerSettings& layer, + const SkRect& imageBounds) { + if (mBuilder == nullptr) { + const static SkRuntimeEffect::Result instance = SkRuntimeEffect::MakeForShader(edgeShader); + if (!instance.errorText.isEmpty()) { + ALOGE("EdgeExtensionShaderFactory terminated with an error: %s", + instance.errorText.c_str()); + return nullptr; + } + mBuilder = std::make_unique<SkRuntimeShaderBuilder>(instance.effect); + } + mBuilder->child("uContentTexture") = inputShader; + if (imageBounds.isEmpty()) { + mBuilder->uniform("uImgSize") = SkPoint{layer.geometry.boundaries.getWidth(), + layer.geometry.boundaries.getHeight()}; + } else { + mBuilder->uniform("uImgSize") = SkPoint{imageBounds.width(), imageBounds.height()}; + } + return mBuilder->makeShader(); +} +} // namespace android::renderengine::skia
\ No newline at end of file diff --git a/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.h b/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.h new file mode 100644 index 0000000000..b0a8a9357e --- /dev/null +++ b/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2024 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. + */ + +#pragma once + +#include <SkImage.h> +#include <SkRect.h> +#include <SkRuntimeEffect.h> +#include <SkShader.h> +#include <renderengine/LayerSettings.h> +#include <ui/EdgeExtensionEffect.h> + +namespace android::renderengine::skia { + +/** + * This shader is designed to prolong the texture of a surface whose bounds have been extended over + * the size of the texture. This shader is similar to the default clamp, but adds a blur effect and + * samples from close to the edge (compared to on the edge) to avoid weird artifacts when elements + * (in particular, scrollbars) touch the edge. + */ +class EdgeExtensionShaderFactory { +public: + sk_sp<SkShader> createSkShader(const sk_sp<SkShader>& inputShader, const LayerSettings& layer, + const SkRect& imageBounds); + +private: + std::unique_ptr<SkRuntimeShaderBuilder> mBuilder; +}; +} // namespace android::renderengine::skia diff --git a/libs/ui/include/ui/EdgeExtensionEffect.h b/libs/ui/include/ui/EdgeExtensionEffect.h new file mode 100644 index 0000000000..02126b12be --- /dev/null +++ b/libs/ui/include/ui/EdgeExtensionEffect.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2024 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. + */ + +#pragma once + +/** + * Stores the edge that will be extended + */ +namespace android { + +enum CanonicalDirections { NONE = 0, LEFT = 1, RIGHT = 2, TOP = 4, BOTTOM = 8 }; + +inline std::string to_string(CanonicalDirections direction) { + switch (direction) { + case LEFT: + return "LEFT"; + case RIGHT: + return "RIGHT"; + case TOP: + return "TOP"; + case BOTTOM: + return "BOTTOM"; + case NONE: + return "NONE"; + } +} + +struct EdgeExtensionEffect { + EdgeExtensionEffect(bool left, bool right, bool top, bool bottom) { + extensionEdges = NONE; + if (left) { + extensionEdges |= LEFT; + } + if (right) { + extensionEdges |= RIGHT; + } + if (top) { + extensionEdges |= TOP; + } + if (bottom) { + extensionEdges |= BOTTOM; + } + } + + EdgeExtensionEffect() { EdgeExtensionEffect(false, false, false, false); } + + bool extendsEdge(CanonicalDirections edge) const { return extensionEdges & edge; } + + bool hasEffect() const { return extensionEdges != NONE; }; + + void reset() { extensionEdges = NONE; } + + bool operator==(const EdgeExtensionEffect& other) const { + return extensionEdges == other.extensionEdges; + } + + bool operator!=(const EdgeExtensionEffect& other) const { return !(*this == other); } + +private: + int extensionEdges; +}; + +inline std::string to_string(const EdgeExtensionEffect& effect) { + std::string s = "EdgeExtensionEffect={edges=["; + if (effect.hasEffect()) { + for (CanonicalDirections edge : {LEFT, RIGHT, TOP, BOTTOM}) { + if (effect.extendsEdge(edge)) { + s += to_string(edge) + ", "; + } + } + } else { + s += to_string(NONE); + } + s += "]}"; + return s; +} + +inline std::ostream& operator<<(std::ostream& os, const EdgeExtensionEffect effect) { + os << to_string(effect); + return os; +} +} // namespace android diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h index 11759b855f..d1429a2ec6 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -35,6 +35,7 @@ #pragma clang diagnostic ignored "-Wextra" #include <gui/BufferQueue.h> +#include <ui/EdgeExtensionEffect.h> #include <ui/GraphicBuffer.h> #include <ui/GraphicTypes.h> #include <ui/StretchEffect.h> @@ -133,12 +134,16 @@ struct LayerFECompositionState { // The bounds of the layer in layer local coordinates FloatRect geomLayerBounds; + // The crop to apply to the layer in layer local coordinates + FloatRect geomLayerCrop; + ShadowSettings shadowSettings; // List of regions that require blur std::vector<BlurRegion> blurRegions; StretchEffect stretchEffect; + EdgeExtensionEffect edgeExtensionEffect; /* * Geometry state diff --git a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp index bdaa1d0ae1..d9018bc3ab 100644 --- a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp +++ b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp @@ -37,7 +37,8 @@ inline bool equalIgnoringSource(const renderengine::LayerSettings& lhs, lhs.colorTransform == rhs.colorTransform && lhs.disableBlending == rhs.disableBlending && lhs.shadow == rhs.shadow && lhs.backgroundBlurRadius == rhs.backgroundBlurRadius && - lhs.stretchEffect == rhs.stretchEffect; + lhs.stretchEffect == rhs.stretchEffect && + lhs.edgeExtensionEffect == rhs.edgeExtensionEffect; } inline bool equalIgnoringBuffer(const renderengine::Buffer& lhs, const renderengine::Buffer& rhs) { diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp index 70e3c64a0f..e5f6b7bcd1 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp @@ -322,6 +322,10 @@ std::ostream& operator<<(std::ostream& out, const LayerSnapshot& obj) { << touchableRegion.bottom << "," << touchableRegion.right << "}" << "}"; } + + if (obj.edgeExtensionEffect.hasEffect()) { + out << obj.edgeExtensionEffect; + } return out; } @@ -492,8 +496,10 @@ void LayerSnapshot::merge(const RequestedLayerState& requested, bool forceUpdate requested.what & (layer_state_t::eBufferChanged | layer_state_t::eDataspaceChanged | layer_state_t::eApiChanged | layer_state_t::eShadowRadiusChanged | - layer_state_t::eBlurRegionsChanged | layer_state_t::eStretchChanged)) { - forceClientComposition = shadowSettings.length > 0 || stretchEffect.hasEffect(); + layer_state_t::eBlurRegionsChanged | layer_state_t::eStretchChanged | + layer_state_t::eEdgeExtensionChanged)) { + forceClientComposition = shadowSettings.length > 0 || stretchEffect.hasEffect() || + edgeExtensionEffect.hasEffect(); } if (forceUpdate || diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index 2b1b2c85b3..4e093816dd 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -367,6 +367,7 @@ LayerSnapshot LayerSnapshotBuilder::getRootSnapshot() { snapshot.geomLayerBounds = getMaxDisplayBounds({}); snapshot.roundedCorner = RoundedCornerState(); snapshot.stretchEffect = {}; + snapshot.edgeExtensionEffect = {}; snapshot.outputFilter.layerStack = ui::DEFAULT_LAYER_STACK; snapshot.outputFilter.toInternalDisplay = false; snapshot.isSecure = false; @@ -811,6 +812,32 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a : parentSnapshot.stretchEffect; } + if (forceUpdate || + (snapshot.clientChanges | parentSnapshot.clientChanges) & + layer_state_t::eEdgeExtensionChanged) { + if (requested.edgeExtensionParameters.extendLeft || + requested.edgeExtensionParameters.extendRight || + requested.edgeExtensionParameters.extendTop || + requested.edgeExtensionParameters.extendBottom) { + // This is the root layer to which the extension is applied + snapshot.edgeExtensionEffect = + EdgeExtensionEffect(requested.edgeExtensionParameters.extendLeft, + requested.edgeExtensionParameters.extendRight, + requested.edgeExtensionParameters.extendTop, + requested.edgeExtensionParameters.extendBottom); + } else if (parentSnapshot.clientChanges & layer_state_t::eEdgeExtensionChanged) { + // Extension is inherited + snapshot.edgeExtensionEffect = parentSnapshot.edgeExtensionEffect; + } else { + // There is no edge extension + snapshot.edgeExtensionEffect.reset(); + } + if (snapshot.edgeExtensionEffect.hasEffect()) { + snapshot.clientChanges |= layer_state_t::eEdgeExtensionChanged; + snapshot.changes |= RequestedLayerState::Changes::Geometry; + } + } + if (forceUpdate || snapshot.clientChanges & layer_state_t::eColorTransformChanged) { if (!parentSnapshot.colorTransformIsIdentity) { snapshot.colorTransform = parentSnapshot.colorTransform * requested.colorTransform; @@ -899,6 +926,10 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a updateLayerBounds(snapshot, requested, parentSnapshot, primaryDisplayRotationFlags); } + if (snapshot.edgeExtensionEffect.hasEffect()) { + updateBoundsForEdgeExtension(snapshot); + } + if (forceUpdate || snapshot.clientChanges & layer_state_t::eCornerRadiusChanged || snapshot.changes.any(RequestedLayerState::Changes::Geometry | RequestedLayerState::Changes::BufferUsageFlags)) { @@ -917,8 +948,8 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a } // computed snapshot properties - snapshot.forceClientComposition = - snapshot.shadowSettings.length > 0 || snapshot.stretchEffect.hasEffect(); + snapshot.forceClientComposition = snapshot.shadowSettings.length > 0 || + snapshot.stretchEffect.hasEffect() || snapshot.edgeExtensionEffect.hasEffect(); snapshot.contentOpaque = snapshot.isContentOpaque(); snapshot.isOpaque = snapshot.contentOpaque && !snapshot.roundedCorner.hasRoundedCorners() && snapshot.color.a == 1.f; @@ -973,6 +1004,31 @@ void LayerSnapshotBuilder::updateRoundedCorner(LayerSnapshot& snapshot, } } +/** + * According to the edges that we are requested to extend, we increase the bounds to the maximum + * extension allowed by the crop (parent crop + requested crop). The animation that called + * Transition#setEdgeExtensionEffect is in charge of setting the requested crop. + * @param snapshot + */ +void LayerSnapshotBuilder::updateBoundsForEdgeExtension(LayerSnapshot& snapshot) { + EdgeExtensionEffect& effect = snapshot.edgeExtensionEffect; + + if (effect.extendsEdge(LEFT)) { + snapshot.geomLayerBounds.left = snapshot.geomLayerCrop.left; + } + if (effect.extendsEdge(RIGHT)) { + snapshot.geomLayerBounds.right = snapshot.geomLayerCrop.right; + } + if (effect.extendsEdge(TOP)) { + snapshot.geomLayerBounds.top = snapshot.geomLayerCrop.top; + } + if (effect.extendsEdge(BOTTOM)) { + snapshot.geomLayerBounds.bottom = snapshot.geomLayerCrop.bottom; + } + + snapshot.transformedBounds = snapshot.geomLayerTransform.transform(snapshot.geomLayerBounds); +} + void LayerSnapshotBuilder::updateLayerBounds(LayerSnapshot& snapshot, const RequestedLayerState& requested, const LayerSnapshot& parentSnapshot, @@ -1012,11 +1068,12 @@ void LayerSnapshotBuilder::updateLayerBounds(LayerSnapshot& snapshot, FloatRect parentBounds = parentSnapshot.geomLayerBounds; parentBounds = snapshot.localTransform.inverse().transform(parentBounds); snapshot.geomLayerBounds = - (requested.externalTexture) ? snapshot.bufferSize.toFloatRect() : parentBounds; + requested.externalTexture ? snapshot.bufferSize.toFloatRect() : parentBounds; + snapshot.geomLayerCrop = parentBounds; if (!requested.crop.isEmpty()) { - snapshot.geomLayerBounds = snapshot.geomLayerBounds.intersect(requested.crop.toFloatRect()); + snapshot.geomLayerCrop = snapshot.geomLayerCrop.intersect(requested.crop.toFloatRect()); } - snapshot.geomLayerBounds = snapshot.geomLayerBounds.intersect(parentBounds); + snapshot.geomLayerBounds = snapshot.geomLayerBounds.intersect(snapshot.geomLayerCrop); snapshot.transformedBounds = snapshot.geomLayerTransform.transform(snapshot.geomLayerBounds); const Rect geomLayerBoundsWithoutTransparentRegion = RequestedLayerState::reduce(Rect(snapshot.geomLayerBounds), diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h index dbbad7664a..f3c56a4ef0 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h @@ -113,6 +113,10 @@ private: static void resetRelativeState(LayerSnapshot& snapshot); static void updateRoundedCorner(LayerSnapshot& snapshot, const RequestedLayerState& layerState, const LayerSnapshot& parentSnapshot, const Args& args); + static bool extensionEdgeSharedWithParent(LayerSnapshot& snapshot, + const RequestedLayerState& requested, + const LayerSnapshot& parentSnapshot); + static void updateBoundsForEdgeExtension(LayerSnapshot& snapshot); void updateLayerBounds(LayerSnapshot& snapshot, const RequestedLayerState& layerState, const LayerSnapshot& parentSnapshot, uint32_t displayRotationFlags); static void updateShadows(LayerSnapshot& snapshot, const RequestedLayerState& requested, diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index 17d3f4bf38..17d2610d7a 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -609,8 +609,9 @@ bool RequestedLayerState::isSimpleBufferUpdate(const layer_state_t& s) const { layer_state_t::eSidebandStreamChanged | layer_state_t::eColorSpaceAgnosticChanged | layer_state_t::eShadowRadiusChanged | layer_state_t::eFixedTransformHintChanged | layer_state_t::eTrustedOverlayChanged | layer_state_t::eStretchChanged | - layer_state_t::eBufferCropChanged | layer_state_t::eDestinationFrameChanged | - layer_state_t::eDimmingEnabledChanged | layer_state_t::eExtendedRangeBrightnessChanged | + layer_state_t::eEdgeExtensionChanged | layer_state_t::eBufferCropChanged | + layer_state_t::eDestinationFrameChanged | layer_state_t::eDimmingEnabledChanged | + layer_state_t::eExtendedRangeBrightnessChanged | layer_state_t::eDesiredHdrHeadroomChanged | (FlagManager::getInstance().latch_unsignaled_with_auto_refresh_changed() ? layer_state_t::eFlagsChanged diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp index 8f819b25e0..b05f0eecc4 100644 --- a/services/surfaceflinger/LayerFE.cpp +++ b/services/surfaceflinger/LayerFE.cpp @@ -173,6 +173,7 @@ std::optional<compositionengine::LayerFE::LayerSettings> LayerFE::prepareClientC break; } layerSettings.stretchEffect = mSnapshot->stretchEffect; + layerSettings.edgeExtensionEffect = mSnapshot->edgeExtensionEffect; // Record the name of the layer for debugging further down the stack. layerSettings.name = mSnapshot->name; |