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