Merge "Move sparkle animation to RenderThread" into sc-dev

This commit is contained in:
Lucas Dupin
2021-04-16 15:08:52 +00:00
committed by Android (Google) Code Review
13 changed files with 185 additions and 85 deletions

View File

@@ -226,10 +226,12 @@ public final class RecordingCanvas extends BaseRecordingCanvas {
*/ */
public void drawRipple(CanvasProperty<Float> cx, CanvasProperty<Float> cy, public void drawRipple(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
CanvasProperty<Float> radius, CanvasProperty<Paint> paint, CanvasProperty<Float> radius, CanvasProperty<Paint> paint,
CanvasProperty<Float> progress, RuntimeShader shader) { CanvasProperty<Float> progress, CanvasProperty<Float> turbulencePhase,
RuntimeShader shader) {
nDrawRipple(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(), nDrawRipple(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(),
radius.getNativeContainer(), paint.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); long propCy, long propRadius, long propPaint);
@CriticalNative @CriticalNative
private static native void nDrawRipple(long renderer, long propCx, long propCy, long propRadius, 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 @CriticalNative
private static native void nDrawRoundRect(long renderer, long propLeft, long propTop, private static native void nDrawRoundRect(long renderer, long propLeft, long propTop,
long propRight, long propBottom, long propRx, long propRy, long propPaint); long propRight, long propBottom, long propRx, long propRy, long propPaint);

View File

@@ -40,6 +40,8 @@ public final class RippleAnimationSession {
private static final String TAG = "RippleAnimationSession"; private static final String TAG = "RippleAnimationSession";
private static final int ENTER_ANIM_DURATION = 450; private static final int ENTER_ANIM_DURATION = 450;
private static final int EXIT_ANIM_DURATION = 300; 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 TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
private static final Interpolator FAST_OUT_SLOW_IN = private static final Interpolator FAST_OUT_SLOW_IN =
new PathInterpolator(0.4f, 0f, 0.2f, 1f); new PathInterpolator(0.4f, 0f, 0.2f, 1f);
@@ -49,7 +51,7 @@ public final class RippleAnimationSession {
private Runnable mOnUpdate; private Runnable mOnUpdate;
private long mStartTime; private long mStartTime;
private boolean mForceSoftware; private boolean mForceSoftware;
private boolean mAnimateSparkle; private Animator mLoopAnimation;
RippleAnimationSession(@NonNull AnimationProperties<Float, Paint> properties, RippleAnimationSession(@NonNull AnimationProperties<Float, Paint> properties,
boolean forceSoftware) { boolean forceSoftware) {
@@ -88,16 +90,6 @@ public final class RippleAnimationSession {
return this; 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) { private boolean isHwAccelerated(Canvas canvas) {
return canvas.isHardwareAccelerated() && !mForceSoftware; return canvas.isHardwareAccelerated() && !mForceSoftware;
} }
@@ -114,7 +106,7 @@ public final class RippleAnimationSession {
@Override @Override
public void onAnimationEnd(Animator animation) { public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation); super.onAnimationEnd(animation);
mAnimateSparkle = false; if (mLoopAnimation != null) mLoopAnimation.cancel();
Consumer<RippleAnimationSession> onEnd = mOnSessionEnd; Consumer<RippleAnimationSession> onEnd = mOnSessionEnd;
if (onEnd != null) onEnd.accept(RippleAnimationSession.this); if (onEnd != null) onEnd.accept(RippleAnimationSession.this);
} }
@@ -148,7 +140,7 @@ public final class RippleAnimationSession {
@Override @Override
public void onAnimationEnd(Animator animation) { public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation); super.onAnimationEnd(animation);
mAnimateSparkle = false; if (mLoopAnimation != null) mLoopAnimation.cancel();
Consumer<RippleAnimationSession> onEnd = mOnSessionEnd; Consumer<RippleAnimationSession> onEnd = mOnSessionEnd;
if (onEnd != null) onEnd.accept(RippleAnimationSession.this); if (onEnd != null) onEnd.accept(RippleAnimationSession.this);
} }
@@ -167,24 +159,42 @@ public final class RippleAnimationSession {
RenderNodeAnimator expand = RenderNodeAnimator expand =
new RenderNodeAnimator(props.getProgress(), .5f); new RenderNodeAnimator(props.getProgress(), .5f);
expand.setTarget(canvas); 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.setDuration(ENTER_ANIM_DURATION);
expand.addListener(new AnimatorListener(this)); expand.addListener(new AnimatorListener(this));
expand.setInterpolator(FAST_OUT_SLOW_IN); expand.setInterpolator(FAST_OUT_SLOW_IN);
expand.start(); 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() { private void enterSoftware() {
ValueAnimator expand = ValueAnimator.ofFloat(0f, 0.5f); ValueAnimator expand = ValueAnimator.ofFloat(0f, 0.5f);
expand.addUpdateListener(updatedAnimation -> { expand.addUpdateListener(updatedAnimation -> {
notifyUpdate(); 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<Float, Paint> getProperties() { @NonNull AnimationProperties<Float, Paint> getProperties() {
@@ -198,6 +208,7 @@ public final class RippleAnimationSession {
CanvasProperty.createFloat(mProperties.getX()), CanvasProperty.createFloat(mProperties.getX()),
CanvasProperty.createFloat(mProperties.getY()), CanvasProperty.createFloat(mProperties.getY()),
CanvasProperty.createFloat(mProperties.getMaxRadius()), CanvasProperty.createFloat(mProperties.getMaxRadius()),
CanvasProperty.createFloat(mProperties.getNoisePhase()),
CanvasProperty.createPaint(mProperties.getPaint()), CanvasProperty.createPaint(mProperties.getPaint()),
CanvasProperty.createFloat(mProperties.getProgress()), CanvasProperty.createFloat(mProperties.getProgress()),
mProperties.getShader()); mProperties.getShader());
@@ -236,16 +247,18 @@ public final class RippleAnimationSession {
static class AnimationProperties<FloatType, PaintType> { static class AnimationProperties<FloatType, PaintType> {
private final FloatType mProgress; private final FloatType mProgress;
private final FloatType mMaxRadius; private final FloatType mMaxRadius;
private final FloatType mNoisePhase;
private final PaintType mPaint; private final PaintType mPaint;
private final RippleShader mShader; private final RippleShader mShader;
private FloatType mX; private FloatType mX;
private FloatType mY; 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) { PaintType paint, FloatType progress, RippleShader shader) {
mY = y; mY = y;
mX = x; mX = x;
mMaxRadius = maxRadius; mMaxRadius = maxRadius;
mNoisePhase = noisePhase;
mPaint = paint; mPaint = paint;
mShader = shader; mShader = shader;
mProgress = progress; mProgress = progress;
@@ -279,5 +292,9 @@ public final class RippleAnimationSession {
RippleShader getShader() { RippleShader getShader() {
return mShader; return mShader;
} }
FloatType getNoisePhase() {
return mNoisePhase;
}
} }
} }

View File

@@ -858,15 +858,6 @@ public class RippleDrawable extends LayerDrawable {
} }
for (int i = 0; i < mRunningAnimations.size(); i++) { for (int i = 0; i < mRunningAnimations.size(); i++) {
RippleAnimationSession s = mRunningAnimations.get(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) { if (useCanvasProps) {
RippleAnimationSession.AnimationProperties<CanvasProperty<Float>, RippleAnimationSession.AnimationProperties<CanvasProperty<Float>,
CanvasProperty<Paint>> CanvasProperty<Paint>>
@@ -883,7 +874,7 @@ public class RippleDrawable extends LayerDrawable {
yProp = p.getY(); yProp = p.getY();
} }
can.drawRipple(xProp, yProp, p.getMaxRadius(), p.getPaint(), can.drawRipple(xProp, yProp, p.getMaxRadius(), p.getPaint(),
p.getProgress(), p.getShader()); p.getProgress(), p.getNoisePhase(), p.getShader());
} else { } else {
RippleAnimationSession.AnimationProperties<Float, Paint> p = RippleAnimationSession.AnimationProperties<Float, Paint> p =
s.getProperties(); s.getProperties();
@@ -953,7 +944,7 @@ public class RippleDrawable extends LayerDrawable {
shader.setRadius(radius); shader.setRadius(radius);
shader.setProgress(.0f); shader.setProgress(.0f);
properties = new RippleAnimationSession.AnimationProperties<>( properties = new RippleAnimationSession.AnimationProperties<>(
cx, cy, radius, p, 0f, shader); cx, cy, radius, 0f, p, 0f, shader);
if (mMaskShader == null) { if (mMaskShader == null) {
shader.setShader(null); shader.setShader(null);
} else { } else {

View File

@@ -167,6 +167,9 @@ final class RippleShader extends RuntimeShader {
final float turbulencePhase = (float) ((mProgress + mNoisePhase * 0.333f) * 5f * Math.PI); final float turbulencePhase = (float) ((mProgress + mNoisePhase * 0.333f) * 5f * Math.PI);
setUniform("in_turbulencePhase", turbulencePhase); setUniform("in_turbulencePhase", turbulencePhase);
//
// Keep in sync with: frameworks/base/libs/hwui/pipeline/skia/AnimatedDrawables.h
//
final float scale = 1.5f; final float scale = 1.5f;
setUniform("in_tCircle1", new float[]{ setUniform("in_tCircle1", new float[]{
(float) (scale * 0.5 + (turbulencePhase * 0.01 * Math.cos(scale * 0.55))), (float) (scale * 0.5 + (turbulencePhase * 0.01 * Math.cos(scale * 0.55))),

View File

@@ -820,10 +820,11 @@ void SkiaCanvas::drawRipple(uirenderer::CanvasPropertyPrimitive* x,
uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint, uirenderer::CanvasPropertyPaint* paint,
uirenderer::CanvasPropertyPrimitive* progress, uirenderer::CanvasPropertyPrimitive* progress,
uirenderer::CanvasPropertyPrimitive* turbulencePhase,
const SkRuntimeShaderBuilder& effectBuilder) { const SkRuntimeShaderBuilder& effectBuilder) {
sk_sp<uirenderer::skiapipeline::AnimatedRipple> drawable( sk_sp<uirenderer::skiapipeline::AnimatedRipple> drawable(
new uirenderer::skiapipeline::AnimatedRipple(x, y, radius, paint, progress, new uirenderer::skiapipeline::AnimatedRipple(x, y, radius, paint, progress,
effectBuilder)); turbulencePhase, effectBuilder));
mCanvas->drawDrawable(drawable.get()); mCanvas->drawDrawable(drawable.get());
} }

View File

@@ -153,6 +153,7 @@ public:
uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint, uirenderer::CanvasPropertyPaint* paint,
uirenderer::CanvasPropertyPrimitive* progress, uirenderer::CanvasPropertyPrimitive* progress,
uirenderer::CanvasPropertyPrimitive* turbulencePhase,
const SkRuntimeShaderBuilder& effectBuilder) override; const SkRuntimeShaderBuilder& effectBuilder) override;
virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) override; virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) override;

View File

@@ -152,32 +152,66 @@ struct CanvasOp<CanvasOpType::DrawRippleProperty> {
sp<uirenderer::CanvasPropertyPrimitive> radius; sp<uirenderer::CanvasPropertyPrimitive> radius;
sp<uirenderer::CanvasPropertyPaint> paint; sp<uirenderer::CanvasPropertyPaint> paint;
sp<uirenderer::CanvasPropertyPrimitive> progress; sp<uirenderer::CanvasPropertyPrimitive> progress;
sp<uirenderer::CanvasPropertyPrimitive> turbulencePhase;
sk_sp<SkRuntimeEffect> effect; sk_sp<SkRuntimeEffect> 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 { void draw(SkCanvas* canvas) const {
SkRuntimeShaderBuilder runtimeEffectBuilder(effect); SkRuntimeShaderBuilder runtimeEffectBuilder(effect);
SkRuntimeShaderBuilder::BuilderUniform center = runtimeEffectBuilder.uniform("in_origin"); setUniform2f(runtimeEffectBuilder, "in_origin", x->value, y->value);
if (center.fVar != nullptr) { setUniform(runtimeEffectBuilder, "in_radius", radius);
center = SkV2{x->value, y->value}; setUniform(runtimeEffectBuilder, "in_progress", progress);
} setUniform(runtimeEffectBuilder, "in_turbulencePhase", turbulencePhase);
SkRuntimeShaderBuilder::BuilderUniform radiusU = //
runtimeEffectBuilder.uniform("in_radius"); // Keep in sync with:
if (radiusU.fVar != nullptr) { // frameworks/base/graphics/java/android/graphics/drawable/RippleShader.java
radiusU = radius->value; //
} const float turbulence = turbulencePhase->value;
setUniform2f(runtimeEffectBuilder, "in_tCircle1", SCALE * 0.5 + (turbulence * CIRCLE_X_1),
SkRuntimeShaderBuilder::BuilderUniform progressU = SCALE * 0.5 + (turbulence * CIRCLE_Y_1));
runtimeEffectBuilder.uniform("in_progress"); setUniform2f(runtimeEffectBuilder, "in_tCircle2", SCALE * 0.2 + (turbulence * CIRCLE_X_2),
if (progressU.fVar != nullptr) { SCALE * 0.2 + (turbulence * CIRCLE_Y_2));
progressU = progress->value; 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; SkPaint paintMod = paint->value;
paintMod.setShader(runtimeEffectBuilder.makeShader(nullptr, false)); paintMod.setShader(runtimeEffectBuilder.makeShader(nullptr, false));
canvas->drawCircle(x->value, y->value, radius->value, paintMod); canvas->drawCircle(x->value, y->value, radius->value, paintMod);
} }
void setUniform(SkRuntimeShaderBuilder& effect, std::string name,
sp<uirenderer::CanvasPropertyPrimitive> 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() ASSERT_DRAWABLE()
}; };

View File

@@ -146,6 +146,7 @@ public:
uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint, uirenderer::CanvasPropertyPaint* paint,
uirenderer::CanvasPropertyPrimitive* progress, uirenderer::CanvasPropertyPrimitive* progress,
uirenderer::CanvasPropertyPrimitive* turbulencePhase,
const SkRuntimeShaderBuilder& effectBuilder) = 0; const SkRuntimeShaderBuilder& effectBuilder) = 0;
virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) = 0; virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) = 0;

View File

@@ -141,20 +141,22 @@ static void android_view_DisplayListCanvas_drawCircleProps(CRITICAL_JNI_PARAMS_C
canvas->drawCircle(xProp, yProp, radiusProp, paintProp); canvas->drawCircle(xProp, yProp, radiusProp, paintProp);
} }
static void android_view_DisplayListCanvas_drawRippleProps(CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr, static void android_view_DisplayListCanvas_drawRippleProps(
jlong xPropPtr, jlong yPropPtr, CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr, jlong xPropPtr, jlong yPropPtr,
jlong radiusPropPtr, jlong paintPropPtr, jlong radiusPropPtr, jlong paintPropPtr, jlong progressPropPtr, jlong turbulencePhasePtr,
jlong progressPropPtr, jlong builderPtr) {
jlong builderPtr) {
Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr); Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr); CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr); CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr);
CanvasPropertyPrimitive* radiusProp = reinterpret_cast<CanvasPropertyPrimitive*>(radiusPropPtr); CanvasPropertyPrimitive* radiusProp = reinterpret_cast<CanvasPropertyPrimitive*>(radiusPropPtr);
CanvasPropertyPrimitive* turbulencePhaseProp =
reinterpret_cast<CanvasPropertyPrimitive*>(turbulencePhasePtr);
CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(paintPropPtr); CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(paintPropPtr);
CanvasPropertyPrimitive* progressProp = CanvasPropertyPrimitive* progressProp =
reinterpret_cast<CanvasPropertyPrimitive*>(progressPropPtr); reinterpret_cast<CanvasPropertyPrimitive*>(progressPropPtr);
SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(builderPtr); SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(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) { 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"; const char* const kClassPathName = "android/graphics/RecordingCanvas";
static JNINativeMethod gMethods[] = { static JNINativeMethod gMethods[] = {
// ------------ @CriticalNative -------------- // ------------ @CriticalNative --------------
{ "nCreateDisplayListCanvas", "(JII)J", (void*) android_view_DisplayListCanvas_createDisplayListCanvas }, {"nCreateDisplayListCanvas", "(JII)J",
{ "nResetDisplayListCanvas", "(JJII)V", (void*) android_view_DisplayListCanvas_resetDisplayListCanvas }, (void*)android_view_DisplayListCanvas_createDisplayListCanvas},
{ "nGetMaximumTextureWidth", "()I", (void*) android_view_DisplayListCanvas_getMaxTextureSize }, {"nResetDisplayListCanvas", "(JJII)V",
{ "nGetMaximumTextureHeight", "()I", (void*) android_view_DisplayListCanvas_getMaxTextureSize }, (void*)android_view_DisplayListCanvas_resetDisplayListCanvas},
{ "nEnableZ", "(JZ)V", (void*) android_view_DisplayListCanvas_enableZ }, {"nGetMaximumTextureWidth", "()I", (void*)android_view_DisplayListCanvas_getMaxTextureSize},
{ "nFinishRecording", "(JJ)V", (void*) android_view_DisplayListCanvas_finishRecording }, {"nGetMaximumTextureHeight", "()I",
{ "nDrawRenderNode", "(JJ)V", (void*) android_view_DisplayListCanvas_drawRenderNode }, (void*)android_view_DisplayListCanvas_getMaxTextureSize},
{ "nDrawTextureLayer", "(JJ)V", (void*) android_view_DisplayListCanvas_drawTextureLayer }, {"nEnableZ", "(JZ)V", (void*)android_view_DisplayListCanvas_enableZ},
{ "nDrawCircle", "(JJJJJ)V", (void*) android_view_DisplayListCanvas_drawCircleProps }, {"nFinishRecording", "(JJ)V", (void*)android_view_DisplayListCanvas_finishRecording},
{ "nDrawRoundRect", "(JJJJJJJJ)V",(void*) android_view_DisplayListCanvas_drawRoundRectProps }, {"nDrawRenderNode", "(JJ)V", (void*)android_view_DisplayListCanvas_drawRenderNode},
{ "nDrawWebViewFunctor", "(JI)V", (void*) android_view_DisplayListCanvas_drawWebViewFunctor }, {"nDrawTextureLayer", "(JJ)V", (void*)android_view_DisplayListCanvas_drawTextureLayer},
{ "nDrawRipple", "(JJJJJJJ)V", (void*) android_view_DisplayListCanvas_drawRippleProps }, {"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) { int register_android_view_DisplayListCanvas(JNIEnv* env) {

View File

@@ -19,6 +19,7 @@
#include <SkCanvas.h> #include <SkCanvas.h>
#include <SkDrawable.h> #include <SkDrawable.h>
#include <SkRuntimeEffect.h> #include <SkRuntimeEffect.h>
#include <math.h>
#include <utils/RefBase.h> #include <utils/RefBase.h>
#include "CanvasProperty.h" #include "CanvasProperty.h"
@@ -61,12 +62,14 @@ public:
uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint, uirenderer::CanvasPropertyPaint* paint,
uirenderer::CanvasPropertyPrimitive* progress, uirenderer::CanvasPropertyPrimitive* progress,
uirenderer::CanvasPropertyPrimitive* turbulencePhase,
const SkRuntimeShaderBuilder& effectBuilder) const SkRuntimeShaderBuilder& effectBuilder)
: mX(x) : mX(x)
, mY(y) , mY(y)
, mRadius(radius) , mRadius(radius)
, mPaint(paint) , mPaint(paint)
, mProgress(progress) , mProgress(progress)
, mTurbulencePhase(turbulencePhase)
, mRuntimeEffectBuilder(effectBuilder) {} , mRuntimeEffectBuilder(effectBuilder) {}
protected: protected:
@@ -77,22 +80,28 @@ protected:
return SkRect::MakeLTRB(x - radius, y - radius, x + radius, y + radius); return SkRect::MakeLTRB(x - radius, y - radius, x + radius, y + radius);
} }
virtual void onDraw(SkCanvas* canvas) override { virtual void onDraw(SkCanvas* canvas) override {
SkRuntimeShaderBuilder::BuilderUniform center = mRuntimeEffectBuilder.uniform("in_origin"); setUniform2f("in_origin", mX->value, mY->value);
if (center.fVar != nullptr) { setUniform("in_radius", mRadius);
center = SkV2{mX->value, mY->value}; setUniform("in_progress", mProgress);
} setUniform("in_turbulencePhase", mTurbulencePhase);
SkRuntimeShaderBuilder::BuilderUniform radiusU = //
mRuntimeEffectBuilder.uniform("in_radius"); // Keep in sync with:
if (radiusU.fVar != nullptr) { // frameworks/base/graphics/java/android/graphics/drawable/RippleShader.java
radiusU = mRadius->value; //
} const float turbulencePhase = mTurbulencePhase->value;
setUniform2f("in_tCircle1", SCALE * 0.5 + (turbulencePhase * CIRCLE_X_1),
SkRuntimeShaderBuilder::BuilderUniform progressU = SCALE * 0.5 + (turbulencePhase * CIRCLE_Y_1));
mRuntimeEffectBuilder.uniform("in_progress"); setUniform2f("in_tCircle2", SCALE * 0.2 + (turbulencePhase * CIRCLE_X_2),
if (progressU.fVar != nullptr) { SCALE * 0.2 + (turbulencePhase * CIRCLE_Y_2));
progressU = mProgress->value; 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; SkPaint paint = mPaint->value;
paint.setShader(mRuntimeEffectBuilder.makeShader(nullptr, false)); paint.setShader(mRuntimeEffectBuilder.makeShader(nullptr, false));
@@ -105,7 +114,35 @@ private:
sp<uirenderer::CanvasPropertyPrimitive> mRadius; sp<uirenderer::CanvasPropertyPrimitive> mRadius;
sp<uirenderer::CanvasPropertyPaint> mPaint; sp<uirenderer::CanvasPropertyPaint> mPaint;
sp<uirenderer::CanvasPropertyPrimitive> mProgress; sp<uirenderer::CanvasPropertyPrimitive> mProgress;
sp<uirenderer::CanvasPropertyPrimitive> mTurbulencePhase;
SkRuntimeShaderBuilder mRuntimeEffectBuilder; 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<uirenderer::CanvasPropertyPrimitive> 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 { class AnimatedCircle : public SkDrawable {

View File

@@ -114,9 +114,10 @@ void SkiaRecordingCanvas::drawRipple(uirenderer::CanvasPropertyPrimitive* x,
uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint, uirenderer::CanvasPropertyPaint* paint,
uirenderer::CanvasPropertyPrimitive* progress, uirenderer::CanvasPropertyPrimitive* progress,
uirenderer::CanvasPropertyPrimitive* turbulencePhase,
const SkRuntimeShaderBuilder& effectBuilder) { const SkRuntimeShaderBuilder& effectBuilder) {
drawDrawable(mDisplayList->allocateDrawable<AnimatedRipple>(x, y, radius, paint, progress, drawDrawable(mDisplayList->allocateDrawable<AnimatedRipple>(x, y, radius, paint, progress,
effectBuilder)); turbulencePhase, effectBuilder));
} }
void SkiaRecordingCanvas::enableZ(bool enableZ) { void SkiaRecordingCanvas::enableZ(bool enableZ) {

View File

@@ -75,6 +75,7 @@ public:
uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint, uirenderer::CanvasPropertyPaint* paint,
uirenderer::CanvasPropertyPrimitive* progress, uirenderer::CanvasPropertyPrimitive* progress,
uirenderer::CanvasPropertyPrimitive* turbulencePhase,
const SkRuntimeShaderBuilder& effectBuilder) override; const SkRuntimeShaderBuilder& effectBuilder) override;
virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override; virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;

View File

@@ -56,6 +56,7 @@ public class RippleActivity extends Activity {
CanvasProperty<Float> mY; CanvasProperty<Float> mY;
CanvasProperty<Float> mRadius; CanvasProperty<Float> mRadius;
CanvasProperty<Float> mProgress; CanvasProperty<Float> mProgress;
CanvasProperty<Float> mNoisePhase;
CanvasProperty<Paint> mPaint; CanvasProperty<Paint> mPaint;
RuntimeShader mRuntimeShader; RuntimeShader mRuntimeShader;
@@ -99,6 +100,7 @@ public class RippleActivity extends Activity {
mY = CanvasProperty.createFloat(200.0f); mY = CanvasProperty.createFloat(200.0f);
mRadius = CanvasProperty.createFloat(150.0f); mRadius = CanvasProperty.createFloat(150.0f);
mProgress = CanvasProperty.createFloat(0.0f); mProgress = CanvasProperty.createFloat(0.0f);
mNoisePhase = CanvasProperty.createFloat(0.0f);
Paint p = new Paint(); Paint p = new Paint();
p.setAntiAlias(true); p.setAntiAlias(true);
@@ -115,7 +117,8 @@ public class RippleActivity extends Activity {
if (canvas.isHardwareAccelerated()) { if (canvas.isHardwareAccelerated()) {
RecordingCanvas recordingCanvas = (RecordingCanvas) canvas; 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( mRunningAnimations.add(new RenderNodeAnimator(
mProgress, mToggle ? 1.0f : 0.0f)); mProgress, mToggle ? 1.0f : 0.0f));
mRunningAnimations.add(new RenderNodeAnimator(
mNoisePhase, DURATION));
mRunningAnimations.add(new RenderNodeAnimator( mRunningAnimations.add(new RenderNodeAnimator(
mPaint, RenderNodeAnimator.PAINT_ALPHA, 64.0f)); mPaint, RenderNodeAnimator.PAINT_ALPHA, 64.0f));