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