Move sparkle animation to RenderThread
The sparkle loop animation was happening on the UI thread and is poses
some interesting challengers:
- Animations freezes when UI thread is busy, for example when
startActivity is called.
- onDraw calls add unnecessary work to the UI thread, leading to jank
in some cases, like PIP
Test: manual
Fixes: 184760248
Change-Id: Ie2840c767da61476678839eaac215dc3aff95b5c
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 4c4a152..3056e97 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -820,10 +820,11 @@
uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint,
uirenderer::CanvasPropertyPrimitive* progress,
+ uirenderer::CanvasPropertyPrimitive* turbulencePhase,
const SkRuntimeShaderBuilder& effectBuilder) {
sk_sp<uirenderer::skiapipeline::AnimatedRipple> 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 e0a0be5..995f00c 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -153,6 +153,7 @@
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 855cd0d..173f394 100644
--- a/libs/hwui/canvas/CanvasOps.h
+++ b/libs/hwui/canvas/CanvasOps.h
@@ -152,32 +152,66 @@
sp<uirenderer::CanvasPropertyPrimitive> radius;
sp<uirenderer::CanvasPropertyPaint> paint;
sp<uirenderer::CanvasPropertyPrimitive> progress;
+ sp<uirenderer::CanvasPropertyPrimitive> turbulencePhase;
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 {
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<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()
};
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index c1feb76..837b055 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -146,6 +146,7 @@
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 855d56e..eb5a88a 100644
--- a/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
+++ b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
@@ -141,20 +141,22 @@
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<Canvas*>(canvasPtr);
CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr);
CanvasPropertyPrimitive* radiusProp = reinterpret_cast<CanvasPropertyPrimitive*>(radiusPropPtr);
+ CanvasPropertyPrimitive* turbulencePhaseProp =
+ reinterpret_cast<CanvasPropertyPrimitive*>(turbulencePhasePtr);
CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(paintPropPtr);
CanvasPropertyPrimitive* progressProp =
reinterpret_cast<CanvasPropertyPrimitive*>(progressPropPtr);
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) {
@@ -169,19 +171,22 @@
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 7859145..7d65be1 100644
--- a/libs/hwui/pipeline/skia/AnimatedDrawables.h
+++ b/libs/hwui/pipeline/skia/AnimatedDrawables.h
@@ -19,6 +19,7 @@
#include <SkCanvas.h>
#include <SkDrawable.h>
#include <SkRuntimeEffect.h>
+#include <math.h>
#include <utils/RefBase.h>
#include "CanvasProperty.h"
@@ -61,12 +62,14 @@
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 @@
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 @@
sp<uirenderer::CanvasPropertyPrimitive> mRadius;
sp<uirenderer::CanvasPropertyPaint> mPaint;
sp<uirenderer::CanvasPropertyPrimitive> mProgress;
+ sp<uirenderer::CanvasPropertyPrimitive> 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<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 {
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 82814de..a8e427d 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -115,9 +115,10 @@
uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint,
uirenderer::CanvasPropertyPrimitive* progress,
+ uirenderer::CanvasPropertyPrimitive* turbulencePhase,
const SkRuntimeShaderBuilder& effectBuilder) {
drawDrawable(mDisplayList->allocateDrawable<AnimatedRipple>(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 06f2a27..4deb3b9 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -75,6 +75,7 @@
uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint,
uirenderer::CanvasPropertyPrimitive* progress,
+ uirenderer::CanvasPropertyPrimitive* turbulencePhase,
const SkRuntimeShaderBuilder& effectBuilder) override;
virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;