diff --git a/graphics/java/android/graphics/RecordingCanvas.java b/graphics/java/android/graphics/RecordingCanvas.java index 6c03ddc4a12d..e9e58c6213bf 100644 --- a/graphics/java/android/graphics/RecordingCanvas.java +++ b/graphics/java/android/graphics/RecordingCanvas.java @@ -226,10 +226,12 @@ public final class RecordingCanvas extends BaseRecordingCanvas { */ public void drawRipple(CanvasProperty cx, CanvasProperty cy, CanvasProperty radius, CanvasProperty paint, - CanvasProperty progress, RuntimeShader shader) { + CanvasProperty progress, CanvasProperty turbulencePhase, + RuntimeShader shader) { nDrawRipple(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(), radius.getNativeContainer(), paint.getNativeContainer(), - progress.getNativeContainer(), shader.getNativeShaderBuilder()); + progress.getNativeContainer(), turbulencePhase.getNativeContainer(), + shader.getNativeShaderBuilder()); } /** @@ -290,7 +292,7 @@ public final class RecordingCanvas extends BaseRecordingCanvas { long propCy, long propRadius, long propPaint); @CriticalNative private static native void nDrawRipple(long renderer, long propCx, long propCy, long propRadius, - long propPaint, long propProgress, long runtimeEffect); + long propPaint, long propProgress, long turbulencePhase, long runtimeEffect); @CriticalNative private static native void nDrawRoundRect(long renderer, long propLeft, long propTop, long propRight, long propBottom, long propRx, long propRy, long propPaint); diff --git a/graphics/java/android/graphics/drawable/RippleAnimationSession.java b/graphics/java/android/graphics/drawable/RippleAnimationSession.java index c317831eb816..1cd4cf115180 100644 --- a/graphics/java/android/graphics/drawable/RippleAnimationSession.java +++ b/graphics/java/android/graphics/drawable/RippleAnimationSession.java @@ -40,6 +40,8 @@ public final class RippleAnimationSession { private static final String TAG = "RippleAnimationSession"; private static final int ENTER_ANIM_DURATION = 450; private static final int EXIT_ANIM_DURATION = 300; + private static final long NOISE_ANIMATION_DURATION = 7000; + private static final long MAX_NOISE_PHASE = NOISE_ANIMATION_DURATION / 120; private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator(); private static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f); @@ -49,7 +51,7 @@ public final class RippleAnimationSession { private Runnable mOnUpdate; private long mStartTime; private boolean mForceSoftware; - private boolean mAnimateSparkle; + private Animator mLoopAnimation; RippleAnimationSession(@NonNull AnimationProperties properties, boolean forceSoftware) { @@ -88,16 +90,6 @@ public final class RippleAnimationSession { return this; } - public boolean shouldAnimateSparkle() { - return mAnimateSparkle && ValueAnimator.getDurationScale() > 0; - } - - public float getSparklePhase() { - final long now = AnimationUtils.currentAnimationTimeMillis(); - final long elapsed = now - mStartTime; - return (float) elapsed / 800; - } - private boolean isHwAccelerated(Canvas canvas) { return canvas.isHardwareAccelerated() && !mForceSoftware; } @@ -114,7 +106,7 @@ public final class RippleAnimationSession { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); - mAnimateSparkle = false; + if (mLoopAnimation != null) mLoopAnimation.cancel(); Consumer onEnd = mOnSessionEnd; if (onEnd != null) onEnd.accept(RippleAnimationSession.this); } @@ -148,7 +140,7 @@ public final class RippleAnimationSession { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); - mAnimateSparkle = false; + if (mLoopAnimation != null) mLoopAnimation.cancel(); Consumer onEnd = mOnSessionEnd; if (onEnd != null) onEnd.accept(RippleAnimationSession.this); } @@ -167,24 +159,42 @@ public final class RippleAnimationSession { RenderNodeAnimator expand = new RenderNodeAnimator(props.getProgress(), .5f); expand.setTarget(canvas); - startAnimation(expand); + RenderNodeAnimator loop = new RenderNodeAnimator(props.getNoisePhase(), MAX_NOISE_PHASE); + loop.setTarget(canvas); + startAnimation(expand, loop); } - private void startAnimation(Animator expand) { + private void startAnimation(Animator expand, Animator loop) { expand.setDuration(ENTER_ANIM_DURATION); expand.addListener(new AnimatorListener(this)); expand.setInterpolator(FAST_OUT_SLOW_IN); expand.start(); - mAnimateSparkle = true; + loop.setDuration(NOISE_ANIMATION_DURATION); + loop.addListener(new AnimatorListener(this) { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + mLoopAnimation = null; + } + }); + loop.setInterpolator(LINEAR_INTERPOLATOR); + loop.start(); + if (mLoopAnimation != null) mLoopAnimation.cancel(); + mLoopAnimation = loop; } private void enterSoftware() { ValueAnimator expand = ValueAnimator.ofFloat(0f, 0.5f); expand.addUpdateListener(updatedAnimation -> { notifyUpdate(); - mProperties.getShader().setProgress((Float) expand.getAnimatedValue()); + mProperties.getShader().setProgress((float) expand.getAnimatedValue()); }); - startAnimation(expand); + ValueAnimator loop = ValueAnimator.ofFloat(0f, MAX_NOISE_PHASE); + loop.addUpdateListener(updatedAnimation -> { + notifyUpdate(); + mProperties.getShader().setNoisePhase((float) loop.getAnimatedValue()); + }); + startAnimation(expand, loop); } @NonNull AnimationProperties getProperties() { @@ -198,6 +208,7 @@ public final class RippleAnimationSession { CanvasProperty.createFloat(mProperties.getX()), CanvasProperty.createFloat(mProperties.getY()), CanvasProperty.createFloat(mProperties.getMaxRadius()), + CanvasProperty.createFloat(mProperties.getNoisePhase()), CanvasProperty.createPaint(mProperties.getPaint()), CanvasProperty.createFloat(mProperties.getProgress()), mProperties.getShader()); @@ -236,16 +247,18 @@ public final class RippleAnimationSession { static class AnimationProperties { private final FloatType mProgress; private final FloatType mMaxRadius; + private final FloatType mNoisePhase; private final PaintType mPaint; private final RippleShader mShader; private FloatType mX; private FloatType mY; - AnimationProperties(FloatType x, FloatType y, FloatType maxRadius, + AnimationProperties(FloatType x, FloatType y, FloatType maxRadius, FloatType noisePhase, PaintType paint, FloatType progress, RippleShader shader) { mY = y; mX = x; mMaxRadius = maxRadius; + mNoisePhase = noisePhase; mPaint = paint; mShader = shader; mProgress = progress; @@ -279,5 +292,9 @@ public final class RippleAnimationSession { RippleShader getShader() { return mShader; } + + FloatType getNoisePhase() { + return mNoisePhase; + } } } diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java index 086533263634..c972a24fb04b 100644 --- a/graphics/java/android/graphics/drawable/RippleDrawable.java +++ b/graphics/java/android/graphics/drawable/RippleDrawable.java @@ -858,15 +858,6 @@ public class RippleDrawable extends LayerDrawable { } for (int i = 0; i < mRunningAnimations.size(); i++) { RippleAnimationSession s = mRunningAnimations.get(i); - if (s.shouldAnimateSparkle()) { - final float phase = s.getSparklePhase(); - if (useCanvasProps) { - s.getCanvasProperties().getShader().setNoisePhase(phase); - } else { - s.getProperties().getShader().setNoisePhase(phase); - } - invalidateSelf(); - } if (useCanvasProps) { RippleAnimationSession.AnimationProperties, CanvasProperty> @@ -883,7 +874,7 @@ public class RippleDrawable extends LayerDrawable { yProp = p.getY(); } can.drawRipple(xProp, yProp, p.getMaxRadius(), p.getPaint(), - p.getProgress(), p.getShader()); + p.getProgress(), p.getNoisePhase(), p.getShader()); } else { RippleAnimationSession.AnimationProperties p = s.getProperties(); @@ -953,7 +944,7 @@ public class RippleDrawable extends LayerDrawable { shader.setRadius(radius); shader.setProgress(.0f); properties = new RippleAnimationSession.AnimationProperties<>( - cx, cy, radius, p, 0f, shader); + cx, cy, radius, 0f, p, 0f, shader); if (mMaskShader == null) { shader.setShader(null); } else { diff --git a/graphics/java/android/graphics/drawable/RippleShader.java b/graphics/java/android/graphics/drawable/RippleShader.java index 4608d0276b49..c1c6afceadd9 100644 --- a/graphics/java/android/graphics/drawable/RippleShader.java +++ b/graphics/java/android/graphics/drawable/RippleShader.java @@ -167,6 +167,9 @@ final class RippleShader extends RuntimeShader { final float turbulencePhase = (float) ((mProgress + mNoisePhase * 0.333f) * 5f * Math.PI); setUniform("in_turbulencePhase", turbulencePhase); + // + // Keep in sync with: frameworks/base/libs/hwui/pipeline/skia/AnimatedDrawables.h + // final float scale = 1.5f; setUniform("in_tCircle1", new float[]{ (float) (scale * 0.5 + (turbulencePhase * 0.01 * Math.cos(scale * 0.55))), diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index 4c4a15295690..3056e977f841 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -820,10 +820,11 @@ void SkiaCanvas::drawRipple(uirenderer::CanvasPropertyPrimitive* x, uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPaint* paint, uirenderer::CanvasPropertyPrimitive* progress, + uirenderer::CanvasPropertyPrimitive* turbulencePhase, const SkRuntimeShaderBuilder& effectBuilder) { sk_sp drawable( new uirenderer::skiapipeline::AnimatedRipple(x, y, radius, paint, progress, - effectBuilder)); + turbulencePhase, effectBuilder)); mCanvas->drawDrawable(drawable.get()); } diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h index e0a0be54fb39..995f00c6aa8d 100644 --- a/libs/hwui/SkiaCanvas.h +++ b/libs/hwui/SkiaCanvas.h @@ -153,6 +153,7 @@ public: uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPaint* paint, uirenderer::CanvasPropertyPrimitive* progress, + uirenderer::CanvasPropertyPrimitive* turbulencePhase, const SkRuntimeShaderBuilder& effectBuilder) override; virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) override; diff --git a/libs/hwui/canvas/CanvasOps.h b/libs/hwui/canvas/CanvasOps.h index 855cd0d6436b..173f3948dd0e 100644 --- a/libs/hwui/canvas/CanvasOps.h +++ b/libs/hwui/canvas/CanvasOps.h @@ -152,32 +152,66 @@ struct CanvasOp { sp radius; sp paint; sp progress; + sp turbulencePhase; sk_sp effect; + const float PI = 3.1415926535897932384626; + const float PI_ROTATE_RIGHT = PI * 0.0078125; + const float PI_ROTATE_LEFT = PI * -0.0078125; + const float SCALE = 1.5; + const float CIRCLE_X_1 = 0.01 * cos(SCALE * 0.55); + const float CIRCLE_Y_1 = 0.01 * sin(SCALE * 0.55); + const float CIRCLE_X_2 = -0.0066 * cos(SCALE * 0.45); + const float CIRCLE_Y_2 = -0.0066 * sin(SCALE * 0.45); + const float CIRCLE_X_3 = -0.0066 * cos(SCALE * 0.35); + const float CIRCLE_Y_3 = -0.0066 * sin(SCALE * 0.35); + void draw(SkCanvas* canvas) const { SkRuntimeShaderBuilder runtimeEffectBuilder(effect); - SkRuntimeShaderBuilder::BuilderUniform center = runtimeEffectBuilder.uniform("in_origin"); - if (center.fVar != nullptr) { - center = SkV2{x->value, y->value}; - } + setUniform2f(runtimeEffectBuilder, "in_origin", x->value, y->value); + setUniform(runtimeEffectBuilder, "in_radius", radius); + setUniform(runtimeEffectBuilder, "in_progress", progress); + setUniform(runtimeEffectBuilder, "in_turbulencePhase", turbulencePhase); - SkRuntimeShaderBuilder::BuilderUniform radiusU = - runtimeEffectBuilder.uniform("in_radius"); - if (radiusU.fVar != nullptr) { - radiusU = radius->value; - } - - SkRuntimeShaderBuilder::BuilderUniform progressU = - runtimeEffectBuilder.uniform("in_progress"); - if (progressU.fVar != nullptr) { - progressU = progress->value; - } + // + // Keep in sync with: + // frameworks/base/graphics/java/android/graphics/drawable/RippleShader.java + // + const float turbulence = turbulencePhase->value; + setUniform2f(runtimeEffectBuilder, "in_tCircle1", SCALE * 0.5 + (turbulence * CIRCLE_X_1), + SCALE * 0.5 + (turbulence * CIRCLE_Y_1)); + setUniform2f(runtimeEffectBuilder, "in_tCircle2", SCALE * 0.2 + (turbulence * CIRCLE_X_2), + SCALE * 0.2 + (turbulence * CIRCLE_Y_2)); + setUniform2f(runtimeEffectBuilder, "in_tCircle3", SCALE + (turbulence * CIRCLE_X_3), + SCALE + (turbulence * CIRCLE_Y_3)); + const float rotation1 = turbulence * PI_ROTATE_RIGHT + 1.7 * PI; + setUniform2f(runtimeEffectBuilder, "in_tRotation1", cos(rotation1), sin(rotation1)); + const float rotation2 = turbulence * PI_ROTATE_LEFT + 2 * PI; + setUniform2f(runtimeEffectBuilder, "in_tRotation2", cos(rotation2), sin(rotation2)); + const float rotation3 = turbulence * PI_ROTATE_RIGHT + 2.75 * PI; + setUniform2f(runtimeEffectBuilder, "in_tRotation3", cos(rotation3), sin(rotation3)); SkPaint paintMod = paint->value; paintMod.setShader(runtimeEffectBuilder.makeShader(nullptr, false)); canvas->drawCircle(x->value, y->value, radius->value, paintMod); } + + void setUniform(SkRuntimeShaderBuilder& effect, std::string name, + sp property) const { + SkRuntimeShaderBuilder::BuilderUniform uniform = effect.uniform(name.c_str()); + if (uniform.fVar != nullptr) { + uniform = property->value; + } + } + + void setUniform2f(SkRuntimeShaderBuilder effect, std::string name, float a, float b) const { + SkRuntimeShaderBuilder::BuilderUniform uniform = effect.uniform(name.c_str()); + if (uniform.fVar != nullptr) { + uniform = SkV2{a, b}; + } + } + ASSERT_DRAWABLE() }; diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h index c1feb767b459..837b055a8f42 100644 --- a/libs/hwui/hwui/Canvas.h +++ b/libs/hwui/hwui/Canvas.h @@ -146,6 +146,7 @@ public: uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPaint* paint, uirenderer::CanvasPropertyPrimitive* progress, + uirenderer::CanvasPropertyPrimitive* turbulencePhase, const SkRuntimeShaderBuilder& effectBuilder) = 0; virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) = 0; diff --git a/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp index 855d56ee2e55..eb5a88ad7ae8 100644 --- a/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp +++ b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp @@ -141,20 +141,22 @@ static void android_view_DisplayListCanvas_drawCircleProps(CRITICAL_JNI_PARAMS_C canvas->drawCircle(xProp, yProp, radiusProp, paintProp); } -static void android_view_DisplayListCanvas_drawRippleProps(CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr, - jlong xPropPtr, jlong yPropPtr, - jlong radiusPropPtr, jlong paintPropPtr, - jlong progressPropPtr, - jlong builderPtr) { +static void android_view_DisplayListCanvas_drawRippleProps( + CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr, jlong xPropPtr, jlong yPropPtr, + jlong radiusPropPtr, jlong paintPropPtr, jlong progressPropPtr, jlong turbulencePhasePtr, + jlong builderPtr) { Canvas* canvas = reinterpret_cast(canvasPtr); CanvasPropertyPrimitive* xProp = reinterpret_cast(xPropPtr); CanvasPropertyPrimitive* yProp = reinterpret_cast(yPropPtr); CanvasPropertyPrimitive* radiusProp = reinterpret_cast(radiusPropPtr); + CanvasPropertyPrimitive* turbulencePhaseProp = + reinterpret_cast(turbulencePhasePtr); CanvasPropertyPaint* paintProp = reinterpret_cast(paintPropPtr); CanvasPropertyPrimitive* progressProp = reinterpret_cast(progressPropPtr); SkRuntimeShaderBuilder* builder = reinterpret_cast(builderPtr); - canvas->drawRipple(xProp, yProp, radiusProp, paintProp, progressProp, *builder); + canvas->drawRipple(xProp, yProp, radiusProp, paintProp, progressProp, turbulencePhaseProp, + *builder); } static void android_view_DisplayListCanvas_drawWebViewFunctor(CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr, jint functor) { @@ -169,19 +171,22 @@ static void android_view_DisplayListCanvas_drawWebViewFunctor(CRITICAL_JNI_PARAM const char* const kClassPathName = "android/graphics/RecordingCanvas"; static JNINativeMethod gMethods[] = { - // ------------ @CriticalNative -------------- - { "nCreateDisplayListCanvas", "(JII)J", (void*) android_view_DisplayListCanvas_createDisplayListCanvas }, - { "nResetDisplayListCanvas", "(JJII)V", (void*) android_view_DisplayListCanvas_resetDisplayListCanvas }, - { "nGetMaximumTextureWidth", "()I", (void*) android_view_DisplayListCanvas_getMaxTextureSize }, - { "nGetMaximumTextureHeight", "()I", (void*) android_view_DisplayListCanvas_getMaxTextureSize }, - { "nEnableZ", "(JZ)V", (void*) android_view_DisplayListCanvas_enableZ }, - { "nFinishRecording", "(JJ)V", (void*) android_view_DisplayListCanvas_finishRecording }, - { "nDrawRenderNode", "(JJ)V", (void*) android_view_DisplayListCanvas_drawRenderNode }, - { "nDrawTextureLayer", "(JJ)V", (void*) android_view_DisplayListCanvas_drawTextureLayer }, - { "nDrawCircle", "(JJJJJ)V", (void*) android_view_DisplayListCanvas_drawCircleProps }, - { "nDrawRoundRect", "(JJJJJJJJ)V",(void*) android_view_DisplayListCanvas_drawRoundRectProps }, - { "nDrawWebViewFunctor", "(JI)V", (void*) android_view_DisplayListCanvas_drawWebViewFunctor }, - { "nDrawRipple", "(JJJJJJJ)V", (void*) android_view_DisplayListCanvas_drawRippleProps }, + // ------------ @CriticalNative -------------- + {"nCreateDisplayListCanvas", "(JII)J", + (void*)android_view_DisplayListCanvas_createDisplayListCanvas}, + {"nResetDisplayListCanvas", "(JJII)V", + (void*)android_view_DisplayListCanvas_resetDisplayListCanvas}, + {"nGetMaximumTextureWidth", "()I", (void*)android_view_DisplayListCanvas_getMaxTextureSize}, + {"nGetMaximumTextureHeight", "()I", + (void*)android_view_DisplayListCanvas_getMaxTextureSize}, + {"nEnableZ", "(JZ)V", (void*)android_view_DisplayListCanvas_enableZ}, + {"nFinishRecording", "(JJ)V", (void*)android_view_DisplayListCanvas_finishRecording}, + {"nDrawRenderNode", "(JJ)V", (void*)android_view_DisplayListCanvas_drawRenderNode}, + {"nDrawTextureLayer", "(JJ)V", (void*)android_view_DisplayListCanvas_drawTextureLayer}, + {"nDrawCircle", "(JJJJJ)V", (void*)android_view_DisplayListCanvas_drawCircleProps}, + {"nDrawRoundRect", "(JJJJJJJJ)V", (void*)android_view_DisplayListCanvas_drawRoundRectProps}, + {"nDrawWebViewFunctor", "(JI)V", (void*)android_view_DisplayListCanvas_drawWebViewFunctor}, + {"nDrawRipple", "(JJJJJJJJ)V", (void*)android_view_DisplayListCanvas_drawRippleProps}, }; int register_android_view_DisplayListCanvas(JNIEnv* env) { diff --git a/libs/hwui/pipeline/skia/AnimatedDrawables.h b/libs/hwui/pipeline/skia/AnimatedDrawables.h index 78591450f10a..7d65be1a76e6 100644 --- a/libs/hwui/pipeline/skia/AnimatedDrawables.h +++ b/libs/hwui/pipeline/skia/AnimatedDrawables.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "CanvasProperty.h" @@ -61,12 +62,14 @@ public: uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPaint* paint, uirenderer::CanvasPropertyPrimitive* progress, + uirenderer::CanvasPropertyPrimitive* turbulencePhase, const SkRuntimeShaderBuilder& effectBuilder) : mX(x) , mY(y) , mRadius(radius) , mPaint(paint) , mProgress(progress) + , mTurbulencePhase(turbulencePhase) , mRuntimeEffectBuilder(effectBuilder) {} protected: @@ -77,22 +80,28 @@ protected: return SkRect::MakeLTRB(x - radius, y - radius, x + radius, y + radius); } virtual void onDraw(SkCanvas* canvas) override { - SkRuntimeShaderBuilder::BuilderUniform center = mRuntimeEffectBuilder.uniform("in_origin"); - if (center.fVar != nullptr) { - center = SkV2{mX->value, mY->value}; - } + setUniform2f("in_origin", mX->value, mY->value); + setUniform("in_radius", mRadius); + setUniform("in_progress", mProgress); + setUniform("in_turbulencePhase", mTurbulencePhase); - SkRuntimeShaderBuilder::BuilderUniform radiusU = - mRuntimeEffectBuilder.uniform("in_radius"); - if (radiusU.fVar != nullptr) { - radiusU = mRadius->value; - } - - SkRuntimeShaderBuilder::BuilderUniform progressU = - mRuntimeEffectBuilder.uniform("in_progress"); - if (progressU.fVar != nullptr) { - progressU = mProgress->value; - } + // + // Keep in sync with: + // frameworks/base/graphics/java/android/graphics/drawable/RippleShader.java + // + const float turbulencePhase = mTurbulencePhase->value; + setUniform2f("in_tCircle1", SCALE * 0.5 + (turbulencePhase * CIRCLE_X_1), + SCALE * 0.5 + (turbulencePhase * CIRCLE_Y_1)); + setUniform2f("in_tCircle2", SCALE * 0.2 + (turbulencePhase * CIRCLE_X_2), + SCALE * 0.2 + (turbulencePhase * CIRCLE_Y_2)); + setUniform2f("in_tCircle3", SCALE + (turbulencePhase * CIRCLE_X_3), + SCALE + (turbulencePhase * CIRCLE_Y_3)); + const float rotation1 = turbulencePhase * PI_ROTATE_RIGHT + 1.7 * PI; + setUniform2f("in_tRotation1", cos(rotation1), sin(rotation1)); + const float rotation2 = turbulencePhase * PI_ROTATE_LEFT + 2 * PI; + setUniform2f("in_tRotation2", cos(rotation2), sin(rotation2)); + const float rotation3 = turbulencePhase * PI_ROTATE_RIGHT + 2.75 * PI; + setUniform2f("in_tRotation3", cos(rotation3), sin(rotation3)); SkPaint paint = mPaint->value; paint.setShader(mRuntimeEffectBuilder.makeShader(nullptr, false)); @@ -105,7 +114,35 @@ private: sp mRadius; sp mPaint; sp mProgress; + sp mTurbulencePhase; SkRuntimeShaderBuilder mRuntimeEffectBuilder; + + const float PI = 3.1415926535897932384626; + const float PI_ROTATE_RIGHT = PI * 0.0078125; + const float PI_ROTATE_LEFT = PI * -0.0078125; + const float SCALE = 1.5; + const float CIRCLE_X_1 = 0.01 * cos(SCALE * 0.55); + const float CIRCLE_Y_1 = 0.01 * sin(SCALE * 0.55); + const float CIRCLE_X_2 = -0.0066 * cos(SCALE * 0.45); + const float CIRCLE_Y_2 = -0.0066 * sin(SCALE * 0.45); + const float CIRCLE_X_3 = -0.0066 * cos(SCALE * 0.35); + const float CIRCLE_Y_3 = -0.0066 * sin(SCALE * 0.35); + + virtual void setUniform(std::string name, sp property) { + SkRuntimeShaderBuilder::BuilderUniform uniform = + mRuntimeEffectBuilder.uniform(name.c_str()); + if (uniform.fVar != nullptr) { + uniform = property->value; + } + } + + virtual void setUniform2f(std::string name, float a, float b) { + SkRuntimeShaderBuilder::BuilderUniform uniform = + mRuntimeEffectBuilder.uniform(name.c_str()); + if (uniform.fVar != nullptr) { + uniform = SkV2{a, b}; + } + } }; class AnimatedCircle : public SkDrawable { diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index 82814def6962..a8e427d30e1b 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -115,9 +115,10 @@ void SkiaRecordingCanvas::drawRipple(uirenderer::CanvasPropertyPrimitive* x, uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPaint* paint, uirenderer::CanvasPropertyPrimitive* progress, + uirenderer::CanvasPropertyPrimitive* turbulencePhase, const SkRuntimeShaderBuilder& effectBuilder) { drawDrawable(mDisplayList->allocateDrawable(x, y, radius, paint, progress, - effectBuilder)); + turbulencePhase, effectBuilder)); } void SkiaRecordingCanvas::enableZ(bool enableZ) { diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h index 06f2a27d22a5..4deb3b9c47c8 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h @@ -75,6 +75,7 @@ public: uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPaint* paint, uirenderer::CanvasPropertyPrimitive* progress, + uirenderer::CanvasPropertyPrimitive* turbulencePhase, const SkRuntimeShaderBuilder& effectBuilder) override; virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override; diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java index f6d9a7301949..487c8566ce37 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java @@ -56,6 +56,7 @@ public class RippleActivity extends Activity { CanvasProperty mY; CanvasProperty mRadius; CanvasProperty mProgress; + CanvasProperty mNoisePhase; CanvasProperty mPaint; RuntimeShader mRuntimeShader; @@ -99,6 +100,7 @@ public class RippleActivity extends Activity { mY = CanvasProperty.createFloat(200.0f); mRadius = CanvasProperty.createFloat(150.0f); mProgress = CanvasProperty.createFloat(0.0f); + mNoisePhase = CanvasProperty.createFloat(0.0f); Paint p = new Paint(); p.setAntiAlias(true); @@ -115,7 +117,8 @@ public class RippleActivity extends Activity { if (canvas.isHardwareAccelerated()) { RecordingCanvas recordingCanvas = (RecordingCanvas) canvas; - recordingCanvas.drawRipple(mX, mY, mRadius, mPaint, mProgress, mRuntimeShader); + recordingCanvas.drawRipple(mX, mY, mRadius, mPaint, mProgress, mNoisePhase, + mRuntimeShader); } } @@ -140,6 +143,9 @@ public class RippleActivity extends Activity { mRunningAnimations.add(new RenderNodeAnimator( mProgress, mToggle ? 1.0f : 0.0f)); + mRunningAnimations.add(new RenderNodeAnimator( + mNoisePhase, DURATION)); + mRunningAnimations.add(new RenderNodeAnimator( mPaint, RenderNodeAnimator.PAINT_ALPHA, 64.0f));