1 /*
2  * Copyright 2021 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 androidx.graphics.opengl.egl
18 
19 import android.opengl.EGL14
20 
21 /**
22  * Construct an instance of [EGLConfigAttributes] that includes a mapping of EGL attributes to their
23  * corresponding value. The full set of attributes can be found here:
24  * https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglChooseConfig.xhtml
25  *
26  * The resultant array of attributes automatically is terminated with EGL_NONE.
27  *
28  * For example to create an 8888 configuration, this can be done with the following:
29  * ```
30  * EGLConfigAttributes {
31  *      EGL14.EGL_RENDERABLE_TYPE to EGL14.EGL_OPENGL_ES2_BIT
32  *      EGL14.EGL_RED_SIZE to 8
33  *      EGL14.EGL_GREEN_SIZE to 8
34  *      EGL14.EGL_BLUE_SIZE to 8
35  *      EGL14.EGL_ALPHA_SIZE to 8
36  *      EGL14.EGL_DEPTH_SIZE to 0
37  *      EGL14.EGL_CONFIG_CAVEAT to EGL14.EGL_NONE
38  *      EGL14.EGL_STENCIL_SIZE to 8
39  *      EGL14.EGL_SURFACE_TYPE to EGL14.EGL_WINDOW_BIT
40  * }
41  * ```
42  *
43  * @see EGLConfigAttributes.RGBA_8888
44  */
45 @JvmSynthetic
EGLConfigAttributesnull46 inline fun EGLConfigAttributes(block: EGLConfigAttributes.Builder.() -> Unit): EGLConfigAttributes =
47     EGLConfigAttributes.Builder().apply { block() }.build()
48 
49 /**
50  * Class responsible for containing configuration parameters to be consumed by [EGLSpec.loadConfig]
51  * This contains a mapping of key value pairs for attribute names to values. This handles flattening
52  * the pairs into a single integer based array when passed to corresponding EGL based APIs with
53  * alternating key/value pairs and ends with [EGL14.EGL_NONE]. Consumers can create an instance by
54  * using [EGLConfigAttributes.Builder] or using the DSL based Kotlin API [EGLConfigAttributes]
55  * factory method. [EGLConfigAttributes] also provides a few constants for commonly used
56  * configurations such as [EGLConfigAttributes.RGBA_8888], [EGLConfigAttributes.RGBA_1010102], or
57  * [EGLConfigAttributes.RGBA_F16]
58  *
59  * For example from Java:
60  * ```
61  * EGLConfigAttributes config = new EGLConfigAttributes.Builder()
62  *   .setAttribute(EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT)
63  *   .setAttribute(EGL14.EGL_RED_SIZE, 8)
64  *   .setAttribute(EGL14.EGL_GREEN_SIZE, 8)
65  *   .setAttribute(EGL14.EGL_BLUE_SIZE, 8)
66  *   .setAttribute(EGL14.EGL_ALPHA_SIZE, 8)
67  *   .setAttribute(EGL14.EGL_DEPTH_SIZE, 0)
68  *   .setAttribute(EGL14.EGL_CONFIG_CAVEAT, EGL14.EGL_NONE)
69  *   .setAttribute(EGL14.STENCIL_SIZE, 8)
70  *   .setAttribute(EGL14.EGL_SURFACE_TYPE, EGL14.EGL_WINDOW_BIT)
71  *   .build();
72  *
73  * ```
74  *
75  * Or from the Kotlin factory method:
76  * ```
77  * val config = EGLConfigAttributes {
78  *      EGL14.EGL_RENDERABLE_TYPE to EGL14.EGL_OPENGL_ES2_BIT
79  *      EGL14.EGL_RED_SIZE to 8
80  *      EGL14.EGL_GREEN_SIZE to 8
81  *      EGL14.EGL_BLUE_SIZE to 8
82  *      EGL14.EGL_ALPHA_SIZE to 8
83  *      EGL14.EGL_DEPTH_SIZE to 0
84  *      EGL14.EGL_CONFIG_CAVEAT to EGL14.EGL_NONE
85  *      EGL14.EGL_STENCIL_SIZE to 8
86  *      EGL14.EGL_SURFACE_TYPE to EGL14.EGL_WINDOW_BIT
87  * }
88  * ```
89  */
90 class EGLConfigAttributes internal constructor(@PublishedApi internal val attrs: IntArray) {
91 
92     /**
93      * Return a copy of the created integer array used for EGL methods. Most consumers would pass
94      * the [EGLConfigAttributes] instance as a parameter instead, however, this method is provided
95      * as a convenience for debugging and testing purposes.
96      */
toArraynull97     fun toArray(): IntArray = attrs.clone()
98 
99     /**
100      * Builder used to create an instance of [EGLConfigAttributes] Allows for a mapping of EGL
101      * configuration attributes to their corresponding values as well as including a previously
102      * generated [EGLConfigAttributes] instance to be used as a template and conditionally update
103      * individual mapped values
104      */
105     class Builder {
106         private val attrs = HashMap<Int, Int>()
107 
108         /** Map a given EGL configuration attribute key to the given EGL configuration value */
109         @SuppressWarnings("BuilderSetStyle")
110         @JvmSynthetic
111         infix fun Int.to(that: Int) {
112             setAttribute(this, that)
113         }
114 
115         /**
116          * Map a given EGL configuration attribute key to the given EGL configuration value
117          *
118          * @param attribute EGL attribute name such as [EGL14.EGL_RED_SIZE]
119          * @param value Corresponding value for the [attribute]
120          */
121         @Suppress("MissingGetterMatchingBuilder")
122         fun setAttribute(attribute: Int, value: Int): Builder {
123             attrs[attribute] = value
124             return this
125         }
126 
127         /**
128          * Include all the attributes of the given [EGLConfigAttributes] instance. This is useful
129          * for creating a new [EGLConfigAttributes] instance with all the same attributes as
130          * another, allowing for modification of attributes after the fact. For example, the
131          * following code snippet can be used to create an [EGLConfigAttributes] instance that has
132          * all the same configuration as [RGBA_8888] but with a 16 bit stencil buffer size:
133          *
134          * For example from Java:
135          *
136          * new EglConfigAttributes.Builder() .include(EGLConfigAttributes.RGBA_8888)
137          * .setAttribute(EGL14.EGL_STENCIL_SIZE, 16) .build()
138          *
139          * Or from the Kotlin factory method:
140          * ```
141          * EGLConfigAttributes {
142          *      include(EGLConfigAttributes.RGBA_8888)
143          *      EGL14.EGL_STENCIL_SIZE to 16
144          * }
145          * ```
146          *
147          * That is all attributes configured after the include will overwrite the attributes
148          * configured previously.
149          */
150         @SuppressWarnings("BuilderSetStyle")
151         fun include(attributes: EGLConfigAttributes) {
152             val attrsArray = attributes.attrs
153             for (i in 0 until attrsArray.size - 1 step 2) {
154                 attrs[attrsArray[i]] = attrsArray[i + 1]
155             }
156         }
157 
158         /**
159          * Construct an instance of [EGLConfigAttributes] with the mappings of integer keys to their
160          * respective values. This creates a flat integer array with alternating values for the key
161          * value pairs and ends with EGL_NONE
162          */
163         fun build(): EGLConfigAttributes {
164             val entries = attrs.entries
165             val attrArray = IntArray(entries.size * 2 + 1) // Array must end with EGL_NONE
166             var index = 0
167             for (entry in entries) {
168                 attrArray[index] = entry.key
169                 attrArray[index + 1] = entry.value
170                 index += 2
171             }
172             attrArray[index] = EGL14.EGL_NONE
173             return EGLConfigAttributes(attrArray)
174         }
175     }
176 
177     companion object {
178         /**
179          * EGL configuration attribute used to expose EGLConfigs that support formats with floating
180          * point RGBA components. This attribute is exposed through the EGL_EXT_pixel_format_float
181          * EGL extension
182          *
183          * See: https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_pixel_format_float.txt
184          */
185         const val EGL_COLOR_COMPONENT_TYPE_EXT = 0x3339
186 
187         /** EGL configuration attribute value that represents fixed point RGBA components */
188         const val EGL_COLOR_COMPONENT_TYPE_FIXED_EXT = 0x333A
189 
190         /** EGL configuration attribute value that represents floating point RGBA components */
191         const val EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT = 0x333B
192 
193         /**
194          * EGL Attributes to create an 8 bit EGL config for red, green, blue, and alpha channels as
195          * well as an 8 bit stencil size
196          */
197         @JvmField
<lambda>null198         val RGBA_8888 = EGLConfigAttributes {
199             EGL14.EGL_RENDERABLE_TYPE to EGL14.EGL_OPENGL_ES2_BIT
200             EGL14.EGL_RED_SIZE to 8
201             EGL14.EGL_GREEN_SIZE to 8
202             EGL14.EGL_BLUE_SIZE to 8
203             EGL14.EGL_ALPHA_SIZE to 8
204             EGL14.EGL_DEPTH_SIZE to 0
205             EGL14.EGL_CONFIG_CAVEAT to EGL14.EGL_NONE
206             EGL14.EGL_STENCIL_SIZE to 0
207             EGL14.EGL_SURFACE_TYPE to EGL14.EGL_WINDOW_BIT
208         }
209 
210         /**
211          * EGL Attributes to create a 10 bit EGL config for red, green, blue, channels and a 2 bit
212          * alpha channels. This does not include any bits for depth and stencil buffers.
213          */
214         @JvmField
<lambda>null215         val RGBA_1010102 = EGLConfigAttributes {
216             EGL14.EGL_RENDERABLE_TYPE to EGL14.EGL_OPENGL_ES2_BIT
217             EGL14.EGL_RED_SIZE to 10
218             EGL14.EGL_GREEN_SIZE to 10
219             EGL14.EGL_BLUE_SIZE to 10
220             EGL14.EGL_ALPHA_SIZE to 2
221             EGL14.EGL_DEPTH_SIZE to 0
222             EGL14.EGL_STENCIL_SIZE to 0
223             EGL14.EGL_SURFACE_TYPE to EGL14.EGL_WINDOW_BIT
224         }
225 
226         /**
227          * EGL Attributes to create a 16 bit floating point EGL config for red, green, blue and
228          * alpha channels without a depth or stencil channel.
229          */
230         @JvmField
<lambda>null231         val RGBA_F16 = EGLConfigAttributes {
232             EGL14.EGL_RENDERABLE_TYPE to EGL14.EGL_OPENGL_ES2_BIT
233             EGL_COLOR_COMPONENT_TYPE_EXT to EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT
234             EGL14.EGL_RED_SIZE to 16
235             EGL14.EGL_GREEN_SIZE to 16
236             EGL14.EGL_BLUE_SIZE to 16
237             EGL14.EGL_ALPHA_SIZE to 16
238             EGL14.EGL_DEPTH_SIZE to 0
239             EGL14.EGL_STENCIL_SIZE to 0
240             EGL14.EGL_SURFACE_TYPE to EGL14.EGL_WINDOW_BIT
241         }
242     }
243 }
244