Merge "Refactor RuntimeShader to support easier assignment of uniforms."
This commit is contained in:
committed by
Android (Google) Code Review
commit
106f1b33b4
@@ -220,7 +220,7 @@ public final class RecordingCanvas extends BaseRecordingCanvas {
|
||||
CanvasProperty<Float> progress, RuntimeShader shader) {
|
||||
nDrawRipple(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(),
|
||||
radius.getNativeContainer(), paint.getNativeContainer(),
|
||||
progress.getNativeContainer(), shader.getNativeShaderFactory());
|
||||
progress.getNativeContainer(), shader.getNativeShaderBuilder());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package android.graphics;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
|
||||
import libcore.util.NativeAllocationRegistry;
|
||||
|
||||
@@ -33,14 +32,12 @@ public class RuntimeShader extends Shader {
|
||||
RuntimeShader.class.getClassLoader(), nativeGetFinalizer());
|
||||
}
|
||||
|
||||
private byte[] mUniforms;
|
||||
private Shader[] mInputShaders;
|
||||
private boolean mIsOpaque;
|
||||
|
||||
/**
|
||||
* Current native shader factory instance.
|
||||
* Current native shader builder instance.
|
||||
*/
|
||||
private long mNativeInstanceRuntimeShaderFactory;
|
||||
private long mNativeInstanceRuntimeShaderBuilder;
|
||||
|
||||
/**
|
||||
* Creates a new RuntimeShader.
|
||||
@@ -50,80 +47,86 @@ public class RuntimeShader extends Shader {
|
||||
* on number of uniforms declared by sksl.
|
||||
* @param isOpaque True if all pixels have alpha 1.0f.
|
||||
*/
|
||||
public RuntimeShader(@NonNull String sksl, @Nullable byte[] uniforms, boolean isOpaque) {
|
||||
this(sksl, uniforms, null, isOpaque, ColorSpace.get(ColorSpace.Named.SRGB));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new RuntimeShader.
|
||||
*
|
||||
* @param sksl The text of SKSL program to run on the GPU.
|
||||
* @param uniforms Array of parameters passed by the SKSL shader. Array size depends
|
||||
* on number of uniforms declared by sksl.
|
||||
* @param shaderInputs Array of shaders passed to the SKSL shader. Array size depends
|
||||
* on the number of input shaders declared in the sksl
|
||||
* @param isOpaque True if all pixels have alpha 1.0f.
|
||||
*/
|
||||
public RuntimeShader(@NonNull String sksl, @Nullable byte[] uniforms,
|
||||
@Nullable Shader[] shaderInputs, boolean isOpaque) {
|
||||
this(sksl, uniforms, shaderInputs, isOpaque, ColorSpace.get(ColorSpace.Named.SRGB));
|
||||
}
|
||||
|
||||
private RuntimeShader(@NonNull String sksl, @Nullable byte[] uniforms,
|
||||
@Nullable Shader[] shaderInputs, boolean isOpaque,
|
||||
ColorSpace colorSpace) {
|
||||
super(colorSpace);
|
||||
mUniforms = uniforms;
|
||||
mInputShaders = shaderInputs;
|
||||
public RuntimeShader(@NonNull String sksl, boolean isOpaque) {
|
||||
super(ColorSpace.get(ColorSpace.Named.SRGB));
|
||||
mIsOpaque = isOpaque;
|
||||
mNativeInstanceRuntimeShaderFactory = nativeCreateShaderFactory(sksl);
|
||||
NoImagePreloadHolder.sRegistry.registerNativeAllocation(this,
|
||||
mNativeInstanceRuntimeShaderFactory);
|
||||
mNativeInstanceRuntimeShaderBuilder = nativeCreateBuilder(sksl);
|
||||
NoImagePreloadHolder.sRegistry.registerNativeAllocation(
|
||||
this, mNativeInstanceRuntimeShaderBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets new value for shader parameters.
|
||||
* Sets the uniform value corresponding to this shader. If the shader does not have a uniform
|
||||
* with that name or if the uniform is declared with a type other than float then an
|
||||
* IllegalArgumentException is thrown.
|
||||
*
|
||||
* @param uniforms Array of parameters passed by the SKSL shader. Array size depends
|
||||
* on number of uniforms declared by mSksl.
|
||||
* @param uniformName name matching the uniform declared in the SKSL shader
|
||||
* @param value
|
||||
*/
|
||||
public void updateUniforms(@Nullable byte[] uniforms) {
|
||||
mUniforms = uniforms;
|
||||
public void setUniform(@NonNull String uniformName, float value) {
|
||||
setUniform(uniformName, new float[] {value});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the uniform value corresponding to this shader. If the shader does not have a uniform
|
||||
* with that name or if the uniform is declared with a type other than float2/vec2 then an
|
||||
* IllegalArgumentException is thrown.
|
||||
*
|
||||
* @param uniformName name matching the uniform declared in the SKSL shader
|
||||
* @param value1
|
||||
* @param value2
|
||||
*/
|
||||
public void setUniform(@NonNull String uniformName, float value1, float value2) {
|
||||
setUniform(uniformName, new float[] {value1, value2});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the uniform value corresponding to this shader. If the shader does not have a uniform
|
||||
* with that name or if the uniform is declared with a type other than a vecN/floatN where N is
|
||||
* the size of the values array then an IllegalArgumentException is thrown.
|
||||
*
|
||||
* @param uniformName name matching the uniform declared in the SKSL shader
|
||||
* @param values
|
||||
*/
|
||||
public void setUniform(@NonNull String uniformName, float[] values) {
|
||||
nativeUpdateUniforms(mNativeInstanceRuntimeShaderBuilder, uniformName, values);
|
||||
discardNativeInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets new values for the shaders that serve as inputs to this shader.
|
||||
* Sets the uniform shader that is declares as input to this shader. If the shader does not
|
||||
* have a uniform shader with that name then an IllegalArgumentException is thrown.
|
||||
*
|
||||
* @param shaderInputs Array of Shaders passed into the SKSL shader. Array size depends
|
||||
* on number of input shaders declared by sksl.
|
||||
* @param shaderName name matching the uniform declared in the SKSL shader
|
||||
* @param shader shader passed into the SKSL shader for sampling
|
||||
*/
|
||||
public void updateInputShaders(@Nullable Shader[] shaderInputs) {
|
||||
mInputShaders = shaderInputs;
|
||||
public void setInputShader(@NonNull String shaderName, @NonNull Shader shader) {
|
||||
nativeUpdateShader(
|
||||
mNativeInstanceRuntimeShaderBuilder, shaderName, shader.getNativeInstance());
|
||||
discardNativeInstance();
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
protected long createNativeInstance(long nativeMatrix, boolean filterFromPaint) {
|
||||
long[] nativeShaders = mInputShaders.length > 0 ? new long[mInputShaders.length] : null;
|
||||
for (int i = 0; i < mInputShaders.length; i++) {
|
||||
nativeShaders[i] = mInputShaders[i].getNativeInstance(filterFromPaint);
|
||||
}
|
||||
|
||||
return nativeCreate(mNativeInstanceRuntimeShaderFactory, nativeMatrix, mUniforms,
|
||||
nativeShaders, colorSpace().getNativeInstance(), mIsOpaque);
|
||||
return nativeCreateShader(mNativeInstanceRuntimeShaderBuilder, nativeMatrix, mIsOpaque);
|
||||
}
|
||||
|
||||
public long getNativeShaderFactory() {
|
||||
return mNativeInstanceRuntimeShaderFactory;
|
||||
public long getNativeShaderBuilder() {
|
||||
return mNativeInstanceRuntimeShaderBuilder;
|
||||
}
|
||||
|
||||
private static native long nativeCreate(long shaderFactory, long matrix, byte[] inputs,
|
||||
long[] shaderInputs, long colorSpaceHandle, boolean isOpaque);
|
||||
|
||||
private static native long nativeCreateShaderFactory(String sksl);
|
||||
public boolean isOpaque() {
|
||||
return mIsOpaque;
|
||||
}
|
||||
|
||||
private static native long nativeGetFinalizer();
|
||||
private static native long nativeCreateBuilder(String sksl);
|
||||
private static native long nativeCreateShader(
|
||||
long shaderBuilder, long matrix, boolean isOpaque);
|
||||
private static native void nativeUpdateUniforms(
|
||||
long shaderBuilder, String uniformName, float[] uniforms);
|
||||
private static native void nativeUpdateShader(
|
||||
long shaderBuilder, String shaderName, long shader);
|
||||
}
|
||||
|
||||
|
||||
@@ -819,10 +819,10 @@ void SkiaCanvas::drawRipple(uirenderer::CanvasPropertyPrimitive* x,
|
||||
uirenderer::CanvasPropertyPrimitive* radius,
|
||||
uirenderer::CanvasPropertyPaint* paint,
|
||||
uirenderer::CanvasPropertyPrimitive* progress,
|
||||
sk_sp<SkRuntimeEffect> runtimeEffect) {
|
||||
const SkRuntimeShaderBuilder& effectBuilder) {
|
||||
sk_sp<uirenderer::skiapipeline::AnimatedRipple> drawable(
|
||||
new uirenderer::skiapipeline::AnimatedRipple(x, y, radius, paint, progress,
|
||||
runtimeEffect));
|
||||
effectBuilder));
|
||||
mCanvas->drawDrawable(drawable.get());
|
||||
}
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ public:
|
||||
uirenderer::CanvasPropertyPrimitive* radius,
|
||||
uirenderer::CanvasPropertyPaint* paint,
|
||||
uirenderer::CanvasPropertyPrimitive* progress,
|
||||
sk_sp<SkRuntimeEffect> runtimeEffect) override;
|
||||
const SkRuntimeShaderBuilder& effectBuilder) override;
|
||||
|
||||
virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) override;
|
||||
virtual void drawRenderNode(uirenderer::RenderNode* renderNode) override;
|
||||
|
||||
@@ -161,7 +161,7 @@ struct CanvasOp<CanvasOpType::DrawRippleProperty> {
|
||||
}
|
||||
|
||||
SkRuntimeShaderBuilder::BuilderUniform radiusU =
|
||||
runtimeEffectBuilder.uniform("in_maxRadius");
|
||||
runtimeEffectBuilder.uniform("in_radius");
|
||||
if (radiusU.fVar != nullptr) {
|
||||
radiusU = radius->value;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
class SkAnimatedImage;
|
||||
class SkCanvasState;
|
||||
class SkRuntimeEffect;
|
||||
class SkRuntimeShaderBuilder;
|
||||
class SkVertices;
|
||||
|
||||
namespace minikin {
|
||||
@@ -139,7 +139,7 @@ public:
|
||||
uirenderer::CanvasPropertyPrimitive* radius,
|
||||
uirenderer::CanvasPropertyPaint* paint,
|
||||
uirenderer::CanvasPropertyPrimitive* progress,
|
||||
sk_sp<SkRuntimeEffect> runtimeEffect) = 0;
|
||||
const SkRuntimeShaderBuilder& effectBuilder) = 0;
|
||||
|
||||
virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) = 0;
|
||||
virtual void drawRenderNode(uirenderer::RenderNode* renderNode) = 0;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#undef LOG_TAG
|
||||
#define LOG_TAG "ShaderJNI"
|
||||
|
||||
#include "GraphicsJNI.h"
|
||||
#include "SkColorFilter.h"
|
||||
#include "SkGradientShader.h"
|
||||
@@ -232,53 +235,72 @@ static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderFactory, jlong matrixPtr,
|
||||
jbyteArray inputs, jlongArray inputShaders, jlong colorSpaceHandle, jboolean isOpaque) {
|
||||
SkRuntimeEffect* effect = reinterpret_cast<SkRuntimeEffect*>(shaderFactory);
|
||||
AutoJavaByteArray arInputs(env, inputs);
|
||||
|
||||
std::vector<sk_sp<SkShader>> shaderVector;
|
||||
if (inputShaders) {
|
||||
jsize shaderCount = env->GetArrayLength(inputShaders);
|
||||
shaderVector.resize(shaderCount);
|
||||
jlong* arrayPtr = env->GetLongArrayElements(inputShaders, NULL);
|
||||
for (int i = 0; i < shaderCount; i++) {
|
||||
shaderVector[i] = sk_ref_sp(reinterpret_cast<SkShader*>(arrayPtr[i]));
|
||||
}
|
||||
env->ReleaseLongArrayElements(inputShaders, arrayPtr, 0);
|
||||
}
|
||||
|
||||
sk_sp<SkData> fData;
|
||||
fData = SkData::MakeWithCopy(arInputs.ptr(), arInputs.length());
|
||||
const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
|
||||
sk_sp<SkShader> shader = effect->makeShader(fData, shaderVector.data(), shaderVector.size(),
|
||||
matrix, isOpaque == JNI_TRUE);
|
||||
ThrowIAE_IfNull(env, shader);
|
||||
|
||||
return reinterpret_cast<jlong>(shader.release());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static jlong RuntimeShader_createShaderFactory(JNIEnv* env, jobject, jstring sksl) {
|
||||
static jlong RuntimeShader_createShaderBuilder(JNIEnv* env, jobject, jstring sksl) {
|
||||
ScopedUtfChars strSksl(env, sksl);
|
||||
auto result = SkRuntimeEffect::Make(SkString(strSksl.c_str()));
|
||||
sk_sp<SkRuntimeEffect> effect = std::get<0>(result);
|
||||
if (!effect) {
|
||||
if (effect.get() == nullptr) {
|
||||
const auto& err = std::get<1>(result);
|
||||
doThrowIAE(env, err.c_str());
|
||||
return 0;
|
||||
}
|
||||
return reinterpret_cast<jlong>(effect.release());
|
||||
return reinterpret_cast<jlong>(new SkRuntimeShaderBuilder(std::move(effect)));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void Effect_safeUnref(SkRuntimeEffect* effect) {
|
||||
SkSafeUnref(effect);
|
||||
static void SkRuntimeShaderBuilder_delete(SkRuntimeShaderBuilder* builder) {
|
||||
delete builder;
|
||||
}
|
||||
|
||||
static jlong RuntimeShader_getNativeFinalizer(JNIEnv*, jobject) {
|
||||
return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Effect_safeUnref));
|
||||
return static_cast<jlong>(reinterpret_cast<uintptr_t>(&SkRuntimeShaderBuilder_delete));
|
||||
}
|
||||
|
||||
static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderBuilder, jlong matrixPtr,
|
||||
jboolean isOpaque) {
|
||||
SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
|
||||
const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
|
||||
sk_sp<SkShader> shader = builder->makeShader(matrix, isOpaque == JNI_TRUE);
|
||||
ThrowIAE_IfNull(env, shader);
|
||||
return reinterpret_cast<jlong>(shader.release());
|
||||
}
|
||||
|
||||
static inline int ThrowIAEFmt(JNIEnv* env, const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
return jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static void RuntimeShader_updateUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
|
||||
jstring jUniformName, jfloatArray jvalues) {
|
||||
SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
|
||||
ScopedUtfChars name(env, jUniformName);
|
||||
AutoJavaFloatArray autoValues(env, jvalues, 0, kRO_JNIAccess);
|
||||
|
||||
SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(name.c_str());
|
||||
if (uniform.fVar == nullptr) {
|
||||
ThrowIAEFmt(env, "unable to find uniform named %s", name.c_str());
|
||||
} else if (!uniform.set<float>(autoValues.ptr(), autoValues.length())) {
|
||||
ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
|
||||
uniform.fVar->sizeInBytes(), sizeof(float) * autoValues.length());
|
||||
}
|
||||
}
|
||||
|
||||
static void RuntimeShader_updateShader(JNIEnv* env, jobject, jlong shaderBuilder,
|
||||
jstring jUniformName, jlong shaderHandle) {
|
||||
SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
|
||||
ScopedUtfChars name(env, jUniformName);
|
||||
SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
|
||||
|
||||
SkRuntimeShaderBuilder::BuilderChild child = builder->child(name.c_str());
|
||||
if (child.fIndex == -1) {
|
||||
ThrowIAEFmt(env, "unable to find shader named %s", name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
builder->child(name.c_str()) = sk_ref_sp(shader);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -313,10 +335,11 @@ static const JNINativeMethod gComposeShaderMethods[] = {
|
||||
};
|
||||
|
||||
static const JNINativeMethod gRuntimeShaderMethods[] = {
|
||||
{ "nativeGetFinalizer", "()J", (void*)RuntimeShader_getNativeFinalizer },
|
||||
{ "nativeCreate", "(JJ[B[JJZ)J", (void*)RuntimeShader_create },
|
||||
{ "nativeCreateShaderFactory", "(Ljava/lang/String;)J",
|
||||
(void*)RuntimeShader_createShaderFactory },
|
||||
{"nativeGetFinalizer", "()J", (void*)RuntimeShader_getNativeFinalizer},
|
||||
{"nativeCreateShader", "(JJZ)J", (void*)RuntimeShader_create},
|
||||
{"nativeCreateBuilder", "(Ljava/lang/String;)J", (void*)RuntimeShader_createShaderBuilder},
|
||||
{"nativeUpdateUniforms", "(JLjava/lang/String;[F)V", (void*)RuntimeShader_updateUniforms},
|
||||
{"nativeUpdateShader", "(JLjava/lang/String;J)V", (void*)RuntimeShader_updateShader},
|
||||
};
|
||||
|
||||
int register_android_graphics_Shader(JNIEnv* env)
|
||||
|
||||
@@ -144,7 +144,8 @@ static void android_view_DisplayListCanvas_drawCircleProps(CRITICAL_JNI_PARAMS_C
|
||||
static void android_view_DisplayListCanvas_drawRippleProps(CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr,
|
||||
jlong xPropPtr, jlong yPropPtr,
|
||||
jlong radiusPropPtr, jlong paintPropPtr,
|
||||
jlong progressPropPtr, jlong effectPtr) {
|
||||
jlong progressPropPtr,
|
||||
jlong builderPtr) {
|
||||
Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
|
||||
CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
|
||||
CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr);
|
||||
@@ -152,8 +153,8 @@ static void android_view_DisplayListCanvas_drawRippleProps(CRITICAL_JNI_PARAMS_C
|
||||
CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(paintPropPtr);
|
||||
CanvasPropertyPrimitive* progressProp =
|
||||
reinterpret_cast<CanvasPropertyPrimitive*>(progressPropPtr);
|
||||
SkRuntimeEffect* effect = reinterpret_cast<SkRuntimeEffect*>(effectPtr);
|
||||
canvas->drawRipple(xProp, yProp, radiusProp, paintProp, progressProp, sk_ref_sp(effect));
|
||||
SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(builderPtr);
|
||||
canvas->drawRipple(xProp, yProp, radiusProp, paintProp, progressProp, *builder);
|
||||
}
|
||||
|
||||
static void android_view_DisplayListCanvas_drawWebViewFunctor(CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr, jint functor) {
|
||||
|
||||
@@ -61,13 +61,13 @@ public:
|
||||
uirenderer::CanvasPropertyPrimitive* radius,
|
||||
uirenderer::CanvasPropertyPaint* paint,
|
||||
uirenderer::CanvasPropertyPrimitive* progress,
|
||||
sk_sp<SkRuntimeEffect> runtimeEffect)
|
||||
const SkRuntimeShaderBuilder& effectBuilder)
|
||||
: mX(x)
|
||||
, mY(y)
|
||||
, mRadius(radius)
|
||||
, mPaint(paint)
|
||||
, mProgress(progress)
|
||||
, mRuntimeEffectBuilder(std::move(runtimeEffect)) {}
|
||||
, mRuntimeEffectBuilder(effectBuilder) {}
|
||||
|
||||
protected:
|
||||
virtual SkRect onGetBounds() override {
|
||||
@@ -83,7 +83,7 @@ protected:
|
||||
}
|
||||
|
||||
SkRuntimeShaderBuilder::BuilderUniform radiusU =
|
||||
mRuntimeEffectBuilder.uniform("in_maxRadius");
|
||||
mRuntimeEffectBuilder.uniform("in_radius");
|
||||
if (radiusU.fVar != nullptr) {
|
||||
radiusU = mRadius->value;
|
||||
}
|
||||
|
||||
@@ -90,9 +90,9 @@ void SkiaRecordingCanvas::drawRipple(uirenderer::CanvasPropertyPrimitive* x,
|
||||
uirenderer::CanvasPropertyPrimitive* radius,
|
||||
uirenderer::CanvasPropertyPaint* paint,
|
||||
uirenderer::CanvasPropertyPrimitive* progress,
|
||||
sk_sp<SkRuntimeEffect> runtimeEffect) {
|
||||
const SkRuntimeShaderBuilder& effectBuilder) {
|
||||
drawDrawable(mDisplayList->allocateDrawable<AnimatedRipple>(x, y, radius, paint, progress,
|
||||
runtimeEffect));
|
||||
effectBuilder));
|
||||
}
|
||||
|
||||
void SkiaRecordingCanvas::enableZ(bool enableZ) {
|
||||
|
||||
@@ -71,7 +71,7 @@ public:
|
||||
uirenderer::CanvasPropertyPrimitive* radius,
|
||||
uirenderer::CanvasPropertyPaint* paint,
|
||||
uirenderer::CanvasPropertyPrimitive* progress,
|
||||
sk_sp<SkRuntimeEffect> runtimeEffect) override;
|
||||
const SkRuntimeShaderBuilder& effectBuilder) override;
|
||||
|
||||
virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;
|
||||
|
||||
|
||||
@@ -1016,6 +1016,15 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="RippleActivity"
|
||||
android:label="Animation/Ripple Animation"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="com.android.test.hwui.TEST"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="MultiProducerActivity"
|
||||
android:label="Threads/Multiple Producers"
|
||||
android:exported="true">
|
||||
|
||||
@@ -35,9 +35,6 @@ import android.graphics.Shader;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
public class ColorFiltersMutateActivity extends Activity {
|
||||
@Override
|
||||
@@ -54,11 +51,13 @@ public class ColorFiltersMutateActivity extends Activity {
|
||||
private final Paint mLightingPaint;
|
||||
private final Paint mBlendPaint;
|
||||
private final Paint mShaderPaint;
|
||||
private final RuntimeShader mRuntimeShader;
|
||||
|
||||
private float mSaturation = 0.0f;
|
||||
private int mLightAdd = 0;
|
||||
private int mLightMul = 0;
|
||||
private int mPorterDuffColor = 0;
|
||||
private float mShaderParam1 = 0.0f;
|
||||
|
||||
static final String sSkSL =
|
||||
"in shader bitmapShader;\n"
|
||||
@@ -67,8 +66,6 @@ public class ColorFiltersMutateActivity extends Activity {
|
||||
+ " return half4(sample(bitmapShader, xy).rgb, param1);\n"
|
||||
+ "}\n";
|
||||
|
||||
private byte[] mUniforms = new byte[4];
|
||||
|
||||
BitmapsView(Context c) {
|
||||
super(c);
|
||||
|
||||
@@ -86,11 +83,13 @@ public class ColorFiltersMutateActivity extends Activity {
|
||||
mBlendPaint = new Paint();
|
||||
mBlendPaint.setColorFilter(new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_OVER));
|
||||
|
||||
mRuntimeShader = new RuntimeShader(sSkSL, false);
|
||||
mRuntimeShader.setUniform("param1", mShaderParam1);
|
||||
mRuntimeShader.setInputShader("bitmapShader", new BitmapShader(mBitmap1,
|
||||
Shader.TileMode.CLAMP,
|
||||
Shader.TileMode.CLAMP));
|
||||
mShaderPaint = new Paint();
|
||||
Shader[] inputShaders = { new BitmapShader(mBitmap1, Shader.TileMode.CLAMP,
|
||||
Shader.TileMode.CLAMP) };
|
||||
mShaderPaint.setShader(new RuntimeShader(sSkSL, mUniforms, inputShaders, true));
|
||||
setShaderParam1(0.0f);
|
||||
mShaderPaint.setShader(mRuntimeShader);
|
||||
|
||||
ObjectAnimator sat = ObjectAnimator.ofFloat(this, "saturation", 1.0f);
|
||||
sat.setDuration(1000);
|
||||
@@ -177,20 +176,15 @@ public class ColorFiltersMutateActivity extends Activity {
|
||||
}
|
||||
|
||||
public void setShaderParam1(float value) {
|
||||
RuntimeShader shader = (RuntimeShader) mShaderPaint.getShader();
|
||||
ByteBuffer buffer = ByteBuffer.wrap(mUniforms);
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer.putFloat(value);
|
||||
shader.updateUniforms(mUniforms);
|
||||
mShaderParam1 = value;
|
||||
mRuntimeShader.setUniform("param1", mShaderParam1);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
// If either valueFrom or valueTo is null, then a getter function will also be derived
|
||||
// and called by the animator class.
|
||||
public float getShaderParam1() {
|
||||
ByteBuffer buffer = ByteBuffer.wrap(mUniforms);
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
return buffer.getFloat();
|
||||
return mShaderParam1;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (C) 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.
|
||||
*/
|
||||
|
||||
package com.android.test.hwui;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.CanvasProperty;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RecordingCanvas;
|
||||
import android.graphics.RuntimeShader;
|
||||
import android.os.Bundle;
|
||||
import android.os.Trace;
|
||||
import android.view.RenderNodeAnimator;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.LinearLayout.LayoutParams;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class RippleActivity extends Activity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
final LinearLayout layout = new LinearLayout(this);
|
||||
layout.setOrientation(LinearLayout.VERTICAL);
|
||||
layout.addView(new RippleView(this),
|
||||
new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
|
||||
|
||||
setContentView(layout);
|
||||
}
|
||||
|
||||
static class RippleView extends View {
|
||||
static final int DURATION = 1000;
|
||||
static final int MAX_RADIUS = 250;
|
||||
|
||||
private boolean mToggle = false;
|
||||
ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<RenderNodeAnimator>();
|
||||
|
||||
CanvasProperty<Float> mX;
|
||||
CanvasProperty<Float> mY;
|
||||
CanvasProperty<Float> mRadius;
|
||||
CanvasProperty<Float> mProgress;
|
||||
CanvasProperty<Paint> mPaint;
|
||||
RuntimeShader mRuntimeShader;
|
||||
|
||||
static final String sSkSL = ""
|
||||
+ "uniform float2 in_origin;"
|
||||
+ "uniform float in_progress;\n"
|
||||
+ "uniform float in_maxRadius;\n"
|
||||
+ "uniform shader in_paintColor;\n"
|
||||
+ "float dist2(float2 p0, float2 pf) { return sqrt((pf.x - p0.x) * (pf.x - p0.x) + "
|
||||
+ "(pf.y - p0.y) * (pf.y - p0.y)); }\n"
|
||||
+ "float mod2(float a, float b) { return a - (b * floor(a / b)); }\n"
|
||||
+ "float rand(float2 src) { return fract(sin(dot(src.xy, float2(12.9898, 78.233)))"
|
||||
+ " * 43758.5453123); }\n"
|
||||
+ "float4 main(float2 p)\n"
|
||||
+ "{\n"
|
||||
+ " float fraction = in_progress;\n"
|
||||
+ " float2 fragCoord = p;//sk_FragCoord.xy;\n"
|
||||
+ " float maxDist = in_maxRadius;\n"
|
||||
+ " float fragDist = dist2(in_origin, fragCoord.xy);\n"
|
||||
+ " float circleRadius = maxDist * fraction;\n"
|
||||
+ " float colorVal = (fragDist - circleRadius) / maxDist;\n"
|
||||
+ " float d = fragDist < circleRadius \n"
|
||||
+ " ? 1. - abs(colorVal * 2. * smoothstep(0., 1., fraction)) \n"
|
||||
+ " : 1. - abs(colorVal * 3.);\n"
|
||||
+ " d = smoothstep(0., 1., d);\n"
|
||||
+ " float divider = 2.;\n"
|
||||
+ " float x = floor(fragCoord.x / divider);\n"
|
||||
+ " float y = floor(fragCoord.y / divider);\n"
|
||||
+ " float density = .95;\n"
|
||||
+ " d = rand(float2(x, y)) > density ? d : d * .2;\n"
|
||||
+ " d = d * rand(float2(fraction, x * y));\n"
|
||||
+ " float alpha = 1. - pow(fraction, 3.);\n"
|
||||
+ " return float4(sample(in_paintColor).rgb, d * alpha);\n"
|
||||
+ "}";
|
||||
|
||||
RippleView(Context c) {
|
||||
super(c);
|
||||
setClickable(true);
|
||||
|
||||
mX = CanvasProperty.createFloat(200.0f);
|
||||
mY = CanvasProperty.createFloat(200.0f);
|
||||
mRadius = CanvasProperty.createFloat(150.0f);
|
||||
mProgress = CanvasProperty.createFloat(0.0f);
|
||||
|
||||
Paint p = new Paint();
|
||||
p.setAntiAlias(true);
|
||||
p.setColor(0xFFFF0000);
|
||||
mPaint = CanvasProperty.createPaint(p);
|
||||
|
||||
mRuntimeShader = new RuntimeShader(sSkSL, false);
|
||||
mRuntimeShader.setUniform("in_maxRadius", MAX_RADIUS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
if (canvas.isHardwareAccelerated()) {
|
||||
RecordingCanvas recordingCanvas = (RecordingCanvas) canvas;
|
||||
recordingCanvas.drawRipple(mX, mY, mRadius, mPaint, mProgress, mRuntimeShader);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performClick() {
|
||||
for (int i = 0; i < mRunningAnimations.size(); i++) {
|
||||
mRunningAnimations.get(i).cancel();
|
||||
}
|
||||
mRunningAnimations.clear();
|
||||
|
||||
mToggle = !mToggle;
|
||||
|
||||
mRunningAnimations.add(new RenderNodeAnimator(
|
||||
mX, mToggle ? 400.0f : 200.0f));
|
||||
|
||||
mRunningAnimations.add(new RenderNodeAnimator(
|
||||
mY, mToggle ? 600.0f : 200.0f));
|
||||
|
||||
mRunningAnimations.add(new RenderNodeAnimator(
|
||||
mRadius, mToggle ? MAX_RADIUS : 150.0f));
|
||||
|
||||
mRunningAnimations.add(new RenderNodeAnimator(
|
||||
mProgress, mToggle ? 1.0f : 0.0f));
|
||||
|
||||
mRunningAnimations.add(new RenderNodeAnimator(
|
||||
mPaint, RenderNodeAnimator.PAINT_ALPHA, 64.0f));
|
||||
|
||||
// Will be "chained" to run after the above
|
||||
mRunningAnimations.add(new RenderNodeAnimator(
|
||||
mPaint, RenderNodeAnimator.PAINT_ALPHA, 255.0f));
|
||||
|
||||
for (int i = 0; i < mRunningAnimations.size(); i++) {
|
||||
RenderNodeAnimator anim = mRunningAnimations.get(i);
|
||||
anim.setDuration(DURATION);
|
||||
anim.setTarget(this);
|
||||
if (i == (mRunningAnimations.size() - 1)) {
|
||||
// "chain" test
|
||||
anim.setStartValue(64.0f);
|
||||
anim.setStartDelay(anim.getDuration());
|
||||
}
|
||||
anim.start();
|
||||
}
|
||||
|
||||
if (mToggle) {
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "pretendBusy");
|
||||
try {
|
||||
Thread.sleep(DURATION);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
|
||||
}
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user