• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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