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