| /* |
| * 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; |
| |
| import libcore.util.NativeAllocationRegistry; |
| |
| |
| /** |
| * <p>A {@link RuntimeXfermode} 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 two input colors to be operated on. These colors are 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 src, half4 dst); |
| * </pre> |
| */ |
| @FlaggedApi(Flags.FLAG_RUNTIME_COLOR_FILTERS_BLENDERS) |
| @android.ravenwood.annotation.RavenwoodKeepWholeClass |
| public class RuntimeXfermode extends Xfermode { |
| |
| private static class NoImagePreloadHolder { |
| public static final NativeAllocationRegistry sRegistry = |
| NativeAllocationRegistry.createMalloced( |
| RuntimeXfermode.class.getClassLoader(), nativeGetFinalizer()); |
| } |
| |
| private long mBuilderNativeInstance; |
| |
| /** |
| * Creates a new RuntimeBlender. |
| * |
| * @param agsl The text of AGSL color filter program to run. |
| */ |
| public RuntimeXfermode(@NonNull String agsl) { |
| if (agsl == null) { |
| throw new NullPointerException("RuntimeShader requires a non-null AGSL string"); |
| } |
| mBuilderNativeInstance = nativeCreateBlenderBuilder(agsl); |
| RuntimeXfermode.NoImagePreloadHolder.sRegistry.registerNativeAllocation( |
| this, mBuilderNativeInstance); |
| } |
| /** |
| * 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(mBuilderNativeInstance, 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(mBuilderNativeInstance, 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(mBuilderNativeInstance, 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(mBuilderNativeInstance, 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(mBuilderNativeInstance, 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"); |
| } |
| nativeUpdateColorFilter(mBuilderNativeInstance, filterName, |
| colorFilter.getNativeInstance()); |
| } |
| |
| /** |
| * Assigns the uniform xfermode to the provided xfermode parameter. If the shader program does |
| * not have a uniform xfermode with that name then an IllegalArgumentException is thrown. |
| * |
| * @param xfermodeName name matching the uniform declared in the AGSL program |
| * @param xfermode xfermode function passed into the AGSL program for sampling |
| */ |
| public void setInputXfermode(@NonNull String xfermodeName, @NonNull RuntimeXfermode xfermode) { |
| if (xfermodeName == null) { |
| throw new NullPointerException("The xfermodeName parameter must not be null"); |
| } |
| if (xfermode == null) { |
| throw new NullPointerException("The xfermode parameter must not be null"); |
| } |
| nativeUpdateChild(mBuilderNativeInstance, xfermodeName, xfermode.createNativeInstance()); |
| } |
| |
| /** @hide */ |
| public long createNativeInstance() { |
| return nativeCreateNativeInstance(mBuilderNativeInstance); |
| } |
| |
| /** @hide */ |
| private static native long nativeGetFinalizer(); |
| private static native long nativeCreateBlenderBuilder(String agsl); |
| private static native long nativeCreateNativeInstance(long builder); |
| private static native void nativeUpdateUniforms( |
| long builder, String uniformName, float[] uniforms, boolean isColor); |
| private static native void nativeUpdateUniforms( |
| long builder, String uniformName, float value1, float value2, float value3, |
| float value4, int count); |
| private static native void nativeUpdateUniforms( |
| long builder, String uniformName, int[] uniforms); |
| private static native void nativeUpdateUniforms( |
| long builder, String uniformName, int value1, int value2, int value3, |
| int value4, int count); |
| private static native void nativeUpdateChild(long builder, String childName, long child); |
| private static native void nativeUpdateColorFilter(long builder, String childName, long filter); |
| |
| } |