1 /* 2 * Copyright (C) 2022 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.IntDef; 20 import android.annotation.IntRange; 21 import android.annotation.NonNull; 22 import android.annotation.Size; 23 import android.annotation.SuppressLint; 24 25 import libcore.util.NativeAllocationRegistry; 26 27 import java.lang.annotation.Retention; 28 import java.lang.annotation.RetentionPolicy; 29 30 /** 31 * Class responsible for holding specifications for {@link Mesh} creations. This class generates a 32 * {@link MeshSpecification} via the 33 * {@link MeshSpecification#make(Attribute[], int, Varying[], String, String)} method, 34 * where multiple parameters to set up the mesh are supplied, including attributes, vertex stride, 35 * {@link Varying}, and vertex/fragment shaders. There are also additional methods to provide an 36 * optional {@link ColorSpace} as well as an alpha type. 37 * 38 * For example a vertex shader that leverages a {@link Varying} may look like the following: 39 * 40 * <pre> 41 * Varyings main(const Attributes attributes) { 42 * Varyings varyings; 43 * varyings.position = attributes.position; 44 * return varyings; 45 * } 46 * </pre> 47 * 48 * The corresponding fragment shader that may consume the varying look like the following: 49 * 50 * <pre> 51 * float2 main(const Varyings varyings, out float4 color) { 52 * color = vec4(1.0, 0.0, 0.0, 1.0); 53 * return varyings.position; 54 * } 55 * </pre> 56 * 57 * The color returned from this fragment shader is blended with the other parameters that are 58 * configured on the Paint object (ex. {@link Paint#setBlendMode(BlendMode)} used to draw the mesh. 59 * 60 * The position returned in the fragment shader can be consumed by any following fragment shaders in 61 * the shader chain. 62 * 63 * See https://developer.android.com/develop/ui/views/graphics/agsl for more information 64 * regarding Android Graphics Shader Language. 65 * 66 * Note that there are several limitations on various mesh specifications: 67 * 1. The max amount of attributes allowed is 8. 68 * 2. The offset alignment length is 4 bytes. 69 * 2. The max stride length is 1024. 70 * 3. The max amount of varyings is 6. 71 * 72 * These should be kept in mind when generating a mesh specification, as exceeding them will 73 * lead to errors. 74 */ 75 @android.ravenwood.annotation.RavenwoodKeepWholeClass 76 public class MeshSpecification { 77 long mNativeMeshSpec; 78 79 /** 80 * Constants for {@link #make(Attribute[], int, Varying[], String, String)} 81 * to determine alpha type. Describes how to interpret the alpha component of a pixel. 82 * 83 * @hide 84 */ 85 @IntDef( 86 prefix = {"ALPHA_TYPE_"}, 87 value = {ALPHA_TYPE_UNKNOWN, ALPHA_TYPE_OPAQUE, ALPHA_TYPE_PREMULTIPLIED, 88 ALPHA_TYPE_UNPREMULTIPLIED} 89 ) 90 @Retention(RetentionPolicy.SOURCE) 91 private @interface AlphaType {} 92 93 /** 94 * uninitialized. 95 */ 96 public static final int ALPHA_TYPE_UNKNOWN = 0; 97 98 /** 99 * Pixel is opaque. 100 */ 101 public static final int ALPHA_TYPE_OPAQUE = 1; 102 103 /** 104 * Pixel components are premultiplied by alpha. 105 */ 106 public static final int ALPHA_TYPE_PREMULTIPLIED = 2; 107 108 /** 109 * Pixel components are independent of alpha. 110 */ 111 public static final int ALPHA_TYPE_UNPREMULTIPLIED = 3; 112 113 /** 114 * Constants for {@link Attribute} and {@link Varying} for determining the data type. 115 * 116 * @hide 117 */ 118 @IntDef( 119 prefix = {"TYPE_"}, 120 value = {TYPE_FLOAT, TYPE_FLOAT2, TYPE_FLOAT3, TYPE_FLOAT4, TYPE_UBYTE4} 121 ) 122 @Retention(RetentionPolicy.SOURCE) 123 private @interface Type {} 124 125 /** 126 * Represents one float. Its equivalent shader type is float. 127 */ 128 public static final int TYPE_FLOAT = 0; 129 130 /** 131 * Represents two floats. Its equivalent shader type is float2. 132 */ 133 public static final int TYPE_FLOAT2 = 1; 134 135 /** 136 * Represents three floats. Its equivalent shader type is float3. 137 */ 138 public static final int TYPE_FLOAT3 = 2; 139 140 /** 141 * Represents four floats. Its equivalent shader type is float4. 142 */ 143 public static final int TYPE_FLOAT4 = 3; 144 145 /** 146 * Represents four bytes. Its equivalent shader type is half4. 147 */ 148 public static final int TYPE_UBYTE4 = 4; 149 150 /** 151 * Data class to represent a single attribute in a shader. An attribute is a variable that 152 * accompanies a vertex, this can be a color or texture coordinates. 153 * 154 * See https://developer.android.com/develop/ui/views/graphics/agsl for more information 155 * regarding Android Graphics Shader Language. 156 * 157 * Note that offset is the offset in number of bytes. For example, if we had two attributes 158 * 159 * <pre> 160 * Float3 att1 161 * Float att2 162 * </pre> 163 * 164 * att1 would have an offset of 0, while att2 would have an offset of 12 bytes. 165 * 166 * This is consumed as part of 167 * {@link MeshSpecification#make(Attribute[], int, Varying[], String, String, ColorSpace, int)} 168 * to create a {@link MeshSpecification} instance. 169 */ 170 public static class Attribute { 171 @Type 172 private final int mType; 173 private final int mOffset; 174 private final String mName; 175 Attribute(@ype int type, int offset, @NonNull String name)176 public Attribute(@Type int type, int offset, @NonNull String name) { 177 mType = type; 178 mOffset = offset; 179 mName = name; 180 } 181 182 /** 183 * Return the corresponding data type for this {@link Attribute}. 184 */ 185 @Type getType()186 public int getType() { 187 return mType; 188 } 189 190 /** 191 * Return the offset of the attribute in bytes 192 */ getOffset()193 public int getOffset() { 194 return mOffset; 195 } 196 197 /** 198 * Return the name of this {@link Attribute} 199 */ 200 @NonNull getName()201 public String getName() { 202 return mName; 203 } 204 205 @Override toString()206 public String toString() { 207 return "Attribute{" 208 + "mType=" + mType 209 + ", mOffset=" + mOffset 210 + ", mName='" + mName + '\'' 211 + '}'; 212 } 213 } 214 215 /** 216 * Data class to represent a single varying variable. A Varying variable can be altered by the 217 * vertex shader defined on the mesh but not by the fragment shader defined by AGSL. 218 * 219 * See https://developer.android.com/develop/ui/views/graphics/agsl for more information 220 * regarding Android Graphics Shader Language. 221 * 222 * This is consumed as part of 223 * {@link MeshSpecification#make(Attribute[], int, Varying[], String, String, ColorSpace, int)} 224 * to create a {@link MeshSpecification} instance. 225 */ 226 public static class Varying { 227 @Type 228 private final int mType; 229 private final String mName; 230 Varying(@ype int type, @NonNull String name)231 public Varying(@Type int type, @NonNull String name) { 232 mType = type; 233 mName = name; 234 } 235 236 /** 237 * Return the corresponding data type for this {@link Varying}. 238 */ 239 @Type getType()240 public int getType() { 241 return mType; 242 } 243 244 /** 245 * Return the name of this {@link Varying} 246 */ 247 @NonNull getName()248 public String getName() { 249 return mName; 250 } 251 252 @Override toString()253 public String toString() { 254 return "Varying{" 255 + "mType=" + mType 256 + ", mName='" + mName + '\'' 257 + '}'; 258 } 259 } 260 261 private static class MeshSpecificationHolder { 262 public static final NativeAllocationRegistry MESH_SPECIFICATION_REGISTRY = 263 NativeAllocationRegistry.createMalloced( 264 MeshSpecification.class.getClassLoader(), nativeGetFinalizer()); 265 } 266 267 /** 268 * Creates a {@link MeshSpecification} object for use within {@link Mesh}. This uses a default 269 * color space of {@link ColorSpace.Named#SRGB} and alphaType of 270 * {@link #ALPHA_TYPE_PREMULTIPLIED}. 271 * 272 * @param attributes list of attributes represented by {@link Attribute}. Can hold a max of 273 * 8. 274 * @param vertexStride length of vertex stride in bytes. This should be the size of a single 275 * vertex' attributes. Max of 1024 is accepted. 276 * @param varyings List of varyings represented by {@link Varying}. Can hold a max of 6. 277 * Note that `position` is provided by default, does not need to be 278 * provided in the list, and does not count towards 279 * the 6 varyings allowed. 280 * @param vertexShader vertex shader to be supplied to the mesh. Ensure that the position 281 * varying is set within the shader to get proper results. 282 * See {@link MeshSpecification} for an example vertex shader 283 * implementation 284 * @param fragmentShader fragment shader to be supplied to the mesh. 285 * See {@link MeshSpecification} for an example fragment shader 286 * implementation 287 * @return {@link MeshSpecification} object for use when creating {@link Mesh} 288 */ 289 @NonNull make( @uppressLint"ArrayReturn") @onNull @izemax = 8) Attribute[] attributes, @IntRange(from = 1, to = 1024) int vertexStride, @SuppressLint("ArrayReturn") @NonNull @Size(max = 6) Varying[] varyings, @NonNull String vertexShader, @NonNull String fragmentShader)290 public static MeshSpecification make( 291 @SuppressLint("ArrayReturn") @NonNull @Size(max = 8) Attribute[] attributes, 292 @IntRange(from = 1, to = 1024) int vertexStride, 293 @SuppressLint("ArrayReturn") @NonNull @Size(max = 6) Varying[] varyings, 294 @NonNull String vertexShader, 295 @NonNull String fragmentShader) { 296 long nativeMeshSpec = nativeMake(attributes, 297 vertexStride, varyings, vertexShader, 298 fragmentShader); 299 if (nativeMeshSpec == 0) { 300 throw new IllegalArgumentException("MeshSpecification construction failed"); 301 } 302 return new MeshSpecification(nativeMeshSpec); 303 } 304 305 /** 306 * Creates a {@link MeshSpecification} object. This uses a default alphaType of 307 * {@link #ALPHA_TYPE_PREMULTIPLIED}. 308 * 309 * @param attributes list of attributes represented by {@link Attribute}. Can hold a max of 310 * 8. 311 * @param vertexStride length of vertex stride in bytes. This should be the size of a single 312 * vertex' attributes. Max of 1024 is accepted. 313 * @param varyings List of varyings represented by {@link Varying}. Can hold a max of 6. 314 * Note that `position` is provided by default, does not need to be 315 * provided in the list, and does not count towards 316 * the 6 varyings allowed. 317 * @param vertexShader vertex shader to be supplied to the mesh. Ensure that the position 318 * varying is set within the shader to get proper results. 319 * See {@link MeshSpecification} for an example vertex shader 320 * implementation 321 * @param fragmentShader fragment shader to be supplied to the mesh. 322 * See {@link MeshSpecification} for an example fragment shader 323 * implementation 324 * @param colorSpace {@link ColorSpace} to tell what color space to work in. 325 * @return {@link MeshSpecification} object for use when creating {@link Mesh} 326 */ 327 @NonNull make( @uppressLint"ArrayReturn") @onNull @izemax = 8) Attribute[] attributes, @IntRange(from = 1, to = 1024) int vertexStride, @SuppressLint("ArrayReturn") @NonNull @Size(max = 6) Varying[] varyings, @NonNull String vertexShader, @NonNull String fragmentShader, @NonNull ColorSpace colorSpace )328 public static MeshSpecification make( 329 @SuppressLint("ArrayReturn") @NonNull @Size(max = 8) Attribute[] attributes, 330 @IntRange(from = 1, to = 1024) int vertexStride, 331 @SuppressLint("ArrayReturn") @NonNull @Size(max = 6) Varying[] varyings, 332 @NonNull String vertexShader, 333 @NonNull String fragmentShader, 334 @NonNull ColorSpace colorSpace 335 ) { 336 long nativeMeshSpec = nativeMakeWithCS(attributes, 337 vertexStride, varyings, vertexShader, 338 fragmentShader, colorSpace.getNativeInstance()); 339 if (nativeMeshSpec == 0) { 340 throw new IllegalArgumentException("MeshSpecification construction failed"); 341 } 342 return new MeshSpecification(nativeMeshSpec); 343 } 344 345 /** 346 * Creates a {@link MeshSpecification} object. 347 * 348 * @param attributes list of attributes represented by {@link Attribute}. Can hold a max of 349 * 8. 350 * @param vertexStride length of vertex stride in bytes. This should be the size of a single 351 * vertex' attributes. Max of 1024 is accepted. 352 * @param varyings List of varyings represented by {@link Varying}. Can hold a max of 6. 353 * Note that `position` is provided by default, does not need to be 354 * provided in the list, and does not count towards 355 * the 6 varyings allowed. 356 * @param vertexShader vertex shader to be supplied to the mesh. Ensure that the position 357 * varying is set within the shader to get proper results. 358 * See {@link MeshSpecification} for an example vertex shader 359 * implementation 360 * @param fragmentShader fragment shader to be supplied to the mesh. 361 * See {@link MeshSpecification} for an example fragment shader 362 * implementation 363 * @param colorSpace {@link ColorSpace} to tell what color space to work in. 364 * @param alphaType Describes how to interpret the alpha component for a pixel. Must be 365 * one of 366 * {@link MeshSpecification#ALPHA_TYPE_UNKNOWN}, 367 * {@link MeshSpecification#ALPHA_TYPE_OPAQUE}, 368 * {@link MeshSpecification#ALPHA_TYPE_PREMULTIPLIED}, or 369 * {@link MeshSpecification#ALPHA_TYPE_UNPREMULTIPLIED} 370 * @return {@link MeshSpecification} object for use when creating {@link Mesh} 371 */ 372 @NonNull make( @uppressLint"ArrayReturn") @onNull @izemax = 8) Attribute[] attributes, @IntRange(from = 1, to = 1024) int vertexStride, @SuppressLint("ArrayReturn") @NonNull @Size(max = 6) Varying[] varyings, @NonNull String vertexShader, @NonNull String fragmentShader, @NonNull ColorSpace colorSpace, @AlphaType int alphaType)373 public static MeshSpecification make( 374 @SuppressLint("ArrayReturn") @NonNull @Size(max = 8) Attribute[] attributes, 375 @IntRange(from = 1, to = 1024) int vertexStride, 376 @SuppressLint("ArrayReturn") @NonNull @Size(max = 6) Varying[] varyings, 377 @NonNull String vertexShader, 378 @NonNull String fragmentShader, 379 @NonNull ColorSpace colorSpace, 380 @AlphaType int alphaType) { 381 long nativeMeshSpec = 382 nativeMakeWithAlpha(attributes, vertexStride, varyings, vertexShader, 383 fragmentShader, colorSpace.getNativeInstance(), alphaType); 384 if (nativeMeshSpec == 0) { 385 throw new IllegalArgumentException("MeshSpecification construction failed"); 386 } 387 return new MeshSpecification(nativeMeshSpec); 388 } 389 MeshSpecification(long meshSpec)390 private MeshSpecification(long meshSpec) { 391 mNativeMeshSpec = meshSpec; 392 MeshSpecificationHolder.MESH_SPECIFICATION_REGISTRY.registerNativeAllocation( 393 this, meshSpec); 394 } 395 nativeGetFinalizer()396 private static native long nativeGetFinalizer(); 397 nativeMake(Attribute[] attributes, int vertexStride, Varying[] varyings, String vertexShader, String fragmentShader)398 private static native long nativeMake(Attribute[] attributes, int vertexStride, 399 Varying[] varyings, String vertexShader, String fragmentShader); 400 nativeMakeWithCS(Attribute[] attributes, int vertexStride, Varying[] varyings, String vertexShader, String fragmentShader, long colorSpace)401 private static native long nativeMakeWithCS(Attribute[] attributes, int vertexStride, 402 Varying[] varyings, String vertexShader, String fragmentShader, long colorSpace); 403 nativeMakeWithAlpha(Attribute[] attributes, int vertexStride, Varying[] varyings, String vertexShader, String fragmentShader, long colorSpace, int alphaType)404 private static native long nativeMakeWithAlpha(Attribute[] attributes, int vertexStride, 405 Varying[] varyings, String vertexShader, String fragmentShader, long colorSpace, 406 int alphaType); 407 } 408