Add basic support for input shaders to RuntimeShader.
This adds the ability for Java RuntimeShaders to provide other
shaders as inputs. This is a first pass API and should be updated
to mirror the SkRuntimeShaderBuilder API that enable callers to set
the uniforms and inputs shaders by name instead of passing arrays.
Test: HwAccelerationTests
Bug: n/a
Change-Id: I53a15ad864bede2fecc1e2459dca983d224114a0
diff --git a/graphics/java/android/graphics/RuntimeShader.java b/graphics/java/android/graphics/RuntimeShader.java
index 5a0b4a9..63089e2 100644
--- a/graphics/java/android/graphics/RuntimeShader.java
+++ b/graphics/java/android/graphics/RuntimeShader.java
@@ -34,6 +34,7 @@
}
private byte[] mUniforms;
+ private Shader[] mInputShaders;
private boolean mIsOpaque;
/**
@@ -50,13 +51,30 @@
* @param isOpaque True if all pixels have alpha 1.0f.
*/
public RuntimeShader(@NonNull String sksl, @Nullable byte[] uniforms, boolean isOpaque) {
- this(sksl, uniforms, isOpaque, ColorSpace.get(ColorSpace.Named.SRGB));
+ this(sksl, uniforms, null, isOpaque, ColorSpace.get(ColorSpace.Named.SRGB));
}
- private RuntimeShader(@NonNull String sksl, @Nullable byte[] uniforms, boolean isOpaque,
- ColorSpace colorSpace) {
+ /**
+ * 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;
mIsOpaque = isOpaque;
mNativeInstanceRuntimeShaderFactory = nativeCreateShaderFactory(sksl);
NoImagePreloadHolder.sRegistry.registerNativeAllocation(this,
@@ -74,15 +92,31 @@
discardNativeInstance();
}
+ /**
+ * Sets new values for the shaders that serve as inputs to this shader.
+ *
+ * @param shaderInputs Array of Shaders passed into the SKSL shader. Array size depends
+ * on number of input shaders declared by sksl.
+ */
+ public void updateInputShaders(@Nullable Shader[] shaderInputs) {
+ mInputShaders = shaderInputs;
+ discardNativeInstance();
+ }
+
/** @hide */
@Override
protected long createNativeInstance(long nativeMatrix) {
+ long[] nativeShaders = mInputShaders.length > 0 ? new long[mInputShaders.length] : null;
+ for (int i = 0; i < mInputShaders.length; i++) {
+ nativeShaders[i] = mInputShaders[i].getNativeInstance();
+ }
+
return nativeCreate(mNativeInstanceRuntimeShaderFactory, nativeMatrix, mUniforms,
- colorSpace().getNativeInstance(), mIsOpaque);
+ nativeShaders, colorSpace().getNativeInstance(), mIsOpaque);
}
private static native long nativeCreate(long shaderFactory, long matrix, byte[] inputs,
- long colorSpaceHandle, boolean isOpaque);
+ long[] shaderInputs, long colorSpaceHandle, boolean isOpaque);
private static native long nativeCreateShaderFactory(String sksl);
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index e76aace..e36e355 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -211,14 +211,26 @@
///////////////////////////////////////////////////////////////////////////////////////////////
static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderFactory, jlong matrixPtr,
- jbyteArray inputs, jlong colorSpaceHandle, jboolean isOpaque) {
+ 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, nullptr, 0, matrix, isOpaque == JNI_TRUE);
+ 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());
@@ -280,7 +292,7 @@
static const JNINativeMethod gRuntimeShaderMethods[] = {
{ "nativeGetFinalizer", "()J", (void*)RuntimeShader_getNativeFinalizer },
- { "nativeCreate", "(JJ[BJZ)J", (void*)RuntimeShader_create },
+ { "nativeCreate", "(JJ[B[JJZ)J", (void*)RuntimeShader_create },
{ "nativeCreateShaderFactory", "(Ljava/lang/String;)J",
(void*)RuntimeShader_createShaderFactory },
};
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
index 08144c8..b53b78a 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
@@ -30,6 +31,7 @@
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.RuntimeShader;
+import android.graphics.Shader;
import android.os.Bundle;
import android.view.View;
@@ -59,9 +61,10 @@
private int mPorterDuffColor = 0;
static final String sSkSL =
- "uniform float param1;\n"
- + "void main(float2 xy, inout half4 color) {\n"
- + "color = half4(color.r, half(param1), color.b, 1.0);\n"
+ "in shader bitmapShader;\n"
+ + "uniform float param1;\n"
+ + "half4 main(float2 xy) {\n"
+ + " return half4(sample(bitmapShader, xy).rgb, param1);\n"
+ "}\n";
private byte[] mUniforms = new byte[4];
@@ -84,7 +87,9 @@
mBlendPaint.setColorFilter(new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_OVER));
mShaderPaint = new Paint();
- mShaderPaint.setShader(new RuntimeShader(sSkSL, mUniforms, true));
+ Shader[] inputShaders = { new BitmapShader(mBitmap1, Shader.TileMode.CLAMP,
+ Shader.TileMode.CLAMP) };
+ mShaderPaint.setShader(new RuntimeShader(sSkSL, mUniforms, inputShaders, true));
setShaderParam1(0.0f);
ObjectAnimator sat = ObjectAnimator.ofFloat(this, "saturation", 1.0f);