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