Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 80e3a1a9 authored by Derek Sollenberger's avatar Derek Sollenberger
Browse files

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
parent b7e3d029
Loading
Loading
Loading
Loading
+39 −5
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ public class RuntimeShader extends Shader {
    }

    private byte[] mUniforms;
    private Shader[] mInputShaders;
    private boolean mIsOpaque;

    /**
@@ -50,13 +51,30 @@ public class RuntimeShader extends Shader {
     * @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,
    /**
     * 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 @@ public class RuntimeShader extends Shader {
        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);

+15 −3
Original line number Diff line number Diff line
@@ -211,14 +211,26 @@ static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
///////////////////////////////////////////////////////////////////////////////////////////////

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 gComposeShaderMethods[] = {

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     },
};
+9 −4
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.app.Activity;
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.Paint;
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 @@ public class ColorFiltersMutateActivity extends Activity {
        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 @@ public class ColorFiltersMutateActivity extends Activity {
            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);