diff options
author | 2021-05-06 10:48:18 -0700 | |
---|---|---|
committer | 2021-05-07 22:45:26 -0700 | |
commit | bc341860f042edb649055042c955cb9e38fd65a6 (patch) | |
tree | 47268e9c7c007699bccf6464f88d09758980760a | |
parent | 0408e507b625d180070fb6c1d9a799810d3c00ff (diff) |
Updated HWUI to calculate the stretch bounds for a surface
Added logic to StretchEffect to be able to calculate the
stretched position of a pixel on an input texture based
on the current stretch parameters.
Updated shader to leverage linear easing instead of
cubic in order to have a reversible method that
can be used to map input textures to the corresponding
stretch position.
Bug: 179047472
Test: manual
Change-Id: Id32afcf0df1cca03e68ac0c594d307a1090264f2
-rw-r--r-- | libs/hwui/DamageAccumulator.cpp | 9 | ||||
-rw-r--r-- | libs/hwui/effects/StretchEffect.cpp | 85 | ||||
-rw-r--r-- | libs/hwui/effects/StretchEffect.h | 16 | ||||
-rw-r--r-- | libs/hwui/jni/android_graphics_RenderNode.cpp | 34 |
4 files changed, 133 insertions, 11 deletions
diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp index 94fe243378b1..cf3ef40b688a 100644 --- a/libs/hwui/DamageAccumulator.cpp +++ b/libs/hwui/DamageAccumulator.cpp @@ -272,18 +272,21 @@ void DamageAccumulator::finish(SkRect* totalDirty) { DamageAccumulator::StretchResult DamageAccumulator::findNearestStretchEffect() const { DirtyStack* frame = mHead; + const auto& headProperties = mHead->renderNode->properties(); + float startWidth = headProperties.getWidth(); + float startHeight = headProperties.getHeight(); while (frame->prev != frame) { if (frame->type == TransformRenderNode) { const auto& renderNode = frame->renderNode; const auto& frameRenderNodeProperties = renderNode->properties(); const auto& effect = frameRenderNodeProperties.layerProperties().getStretchEffect(); - const float width = (float) renderNode->getWidth(); - const float height = (float) renderNode->getHeight(); + const float width = (float) frameRenderNodeProperties.getWidth(); + const float height = (float) frameRenderNodeProperties.getHeight(); if (!effect.isEmpty()) { Matrix4 stretchMatrix; computeTransformImpl(mHead, frame, &stretchMatrix); - Rect stretchRect = Rect(0.f, 0.f, width, height); + Rect stretchRect = Rect(0.f, 0.f, startWidth, startHeight); stretchMatrix.mapRect(stretchRect); return StretchResult{ diff --git a/libs/hwui/effects/StretchEffect.cpp b/libs/hwui/effects/StretchEffect.cpp index 1519d69d7053..0599bfaf02f5 100644 --- a/libs/hwui/effects/StretchEffect.cpp +++ b/libs/hwui/effects/StretchEffect.cpp @@ -68,9 +68,8 @@ static const SkString stretchShader = SkString(R"( // and the other way around. uniform float uInterpolationStrength; - float easeInCubic(float t, float d) { - float tmp = t * d; - return tmp * tmp * tmp; + float easeIn(float t, float d) { + return t * d; } float computeOverscrollStart( @@ -83,7 +82,7 @@ static const SkString stretchShader = SkString(R"( ) { float offsetPos = uStretchAffectedDist - inPos; float posBasedVariation = mix( - 1. ,easeInCubic(offsetPos, uInverseStretchAffectedDist), interpolationStrength); + 1. ,easeIn(offsetPos, uInverseStretchAffectedDist), interpolationStrength); float stretchIntensity = overscroll * posBasedVariation; return distanceStretched - (offsetPos / (1. + stretchIntensity)); } @@ -99,7 +98,7 @@ static const SkString stretchShader = SkString(R"( ) { float offsetPos = inPos - reverseStretchDist; float posBasedVariation = mix( - 1. ,easeInCubic(offsetPos, uInverseStretchAffectedDist), interpolationStrength); + 1. ,easeIn(offsetPos, uInverseStretchAffectedDist), interpolationStrength); float stretchIntensity = (-overscroll) * posBasedVariation; return 1 - (distanceStretched - (offsetPos / (1. + stretchIntensity))); } @@ -234,4 +233,80 @@ sk_sp<SkRuntimeEffect> StretchEffect::getStretchEffect() { return instance.effect; } +/** + * Helper method that maps the input texture position to the stretch position + * based on the given overscroll value that represents an overscroll from + * either the top or left + * @param overscroll current overscroll value + * @param input normalized input position (can be x or y) on the input texture + * @return stretched position of the input normalized from 0 to 1 + */ +float reverseMapStart(float overscroll, float input) { + float numerator = (-input * overscroll * overscroll) - + (2 * input * overscroll) - input; + float denominator = 1.f + (.3f * overscroll) + + (.7f * input * overscroll * overscroll) + (.7f * input * overscroll); + return -(numerator / denominator); +} + +/** + * Helper method that maps the input texture position to the stretch position + * based on the given overscroll value that represents an overscroll from + * either the bottom or right + * @param overscroll current overscroll value + * @param input normalized input position (can be x or y) on the input texture + * @return stretched position of the input normalized from 0 to 1 + */ +float reverseMapEnd(float overscroll, float input) { + float numerator = (.3f * overscroll * overscroll) - + (.3f * input * overscroll * overscroll) + + (1.3f * input * overscroll) - overscroll - input; + float denominator = (.7f * input * overscroll * overscroll) - + (.7f * input * overscroll) - (.7f * overscroll * overscroll) + + overscroll - 1.f; + return numerator / denominator; +} + +/** + * Calculates the normalized stretch position given the normalized input + * position. This handles calculating the overscroll from either the + * top or left vs bottom or right depending on the sign of the given overscroll + * value + * + * @param overscroll unit vector of overscroll from -1 to 1 indicating overscroll + * from the bottom or right vs top or left respectively + * @param normalizedInput the + * @return + */ +float computeReverseOverscroll(float overscroll, float normalizedInput) { + float distanceStretched = 1.f / (1.f + abs(overscroll)); + float distanceDiff = distanceStretched - 1.f; + if (overscroll > 0) { + float output = reverseMapStart(overscroll, normalizedInput); + if (output <= 1.0f) { + return output; + } else if (output >= distanceStretched){ + return output - distanceDiff; + } + } + + if (overscroll < 0) { + float output = reverseMapEnd(overscroll, normalizedInput); + if (output >= 0.f) { + return output; + } else if (output < 0.f){ + return output + distanceDiff; + } + } + return normalizedInput; +} + +float StretchEffect::computeStretchedPositionX(float normalizedX) const { + return computeReverseOverscroll(mStretchDirection.x(), normalizedX); +} + +float StretchEffect::computeStretchedPositionY(float normalizedY) const { + return computeReverseOverscroll(mStretchDirection.y(), normalizedY); +} + } // namespace android::uirenderer
\ No newline at end of file diff --git a/libs/hwui/effects/StretchEffect.h b/libs/hwui/effects/StretchEffect.h index 61537f0b5a2c..6d517aca9c85 100644 --- a/libs/hwui/effects/StretchEffect.h +++ b/libs/hwui/effects/StretchEffect.h @@ -75,6 +75,22 @@ public: maxStretchAmountY = std::max(maxStretchAmountY, other.maxStretchAmountY); } + /** + * Return the stretched x position given the normalized x position with + * the current horizontal stretch direction + * @param normalizedX x position on the input texture from 0 to 1 + * @return x position when the horizontal stretch direction applied + */ + float computeStretchedPositionX(float normalizedX) const; + + /** + * Return the stretched y position given the normalized y position with + * the current horizontal stretch direction + * @param normalizedX y position on the input texture from 0 to 1 + * @return y position when the horizontal stretch direction applied + */ + float computeStretchedPositionY(float normalizedY) const; + sk_sp<SkShader> getShader(float width, float height, const sk_sp<SkImage>& snapshotImage) const; diff --git a/libs/hwui/jni/android_graphics_RenderNode.cpp b/libs/hwui/jni/android_graphics_RenderNode.cpp index 5131c646c4a4..f92c32c12c61 100644 --- a/libs/hwui/jni/android_graphics_RenderNode.cpp +++ b/libs/hwui/jni/android_graphics_RenderNode.cpp @@ -572,11 +572,11 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject, info.damageAccumulator->computeCurrentTransform(&transform); const RenderProperties& props = node.properties(); + uirenderer::Rect bounds(props.getWidth(), props.getHeight()); if (info.stretchEffectCount) { - handleStretchEffect(info, transform); + handleStretchEffect(info, bounds); } - uirenderer::Rect bounds(props.getWidth(), props.getHeight()); transform.mapRect(bounds); if (CC_LIKELY(transform.isPureTranslate())) { @@ -639,7 +639,33 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject, return env; } - void handleStretchEffect(const TreeInfo& info, const Matrix4& transform) { + void stretchTargetBounds(const StretchEffect& stretchEffect, + float width, float height, + const SkRect& childRelativeBounds, + uirenderer::Rect& bounds) { + float normalizedLeft = childRelativeBounds.left() / width; + float normalizedTop = childRelativeBounds.top() / height; + float normalizedRight = childRelativeBounds.right() / width; + float normalizedBottom = childRelativeBounds.bottom() / height; + float reverseLeft = width * + (stretchEffect.computeStretchedPositionX(normalizedLeft) - + normalizedLeft); + float reverseTop = height * + (stretchEffect.computeStretchedPositionY(normalizedTop) - + normalizedTop); + float reverseRight = width * + (stretchEffect.computeStretchedPositionX(normalizedRight) - + normalizedLeft); + float reverseBottom = height * + (stretchEffect.computeStretchedPositionY(normalizedBottom) - + normalizedTop); + bounds.left = reverseLeft; + bounds.top = reverseTop; + bounds.right = reverseRight; + bounds.bottom = reverseBottom; + } + + void handleStretchEffect(const TreeInfo& info, uirenderer::Rect& targetBounds) { // Search up to find the nearest stretcheffect parent const DamageAccumulator::StretchResult result = info.damageAccumulator->findNearestStretchEffect(); @@ -649,6 +675,8 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject, } const auto& childRelativeBounds = result.childRelativeBounds; + stretchTargetBounds(*effect, result.width, result.height, + childRelativeBounds,targetBounds); JNIEnv* env = jnienv(); |