Loading core/api/current.txt +19 −0 Original line number Diff line number Diff line Loading @@ -17361,6 +17361,25 @@ package android.graphics { method public boolean setUseCompositingLayer(boolean, @Nullable android.graphics.Paint); } @FlaggedApi("com.android.graphics.hwui.flags.runtime_color_filters_blenders") public class RuntimeColorFilter extends android.graphics.ColorFilter { ctor public RuntimeColorFilter(@NonNull String); method public void setColorUniform(@NonNull String, @ColorInt int); method public void setColorUniform(@NonNull String, @ColorLong long); method public void setColorUniform(@NonNull String, @NonNull android.graphics.Color); method public void setFloatUniform(@NonNull String, float); method public void setFloatUniform(@NonNull String, float, float); method public void setFloatUniform(@NonNull String, float, float, float); method public void setFloatUniform(@NonNull String, float, float, float, float); method public void setFloatUniform(@NonNull String, @NonNull float[]); method public void setInputColorFilter(@NonNull String, @NonNull android.graphics.ColorFilter); method public void setInputShader(@NonNull String, @NonNull android.graphics.Shader); method public void setIntUniform(@NonNull String, int); method public void setIntUniform(@NonNull String, int, int); method public void setIntUniform(@NonNull String, int, int, int); method public void setIntUniform(@NonNull String, int, int, int, int); method public void setIntUniform(@NonNull String, @NonNull int[]); } public class RuntimeShader extends android.graphics.Shader { ctor public RuntimeShader(@NonNull String); method public void setColorUniform(@NonNull String, @ColorInt int); graphics/java/android/graphics/RuntimeColorFilter.java 0 → 100644 +305 −0 Original line number Diff line number Diff line /* * Copyright 2024 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.ColorInt; import android.annotation.ColorLong; import android.annotation.FlaggedApi; import android.annotation.NonNull; import com.android.graphics.hwui.flags.Flags; /** * <p>A {@link RuntimeColorFilter} calculates a per-pixel color based on the output of a user * * defined Android Graphics Shading Language (AGSL) function.</p> * * <p>This AGSL function takes in an input color to be operated on. This color is in sRGB and the * * output is also interpreted as sRGB. The AGSL function signature expects a single input * * of color (packed as a half4 or float4 or vec4).</p> * * <pre class="prettyprint"> * vec4 main(half4 in_color); * </pre> */ @FlaggedApi(Flags.FLAG_RUNTIME_COLOR_FILTERS_BLENDERS) public class RuntimeColorFilter extends ColorFilter { private String mAgsl; /** * Creates a new RuntimeColorFilter. * * @param agsl The text of AGSL color filter program to run. */ public RuntimeColorFilter(@NonNull String agsl) { if (agsl == null) { throw new NullPointerException("RuntimeColorFilter requires a non-null AGSL string"); } mAgsl = agsl; // call to parent class to register native RuntimeColorFilter // TODO: find way to get super class to create native instance without requiring the storage // of agsl string getNativeInstance(); } /** * Sets the uniform color value corresponding to this color filter. If the effect does not have * a uniform with that name or if the uniform is declared with a type other than vec3 or vec4 * and corresponding layout(color) annotation then an IllegalArgumentException is thrown. * * @param uniformName name matching the color uniform declared in the AGSL program * @param color the provided sRGB color */ public void setColorUniform(@NonNull String uniformName, @ColorInt int color) { setUniform(uniformName, Color.valueOf(color).getComponents(), true); } /** * Sets the uniform color value corresponding to this color filter. If the effect does not have * a uniform with that name or if the uniform is declared with a type other than vec3 or vec4 * and corresponding layout(color) annotation then an IllegalArgumentException is thrown. * * @param uniformName name matching the color uniform declared in the AGSL program * @param color the provided sRGB color */ public void setColorUniform(@NonNull String uniformName, @ColorLong long color) { Color exSRGB = Color.valueOf(color).convert(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)); setUniform(uniformName, exSRGB.getComponents(), true); } /** * Sets the uniform color value corresponding to this color filter. If the effect does not have * a uniform with that name or if the uniform is declared with a type other than vec3 or vec4 * and corresponding layout(color) annotation then an IllegalArgumentException is thrown. * * @param uniformName name matching the color uniform declared in the AGSL program * @param color the provided sRGB color */ public void setColorUniform(@NonNull String uniformName, @NonNull Color color) { if (color == null) { throw new NullPointerException("The color parameter must not be null"); } Color exSRGB = color.convert(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)); setUniform(uniformName, exSRGB.getComponents(), true); } /** * Sets the uniform value corresponding to this color filter. If the effect does not have a * uniform with that name or if the uniform is declared with a type other than a float or * float[1] then an IllegalArgumentException is thrown. * * @param uniformName name matching the uniform declared in the AGSL program */ public void setFloatUniform(@NonNull String uniformName, float value) { setFloatUniform(uniformName, value, 0.0f, 0.0f, 0.0f, 1); } /** * Sets the uniform value corresponding to this color filter. If the effect does not have a * uniform with that name or if the uniform is declared with a type other than a vec2 or * float[2] then an IllegalArgumentException is thrown. * * @param uniformName name matching the uniform declared in the AGSL program */ public void setFloatUniform(@NonNull String uniformName, float value1, float value2) { setFloatUniform(uniformName, value1, value2, 0.0f, 0.0f, 2); } /** * Sets the uniform value corresponding to this color filter. If the effect does not have a * uniform with that name or if the uniform is declared with a type other than a vec3 or * float[3] then an IllegalArgumentException is thrown. * * @param uniformName name matching the uniform declared in the AGSL program */ public void setFloatUniform(@NonNull String uniformName, float value1, float value2, float value3) { setFloatUniform(uniformName, value1, value2, value3, 0.0f, 3); } /** * Sets the uniform value corresponding to this color filter. If the effect does not have a * uniform with that name or if the uniform is declared with a type other than a vec4 or * float[4] then an IllegalArgumentException is thrown. * * @param uniformName name matching the uniform declared in the AGSL program */ public void setFloatUniform(@NonNull String uniformName, float value1, float value2, float value3, float value4) { setFloatUniform(uniformName, value1, value2, value3, value4, 4); } /** * Sets the uniform value corresponding to this color filter. If the effect does not have a * uniform with that name or if the uniform is declared with a type other than a float * (for N=1), vecN, or float[N] where N is the length of the values param then an * IllegalArgumentException is thrown. * * @param uniformName name matching the uniform declared in the AGSL program */ public void setFloatUniform(@NonNull String uniformName, @NonNull float[] values) { setUniform(uniformName, values, false); } private void setFloatUniform(@NonNull String uniformName, float value1, float value2, float value3, float value4, int count) { if (uniformName == null) { throw new NullPointerException("The uniformName parameter must not be null"); } nativeUpdateUniforms(getNativeInstance(), uniformName, value1, value2, value3, value4, count); } private void setUniform(@NonNull String uniformName, @NonNull float[] values, boolean isColor) { if (uniformName == null) { throw new NullPointerException("The uniformName parameter must not be null"); } if (values == null) { throw new NullPointerException("The uniform values parameter must not be null"); } nativeUpdateUniforms(getNativeInstance(), uniformName, values, isColor); } /** * Sets the uniform value corresponding to this color filter. If the effect does not have a * uniform with that name or if the uniform is declared with a type other than an int or int[1] * then an IllegalArgumentException is thrown. * * @param uniformName name matching the uniform declared in the AGSL program */ public void setIntUniform(@NonNull String uniformName, int value) { setIntUniform(uniformName, value, 0, 0, 0, 1); } /** * Sets the uniform value corresponding to this color filter. If the effect does not have a * uniform with that name or if the uniform is declared with a type other than an ivec2 or * int[2] then an IllegalArgumentException is thrown. * * @param uniformName name matching the uniform declared in the AGSL program */ public void setIntUniform(@NonNull String uniformName, int value1, int value2) { setIntUniform(uniformName, value1, value2, 0, 0, 2); } /** * Sets the uniform value corresponding to this color filter. If the effect does not have a * uniform with that name or if the uniform is declared with a type other than an ivec3 or * int[3] then an IllegalArgumentException is thrown. * * @param uniformName name matching the uniform declared in the AGSL program */ public void setIntUniform(@NonNull String uniformName, int value1, int value2, int value3) { setIntUniform(uniformName, value1, value2, value3, 0, 3); } /** * Sets the uniform value corresponding to this color filter. If the effect does not have a * uniform with that name or if the uniform is declared with a type other than an ivec4 or * int[4] then an IllegalArgumentException is thrown. * * @param uniformName name matching the uniform declared in the AGSL program */ public void setIntUniform(@NonNull String uniformName, int value1, int value2, int value3, int value4) { setIntUniform(uniformName, value1, value2, value3, value4, 4); } /** * Sets the uniform value corresponding to this color filter. If the effect does not have a * uniform with that name or if the uniform is declared with a type other than an int (for N=1), * ivecN, or int[N] where N is the length of the values param then an IllegalArgumentException * is thrown. * * @param uniformName name matching the uniform declared in the AGSL program */ public void setIntUniform(@NonNull String uniformName, @NonNull int[] values) { if (uniformName == null) { throw new NullPointerException("The uniformName parameter must not be null"); } if (values == null) { throw new NullPointerException("The uniform values parameter must not be null"); } nativeUpdateUniforms(getNativeInstance(), uniformName, values); } private void setIntUniform(@NonNull String uniformName, int value1, int value2, int value3, int value4, int count) { if (uniformName == null) { throw new NullPointerException("The uniformName parameter must not be null"); } nativeUpdateUniforms(getNativeInstance(), uniformName, value1, value2, value3, value4, count); } /** * Assigns the uniform shader to the provided shader parameter. If the shader program does not * have a uniform shader with that name then an IllegalArgumentException is thrown. * * @param shaderName name matching the uniform declared in the AGSL program * @param shader shader passed into the AGSL program for sampling */ public void setInputShader(@NonNull String shaderName, @NonNull Shader shader) { if (shaderName == null) { throw new NullPointerException("The shaderName parameter must not be null"); } if (shader == null) { throw new NullPointerException("The shader parameter must not be null"); } nativeUpdateChild(getNativeInstance(), shaderName, shader.getNativeInstance()); } /** * Assigns the uniform color filter to the provided color filter parameter. If the shader * program does not have a uniform color filter with that name then an IllegalArgumentException * is thrown. * * @param filterName name matching the uniform declared in the AGSL program * @param colorFilter filter passed into the AGSL program for sampling */ public void setInputColorFilter(@NonNull String filterName, @NonNull ColorFilter colorFilter) { if (filterName == null) { throw new NullPointerException("The filterName parameter must not be null"); } if (colorFilter == null) { throw new NullPointerException("The colorFilter parameter must not be null"); } nativeUpdateChild(getNativeInstance(), filterName, colorFilter.getNativeInstance()); } /** @hide */ @Override protected long createNativeInstance() { return nativeCreateRuntimeColorFilter(mAgsl); } private static native long nativeCreateRuntimeColorFilter(String agsl); private static native void nativeUpdateUniforms( long colorFilter, String uniformName, float[] uniforms, boolean isColor); private static native void nativeUpdateUniforms( long colorFilter, String uniformName, float value1, float value2, float value3, float value4, int count); private static native void nativeUpdateUniforms( long colorFilter, String uniformName, int[] uniforms); private static native void nativeUpdateUniforms( long colorFilter, String uniformName, int value1, int value2, int value3, int value4, int count); private static native void nativeUpdateChild(long colorFilter, String childName, long child); } libs/hwui/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -384,6 +384,7 @@ cc_defaults { "jni/ScopedParcel.cpp", "jni/Shader.cpp", "jni/RenderEffect.cpp", "jni/RuntimeEffectUtils.cpp", "jni/Typeface.cpp", "jni/Utils.cpp", "jni/YuvToJpegEncoder.cpp", Loading libs/hwui/ColorFilter.h +31 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include <memory> #include "GraphicsJNI.h" #include "RuntimeEffectUtils.h" #include "SkColorFilter.h" namespace android { Loading Loading @@ -113,6 +114,36 @@ private: std::vector<float> mMatrix; }; class RuntimeColorFilter : public ColorFilter { public: RuntimeColorFilter(SkRuntimeEffectBuilder* builder) : mBuilder(builder) {} void updateUniforms(JNIEnv* env, const char* name, const float vals[], int count, bool isColor) { UpdateFloatUniforms(env, mBuilder, name, vals, count, isColor); discardInstance(); } void updateUniforms(JNIEnv* env, const char* name, const int vals[], int count) { UpdateIntUniforms(env, mBuilder, name, vals, count); discardInstance(); } void updateChild(JNIEnv* env, const char* name, SkFlattenable* childEffect) { UpdateChild(env, mBuilder, name, childEffect); discardInstance(); } private: sk_sp<SkColorFilter> createInstance() override { // TODO: throw error if null return mBuilder->makeColorFilter(); } private: SkRuntimeEffectBuilder* mBuilder; }; } // namespace uirenderer } // namespace android Loading libs/hwui/jni/ColorFilter.cpp +92 −1 Original line number Diff line number Diff line Loading @@ -18,7 +18,9 @@ #include "ColorFilter.h" #include "GraphicsJNI.h" #include "RuntimeEffectUtils.h" #include "SkBlendMode.h" #include "include/effects/SkRuntimeEffect.h" namespace android { Loading Loading @@ -89,6 +91,78 @@ public: filter->setMatrix(getMatrixFromJFloatArray(env, jarray)); } } static jlong RuntimeColorFilter_createColorFilter(JNIEnv* env, jobject, jstring agsl) { ScopedUtfChars strSksl(env, agsl); auto result = SkRuntimeEffect::MakeForColorFilter(SkString(strSksl.c_str()), SkRuntimeEffect::Options{}); if (result.effect.get() == nullptr) { doThrowIAE(env, result.errorText.c_str()); return 0; } auto builder = new SkRuntimeEffectBuilder(std::move(result.effect)); auto* runtimeColorFilter = new RuntimeColorFilter(builder); runtimeColorFilter->incStrong(nullptr); return static_cast<jlong>(reinterpret_cast<uintptr_t>(runtimeColorFilter)); } static void RuntimeColorFilter_updateUniformsFloatArray(JNIEnv* env, jobject, jlong colorFilterPtr, jstring uniformName, jfloatArray uniforms, jboolean isColor) { auto* filter = reinterpret_cast<RuntimeColorFilter*>(colorFilterPtr); ScopedUtfChars name(env, uniformName); AutoJavaFloatArray autoValues(env, uniforms, 0, kRO_JNIAccess); if (filter) { filter->updateUniforms(env, name.c_str(), autoValues.ptr(), autoValues.length(), isColor); } } static void RuntimeColorFilter_updateUniformsFloats(JNIEnv* env, jobject, jlong colorFilterPtr, jstring uniformName, jfloat value1, jfloat value2, jfloat value3, jfloat value4, jint count) { auto* filter = reinterpret_cast<RuntimeColorFilter*>(colorFilterPtr); ScopedUtfChars name(env, uniformName); const float values[4] = {value1, value2, value3, value4}; if (filter) { filter->updateUniforms(env, name.c_str(), values, count, false); } } static void RuntimeColorFilter_updateUniformsIntArray(JNIEnv* env, jobject, jlong colorFilterPtr, jstring uniformName, jintArray uniforms) { auto* filter = reinterpret_cast<RuntimeColorFilter*>(colorFilterPtr); ScopedUtfChars name(env, uniformName); AutoJavaIntArray autoValues(env, uniforms, 0); if (filter) { filter->updateUniforms(env, name.c_str(), autoValues.ptr(), autoValues.length()); } } static void RuntimeColorFilter_updateUniformsInts(JNIEnv* env, jobject, jlong colorFilterPtr, jstring uniformName, jint value1, jint value2, jint value3, jint value4, jint count) { auto* filter = reinterpret_cast<RuntimeColorFilter*>(colorFilterPtr); ScopedUtfChars name(env, uniformName); const int values[4] = {value1, value2, value3, value4}; if (filter) { filter->updateUniforms(env, name.c_str(), values, count); } } static void RuntimeColorFilter_updateChild(JNIEnv* env, jobject, jlong colorFilterPtr, jstring childName, jlong childPtr) { auto* filter = reinterpret_cast<RuntimeColorFilter*>(colorFilterPtr); ScopedUtfChars name(env, childName); auto* child = reinterpret_cast<SkFlattenable*>(childPtr); if (filter && child) { filter->updateChild(env, name.c_str(), child); } } }; static const JNINativeMethod colorfilter_methods[] = { Loading @@ -107,6 +181,20 @@ static const JNINativeMethod colormatrix_methods[] = { {"nativeColorMatrixFilter", "([F)J", (void*)ColorFilterGlue::CreateColorMatrixFilter}, {"nativeSetColorMatrix", "(J[F)V", (void*)ColorFilterGlue::SetColorMatrix}}; static const JNINativeMethod runtime_color_filter_methods[] = { {"nativeCreateRuntimeColorFilter", "(Ljava/lang/String;)J", (void*)ColorFilterGlue::RuntimeColorFilter_createColorFilter}, {"nativeUpdateUniforms", "(JLjava/lang/String;[FZ)V", (void*)ColorFilterGlue::RuntimeColorFilter_updateUniformsFloatArray}, {"nativeUpdateUniforms", "(JLjava/lang/String;FFFFI)V", (void*)ColorFilterGlue::RuntimeColorFilter_updateUniformsFloats}, {"nativeUpdateUniforms", "(JLjava/lang/String;[I)V", (void*)ColorFilterGlue::RuntimeColorFilter_updateUniformsIntArray}, {"nativeUpdateUniforms", "(JLjava/lang/String;IIIII)V", (void*)ColorFilterGlue::RuntimeColorFilter_updateUniformsInts}, {"nativeUpdateChild", "(JLjava/lang/String;J)V", (void*)ColorFilterGlue::RuntimeColorFilter_updateChild}}; int register_android_graphics_ColorFilter(JNIEnv* env) { android::RegisterMethodsOrDie(env, "android/graphics/ColorFilter", colorfilter_methods, NELEM(colorfilter_methods)); Loading @@ -118,6 +206,9 @@ int register_android_graphics_ColorFilter(JNIEnv* env) { NELEM(lighting_methods)); android::RegisterMethodsOrDie(env, "android/graphics/ColorMatrixColorFilter", colormatrix_methods, NELEM(colormatrix_methods)); android::RegisterMethodsOrDie(env, "android/graphics/RuntimeColorFilter", runtime_color_filter_methods, NELEM(runtime_color_filter_methods)); return 0; } Loading Loading
core/api/current.txt +19 −0 Original line number Diff line number Diff line Loading @@ -17361,6 +17361,25 @@ package android.graphics { method public boolean setUseCompositingLayer(boolean, @Nullable android.graphics.Paint); } @FlaggedApi("com.android.graphics.hwui.flags.runtime_color_filters_blenders") public class RuntimeColorFilter extends android.graphics.ColorFilter { ctor public RuntimeColorFilter(@NonNull String); method public void setColorUniform(@NonNull String, @ColorInt int); method public void setColorUniform(@NonNull String, @ColorLong long); method public void setColorUniform(@NonNull String, @NonNull android.graphics.Color); method public void setFloatUniform(@NonNull String, float); method public void setFloatUniform(@NonNull String, float, float); method public void setFloatUniform(@NonNull String, float, float, float); method public void setFloatUniform(@NonNull String, float, float, float, float); method public void setFloatUniform(@NonNull String, @NonNull float[]); method public void setInputColorFilter(@NonNull String, @NonNull android.graphics.ColorFilter); method public void setInputShader(@NonNull String, @NonNull android.graphics.Shader); method public void setIntUniform(@NonNull String, int); method public void setIntUniform(@NonNull String, int, int); method public void setIntUniform(@NonNull String, int, int, int); method public void setIntUniform(@NonNull String, int, int, int, int); method public void setIntUniform(@NonNull String, @NonNull int[]); } public class RuntimeShader extends android.graphics.Shader { ctor public RuntimeShader(@NonNull String); method public void setColorUniform(@NonNull String, @ColorInt int);
graphics/java/android/graphics/RuntimeColorFilter.java 0 → 100644 +305 −0 Original line number Diff line number Diff line /* * Copyright 2024 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.ColorInt; import android.annotation.ColorLong; import android.annotation.FlaggedApi; import android.annotation.NonNull; import com.android.graphics.hwui.flags.Flags; /** * <p>A {@link RuntimeColorFilter} calculates a per-pixel color based on the output of a user * * defined Android Graphics Shading Language (AGSL) function.</p> * * <p>This AGSL function takes in an input color to be operated on. This color is in sRGB and the * * output is also interpreted as sRGB. The AGSL function signature expects a single input * * of color (packed as a half4 or float4 or vec4).</p> * * <pre class="prettyprint"> * vec4 main(half4 in_color); * </pre> */ @FlaggedApi(Flags.FLAG_RUNTIME_COLOR_FILTERS_BLENDERS) public class RuntimeColorFilter extends ColorFilter { private String mAgsl; /** * Creates a new RuntimeColorFilter. * * @param agsl The text of AGSL color filter program to run. */ public RuntimeColorFilter(@NonNull String agsl) { if (agsl == null) { throw new NullPointerException("RuntimeColorFilter requires a non-null AGSL string"); } mAgsl = agsl; // call to parent class to register native RuntimeColorFilter // TODO: find way to get super class to create native instance without requiring the storage // of agsl string getNativeInstance(); } /** * Sets the uniform color value corresponding to this color filter. If the effect does not have * a uniform with that name or if the uniform is declared with a type other than vec3 or vec4 * and corresponding layout(color) annotation then an IllegalArgumentException is thrown. * * @param uniformName name matching the color uniform declared in the AGSL program * @param color the provided sRGB color */ public void setColorUniform(@NonNull String uniformName, @ColorInt int color) { setUniform(uniformName, Color.valueOf(color).getComponents(), true); } /** * Sets the uniform color value corresponding to this color filter. If the effect does not have * a uniform with that name or if the uniform is declared with a type other than vec3 or vec4 * and corresponding layout(color) annotation then an IllegalArgumentException is thrown. * * @param uniformName name matching the color uniform declared in the AGSL program * @param color the provided sRGB color */ public void setColorUniform(@NonNull String uniformName, @ColorLong long color) { Color exSRGB = Color.valueOf(color).convert(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)); setUniform(uniformName, exSRGB.getComponents(), true); } /** * Sets the uniform color value corresponding to this color filter. If the effect does not have * a uniform with that name or if the uniform is declared with a type other than vec3 or vec4 * and corresponding layout(color) annotation then an IllegalArgumentException is thrown. * * @param uniformName name matching the color uniform declared in the AGSL program * @param color the provided sRGB color */ public void setColorUniform(@NonNull String uniformName, @NonNull Color color) { if (color == null) { throw new NullPointerException("The color parameter must not be null"); } Color exSRGB = color.convert(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)); setUniform(uniformName, exSRGB.getComponents(), true); } /** * Sets the uniform value corresponding to this color filter. If the effect does not have a * uniform with that name or if the uniform is declared with a type other than a float or * float[1] then an IllegalArgumentException is thrown. * * @param uniformName name matching the uniform declared in the AGSL program */ public void setFloatUniform(@NonNull String uniformName, float value) { setFloatUniform(uniformName, value, 0.0f, 0.0f, 0.0f, 1); } /** * Sets the uniform value corresponding to this color filter. If the effect does not have a * uniform with that name or if the uniform is declared with a type other than a vec2 or * float[2] then an IllegalArgumentException is thrown. * * @param uniformName name matching the uniform declared in the AGSL program */ public void setFloatUniform(@NonNull String uniformName, float value1, float value2) { setFloatUniform(uniformName, value1, value2, 0.0f, 0.0f, 2); } /** * Sets the uniform value corresponding to this color filter. If the effect does not have a * uniform with that name or if the uniform is declared with a type other than a vec3 or * float[3] then an IllegalArgumentException is thrown. * * @param uniformName name matching the uniform declared in the AGSL program */ public void setFloatUniform(@NonNull String uniformName, float value1, float value2, float value3) { setFloatUniform(uniformName, value1, value2, value3, 0.0f, 3); } /** * Sets the uniform value corresponding to this color filter. If the effect does not have a * uniform with that name or if the uniform is declared with a type other than a vec4 or * float[4] then an IllegalArgumentException is thrown. * * @param uniformName name matching the uniform declared in the AGSL program */ public void setFloatUniform(@NonNull String uniformName, float value1, float value2, float value3, float value4) { setFloatUniform(uniformName, value1, value2, value3, value4, 4); } /** * Sets the uniform value corresponding to this color filter. If the effect does not have a * uniform with that name or if the uniform is declared with a type other than a float * (for N=1), vecN, or float[N] where N is the length of the values param then an * IllegalArgumentException is thrown. * * @param uniformName name matching the uniform declared in the AGSL program */ public void setFloatUniform(@NonNull String uniformName, @NonNull float[] values) { setUniform(uniformName, values, false); } private void setFloatUniform(@NonNull String uniformName, float value1, float value2, float value3, float value4, int count) { if (uniformName == null) { throw new NullPointerException("The uniformName parameter must not be null"); } nativeUpdateUniforms(getNativeInstance(), uniformName, value1, value2, value3, value4, count); } private void setUniform(@NonNull String uniformName, @NonNull float[] values, boolean isColor) { if (uniformName == null) { throw new NullPointerException("The uniformName parameter must not be null"); } if (values == null) { throw new NullPointerException("The uniform values parameter must not be null"); } nativeUpdateUniforms(getNativeInstance(), uniformName, values, isColor); } /** * Sets the uniform value corresponding to this color filter. If the effect does not have a * uniform with that name or if the uniform is declared with a type other than an int or int[1] * then an IllegalArgumentException is thrown. * * @param uniformName name matching the uniform declared in the AGSL program */ public void setIntUniform(@NonNull String uniformName, int value) { setIntUniform(uniformName, value, 0, 0, 0, 1); } /** * Sets the uniform value corresponding to this color filter. If the effect does not have a * uniform with that name or if the uniform is declared with a type other than an ivec2 or * int[2] then an IllegalArgumentException is thrown. * * @param uniformName name matching the uniform declared in the AGSL program */ public void setIntUniform(@NonNull String uniformName, int value1, int value2) { setIntUniform(uniformName, value1, value2, 0, 0, 2); } /** * Sets the uniform value corresponding to this color filter. If the effect does not have a * uniform with that name or if the uniform is declared with a type other than an ivec3 or * int[3] then an IllegalArgumentException is thrown. * * @param uniformName name matching the uniform declared in the AGSL program */ public void setIntUniform(@NonNull String uniformName, int value1, int value2, int value3) { setIntUniform(uniformName, value1, value2, value3, 0, 3); } /** * Sets the uniform value corresponding to this color filter. If the effect does not have a * uniform with that name or if the uniform is declared with a type other than an ivec4 or * int[4] then an IllegalArgumentException is thrown. * * @param uniformName name matching the uniform declared in the AGSL program */ public void setIntUniform(@NonNull String uniformName, int value1, int value2, int value3, int value4) { setIntUniform(uniformName, value1, value2, value3, value4, 4); } /** * Sets the uniform value corresponding to this color filter. If the effect does not have a * uniform with that name or if the uniform is declared with a type other than an int (for N=1), * ivecN, or int[N] where N is the length of the values param then an IllegalArgumentException * is thrown. * * @param uniformName name matching the uniform declared in the AGSL program */ public void setIntUniform(@NonNull String uniformName, @NonNull int[] values) { if (uniformName == null) { throw new NullPointerException("The uniformName parameter must not be null"); } if (values == null) { throw new NullPointerException("The uniform values parameter must not be null"); } nativeUpdateUniforms(getNativeInstance(), uniformName, values); } private void setIntUniform(@NonNull String uniformName, int value1, int value2, int value3, int value4, int count) { if (uniformName == null) { throw new NullPointerException("The uniformName parameter must not be null"); } nativeUpdateUniforms(getNativeInstance(), uniformName, value1, value2, value3, value4, count); } /** * Assigns the uniform shader to the provided shader parameter. If the shader program does not * have a uniform shader with that name then an IllegalArgumentException is thrown. * * @param shaderName name matching the uniform declared in the AGSL program * @param shader shader passed into the AGSL program for sampling */ public void setInputShader(@NonNull String shaderName, @NonNull Shader shader) { if (shaderName == null) { throw new NullPointerException("The shaderName parameter must not be null"); } if (shader == null) { throw new NullPointerException("The shader parameter must not be null"); } nativeUpdateChild(getNativeInstance(), shaderName, shader.getNativeInstance()); } /** * Assigns the uniform color filter to the provided color filter parameter. If the shader * program does not have a uniform color filter with that name then an IllegalArgumentException * is thrown. * * @param filterName name matching the uniform declared in the AGSL program * @param colorFilter filter passed into the AGSL program for sampling */ public void setInputColorFilter(@NonNull String filterName, @NonNull ColorFilter colorFilter) { if (filterName == null) { throw new NullPointerException("The filterName parameter must not be null"); } if (colorFilter == null) { throw new NullPointerException("The colorFilter parameter must not be null"); } nativeUpdateChild(getNativeInstance(), filterName, colorFilter.getNativeInstance()); } /** @hide */ @Override protected long createNativeInstance() { return nativeCreateRuntimeColorFilter(mAgsl); } private static native long nativeCreateRuntimeColorFilter(String agsl); private static native void nativeUpdateUniforms( long colorFilter, String uniformName, float[] uniforms, boolean isColor); private static native void nativeUpdateUniforms( long colorFilter, String uniformName, float value1, float value2, float value3, float value4, int count); private static native void nativeUpdateUniforms( long colorFilter, String uniformName, int[] uniforms); private static native void nativeUpdateUniforms( long colorFilter, String uniformName, int value1, int value2, int value3, int value4, int count); private static native void nativeUpdateChild(long colorFilter, String childName, long child); }
libs/hwui/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -384,6 +384,7 @@ cc_defaults { "jni/ScopedParcel.cpp", "jni/Shader.cpp", "jni/RenderEffect.cpp", "jni/RuntimeEffectUtils.cpp", "jni/Typeface.cpp", "jni/Utils.cpp", "jni/YuvToJpegEncoder.cpp", Loading
libs/hwui/ColorFilter.h +31 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include <memory> #include "GraphicsJNI.h" #include "RuntimeEffectUtils.h" #include "SkColorFilter.h" namespace android { Loading Loading @@ -113,6 +114,36 @@ private: std::vector<float> mMatrix; }; class RuntimeColorFilter : public ColorFilter { public: RuntimeColorFilter(SkRuntimeEffectBuilder* builder) : mBuilder(builder) {} void updateUniforms(JNIEnv* env, const char* name, const float vals[], int count, bool isColor) { UpdateFloatUniforms(env, mBuilder, name, vals, count, isColor); discardInstance(); } void updateUniforms(JNIEnv* env, const char* name, const int vals[], int count) { UpdateIntUniforms(env, mBuilder, name, vals, count); discardInstance(); } void updateChild(JNIEnv* env, const char* name, SkFlattenable* childEffect) { UpdateChild(env, mBuilder, name, childEffect); discardInstance(); } private: sk_sp<SkColorFilter> createInstance() override { // TODO: throw error if null return mBuilder->makeColorFilter(); } private: SkRuntimeEffectBuilder* mBuilder; }; } // namespace uirenderer } // namespace android Loading
libs/hwui/jni/ColorFilter.cpp +92 −1 Original line number Diff line number Diff line Loading @@ -18,7 +18,9 @@ #include "ColorFilter.h" #include "GraphicsJNI.h" #include "RuntimeEffectUtils.h" #include "SkBlendMode.h" #include "include/effects/SkRuntimeEffect.h" namespace android { Loading Loading @@ -89,6 +91,78 @@ public: filter->setMatrix(getMatrixFromJFloatArray(env, jarray)); } } static jlong RuntimeColorFilter_createColorFilter(JNIEnv* env, jobject, jstring agsl) { ScopedUtfChars strSksl(env, agsl); auto result = SkRuntimeEffect::MakeForColorFilter(SkString(strSksl.c_str()), SkRuntimeEffect::Options{}); if (result.effect.get() == nullptr) { doThrowIAE(env, result.errorText.c_str()); return 0; } auto builder = new SkRuntimeEffectBuilder(std::move(result.effect)); auto* runtimeColorFilter = new RuntimeColorFilter(builder); runtimeColorFilter->incStrong(nullptr); return static_cast<jlong>(reinterpret_cast<uintptr_t>(runtimeColorFilter)); } static void RuntimeColorFilter_updateUniformsFloatArray(JNIEnv* env, jobject, jlong colorFilterPtr, jstring uniformName, jfloatArray uniforms, jboolean isColor) { auto* filter = reinterpret_cast<RuntimeColorFilter*>(colorFilterPtr); ScopedUtfChars name(env, uniformName); AutoJavaFloatArray autoValues(env, uniforms, 0, kRO_JNIAccess); if (filter) { filter->updateUniforms(env, name.c_str(), autoValues.ptr(), autoValues.length(), isColor); } } static void RuntimeColorFilter_updateUniformsFloats(JNIEnv* env, jobject, jlong colorFilterPtr, jstring uniformName, jfloat value1, jfloat value2, jfloat value3, jfloat value4, jint count) { auto* filter = reinterpret_cast<RuntimeColorFilter*>(colorFilterPtr); ScopedUtfChars name(env, uniformName); const float values[4] = {value1, value2, value3, value4}; if (filter) { filter->updateUniforms(env, name.c_str(), values, count, false); } } static void RuntimeColorFilter_updateUniformsIntArray(JNIEnv* env, jobject, jlong colorFilterPtr, jstring uniformName, jintArray uniforms) { auto* filter = reinterpret_cast<RuntimeColorFilter*>(colorFilterPtr); ScopedUtfChars name(env, uniformName); AutoJavaIntArray autoValues(env, uniforms, 0); if (filter) { filter->updateUniforms(env, name.c_str(), autoValues.ptr(), autoValues.length()); } } static void RuntimeColorFilter_updateUniformsInts(JNIEnv* env, jobject, jlong colorFilterPtr, jstring uniformName, jint value1, jint value2, jint value3, jint value4, jint count) { auto* filter = reinterpret_cast<RuntimeColorFilter*>(colorFilterPtr); ScopedUtfChars name(env, uniformName); const int values[4] = {value1, value2, value3, value4}; if (filter) { filter->updateUniforms(env, name.c_str(), values, count); } } static void RuntimeColorFilter_updateChild(JNIEnv* env, jobject, jlong colorFilterPtr, jstring childName, jlong childPtr) { auto* filter = reinterpret_cast<RuntimeColorFilter*>(colorFilterPtr); ScopedUtfChars name(env, childName); auto* child = reinterpret_cast<SkFlattenable*>(childPtr); if (filter && child) { filter->updateChild(env, name.c_str(), child); } } }; static const JNINativeMethod colorfilter_methods[] = { Loading @@ -107,6 +181,20 @@ static const JNINativeMethod colormatrix_methods[] = { {"nativeColorMatrixFilter", "([F)J", (void*)ColorFilterGlue::CreateColorMatrixFilter}, {"nativeSetColorMatrix", "(J[F)V", (void*)ColorFilterGlue::SetColorMatrix}}; static const JNINativeMethod runtime_color_filter_methods[] = { {"nativeCreateRuntimeColorFilter", "(Ljava/lang/String;)J", (void*)ColorFilterGlue::RuntimeColorFilter_createColorFilter}, {"nativeUpdateUniforms", "(JLjava/lang/String;[FZ)V", (void*)ColorFilterGlue::RuntimeColorFilter_updateUniformsFloatArray}, {"nativeUpdateUniforms", "(JLjava/lang/String;FFFFI)V", (void*)ColorFilterGlue::RuntimeColorFilter_updateUniformsFloats}, {"nativeUpdateUniforms", "(JLjava/lang/String;[I)V", (void*)ColorFilterGlue::RuntimeColorFilter_updateUniformsIntArray}, {"nativeUpdateUniforms", "(JLjava/lang/String;IIIII)V", (void*)ColorFilterGlue::RuntimeColorFilter_updateUniformsInts}, {"nativeUpdateChild", "(JLjava/lang/String;J)V", (void*)ColorFilterGlue::RuntimeColorFilter_updateChild}}; int register_android_graphics_ColorFilter(JNIEnv* env) { android::RegisterMethodsOrDie(env, "android/graphics/ColorFilter", colorfilter_methods, NELEM(colorfilter_methods)); Loading @@ -118,6 +206,9 @@ int register_android_graphics_ColorFilter(JNIEnv* env) { NELEM(lighting_methods)); android::RegisterMethodsOrDie(env, "android/graphics/ColorMatrixColorFilter", colormatrix_methods, NELEM(colormatrix_methods)); android::RegisterMethodsOrDie(env, "android/graphics/RuntimeColorFilter", runtime_color_filter_methods, NELEM(runtime_color_filter_methods)); return 0; } Loading