diff options
-rw-r--r-- | libs/gui/LayerDebugInfo.cpp | 8 | ||||
-rw-r--r-- | libs/gui/SurfaceComposerClient.cpp | 8 | ||||
-rw-r--r-- | libs/gui/include/gui/SurfaceComposerClient.h | 17 | ||||
-rw-r--r-- | libs/renderengine/Android.bp | 1 | ||||
-rw-r--r-- | libs/renderengine/include/renderengine/LayerSettings.h | 20 | ||||
-rw-r--r-- | libs/renderengine/skia/SkiaGLRenderEngine.cpp | 63 | ||||
-rw-r--r-- | libs/renderengine/skia/SkiaGLRenderEngine.h | 16 | ||||
-rw-r--r-- | libs/renderengine/skia/filters/StretchShaderFactory.cpp | 247 | ||||
-rw-r--r-- | libs/renderengine/skia/filters/StretchShaderFactory.h | 36 | ||||
-rw-r--r-- | libs/ui/include/ui/StretchEffect.h | 58 | ||||
-rw-r--r-- | services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp | 3 | ||||
-rw-r--r-- | services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp | 6 | ||||
-rw-r--r-- | services/surfaceflinger/Layer.cpp | 2 |
13 files changed, 432 insertions, 53 deletions
diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp index e707684618..0827bbe3ee 100644 --- a/libs/gui/LayerDebugInfo.cpp +++ b/libs/gui/LayerDebugInfo.cpp @@ -119,9 +119,11 @@ std::string to_string(const LayerDebugInfo& info) { info.mSurfaceDamageRegion.dump(result, "SurfaceDamageRegion"); if (info.mStretchEffect.hasEffect()) { const auto& se = info.mStretchEffect; - StringAppendF(&result, " StretchEffect area=[%f, %f, %f, %f] vec=(%f, %f) maxAmount=%f\n", - se.area.left, se.area.top, se.area.right, se.area.bottom, se.vectorX, - se.vectorY, se.maxAmount); + StringAppendF(&result, + " StretchEffect width = %f, height = %f vec=(%f, %f) " + "maxAmount=(%f, %f)\n", + se.width, se.height, + se.vectorX, se.vectorY, se.maxAmountX, se.maxAmountY); } StringAppendF(&result, " layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), ", diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 808b731d8f..11b8ebac81 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1648,8 +1648,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setApply } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setStretchEffect( - const sp<SurfaceControl>& sc, float left, float top, float right, float bottom, float vecX, - float vecY, float maxAmount) { + const sp<SurfaceControl>& sc, const StretchEffect& stretchEffect) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; @@ -1657,10 +1656,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setStret } s->what |= layer_state_t::eStretchChanged; - s->stretchEffect = StretchEffect{.area = {left, top, right, bottom}, - .vectorX = vecX, - .vectorY = vecY, - .maxAmount = maxAmount}; + s->stretchEffect = stretchEffect; return *this; } diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index f3439c4c84..35757be988 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -538,9 +538,20 @@ public: // transactions from blocking each other. Transaction& setApplyToken(const sp<IBinder>& token); - Transaction& setStretchEffect(const sp<SurfaceControl>& sc, float left, float top, - float right, float bottom, float vecX, float vecY, - float maxAmount); + /** + * Provides the stretch effect configured on a container that the + * surface is rendered within. + * @param sc target surface the stretch should be applied to + * @param stretchEffect the corresponding stretch effect to be applied + * to the surface. This can be directly on the surface itself or + * configured from a parent of the surface in which case the + * StretchEffect provided has parameters mapping the position of + * the surface within the container that has the stretch configured + * on it + * @return The transaction being constructed + */ + Transaction& setStretchEffect(const sp<SurfaceControl>& sc, + const StretchEffect& stretchEffect); Transaction& setBufferCrop(const sp<SurfaceControl>& sc, const Rect& bufferCrop); diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index f395ab43d8..67ca3a23d5 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -95,6 +95,7 @@ filegroup { "skia/debug/SkiaMemoryReporter.cpp", "skia/filters/BlurFilter.cpp", "skia/filters/LinearEffect.cpp", + "skia/filters/StretchShaderFactory.cpp" ], } diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h index e976a5a7fc..ddbe4c81d3 100644 --- a/libs/renderengine/include/renderengine/LayerSettings.h +++ b/libs/renderengine/include/renderengine/LayerSettings.h @@ -222,7 +222,8 @@ static inline bool operator==(const LayerSettings& lhs, const LayerSettings& rhs lhs.sourceDataspace == rhs.sourceDataspace && lhs.colorTransform == rhs.colorTransform && lhs.disableBlending == rhs.disableBlending && lhs.shadow == rhs.shadow && - lhs.backgroundBlurRadius == rhs.backgroundBlurRadius; + lhs.backgroundBlurRadius == rhs.backgroundBlurRadius && + lhs.stretchEffect == rhs.stretchEffect; } // Defining PrintTo helps with Google Tests. @@ -272,6 +273,21 @@ static inline void PrintTo(const ShadowSettings& settings, ::std::ostream* os) { *os << "\n}"; } +static inline void PrintTo(const StretchEffect& effect, ::std::ostream* os) { + *os << "StretchEffect {"; + *os << "\n .width = " << effect.width; + *os << "\n .height = " << effect.height; + *os << "\n .vectorX = " << effect.vectorX; + *os << "\n .vectorY = " << effect.vectorY; + *os << "\n .maxAmountX = " << effect.maxAmountX; + *os << "\n .maxAmountY = " << effect.maxAmountY; + *os << "\n .mappedLeft = " << effect.mappedChildBounds.left; + *os << "\n .mappedTop = " << effect.mappedChildBounds.top; + *os << "\n .mappedRight = " << effect.mappedChildBounds.right; + *os << "\n .mappedBottom = " << effect.mappedChildBounds.bottom; + *os << "\n}"; +} + static inline void PrintTo(const LayerSettings& settings, ::std::ostream* os) { *os << "LayerSettings {"; *os << "\n .geometry = "; @@ -290,6 +306,8 @@ static inline void PrintTo(const LayerSettings& settings, ::std::ostream* os) { } *os << "\n .shadow = "; PrintTo(settings.shadow, os); + *os << "\n .stretchEffect = "; + PrintTo(settings.stretchEffect, os); *os << "\n}"; } diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index acdb78a212..3e3649edd4 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -56,6 +56,7 @@ #include "log/log_main.h" #include "skia/debug/SkiaCapture.h" #include "skia/debug/SkiaMemoryReporter.h" +#include "skia/filters/StretchShaderFactory.h" #include "system/graphics-base-v1.0.h" namespace { @@ -541,14 +542,19 @@ void SkiaGLRenderEngine::unmapExternalTextureBuffer(const sp<GraphicBuffer>& buf } } -sk_sp<SkShader> SkiaGLRenderEngine::createRuntimeEffectShader(sk_sp<SkShader> shader, - const LayerSettings* layer, - const DisplaySettings& display, - bool undoPremultipliedAlpha, - bool requiresLinearEffect) { - if (layer->stretchEffect.hasEffect()) { - // TODO: Implement +sk_sp<SkShader> SkiaGLRenderEngine::createRuntimeEffectShader( + sk_sp<SkShader> shader, + const LayerSettings* layer, const DisplaySettings& display, bool undoPremultipliedAlpha, + bool requiresLinearEffect) { + const auto stretchEffect = layer->stretchEffect; + if (stretchEffect.hasEffect()) { + const auto targetBuffer = layer->source.buffer.buffer; + const auto graphicsBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr; + if (graphicsBuffer && shader) { + shader = mStretchShaderFactory.createSkShader(shader, stretchEffect); + } } + if (requiresLinearEffect) { const ui::Dataspace inputDataspace = mUseColorManagement ? layer->sourceDataspace : ui::Dataspace::UNKNOWN; @@ -634,6 +640,33 @@ private: int mSaveCount; }; +void drawStretch(const SkRect& bounds, const StretchEffect& stretchEffect, + SkCanvas* canvas, const SkPaint& paint) { + float top = bounds.top(); + float left = bounds.left(); + float bottom = bounds.bottom(); + float right = bounds.right(); + // Adjust the drawing bounds based on the stretch itself. + float stretchOffsetX = + round(bounds.width() * stretchEffect.getStretchWidthMultiplier()); + float stretchOffsetY = + round(bounds.height() * stretchEffect.getStretchHeightMultiplier()); + if (stretchEffect.vectorY < 0.f) { + top -= stretchOffsetY; + } else if (stretchEffect.vectorY > 0.f){ + bottom += stretchOffsetY; + } + + if (stretchEffect.vectorX < 0.f) { + left -= stretchOffsetX; + } else if (stretchEffect.vectorX > 0.f) { + right += stretchOffsetX; + } + + auto stretchBounds = SkRect::MakeLTRB(left, top, right, bottom); + canvas->drawRect(stretchBounds, paint); +} + status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, const std::vector<const LayerSettings*>& layers, const std::shared_ptr<ExternalTexture>& buffer, @@ -671,9 +704,7 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, } else { surfaceTextureRef = std::make_shared<AutoBackendTexture::LocalRef>(grContext.get(), - buffer->getBuffer() - ->toAHardwareBuffer(), - true); + buffer->getBuffer()->toAHardwareBuffer(), true); } const ui::Dataspace dstDataspace = @@ -988,7 +1019,17 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, paint.setAntiAlias(true); canvas->drawRRect(getRoundedRect(layer), paint); } else { - canvas->drawRect(bounds, paint); + auto& stretchEffect = layer->stretchEffect; + // TODO (njawad) temporarily disable manipulation of geometry + // the layer bounds will be updated in HWUI instead of RenderEngine + // in a subsequent CL + // Keep the method call in a dead code path to make -Werror happy + // with unused methods + if (stretchEffect.hasEffect() && /* DISABLES CODE */ (false)) { + drawStretch(bounds, stretchEffect, canvas, paint); + } else { + canvas->drawRect(bounds, paint); + } } if (kFlushAfterEveryLayer) { ATRACE_NAME("flush surface"); diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h index e71c560a1f..98f5ee2081 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.h +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -39,6 +39,7 @@ #include "debug/SkiaCapture.h" #include "filters/BlurFilter.h" #include "filters/LinearEffect.h" +#include "filters/StretchShaderFactory.h" namespace android { namespace renderengine { @@ -101,7 +102,8 @@ private: const ShadowSettings& shadowSettings); // If requiresLinearEffect is true or the layer has a stretchEffect a new shader is returned. // Otherwise it returns the input shader. - sk_sp<SkShader> createRuntimeEffectShader(sk_sp<SkShader> shader, const LayerSettings* layer, + sk_sp<SkShader> createRuntimeEffectShader(sk_sp<SkShader> shader, + const LayerSettings* layer, const DisplaySettings& display, bool undoPremultipliedAlpha, bool requiresLinearEffect); @@ -116,14 +118,20 @@ private: const PixelFormat mDefaultPixelFormat; const bool mUseColorManagement; + // Identifier used or various mappings of layers to various + // textures or shaders + using LayerId = uint64_t; + // Number of external holders of ExternalTexture references, per GraphicBuffer ID. - std::unordered_map<uint64_t, int32_t> mGraphicBufferExternalRefs GUARDED_BY(mRenderingMutex); + std::unordered_map<LayerId, int32_t> mGraphicBufferExternalRefs GUARDED_BY(mRenderingMutex); // Cache of GL textures that we'll store per GraphicBuffer ID, sliced by GPU context. - std::unordered_map<uint64_t, std::shared_ptr<AutoBackendTexture::LocalRef>> mTextureCache + std::unordered_map<LayerId, std::shared_ptr<AutoBackendTexture::LocalRef>> mTextureCache GUARDED_BY(mRenderingMutex); - std::unordered_map<uint64_t, std::shared_ptr<AutoBackendTexture::LocalRef>> + std::unordered_map<LayerId, std::shared_ptr<AutoBackendTexture::LocalRef>> mProtectedTextureCache GUARDED_BY(mRenderingMutex); std::unordered_map<LinearEffect, sk_sp<SkRuntimeEffect>, LinearEffectHasher> mRuntimeEffects; + + StretchShaderFactory mStretchShaderFactory; // Mutex guarding rendering operations, so that: // 1. GL operations aren't interleaved, and // 2. Internal state related to rendering that is potentially modified by diff --git a/libs/renderengine/skia/filters/StretchShaderFactory.cpp b/libs/renderengine/skia/filters/StretchShaderFactory.cpp new file mode 100644 index 0000000000..9b62789159 --- /dev/null +++ b/libs/renderengine/skia/filters/StretchShaderFactory.cpp @@ -0,0 +1,247 @@ +/* + * Copyright 2021 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 "StretchShaderFactory.h" +#include <SkImageFilter.h> +#include <SkRefCnt.h> +#include <SkRuntimeEffect.h> +#include <SkString.h> +#include <SkSurface.h> +#include "log/log.h" +#include <memory> + +namespace android { +namespace renderengine { +namespace skia { + +static const SkString stretchShader = SkString(R"( + uniform shader uContentTexture; + + // multiplier to apply to scale effect + uniform float uMaxStretchIntensity; + + // Maximum percentage to stretch beyond bounds of target + uniform float uStretchAffectedDistX; + uniform float uStretchAffectedDistY; + + // Distance stretched as a function of the normalized overscroll times + // scale intensity + uniform float uDistanceStretchedX; + uniform float uDistanceStretchedY; + uniform float uInverseDistanceStretchedX; + uniform float uInverseDistanceStretchedY; + uniform float uDistDiffX; + + // Difference between the peak stretch amount and overscroll amount normalized + uniform float uDistDiffY; + + // Horizontal offset represented as a ratio of pixels divided by the target width + uniform float uScrollX; + // Vertical offset represented as a ratio of pixels divided by the target height + uniform float uScrollY; + + // Normalized overscroll amount in the horizontal direction + uniform float uOverscrollX; + + // Normalized overscroll amount in the vertical direction + uniform float uOverscrollY; + uniform float viewportWidth; // target height in pixels + uniform float viewportHeight; // target width in pixels + + // uInterpolationStrength is the intensity of the interpolation. + // if uInterpolationStrength is 0, then the stretch is constant for all the + // uStretchAffectedDist. if uInterpolationStrength is 1, then stretch intensity + // is interpolated based on the pixel position in the uStretchAffectedDist area; + // The closer we are from the scroll anchor point, the more it stretches, + // and the other way around. + uniform float uInterpolationStrength; + + float easeInCubic(float t, float d) { + float tmp = t * d; + return tmp * tmp * tmp; + } + + float computeOverscrollStart( + float inPos, + float overscroll, + float uStretchAffectedDist, + float uInverseStretchAffectedDist, + float distanceStretched, + float interpolationStrength + ) { + float offsetPos = uStretchAffectedDist - inPos; + float posBasedVariation = mix( + 1. ,easeInCubic(offsetPos, uInverseStretchAffectedDist), interpolationStrength); + float stretchIntensity = overscroll * posBasedVariation; + return distanceStretched - (offsetPos / (1. + stretchIntensity)); + } + + float computeOverscrollEnd( + float inPos, + float overscroll, + float reverseStretchDist, + float uStretchAffectedDist, + float uInverseStretchAffectedDist, + float distanceStretched, + float interpolationStrength + ) { + float offsetPos = inPos - reverseStretchDist; + float posBasedVariation = mix( + 1. ,easeInCubic(offsetPos, uInverseStretchAffectedDist), interpolationStrength); + float stretchIntensity = (-overscroll) * posBasedVariation; + return 1 - (distanceStretched - (offsetPos / (1. + stretchIntensity))); + } + + // Prefer usage of return values over out parameters as it enables + // SKSL to properly inline method calls and works around potential GPU + // driver issues on Wembly. See b/182566543 for details + float computeOverscroll( + float inPos, + float overscroll, + float uStretchAffectedDist, + float uInverseStretchAffectedDist, + float distanceStretched, + float distanceDiff, + float interpolationStrength + ) { + float outPos = inPos; + // overscroll is provided via uniform so there is no concern + // for potential incoherent branches + if (overscroll > 0) { + if (inPos <= uStretchAffectedDist) { + outPos = computeOverscrollStart( + inPos, + overscroll, + uStretchAffectedDist, + uInverseStretchAffectedDist, + distanceStretched, + interpolationStrength + ); + } else if (inPos >= distanceStretched) { + outPos = distanceDiff + inPos; + } + } + if (overscroll < 0) { + float stretchAffectedDist = 1. - uStretchAffectedDist; + if (inPos >= stretchAffectedDist) { + outPos = computeOverscrollEnd( + inPos, + overscroll, + stretchAffectedDist, + uStretchAffectedDist, + uInverseStretchAffectedDist, + distanceStretched, + interpolationStrength + ); + } else if (inPos < stretchAffectedDist) { + outPos = -distanceDiff + inPos; + } + } + return outPos; + } + + vec4 main(vec2 coord) { + // Normalize SKSL pixel coordinate into a unit vector + float inU = coord.x / viewportWidth; + float inV = coord.y / viewportHeight; + float outU; + float outV; + float stretchIntensity; + // Add the normalized scroll position within scrolling list + inU += uScrollX; + inV += uScrollY; + outU = inU; + outV = inV; + outU = computeOverscroll( + inU, + uOverscrollX, + uStretchAffectedDistX, + uInverseDistanceStretchedX, + uDistanceStretchedX, + uDistDiffX, + uInterpolationStrength + ); + outV = computeOverscroll( + inV, + uOverscrollY, + uStretchAffectedDistY, + uInverseDistanceStretchedY, + uDistanceStretchedY, + uDistDiffY, + uInterpolationStrength + ); + coord.x = (outU - uScrollX) * viewportWidth; + coord.y = (outV - uScrollY) * viewportHeight; + return sample(uContentTexture, coord); + })"); + +const float INTERPOLATION_STRENGTH_VALUE = 0.7f; + +sk_sp<SkShader> StretchShaderFactory::createSkShader(const sk_sp<SkShader>& inputShader, + const StretchEffect& stretchEffect) { + if (!stretchEffect.hasEffect()) { + return nullptr; + } + + float viewportWidth = stretchEffect.width; + float viewportHeight = stretchEffect.height; + float normOverScrollDistX = stretchEffect.vectorX; + float normOverScrollDistY = stretchEffect.vectorY; + float distanceStretchedX = + StretchEffect::CONTENT_DISTANCE_STRETCHED / (1 + abs(normOverScrollDistX)); + float distanceStretchedY = + StretchEffect::CONTENT_DISTANCE_STRETCHED / (1 + abs(normOverScrollDistY)); + float inverseDistanceStretchedX = + 1.f / StretchEffect::CONTENT_DISTANCE_STRETCHED; + float inverseDistanceStretchedY = + 1.f / StretchEffect::CONTENT_DISTANCE_STRETCHED; + float diffX = + distanceStretchedX - StretchEffect::CONTENT_DISTANCE_STRETCHED; + float diffY = + distanceStretchedY - StretchEffect::CONTENT_DISTANCE_STRETCHED; + auto& srcBounds = stretchEffect.mappedChildBounds; + float normalizedScrollX = srcBounds.left / viewportWidth; + float normalizedScrollY = srcBounds.top / viewportHeight; + + if (mBuilder == nullptr) { + const static SkRuntimeEffect::Result instance = + SkRuntimeEffect::MakeForShader(stretchShader); + mBuilder = std::make_unique<SkRuntimeShaderBuilder>(instance.effect); + } + + mBuilder->child("uContentTexture") = inputShader; + mBuilder->uniform("uInterpolationStrength").set(&INTERPOLATION_STRENGTH_VALUE, 1); + mBuilder->uniform("uStretchAffectedDistX").set(&StretchEffect::CONTENT_DISTANCE_STRETCHED, 1); + mBuilder->uniform("uStretchAffectedDistY").set(&StretchEffect::CONTENT_DISTANCE_STRETCHED, 1); + mBuilder->uniform("uDistanceStretchedX").set(&distanceStretchedX, 1); + mBuilder->uniform("uDistanceStretchedY").set(&distanceStretchedY, 1); + mBuilder->uniform("uInverseDistanceStretchedX").set(&inverseDistanceStretchedX, 1); + mBuilder->uniform("uInverseDistanceStretchedY").set(&inverseDistanceStretchedY, 1); + mBuilder->uniform("uDistDiffX").set(&diffX, 1); + mBuilder->uniform("uDistDiffY").set(&diffY, 1); + mBuilder->uniform("uOverscrollX").set(&normOverScrollDistX, 1); + mBuilder->uniform("uOverscrollY").set(&normOverScrollDistY, 1); + mBuilder->uniform("uScrollX").set(&normalizedScrollX, 1); + mBuilder->uniform("uScrollY").set(&normalizedScrollY, 1); + mBuilder->uniform("viewportWidth").set(&viewportWidth, 1); + mBuilder->uniform("viewportHeight").set(&viewportHeight, 1); + + return mBuilder->makeShader(nullptr, false); +} + +} // namespace skia +} // namespace renderengine +} // namespace android
\ No newline at end of file diff --git a/libs/renderengine/skia/filters/StretchShaderFactory.h b/libs/renderengine/skia/filters/StretchShaderFactory.h new file mode 100644 index 0000000000..9c3ab7cb4f --- /dev/null +++ b/libs/renderengine/skia/filters/StretchShaderFactory.h @@ -0,0 +1,36 @@ +/* + * Copyright 2021 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 <SkRuntimeEffect.h> +#include <SkShader.h> +#include <ui/StretchEffect.h> + +namespace android { +namespace renderengine { +namespace skia { +class StretchShaderFactory { +public: + sk_sp<SkShader> createSkShader(const sk_sp<SkShader>& inputShader, + const StretchEffect& stretchEffect); + +private: + std::unique_ptr<SkRuntimeShaderBuilder> mBuilder; +}; +} // namespace skia +} // namespace renderengine +} // namespace android
\ No newline at end of file diff --git a/libs/ui/include/ui/StretchEffect.h b/libs/ui/include/ui/StretchEffect.h index 0803df3828..cf08acb359 100644 --- a/libs/ui/include/ui/StretchEffect.h +++ b/libs/ui/include/ui/StretchEffect.h @@ -25,31 +25,49 @@ namespace android { struct StretchEffect : public LightFlattenablePod<StretchEffect> { - FloatRect area = {0, 0, 0, 0}; - float vectorX = 0; - float vectorY = 0; - float maxAmount = 0; - - bool operator==(const StretchEffect& other) const { - return area == other.area && vectorX == other.vectorX && vectorY == other.vectorY && - maxAmount == other.maxAmount; - } + constexpr static const float CONTENT_DISTANCE_STRETCHED = 1.f; - static bool isZero(float value) { - constexpr float NON_ZERO_EPSILON = 0.001f; - return fabsf(value) <= NON_ZERO_EPSILON; - } + float width = 0; + float height = 0; + float vectorX = 0; + float vectorY = 0; + float maxAmountX = 0; + float maxAmountY = 0; + FloatRect mappedChildBounds = {0, 0, 0, 0}; + + bool operator==(const StretchEffect& other) const { + return width == other.width && height == other.height && + vectorX == other.vectorX && + vectorY == other.vectorY && + maxAmountX == other.maxAmountX && + maxAmountY == other.maxAmountY && + mappedChildBounds == other.mappedChildBounds; + } - bool isNoOp() const { return isZero(vectorX) && isZero(vectorY); } + static bool isZero(float value) { + constexpr float NON_ZERO_EPSILON = 0.001f; + return fabsf(value) <= NON_ZERO_EPSILON; + } - bool hasEffect() const { return !isNoOp(); } + bool isNoOp() const { return isZero(vectorX) && isZero(vectorY); } - void sanitize() { - // If the area is empty, or the max amount is zero, then reset back to defaults - if (area.isEmpty() || isZero(maxAmount)) { - *this = StretchEffect{}; - } + bool hasEffect() const { return !isNoOp(); } + + void sanitize() { + // If the area is empty, or the max amount is zero, then reset back to defaults + if (width == 0.f || height == 0.f || isZero(maxAmountX) || + isZero(maxAmountY)) { + *this = StretchEffect{}; } + } + + float getStretchWidthMultiplier() const { + return CONTENT_DISTANCE_STRETCHED / (1.f + abs(vectorX)); + } + + float getStretchHeightMultiplier() const { + return CONTENT_DISTANCE_STRETCHED / (1.f + abs(vectorY)); + } }; static_assert(std::is_trivially_copyable<StretchEffect>::value, diff --git a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp index 2d9f01b9fd..b1ee3fbf5d 100644 --- a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp +++ b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp @@ -36,7 +36,8 @@ inline bool equalIgnoringSource(const renderengine::LayerSettings& lhs, lhs.sourceDataspace == rhs.sourceDataspace && lhs.colorTransform == rhs.colorTransform && lhs.disableBlending == rhs.disableBlending && lhs.shadow == rhs.shadow && - lhs.backgroundBlurRadius == rhs.backgroundBlurRadius; + lhs.backgroundBlurRadius == rhs.backgroundBlurRadius && + lhs.stretchEffect == rhs.stretchEffect; } inline bool equalIgnoringBuffer(const renderengine::Buffer& lhs, const renderengine::Buffer& rhs) { diff --git a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp index 0cc2c6e637..5565396922 100644 --- a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp +++ b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp @@ -101,9 +101,9 @@ void dumpVal(std::string& out, const char* name, const mat4& tr) { } void dumpVal(std::string& out, const char* name, const StretchEffect& effect) { - StringAppendF(&out, "%s={ area=[%f, %f, %f, %f], vec=(%f, %f), max=%f } ", name, - effect.area.left, effect.area.top, effect.area.right, effect.area.bottom, - effect.vectorX, effect.vectorY, effect.maxAmount); + StringAppendF(&out, "%s={ width =%f, height = %f, vec=(%f, %f), max=(%f, %f) } ", name, + effect.width, effect.height, + effect.vectorX, effect.vectorY, effect.maxAmountX, effect.maxAmountY); } } // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 0d673eab78..a833c85fb4 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -635,7 +635,7 @@ std::optional<compositionengine::LayerFE::LayerSettings> Layer::prepareClientCom layerSettings.blurRegionTransform = getActiveTransform(getDrawingState()).inverse().asMatrix4(); } - layerSettings.stretchEffect = getDrawingState().stretchEffect; + layerSettings.stretchEffect = getStretchEffect(); // Record the name of the layer for debugging further down the stack. layerSettings.name = getName(); return layerSettings; |