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


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


    /**
    /**
@@ -50,13 +51,30 @@ public class RuntimeShader extends Shader {
     * @param isOpaque True if all pixels have alpha 1.0f.
     * @param isOpaque True if all pixels have alpha 1.0f.
     */
     */
    public RuntimeShader(@NonNull String sksl, @Nullable byte[] uniforms, boolean isOpaque) {
    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) {
                          ColorSpace colorSpace) {
        super(colorSpace);
        super(colorSpace);
        mUniforms = uniforms;
        mUniforms = uniforms;
        mInputShaders = shaderInputs;
        mIsOpaque = isOpaque;
        mIsOpaque = isOpaque;
        mNativeInstanceRuntimeShaderFactory = nativeCreateShaderFactory(sksl);
        mNativeInstanceRuntimeShaderFactory = nativeCreateShaderFactory(sksl);
        NoImagePreloadHolder.sRegistry.registerNativeAllocation(this,
        NoImagePreloadHolder.sRegistry.registerNativeAllocation(this,
@@ -74,15 +92,31 @@ public class RuntimeShader extends Shader {
        discardNativeInstance();
        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 */
    /** @hide */
    @Override
    @Override
    protected long createNativeInstance(long nativeMatrix) {
    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,
        return nativeCreate(mNativeInstanceRuntimeShaderFactory, nativeMatrix, mUniforms,
                colorSpace().getNativeInstance(), mIsOpaque);
                nativeShaders, colorSpace().getNativeInstance(), mIsOpaque);
    }
    }


    private static native long nativeCreate(long shaderFactory, long matrix, byte[] inputs,
    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);
    private static native long nativeCreateShaderFactory(String sksl);


+15 −3
Original line number Original line 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,
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);
    SkRuntimeEffect* effect = reinterpret_cast<SkRuntimeEffect*>(shaderFactory);
    AutoJavaByteArray arInputs(env, inputs);
    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;
    sk_sp<SkData> fData;
    fData = SkData::MakeWithCopy(arInputs.ptr(), arInputs.length());
    fData = SkData::MakeWithCopy(arInputs.ptr(), arInputs.length());
    const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
    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);
    ThrowIAE_IfNull(env, shader);


    return reinterpret_cast<jlong>(shader.release());
    return reinterpret_cast<jlong>(shader.release());
@@ -280,7 +292,7 @@ static const JNINativeMethod gComposeShaderMethods[] = {


static const JNINativeMethod gRuntimeShaderMethods[] = {
static const JNINativeMethod gRuntimeShaderMethods[] = {
    { "nativeGetFinalizer",   "()J",    (void*)RuntimeShader_getNativeFinalizer },
    { "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",
    { "nativeCreateShaderFactory",     "(Ljava/lang/String;)J",
      (void*)RuntimeShader_createShaderFactory     },
      (void*)RuntimeShader_createShaderFactory     },
};
};
+9 −4
Original line number Original line Diff line number Diff line
@@ -22,6 +22,7 @@ import android.app.Activity;
import android.content.Context;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.ColorMatrixColorFilter;
@@ -30,6 +31,7 @@ import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.PorterDuffColorFilter;
import android.graphics.RuntimeShader;
import android.graphics.RuntimeShader;
import android.graphics.Shader;
import android.os.Bundle;
import android.os.Bundle;
import android.view.View;
import android.view.View;


@@ -59,9 +61,10 @@ public class ColorFiltersMutateActivity extends Activity {
        private int mPorterDuffColor = 0;
        private int mPorterDuffColor = 0;


        static final String sSkSL =
        static final String sSkSL =
                "uniform float param1;\n"
                "in shader bitmapShader;\n"
                + "void main(float2 xy, inout half4 color) {\n"
                + "uniform float param1;\n"
                + "color = half4(color.r, half(param1), color.b, 1.0);\n"
                + "half4 main(float2 xy) {\n"
                + "  return half4(sample(bitmapShader, xy).rgb, param1);\n"
                + "}\n";
                + "}\n";


        private byte[] mUniforms = new byte[4];
        private byte[] mUniforms = new byte[4];
@@ -84,7 +87,9 @@ public class ColorFiltersMutateActivity extends Activity {
            mBlendPaint.setColorFilter(new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_OVER));
            mBlendPaint.setColorFilter(new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_OVER));


            mShaderPaint = new Paint();
            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);
            setShaderParam1(0.0f);


            ObjectAnimator sat = ObjectAnimator.ofFloat(this, "saturation", 1.0f);
            ObjectAnimator sat = ObjectAnimator.ofFloat(this, "saturation", 1.0f);