Loading core/jni/android/graphics/Shader.cpp +48 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ #include "SkShader.h" #include "SkBlendMode.h" #include "core_jni_helpers.h" #include "src/shaders/SkRTShader.h" #include <jni.h> Loading Loading @@ -212,6 +213,44 @@ 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) { SkRuntimeShaderFactory* factory = reinterpret_cast<SkRuntimeShaderFactory*>(shaderFactory); AutoJavaByteArray arInputs(env, inputs); sk_sp<SkData> fData; fData = SkData::MakeWithCopy(arInputs.ptr(), arInputs.length()); const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); sk_sp<SkShader> shader = factory->make(fData, matrix); ThrowIAE_IfNull(env, shader); return reinterpret_cast<jlong>(shader.release()); } /////////////////////////////////////////////////////////////////////////////////////////////// static jlong RuntimeShader_createShaderFactory(JNIEnv* env, jobject, jstring sksl, jboolean isOpaque) { ScopedUtfChars strSksl(env, sksl); SkRuntimeShaderFactory* shaderFactory = new SkRuntimeShaderFactory(SkString(strSksl.c_str()), isOpaque == JNI_TRUE); ThrowIAE_IfNull(env, shaderFactory); return reinterpret_cast<jlong>(shaderFactory); } /////////////////////////////////////////////////////////////////////////////////////////////// static void RuntimeShader_delete(SkRuntimeShaderFactory* shaderFactory) { delete shaderFactory; } static jlong RuntimeShader_getNativeFinalizer(JNIEnv*, jobject) { return static_cast<jlong>(reinterpret_cast<uintptr_t>(&RuntimeShader_delete)); } /////////////////////////////////////////////////////////////////////////////////////////////// static const JNINativeMethod gColorMethods[] = { { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV }, { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor } Loading Loading @@ -241,6 +280,13 @@ static const JNINativeMethod gComposeShaderMethods[] = { { "nativeCreate", "(JJJI)J", (void*)ComposeShader_create }, }; static const JNINativeMethod gRuntimeShaderMethods[] = { { "nativeGetFinalizer", "()J", (void*)RuntimeShader_getNativeFinalizer }, { "nativeCreate", "(JJ[BJ)J", (void*)RuntimeShader_create }, { "nativeCreateShaderFactory", "(Ljava/lang/String;Z)J", (void*)RuntimeShader_createShaderFactory }, }; int register_android_graphics_Shader(JNIEnv* env) { android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods, Loading @@ -257,6 +303,8 @@ int register_android_graphics_Shader(JNIEnv* env) NELEM(gSweepGradientMethods)); android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods, NELEM(gComposeShaderMethods)); android::RegisterMethodsOrDie(env, "android/graphics/RuntimeShader", gRuntimeShaderMethods, NELEM(gRuntimeShaderMethods)); return 0; } graphics/java/android/graphics/RuntimeShader.java 0 → 100644 +88 −0 Original line number Diff line number Diff line /* * Copyright 2019 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 android.graphics; import android.annotation.NonNull; import android.annotation.Nullable; import libcore.util.NativeAllocationRegistry; /** * Shader that calculates pixel output with a program (fragment shader) running on a GPU. * @hide */ public class RuntimeShader extends Shader { private static class NoImagePreloadHolder { public static final NativeAllocationRegistry sRegistry = NativeAllocationRegistry.createMalloced( RuntimeShader.class.getClassLoader(), nativeGetFinalizer()); } private byte[] mUniforms; /** * Current native shader factory instance. */ private long mNativeInstanceRuntimeShaderFactory; /** * 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 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)); } private RuntimeShader(@NonNull String sksl, @Nullable byte[] uniforms, boolean isOpaque, ColorSpace colorSpace) { super(colorSpace); mUniforms = uniforms; mNativeInstanceRuntimeShaderFactory = nativeCreateShaderFactory(sksl, isOpaque); NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeInstanceRuntimeShaderFactory); } /** * Sets new value for shader parameters. * * @param uniforms Array of parameters passed by the SKSL shader. Array size depends * on number of uniforms declared by mSksl. */ public void updateUniforms(@Nullable byte[] uniforms) { mUniforms = uniforms; discardNativeInstance(); } @Override long createNativeInstance(long nativeMatrix) { return nativeCreate(mNativeInstanceRuntimeShaderFactory, nativeMatrix, mUniforms, colorSpace().getNativeInstance()); } private static native long nativeCreate(long shaderFactory, long matrix, byte[] inputs, long colorSpaceHandle); private static native long nativeCreateShaderFactory(String sksl, boolean isOpaque); private static native long nativeGetFinalizer(); } tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java +48 −0 Original line number Diff line number Diff line Loading @@ -29,9 +29,13 @@ import android.graphics.LightingColorFilter; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.RuntimeShader; import android.os.Bundle; import android.view.View; import java.nio.ByteBuffer; import java.nio.ByteOrder; @SuppressWarnings({"UnusedDeclaration"}) public class ColorFiltersMutateActivity extends Activity { @Override Loading @@ -47,12 +51,21 @@ public class ColorFiltersMutateActivity extends Activity { private final Paint mColorMatrixPaint; private final Paint mLightingPaint; private final Paint mBlendPaint; private final Paint mShaderPaint; private float mSaturation = 0.0f; private int mLightAdd = 0; private int mLightMul = 0; private int mPorterDuffColor = 0; static final String sSkSL = "uniform float param1;\n" + "void main(float x, float y, inout half4 color) {\n" + "color = half4(color.r, half(param1), color.b, 1.0);\n" + "}\n"; private byte[] mUniforms = new byte[4]; BitmapsView(Context c) { super(c); Loading @@ -70,6 +83,10 @@ public class ColorFiltersMutateActivity extends Activity { mBlendPaint = new Paint(); mBlendPaint.setColorFilter(new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_OVER)); mShaderPaint = new Paint(); mShaderPaint.setShader(new RuntimeShader(sSkSL, mUniforms, true)); setShaderParam1(0.0f); ObjectAnimator sat = ObjectAnimator.ofFloat(this, "saturation", 1.0f); sat.setDuration(1000); sat.setRepeatCount(ObjectAnimator.INFINITE); Loading @@ -96,6 +113,12 @@ public class ColorFiltersMutateActivity extends Activity { color.setRepeatCount(ObjectAnimator.INFINITE); color.setRepeatMode(ObjectAnimator.REVERSE); color.start(); ObjectAnimator shaderUniform = ObjectAnimator.ofFloat(this, "shaderParam1", 1.0f); shaderUniform.setDuration(1000); shaderUniform.setRepeatCount(ObjectAnimator.INFINITE); shaderUniform.setRepeatMode(ObjectAnimator.REVERSE); shaderUniform.start(); } public int getPorterDuffColor() { Loading Loading @@ -148,6 +171,23 @@ public class ColorFiltersMutateActivity extends Activity { return mSaturation; } 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); 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(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Loading @@ -163,6 +203,10 @@ public class ColorFiltersMutateActivity extends Activity { canvas.translate(0.0f, 50.0f + mBitmap1.getHeight()); canvas.drawBitmap(mBitmap1, 0.0f, 0.0f, mBlendPaint); canvas.translate(0.0f, 50.0f + mBitmap1.getHeight()); canvas.drawRect(0.0f, 0.0f, mBitmap1.getWidth(), mBitmap1.getHeight(), mShaderPaint); canvas.restore(); canvas.save(); Loading @@ -174,6 +218,10 @@ public class ColorFiltersMutateActivity extends Activity { canvas.translate(0.0f, 50.0f + mBitmap2.getHeight()); canvas.drawBitmap(mBitmap2, 0.0f, 0.0f, mBlendPaint); canvas.translate(0.0f, 50.0f + mBitmap2.getHeight()); canvas.drawRoundRect(0.0f, 0.0f, mBitmap2.getWidth(), mBitmap2.getHeight(), 20, 20, mShaderPaint); canvas.restore(); } } Loading Loading
core/jni/android/graphics/Shader.cpp +48 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ #include "SkShader.h" #include "SkBlendMode.h" #include "core_jni_helpers.h" #include "src/shaders/SkRTShader.h" #include <jni.h> Loading Loading @@ -212,6 +213,44 @@ 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) { SkRuntimeShaderFactory* factory = reinterpret_cast<SkRuntimeShaderFactory*>(shaderFactory); AutoJavaByteArray arInputs(env, inputs); sk_sp<SkData> fData; fData = SkData::MakeWithCopy(arInputs.ptr(), arInputs.length()); const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); sk_sp<SkShader> shader = factory->make(fData, matrix); ThrowIAE_IfNull(env, shader); return reinterpret_cast<jlong>(shader.release()); } /////////////////////////////////////////////////////////////////////////////////////////////// static jlong RuntimeShader_createShaderFactory(JNIEnv* env, jobject, jstring sksl, jboolean isOpaque) { ScopedUtfChars strSksl(env, sksl); SkRuntimeShaderFactory* shaderFactory = new SkRuntimeShaderFactory(SkString(strSksl.c_str()), isOpaque == JNI_TRUE); ThrowIAE_IfNull(env, shaderFactory); return reinterpret_cast<jlong>(shaderFactory); } /////////////////////////////////////////////////////////////////////////////////////////////// static void RuntimeShader_delete(SkRuntimeShaderFactory* shaderFactory) { delete shaderFactory; } static jlong RuntimeShader_getNativeFinalizer(JNIEnv*, jobject) { return static_cast<jlong>(reinterpret_cast<uintptr_t>(&RuntimeShader_delete)); } /////////////////////////////////////////////////////////////////////////////////////////////// static const JNINativeMethod gColorMethods[] = { { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV }, { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor } Loading Loading @@ -241,6 +280,13 @@ static const JNINativeMethod gComposeShaderMethods[] = { { "nativeCreate", "(JJJI)J", (void*)ComposeShader_create }, }; static const JNINativeMethod gRuntimeShaderMethods[] = { { "nativeGetFinalizer", "()J", (void*)RuntimeShader_getNativeFinalizer }, { "nativeCreate", "(JJ[BJ)J", (void*)RuntimeShader_create }, { "nativeCreateShaderFactory", "(Ljava/lang/String;Z)J", (void*)RuntimeShader_createShaderFactory }, }; int register_android_graphics_Shader(JNIEnv* env) { android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods, Loading @@ -257,6 +303,8 @@ int register_android_graphics_Shader(JNIEnv* env) NELEM(gSweepGradientMethods)); android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods, NELEM(gComposeShaderMethods)); android::RegisterMethodsOrDie(env, "android/graphics/RuntimeShader", gRuntimeShaderMethods, NELEM(gRuntimeShaderMethods)); return 0; }
graphics/java/android/graphics/RuntimeShader.java 0 → 100644 +88 −0 Original line number Diff line number Diff line /* * Copyright 2019 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 android.graphics; import android.annotation.NonNull; import android.annotation.Nullable; import libcore.util.NativeAllocationRegistry; /** * Shader that calculates pixel output with a program (fragment shader) running on a GPU. * @hide */ public class RuntimeShader extends Shader { private static class NoImagePreloadHolder { public static final NativeAllocationRegistry sRegistry = NativeAllocationRegistry.createMalloced( RuntimeShader.class.getClassLoader(), nativeGetFinalizer()); } private byte[] mUniforms; /** * Current native shader factory instance. */ private long mNativeInstanceRuntimeShaderFactory; /** * 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 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)); } private RuntimeShader(@NonNull String sksl, @Nullable byte[] uniforms, boolean isOpaque, ColorSpace colorSpace) { super(colorSpace); mUniforms = uniforms; mNativeInstanceRuntimeShaderFactory = nativeCreateShaderFactory(sksl, isOpaque); NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeInstanceRuntimeShaderFactory); } /** * Sets new value for shader parameters. * * @param uniforms Array of parameters passed by the SKSL shader. Array size depends * on number of uniforms declared by mSksl. */ public void updateUniforms(@Nullable byte[] uniforms) { mUniforms = uniforms; discardNativeInstance(); } @Override long createNativeInstance(long nativeMatrix) { return nativeCreate(mNativeInstanceRuntimeShaderFactory, nativeMatrix, mUniforms, colorSpace().getNativeInstance()); } private static native long nativeCreate(long shaderFactory, long matrix, byte[] inputs, long colorSpaceHandle); private static native long nativeCreateShaderFactory(String sksl, boolean isOpaque); private static native long nativeGetFinalizer(); }
tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java +48 −0 Original line number Diff line number Diff line Loading @@ -29,9 +29,13 @@ import android.graphics.LightingColorFilter; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.RuntimeShader; import android.os.Bundle; import android.view.View; import java.nio.ByteBuffer; import java.nio.ByteOrder; @SuppressWarnings({"UnusedDeclaration"}) public class ColorFiltersMutateActivity extends Activity { @Override Loading @@ -47,12 +51,21 @@ public class ColorFiltersMutateActivity extends Activity { private final Paint mColorMatrixPaint; private final Paint mLightingPaint; private final Paint mBlendPaint; private final Paint mShaderPaint; private float mSaturation = 0.0f; private int mLightAdd = 0; private int mLightMul = 0; private int mPorterDuffColor = 0; static final String sSkSL = "uniform float param1;\n" + "void main(float x, float y, inout half4 color) {\n" + "color = half4(color.r, half(param1), color.b, 1.0);\n" + "}\n"; private byte[] mUniforms = new byte[4]; BitmapsView(Context c) { super(c); Loading @@ -70,6 +83,10 @@ public class ColorFiltersMutateActivity extends Activity { mBlendPaint = new Paint(); mBlendPaint.setColorFilter(new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_OVER)); mShaderPaint = new Paint(); mShaderPaint.setShader(new RuntimeShader(sSkSL, mUniforms, true)); setShaderParam1(0.0f); ObjectAnimator sat = ObjectAnimator.ofFloat(this, "saturation", 1.0f); sat.setDuration(1000); sat.setRepeatCount(ObjectAnimator.INFINITE); Loading @@ -96,6 +113,12 @@ public class ColorFiltersMutateActivity extends Activity { color.setRepeatCount(ObjectAnimator.INFINITE); color.setRepeatMode(ObjectAnimator.REVERSE); color.start(); ObjectAnimator shaderUniform = ObjectAnimator.ofFloat(this, "shaderParam1", 1.0f); shaderUniform.setDuration(1000); shaderUniform.setRepeatCount(ObjectAnimator.INFINITE); shaderUniform.setRepeatMode(ObjectAnimator.REVERSE); shaderUniform.start(); } public int getPorterDuffColor() { Loading Loading @@ -148,6 +171,23 @@ public class ColorFiltersMutateActivity extends Activity { return mSaturation; } 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); 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(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Loading @@ -163,6 +203,10 @@ public class ColorFiltersMutateActivity extends Activity { canvas.translate(0.0f, 50.0f + mBitmap1.getHeight()); canvas.drawBitmap(mBitmap1, 0.0f, 0.0f, mBlendPaint); canvas.translate(0.0f, 50.0f + mBitmap1.getHeight()); canvas.drawRect(0.0f, 0.0f, mBitmap1.getWidth(), mBitmap1.getHeight(), mShaderPaint); canvas.restore(); canvas.save(); Loading @@ -174,6 +218,10 @@ public class ColorFiltersMutateActivity extends Activity { canvas.translate(0.0f, 50.0f + mBitmap2.getHeight()); canvas.drawBitmap(mBitmap2, 0.0f, 0.0f, mBlendPaint); canvas.translate(0.0f, 50.0f + mBitmap2.getHeight()); canvas.drawRoundRect(0.0f, 0.0f, mBitmap2.getWidth(), mBitmap2.getHeight(), 20, 20, mShaderPaint); canvas.restore(); } } Loading