• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.graphics;
18 
19 import android.annotation.ColorInt;
20 import android.annotation.ColorLong;
21 import android.annotation.FlaggedApi;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.util.ArrayMap;
25 import android.view.Window;
26 
27 import com.android.graphics.hwui.flags.Flags;
28 
29 import libcore.util.NativeAllocationRegistry;
30 
31 /**
32  * <p>A {@link RuntimeShader} calculates a per-pixel color based on the output of a user defined
33  * Android Graphics Shading Language (AGSL) function.</p>
34  *
35  * <h3>Android Graphics Shading Language</h3>
36  * <p>The AGSL syntax is very similar to OpenGL ES Shading Language, but there are some important
37  * differences that are highlighted here. Most of these differences are summed up in one basic fact:
38  * <b>With GPU shading languages, you are programming a stage of the GPU pipeline. With AGSL, you
39  * are programming a stage of the {@link Canvas} or {@link RenderNode} drawing pipeline.</b></p>
40  *
41  * <p>In particular, a GLSL fragment shader controls the entire behavior of the GPU between the
42  * rasterizer and the blending hardware. That shader does all of the work to compute a color, and
43  * the color it generates is exactly what is fed to the blending stage of the pipeline.</p>
44  *
45  * <p>In contrast, AGSL functions exist as part of a larger pipeline. When you issue a
46  * {@link Canvas} drawing operation, Android (generally) assembles a single GPU fragment shader to
47  * do all of the required work. This shader typically includes several pieces. For example, it might
48  * include:</p>
49  * <ul>
50  *  <li>Evaluating whether a pixel falls inside or outside of the shape being drawn (or on the
51  *  border, where it might apply antialiasing).</li>
52  *  <li>Evaluating whether a pixel falls inside or outside of the clipping region (again, with
53  *  possible antialiasing logic for border pixels).</li>
54  *  <li>Logic for the {@link Shader}, {@link ColorFilter}, and {@link BlendMode} on the
55  *  {@link Paint}.</li>
56  *  <li>Color space conversion code, as part of Android's color management.</li>
57  * </ul>
58  *
59  * <p>A {@link RuntimeShader}, like other {@link Shader} types, effectively contributes a function
60  * to the GPU's fragment shader.</p>
61  *
62  * <h3>AGSL Shader Execution</h3>
63  * <p>Just like a GLSL shader, an AGSL shader begins execution in a main function. Unlike GLSL, the
64  * function receives as an input parameter the position of the pixel within the {@link Canvas} or
65  * {@link RenderNode} coordinate space (similar to gl_fragCoord) and returns the color to be shaded
66  * as a vec4 (similar to out vec4 color or gl_FragColor in GLSL).</p>
67  *
68  * <pre class="prettyprint">
69  * vec4 main(vec2 canvas_coordinates);
70  * </pre>
71  *
72  * <p>AGSL and GLSL use different coordinate spaces by default. In GLSL, the fragment coordinate
73  * (fragCoord) is relative to the lower left. AGSL matches the screen coordinate system of the
74  * Android {@link Canvas} which has its origin as the upper left corner. This means that the
75  * coordinates provided as a parameter in the main function are local to the canvas with the
76  * exception of any {@link Shader#getLocalMatrix(Matrix)} transformations applied to this shader.
77  * Additionally, if the shader is invoked by another using {@link #setInputShader(String, Shader)},
78  * then that parent shader may modify the input coordinates arbitrarily.</p>
79  *
80  * <a id="agsl-and-color-spaces"/>
81  * <h3>AGSL and Color Spaces</h3>
82  * <p>Android Graphics and by extension {@link RuntimeShader} are color managed.  The working
83  * {@link ColorSpace} for an AGSL shader is defined to be the color space of the destination, which
84  * in most cases is determined by {@link Window#setColorMode(int)}.</p>
85  *
86  * <p>When authoring an AGSL shader, you won't know what the working color space is. For many
87  * effects, this is fine because by default color inputs are automatically converted into the
88  * working color space. For certain effects, it may be important to do some math in a fixed, known
89  * color space. A common example is lighting - to get physically accurate lighting, math should be
90  * done in a linear color space. To help with this, AGSL provides two intrinsic functions that
91  * convert colors between the working color space and the
92  * {@link ColorSpace.Named#LINEAR_EXTENDED_SRGB} color space:
93  *
94  * <pre class="prettyprint">
95  * vec3 toLinearSrgb(vec3 color);
96  * vec3 fromLinearSrgb(vec3 color);</pre>
97  *
98  * <h3>AGSL and Premultiplied Alpha</h3>
99  * <p>When dealing with transparent colors, there are two (common) possible representations:
100  * straight (unassociated) alpha and premultiplied (associated) alpha. In ASGL the color returned
101  * by the main function is expected to be premultiplied.  AGSL's use of premultiplied alpha
102  * implies:
103  * </p>
104  *
105  * <ul>
106  *  <li>If your AGSL shader will return transparent colors, be sure to multiply the RGB by A.  The
107  *  resulting color should be [R*A, G*A, B*A, A], not [R, G, B, A].</li>
108  *  <li>For more complex shaders, you must understand which of your colors are premultiplied vs.
109  *  straight. Many operations don't make sense if you mix both kinds of color together.</li>
110  * </ul>
111  *
112  * <h3>Uniforms</h3>
113  * <p>AGSL, like GLSL, exposes the concept of uniforms. An AGSL uniform is defined as a read-only,
114  * global variable that is accessible by the AGSL code and is initialized by a number of setter
115  * methods on {@link RuntimeShader}. AGSL exposes two primitive uniform data types (float, int) and
116  * two specialized types (colors, shaders) that are outlined below.</p>
117  *
118  * <h4>Primitive Uniforms</h4>
119  * <p>There are two primitive uniform types supported by AGSL, float and int. For these types and
120  * uniforms representing a grouping of these types, like arrays and matrices, there are
121  * corresponding {@link RuntimeShader} methods to initialize them.
122  * <table border="2" width="85%" align="center" cellpadding="5">
123  *     <thead>
124  *         <tr><th>Java Type</th> <th>AGSL Type</th> <th>Method</th> </tr>
125  *     </thead>
126  *
127  *     <tbody>
128  *     <tr>
129  *         <td rowspan="4">Floats</td>
130  *         <td>float</td>
131  *         <td>{@link RuntimeShader#setFloatUniform(String, float)}</td>
132  *     </tr>
133  *     <tr>
134  *         <td>vec2</td>
135  *         <td>{@link RuntimeShader#setFloatUniform(String, float, float)}</td>
136  *     </tr>
137  *     <tr>
138  *         <td>vec3</td>
139  *         <td>{@link RuntimeShader#setFloatUniform(String, float, float, float)}</td>
140  *     </tr>
141  *     <tr>
142  *         <td>vec4</td>
143  *         <td>{@link RuntimeShader#setFloatUniform(String, float, float, float, float)}</td>
144  *     </tr>
145  *     <tr>
146  *         <td rowspan="4">Integers</td>
147  *         <td>int</td>
148  *         <td>{@link RuntimeShader#setIntUniform(String, int)}</td>
149  *     </tr>
150  *     <tr>
151  *         <td>ivec2</td>
152  *         <td>{@link RuntimeShader#setIntUniform(String, int, int)}</td>
153  *     </tr>
154  *     <tr>
155  *         <td>ivec3</td>
156  *         <td>{@link RuntimeShader#setIntUniform(String, int, int, int)}</td>
157  *     </tr>
158  *     <tr>
159  *         <td>ivec4</td>
160  *         <td>{@link RuntimeShader#setIntUniform(String, int, int, int, int)}</td>
161  *     </tr>
162  *     <tr>
163  *         <td rowspan="2">Matrices and Arrays</td>
164  *         <td>mat2, mat3, and mat4, and float[]</td>
165  *         <td>{@link RuntimeShader#setFloatUniform(String, float[])}</td>
166  *     </tr>
167  *     <tr>
168  *         <td>int[]</td>
169  *         <td>{@link RuntimeShader#setIntUniform(String, int[])}</td>
170  *     </tr>
171  *     </tbody>
172  * </table>
173  *
174  * For example, a simple AGSL shader making use of a float uniform to modulate the transparency
175  * of the output color would look like:</p>
176  *
177  * <pre class="prettyprint">
178  * uniform float alpha;
179  * vec4 main(vec2 canvas_coordinates) {
180  *     vec3 red = vec3(1.0, 0.0, 0.0);
181  *     return vec4(red * alpha, alpha);
182  * }</pre>
183  *
184  * <p>After creating a {@link RuntimeShader} with that program the uniform can then be initialized
185  * and updated per frame by calling {@link RuntimeShader#setFloatUniform(String, float)} with the
186  * value of alpha.  The value of a primitive uniform defaults to 0 if it is declared in the AGSL
187  * shader but not initialized.</p>
188  *
189  * <h4>Color Uniforms</h4>
190  * <p>AGSL doesn't know if uniform variables contain colors, it won't automatically convert them to
191  * the working colorspace of the shader at runtime.  However, you can label your vec4 uniform with
192  * the "layout(color)" qualifier which lets Android know that the uniform will be used as a color.
193  * Doing so allows AGSL to transform the uniform value to the working color space. In AGSL, declare
194  * the uniform like this:
195  *
196  * <pre class="prettyprint">
197  * layout(color) uniform vec4 inputColorA;
198  * layout(color) uniform vec4 inputColorB;
199  * vec4 main(vec2 canvas_coordinates) {
200  *     // blend the two colors together and return the resulting color
201  *     return mix(inputColorA, inputColorB, 0.5);
202  * }</pre>
203  *
204  * <p>After creating a {@link RuntimeShader} with that program the uniforms can
205  * then be initialized and updated per frame by calling
206  * {@link RuntimeShader#setColorUniform(String, int)},
207  * {@link RuntimeShader#setColorUniform(String, long)}, or
208  * {@link RuntimeShader#setColorUniform(String, Color)} with the desired colors.  The value of a
209  * color uniform is undefined if it is declared in the AGSL shader but not initialized.</p>
210  *
211  * <h4>Shader Uniforms</h4>
212  * In GLSL, a fragment shader can sample a texture. For AGSL instead of sampling textures you can
213  * sample from any {@link Shader}, which includes but is not limited to {@link BitmapShader}. To
214  * make it clear that you are operating on an {@link Shader} object there is no "sample"
215  * method. Instead, the shader uniform has an "eval()" method. This distinction enables AGSL shaders
216  * to sample from existing bitmap and gradient shaders as well as other {@link RuntimeShader}
217  * objects.  In AGSL, declare the uniform like this:
218  *
219  * <pre class="prettyprint">
220  * uniform shader myShader;
221  * vec4 main(vec2 canvas_coordinates) {
222  *     // swap the red and blue color channels when sampling from myShader
223  *     return myShader.eval(canvas_coordinates).bgra;
224  * }</pre>
225  *
226  * <p>After creating a {@link RuntimeShader} with that program the shader uniform can
227  * then be initialized and updated per frame by calling
228  * {@link RuntimeShader#setInputShader(String, Shader)} with the desired shader. The value of a
229  * shader uniform is undefined if it is declared in the AGSL shader but not initialized.</p>
230  *
231  * <p>Although most {@link BitmapShader}s contain colors that should be color managed, some contain
232  * data that isn't actually colors. This includes bitmaps storing normals, material properties
233  * (e.g. roughness), heightmaps, or any other purely mathematical data that happens to be stored in
234  * a bitmap. When using these kinds of shaders in AGSL, you probably want to initialize them with
235  * {@link #setInputBuffer(String, BitmapShader)}. Shaders initialized this way work much like
236  * a regular {@link BitmapShader} (including filtering and tiling), with a few major differences:
237  * <ul>
238  *  <li>No color space transformation is applied (the color space of the bitmap is ignored).</li>
239  *  <li>Bitmaps that return false for {@link Bitmap#isPremultiplied()} are not automatically
240  *  premultiplied.</li>
241  * </ul>
242  *
243  * <p>In addition, when sampling from a {@link BitmapShader} be aware that the shader does not use
244  * normalized coordinates (like a texture in GLSL). It uses (0, 0) in the upper-left corner, and
245  * (width, height) in the bottom-right corner. Normally, this is exactly what you want. If you're
246  * evaluating the shader with coordinates based on the ones passed to your AGSL program, the scale
247  * is correct. However, if you want to adjust those coordinates (to do some kind of re-mapping of
248  * the bitmap), remember that the coordinates are local to the canvas.</p>
249  *
250  */
251 @android.ravenwood.annotation.RavenwoodKeepWholeClass
252 public class RuntimeShader extends Shader {
253 
254     private static class NoImagePreloadHolder {
255         public static final NativeAllocationRegistry sRegistry =
256                 NativeAllocationRegistry.createMalloced(
257                 RuntimeShader.class.getClassLoader(), nativeGetFinalizer());
258     }
259 
260     /**
261      * Current native shader builder instance.
262      */
263     private long mNativeInstanceRuntimeShaderBuilder;
264 
265     /**
266      * For tracking GC usage. Keep a java-side reference for reachable objects to
267      * enable better heap tracking & tooling support
268      */
269     private ArrayMap<String, Shader> mShaderUniforms = new ArrayMap<>();
270     private ArrayMap<String, ColorFilter> mColorFilterUniforms = new ArrayMap<>();
271     private ArrayMap<String, RuntimeXfermode> mXfermodeUniforms = new ArrayMap<>();
272 
273     private ColorSpace mWorkingColorSpace = null;
274 
275 
276     /**
277      * Creates a new RuntimeShader.
278      *
279      * @param shader The text of AGSL shader program to run.
280      */
RuntimeShader(@onNull String shader)281     public RuntimeShader(@NonNull String shader) {
282         // colorspace is required, but the RuntimeShader always produces colors in the destination
283         // buffer's colorspace regardless of the value specified here.
284         super(ColorSpace.get(ColorSpace.Named.SRGB));
285         if (shader == null) {
286             throw new NullPointerException("RuntimeShader requires a non-null AGSL string");
287         }
288         mNativeInstanceRuntimeShaderBuilder = nativeCreateBuilder(shader);
289         NoImagePreloadHolder.sRegistry.registerNativeAllocation(
290                 this, mNativeInstanceRuntimeShaderBuilder);
291     }
292 
293     /**
294      * Sets the working color space for this shader. That is, the shader will be evaluated
295      * in the given colorspace before being converted to the output destination's colorspace.
296      *
297      * <p>By default the RuntimeShader is evaluated in the context of the
298      * <a href="#agsl-and-color-spaces">destination colorspace</a>. By calling this method
299      * that can be overridden to force the shader to be evaluated in the given colorspace first
300      * before then being color converted to the destination colorspace.</p>
301      *
302      * @param colorSpace The ColorSpace to evaluate in. Must be an {@link ColorSpace#getModel() RGB}
303      *                   ColorSpace. Passing null restores default behavior of working in the
304      *                   destination colorspace.
305      * @throws IllegalArgumentException If the colorspace is not RGB
306      */
307     @FlaggedApi(Flags.FLAG_SHADER_COLOR_SPACE)
setWorkingColorSpace(@ullable ColorSpace colorSpace)308     public void setWorkingColorSpace(@Nullable ColorSpace colorSpace) {
309         if (colorSpace != null && colorSpace.getModel() != ColorSpace.Model.RGB) {
310             throw new IllegalArgumentException("ColorSpace must be RGB, given " + colorSpace);
311         }
312         if (mWorkingColorSpace != colorSpace) {
313             mWorkingColorSpace = colorSpace;
314             if (mWorkingColorSpace != null) {
315                 // Just to enforce this can be resolved instead of erroring out later
316                 mWorkingColorSpace.getNativeInstance();
317             }
318             discardNativeInstance();
319         }
320     }
321 
322     /**
323      * Sets the uniform color value corresponding to this shader.  If the shader does not have a
324      * uniform with that name or if the uniform is declared with a type other than vec3 or vec4 and
325      * corresponding layout(color) annotation then an IllegalArgumentException is thrown.
326      *
327      * @param uniformName name matching the color uniform declared in the AGSL shader program
328      * @param color the provided sRGB color will be transformed into the shader program's output
329      *              colorspace and will be available as a vec4 uniform in the program.
330      */
setColorUniform(@onNull String uniformName, @ColorInt int color)331     public void setColorUniform(@NonNull String uniformName, @ColorInt int color) {
332         setUniform(uniformName, Color.valueOf(color).getComponents(), true);
333     }
334 
335     /**
336      * Sets the uniform color value corresponding to this shader.  If the shader does not have a
337      * uniform with that name or if the uniform is declared with a type other than vec3 or vec4 and
338      * corresponding layout(color) annotation then an IllegalArgumentException is thrown.
339      *
340      * @param uniformName name matching the color uniform declared in the AGSL shader program
341      * @param color the provided sRGB color will be transformed into the shader program's output
342      *              colorspace and will be available as a vec4 uniform in the program.
343      */
setColorUniform(@onNull String uniformName, @ColorLong long color)344     public void setColorUniform(@NonNull String uniformName, @ColorLong long color) {
345         Color exSRGB = Color.valueOf(color).convert(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB));
346         setUniform(uniformName, exSRGB.getComponents(), true);
347     }
348 
349     /**
350      * Sets the uniform color value corresponding to this shader.  If the shader does not have a
351      * uniform with that name or if the uniform is declared with a type other than vec3 or vec4 and
352      * corresponding layout(color) annotation then an IllegalArgumentException is thrown.
353      *
354      * @param uniformName name matching the color uniform declared in the AGSL shader program
355      * @param color the provided sRGB color will be transformed into the shader program's output
356      *              colorspace and will be available as a vec4 uniform in the program.
357      */
setColorUniform(@onNull String uniformName, @NonNull Color color)358     public void setColorUniform(@NonNull String uniformName, @NonNull Color color) {
359         if (color == null) {
360             throw new NullPointerException("The color parameter must not be null");
361         }
362         Color exSRGB = color.convert(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB));
363         setUniform(uniformName, exSRGB.getComponents(), true);
364     }
365 
366     /**
367      * Sets the uniform value corresponding to this shader.  If the shader does not have a uniform
368      * with that name or if the uniform is declared with a type other than a float or float[1]
369      * then an IllegalArgumentException is thrown.
370      *
371      * @param uniformName name matching the uniform declared in the AGSL shader program
372      */
setFloatUniform(@onNull String uniformName, float value)373     public void setFloatUniform(@NonNull String uniformName, float value) {
374         setFloatUniform(uniformName, value, 0.0f, 0.0f, 0.0f, 1);
375     }
376 
377     /**
378      * Sets the uniform value corresponding to this shader.  If the shader does not have a uniform
379      * with that name or if the uniform is declared with a type other than vec2 or float[2] then an
380      * IllegalArgumentException is thrown.
381      *
382      * @param uniformName name matching the uniform declared in the AGSL shader program
383      */
setFloatUniform(@onNull String uniformName, float value1, float value2)384     public void setFloatUniform(@NonNull String uniformName, float value1, float value2) {
385         setFloatUniform(uniformName, value1, value2, 0.0f, 0.0f, 2);
386 
387     }
388 
389     /**
390      * Sets the uniform value corresponding to this shader.  If the shader does not have a uniform
391      * with that name or if the uniform is declared with a type other than vec3 or float[3] then an
392      * IllegalArgumentException is thrown.
393      *
394      * @param uniformName name matching the uniform declared in the AGSL shader program
395      */
setFloatUniform(@onNull String uniformName, float value1, float value2, float value3)396     public void setFloatUniform(@NonNull String uniformName, float value1, float value2,
397             float value3) {
398         setFloatUniform(uniformName, value1, value2, value3, 0.0f, 3);
399 
400     }
401 
402     /**
403      * Sets the uniform value corresponding to this shader.  If the shader does not have a uniform
404      * with that name or if the uniform is declared with a type other than vec4 or float[4] then an
405      * IllegalArgumentException is thrown.
406      *
407      * @param uniformName name matching the uniform declared in the AGSL shader program
408      */
setFloatUniform(@onNull String uniformName, float value1, float value2, float value3, float value4)409     public void setFloatUniform(@NonNull String uniformName, float value1, float value2,
410             float value3, float value4) {
411         setFloatUniform(uniformName, value1, value2, value3, value4, 4);
412     }
413 
414     /**
415      * Sets the uniform value corresponding to this shader.  If the shader does not have a uniform
416      * with that name or if the uniform is declared with a type other than a float (for N=1), vecN,
417      * or float[N] where N is the length of the values param then an IllegalArgumentException is
418      * thrown.
419      *
420      * @param uniformName name matching the uniform declared in the AGSL shader program
421      */
setFloatUniform(@onNull String uniformName, @NonNull float[] values)422     public void setFloatUniform(@NonNull String uniformName, @NonNull float[] values) {
423         setUniform(uniformName, values, false);
424     }
425 
setFloatUniform(@onNull String uniformName, float value1, float value2, float value3, float value4, int count)426     private void setFloatUniform(@NonNull String uniformName, float value1, float value2,
427             float value3, float value4, int count) {
428         if (uniformName == null) {
429             throw new NullPointerException("The uniformName parameter must not be null");
430         }
431 
432         nativeUpdateUniforms(mNativeInstanceRuntimeShaderBuilder, uniformName, value1, value2,
433                 value3, value4, count);
434         discardNativeInstance();
435     }
436 
setUniform(@onNull String uniformName, @NonNull float[] values, boolean isColor)437     private void setUniform(@NonNull String uniformName, @NonNull float[] values, boolean isColor) {
438         if (uniformName == null) {
439             throw new NullPointerException("The uniformName parameter must not be null");
440         }
441         if (values == null) {
442             throw new NullPointerException("The uniform values parameter must not be null");
443         }
444 
445         nativeUpdateUniforms(mNativeInstanceRuntimeShaderBuilder, uniformName, values, isColor);
446         discardNativeInstance();
447     }
448 
449     /**
450      * Sets the uniform value corresponding to this shader.  If the shader does not have a uniform
451      * with that name or if the uniform is declared with a type other than an int or int[1]
452      * then an IllegalArgumentException is thrown.
453      *
454      * @param uniformName name matching the uniform declared in the AGSL shader program
455      */
setIntUniform(@onNull String uniformName, int value)456     public void setIntUniform(@NonNull String uniformName, int value) {
457         setIntUniform(uniformName, value, 0, 0, 0, 1);
458     }
459 
460     /**
461      * Sets the uniform value corresponding to this shader.  If the shader does not have a uniform
462      * with that name or if the uniform is declared with a type other than ivec2 or int[2] then an
463      * IllegalArgumentException is thrown.
464      *
465      * @param uniformName name matching the uniform declared in the AGSL shader program
466      */
setIntUniform(@onNull String uniformName, int value1, int value2)467     public void setIntUniform(@NonNull String uniformName, int value1, int value2) {
468         setIntUniform(uniformName, value1, value2, 0, 0, 2);
469 
470     }
471 
472     /**
473      * Sets the uniform value corresponding to this shader.  If the shader does not have a uniform
474      * with that name or if the uniform is declared with a type other than ivec3 or int[3] then an
475      * IllegalArgumentException is thrown.
476      *
477      * @param uniformName name matching the uniform declared in the AGSL shader program
478      */
setIntUniform(@onNull String uniformName, int value1, int value2, int value3)479     public void setIntUniform(@NonNull String uniformName, int value1, int value2, int value3) {
480         setIntUniform(uniformName, value1, value2, value3, 0, 3);
481 
482     }
483 
484     /**
485      * Sets the uniform value corresponding to this shader.  If the shader does not have a uniform
486      * with that name or if the uniform is declared with a type other than ivec4 or int[4] then an
487      * IllegalArgumentException is thrown.
488      *
489      * @param uniformName name matching the uniform declared in the AGSL shader program
490      */
setIntUniform(@onNull String uniformName, int value1, int value2, int value3, int value4)491     public void setIntUniform(@NonNull String uniformName, int value1, int value2,
492             int value3, int value4) {
493         setIntUniform(uniformName, value1, value2, value3, value4, 4);
494     }
495 
496     /**
497      * Sets the uniform value corresponding to this shader.  If the shader does not have a uniform
498      * with that name or if the uniform is declared with a type other than an int (for N=1), ivecN,
499      * or int[N] where N is the length of the values param then an IllegalArgumentException is
500      * thrown.
501      *
502      * @param uniformName name matching the uniform declared in the AGSL shader program
503      */
setIntUniform(@onNull String uniformName, @NonNull int[] values)504     public void setIntUniform(@NonNull String uniformName, @NonNull int[] values) {
505         if (uniformName == null) {
506             throw new NullPointerException("The uniformName parameter must not be null");
507         }
508         if (values == null) {
509             throw new NullPointerException("The uniform values parameter must not be null");
510         }
511         nativeUpdateUniforms(mNativeInstanceRuntimeShaderBuilder, uniformName, values);
512         discardNativeInstance();
513     }
514 
setIntUniform(@onNull String uniformName, int value1, int value2, int value3, int value4, int count)515     private void setIntUniform(@NonNull String uniformName, int value1, int value2, int value3,
516             int value4, int count) {
517         if (uniformName == null) {
518             throw new NullPointerException("The uniformName parameter must not be null");
519         }
520 
521         nativeUpdateUniforms(mNativeInstanceRuntimeShaderBuilder, uniformName, value1, value2,
522                 value3, value4, count);
523         discardNativeInstance();
524     }
525 
526     /**
527      * Assigns the uniform shader to the provided shader parameter.  If the shader program does not
528      * have a uniform shader with that name then an IllegalArgumentException is thrown.
529      *
530      * @param shaderName name matching the uniform declared in the AGSL shader program
531      * @param shader shader passed into the AGSL shader program for sampling
532      */
setInputShader(@onNull String shaderName, @NonNull Shader shader)533     public void setInputShader(@NonNull String shaderName, @NonNull Shader shader) {
534         if (shaderName == null) {
535             throw new NullPointerException("The shaderName parameter must not be null");
536         }
537         if (shader == null) {
538             throw new NullPointerException("The shader parameter must not be null");
539         }
540         mShaderUniforms.put(shaderName, shader);
541         nativeUpdateShader(
542                     mNativeInstanceRuntimeShaderBuilder, shaderName, shader.getNativeInstance());
543         discardNativeInstance();
544     }
545 
546     /**
547      * Assigns the uniform shader to the provided shader parameter.  If the shader program does not
548      * have a uniform shader with that name then an IllegalArgumentException is thrown.
549      *
550      * Unlike setInputShader this method returns samples directly from the bitmap's buffer. This
551      * means that there will be no transformation of the sampled pixels, such as colorspace
552      * conversion or alpha premultiplication.
553      */
setInputBuffer(@onNull String shaderName, @NonNull BitmapShader shader)554     public void setInputBuffer(@NonNull String shaderName, @NonNull BitmapShader shader) {
555         if (shaderName == null) {
556             throw new NullPointerException("The shaderName parameter must not be null");
557         }
558         if (shader == null) {
559             throw new NullPointerException("The shader parameter must not be null");
560         }
561 
562         mShaderUniforms.put(shaderName, shader);
563         nativeUpdateShader(mNativeInstanceRuntimeShaderBuilder, shaderName,
564                 shader.getNativeInstanceWithDirectSampling());
565         discardNativeInstance();
566     }
567 
568     /**
569      * Assigns the uniform color filter to the provided color filter parameter.  If the shader
570      * program does not have a uniform color filter with that name then an IllegalArgumentException
571      * is thrown.
572      *
573      * @param filterName name matching the uniform declared in the AGSL program
574      * @param colorFilter filter passed into the AGSL program for sampling
575      */
576     @FlaggedApi(Flags.FLAG_RUNTIME_COLOR_FILTERS_BLENDERS)
setInputColorFilter(@onNull String filterName, @NonNull ColorFilter colorFilter)577     public void setInputColorFilter(@NonNull String filterName, @NonNull ColorFilter colorFilter) {
578         if (filterName == null) {
579             throw new NullPointerException("The filterName parameter must not be null");
580         }
581         if (colorFilter == null) {
582             throw new NullPointerException("The colorFilter parameter must not be null");
583         }
584         mColorFilterUniforms.put(filterName, colorFilter);
585         nativeUpdateColorFilter(mNativeInstanceRuntimeShaderBuilder, filterName,
586                 colorFilter.getNativeInstance());
587         discardNativeInstance();
588     }
589 
590     /**
591      * Assigns the uniform xfermode to the provided xfermode parameter.  If the shader program does
592      * not have a uniform xfermode with that name then an IllegalArgumentException is thrown.
593      *
594      * @param xfermodeName name matching the uniform declared in the AGSL program
595      * @param xfermode filter passed into the AGSL program for sampling
596      */
597     @FlaggedApi(Flags.FLAG_RUNTIME_COLOR_FILTERS_BLENDERS)
setInputXfermode(@onNull String xfermodeName, @NonNull RuntimeXfermode xfermode)598     public void setInputXfermode(@NonNull String xfermodeName, @NonNull RuntimeXfermode xfermode) {
599         if (xfermodeName == null) {
600             throw new NullPointerException("The xfermodeName parameter must not be null");
601         }
602         if (xfermode == null) {
603             throw new NullPointerException("The xfermode parameter must not be null");
604         }
605         mXfermodeUniforms.put(xfermodeName, xfermode);
606         nativeUpdateChild(mNativeInstanceRuntimeShaderBuilder, xfermodeName,
607                 xfermode.createNativeInstance());
608         discardNativeInstance();
609     }
610 
611 
612     /** @hide */
613     @Override
createNativeInstance(long nativeMatrix, boolean filterFromPaint)614     protected long createNativeInstance(long nativeMatrix, boolean filterFromPaint) {
615         return nativeCreateShader(mNativeInstanceRuntimeShaderBuilder, nativeMatrix,
616                 mWorkingColorSpace != null ? mWorkingColorSpace.getNativeInstance() : 0);
617     }
618 
619     /** @hide */
getNativeShaderBuilder()620     protected long getNativeShaderBuilder() {
621         return mNativeInstanceRuntimeShaderBuilder;
622     }
623 
nativeGetFinalizer()624     private static native long nativeGetFinalizer();
nativeCreateBuilder(String agsl)625     private static native long nativeCreateBuilder(String agsl);
nativeCreateShader(long shaderBuilder, long matrix)626     private static native long nativeCreateShader(long shaderBuilder, long matrix);
nativeCreateShader(long shaderBuilder, long matrix, long colorSpacePtr)627     private static native long nativeCreateShader(long shaderBuilder, long matrix,
628             long colorSpacePtr);
nativeUpdateUniforms( long shaderBuilder, String uniformName, float[] uniforms, boolean isColor)629     private static native void nativeUpdateUniforms(
630             long shaderBuilder, String uniformName, float[] uniforms, boolean isColor);
nativeUpdateUniforms( long shaderBuilder, String uniformName, float value1, float value2, float value3, float value4, int count)631     private static native void nativeUpdateUniforms(
632             long shaderBuilder, String uniformName, float value1, float value2, float value3,
633             float value4, int count);
nativeUpdateUniforms( long shaderBuilder, String uniformName, int[] uniforms)634     private static native void nativeUpdateUniforms(
635             long shaderBuilder, String uniformName, int[] uniforms);
nativeUpdateUniforms( long shaderBuilder, String uniformName, int value1, int value2, int value3, int value4, int count)636     private static native void nativeUpdateUniforms(
637             long shaderBuilder, String uniformName, int value1, int value2, int value3,
638             int value4, int count);
nativeUpdateShader( long shaderBuilder, String shaderName, long shader)639     private static native void nativeUpdateShader(
640             long shaderBuilder, String shaderName, long shader);
nativeUpdateColorFilter( long shaderBuilder, String colorFilterName, long colorFilter)641     private static native void nativeUpdateColorFilter(
642             long shaderBuilder, String colorFilterName, long colorFilter);
nativeUpdateChild( long shaderBuilder, String childName, long child)643     private static native void nativeUpdateChild(
644             long shaderBuilder, String childName, long child);
645 }
646 
647