1 /*
2  * Copyright 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 package androidx.opengl
17 
18 import android.hardware.HardwareBuffer
19 import android.opengl.EGLDisplay
20 import android.os.Build
21 import androidx.annotation.IntDef
22 import androidx.annotation.RequiresApi
23 import androidx.annotation.RestrictTo
24 import androidx.graphics.opengl.egl.EGLConfigAttributes
25 import androidx.graphics.utils.JniVisible
26 import androidx.hardware.SyncFenceCompat
27 import androidx.hardware.SyncFenceV19
28 import androidx.opengl.EGLExt.Companion.eglCreateSyncKHR
29 
30 /** Utility class that provides some helper methods for interacting EGL Extension APIs */
31 class EGLExt private constructor() {
32 
33     companion object {
34 
35         /**
36          * Determines if applications can query the age of the back buffer contents for an EGL
37          * surface as the number of frames elapsed since the contents were recently defined
38          *
39          * See: https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_buffer_age.txt
40          */
41         const val EGL_EXT_BUFFER_AGE = "EGL_EXT_buffer_age"
42 
43         /**
44          * Allows for efficient partial updates to an area of a **buffer** that has changed since
45          * the last time the buffer was used
46          *
47          * See: https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_partial_update.txt
48          */
49         const val EGL_KHR_PARTIAL_UPDATE = "EGL_KHR_partial_update"
50 
51         /**
52          * Allows for efficient partial updates to an area of a **surface** that changes between
53          * frames for the surface. This relates to the differences between two buffers, the current
54          * back buffer and the current front buffer.
55          *
56          * See:
57          * https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_swap_buffers_with_damage.txt
58          */
59         const val EGL_KHR_SWAP_BUFFERS_WITH_DAMAGE = "EGL_KHR_swap_buffers_with_damage"
60 
61         /**
62          * Determines whether to use sRGB format default framebuffers to render sRGB content to
63          * display devices. Supports creation of EGLSurfaces which will be rendered to in sRGB by
64          * OpenGL contexts supporting that capability.
65          *
66          * See: https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_gl_colorspace.txt
67          */
68         const val EGL_KHR_GL_COLORSPACE = "EGL_KHR_gl_colorspace"
69 
70         /**
71          * Determines whether creation of GL and ES contexts without an EGLConfig is allowed
72          *
73          * See: https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_no_config_context.txt
74          */
75         const val EGL_KHR_NO_CONFIG_CONTEXT = "EGL_KHR_no_config_context"
76 
77         /**
78          * Determines whether floating point RGBA components are supported
79          *
80          * See: https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_pixel_format_float.txt
81          */
82         const val EGL_EXT_PIXEL_FORMAT_FLOAT = "EGL_EXT_pixel_format_float"
83 
84         /**
85          * Determines whether extended sRGB color spaces are supported options for EGL Surfaces
86          *
87          * See: https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_gl_colorspace_scrgb.txt
88          */
89         const val EGL_EXT_GL_COLORSPACE_SCRGB = "EGL_EXT_gl_colorspace_scrgb"
90 
91         /**
92          * Determines whether the underlying platform can support rendering framebuffers in the
93          * non-linear Display-P3 color space
94          *
95          * See:
96          * https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_gl_colorspace_display_p3_passthrough.txt
97          */
98         const val EGL_EXT_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH =
99             "EGL_EXT_gl_colorspace_display_p3_passthrough"
100 
101         /**
102          * Determines whether the platform framebuffers support rendering in a larger color gamut
103          * specified in the BT.2020 color space
104          *
105          * See:
106          * https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_gl_colorspace_bt2020_linear.txt
107          */
108         const val EGL_EXT_GL_COLORSPACE_BT2020_PQ = "EGL_EXT_gl_colorspace_bt2020_pq"
109 
110         /**
111          * Determines whether an EGLContext can be created with a priority hint. Not all
112          * implementations are guaranteed to honor the hint.
113          *
114          * See: https://www.khronos.org/registry/EGL/extensions/IMG/EGL_IMG_context_priority.txt
115          */
116         const val EGL_IMG_CONTEXT_PRIORITY = "EGL_IMG_context_priority"
117 
118         /**
119          * Determines whether creation of an EGL Context without a surface is supported. This is
120          * useful for applications that only want to render to client API targets (such as OpenGL
121          * framebuffer objects) and avoid the need to a throw-away EGL surface just to get a current
122          * context.
123          *
124          * See: https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_surfaceless_context.txt
125          */
126         const val EGL_KHR_SURFACELESS_CONTEXT = "EGL_KHR_surfaceless_context"
127 
128         /**
129          * Determines whether sync objects are supported. Sync objects are synchronization
130          * primitives that represent events whose completion can be tested or waited upon.
131          *
132          * See: https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_fence_sync.txt
133          */
134         const val EGL_KHR_FENCE_SYNC = "EGL_KHR_fence_sync"
135 
136         /**
137          * Determines whether waiting for signaling of sync objects is supported. This form of wait
138          * does not necessarily block the application thread which issued the wait. Therefore
139          * applications may continue to issue commands to the client API or perform other work in
140          * parallel leading to increased performance.
141          *
142          * See: https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_wait_sync.txt
143          */
144         const val EGL_KHR_WAIT_SYNC = "EGL_KHR_wait_sync"
145 
146         /**
147          * Determines whether creation of platform specific sync objects are supported. These
148          * objects that are associated with a native synchronization fence object using a file
149          * descriptor.
150          *
151          * See:
152          * https://www.khronos.org/registry/EGL/extensions/ANDROID/EGL_ANDROID_native_fence_sync.txt
153          */
154         const val EGL_ANDROID_NATIVE_FENCE_SYNC = "EGL_ANDROID_native_fence_sync"
155 
156         /**
157          * Enables using an Android window buffer (struct ANativeWindowBuffer) as an EGLImage source
158          *
159          * See:
160          * https://www.khronos.org/registry/EGL/extensions/ANDROID/EGL_ANDROID_image_native_buffer.txt
161          */
162         const val EGL_ANDROID_IMAGE_NATIVE_BUFFER = "EGL_ANDROID_image_native_buffer"
163 
164         /**
165          * Extension for supporting a new EGL resource type that is suitable for sharing 2D arrays
166          * of image data between client APIs, the EGLImage. Although the intended purpose is sharing
167          * 2D image data, the underlying interface makes no assumptions about the format or purpose
168          * of the resource being shared, leaving those decisions to the application and associated
169          * client APIs.
170          *
171          * See: https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_image_base.txt
172          */
173         const val EGL_KHR_IMAGE_BASE = "EGL_KHR_image_base"
174 
175         /**
176          * Extension that allows creating an EGLClientBuffer from an Android [HardwareBuffer] object
177          * which can later be used to create an [EGLImageKHR] instance. See:
178          * https://registry.khronos.org/EGL/extensions/ANDROID/EGL_ANDROID_get_native_client_buffer.txt
179          */
180         const val EGL_ANDROID_CLIENT_BUFFER = "EGL_ANDROID_get_native_client_buffer"
181 
182         /**
183          * Extension that defines a new EGL resource type that is suitable for sharing 2D arrays of
184          * image data between client APIs, the EGLImage, and allows creating EGLImages from EGL
185          * native pixmaps.
186          *
187          * See: https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_image.txt
188          */
189         const val EGL_KHR_IMAGE = "EGL_KHR_image"
190 
191         /** Specifies the types of attributes that can be queried in [eglGetSyncAttribKHR] */
192         @RestrictTo(RestrictTo.Scope.LIBRARY)
193         @IntDef(value = [EGL_SYNC_TYPE_KHR, EGL_SYNC_STATUS_KHR, EGL_SYNC_CONDITION_KHR])
194         annotation class EGLSyncAttribute
195 
196         /**
197          * Attribute that can be queried in [eglGetSyncAttribKHR]. The results can be either
198          * [EGL_SYNC_FENCE_KHR] or [EGL_SYNC_NATIVE_FENCE_ANDROID].
199          *
200          * See: https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_fence_sync.txt
201          */
202         const val EGL_SYNC_TYPE_KHR = 0x30F7
203 
204         /**
205          * Attribute that can be queried in [eglGetSyncAttribKHR]. The results can be either
206          * [EGL_SIGNALED_KHR] or [EGL_UNSIGNALED_KHR] representing whether or not the sync object
207          * has been signalled or not. This can be queried on all sync object types.
208          *
209          * See: https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_fence_sync.txt
210          */
211         const val EGL_SYNC_STATUS_KHR = 0x30F1
212 
213         /**
214          * Attribute that can be queried in [eglGetSyncAttribKHR]. This attribute can only be
215          * queried on sync objects of the type [EGL_SYNC_FENCE_KHR].
216          *
217          * See: https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_fence_sync.txt
218          */
219         const val EGL_SYNC_CONDITION_KHR = 0x30F8
220 
221         /**
222          * Return value when [eglGetSyncAttribKHR] is called with [EGL_SYNC_STATUS_KHR] indicating
223          * that the sync object has already been signalled.
224          *
225          * See: https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_fence_sync.txt
226          */
227         const val EGL_SIGNALED_KHR = 0x30F2
228 
229         /**
230          * Return value when [eglGetSyncAttribKHR] is called with [EGL_SYNC_STATUS_KHR] indicating
231          * that the sync object has not yet been signalled.
232          *
233          * See: https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_fence_sync.txt
234          */
235         const val EGL_UNSIGNALED_KHR = 0x30F3
236 
237         /**
238          * Return value when [eglGetSyncAttribKHR] is called with [EGL_SYNC_CONDITION_KHR]. This
239          * indicates that the sync object will signal on the condition of the completion of the
240          * fence command on the corresponding sync object and all preceding commands in th EGL
241          * client API's command stream.
242          */
243         const val EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR = 0x30F0
244 
245         /** Specifies the type of fence to create in [eglCreateSyncKHR] */
246         @RestrictTo(RestrictTo.Scope.LIBRARY)
247         @IntDef(value = [EGL_SYNC_FENCE_KHR, EGL_SYNC_NATIVE_FENCE_ANDROID])
248         annotation class EGLFenceType
249 
250         /**
251          * Create an EGL fence sync object for signalling one time events. The fence object created
252          * is not associated with the Android Sync fence object and is not recommended for waiting
253          * for events in a portable manner across Android/EGL boundaries but rather other EGL
254          * primitives.
255          *
256          * See: https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_fence_sync.txt
257          */
258         const val EGL_SYNC_FENCE_KHR = 0x30F9
259 
260         /**
261          * This extension enables the creation of EGL fence sync objects that are associated with a
262          * native synchronization fence object that is referenced using a file descriptor. These EGL
263          * fence sync objects have nearly identical semantics to those defined by the KHR_fence_sync
264          * extension, except that they have an additional attribute storing the file descriptor
265          * referring to the native fence object. This differs from EGL_SYNC_FENCE_KHR as the fence
266          * sync object is associated with an Android Sync HAL fence object.
267          *
268          * This extension assumes the existence of a native fence synchronization object that
269          * behaves similarly to an EGL fence sync object. These native objects must have a signal
270          * status like that of an EGLSyncKHR object that indicates whether the fence has ever been
271          * signaled. Once signaled the native object's signal status may not change again.
272          *
273          * See:
274          * https://www.khronos.org/registry/EGL/extensions/ANDROID/EGL_ANDROID_native_fence_sync.txt
275          */
276         const val EGL_SYNC_NATIVE_FENCE_ANDROID = 0x3144
277 
278         /**
279          * Value that can be sent as the timeoutNanos parameter of [eglClientWaitSyncKHR] indicating
280          * that waiting on the sync object to signal will never time out.
281          */
282         // Note EGL has EGL_FOREVER_KHR defined as 0xFFFFFFFFFFFFFFFFuL. However, Java does not
283         // support unsigned long types. So use -1 as the constant value here as it will be casted
284         // as an EGLTimeKHR type which is uint64 in the corresponding JNI method
285         const val EGL_FOREVER_KHR = -1L
286 
287         /** Specifies various return values for the [eglClientWaitSyncKHR] method */
288         @RestrictTo(RestrictTo.Scope.LIBRARY)
289         @Target(AnnotationTarget.TYPE)
290         @IntDef(value = [EGL_CONDITION_SATISFIED_KHR, EGL_TIMEOUT_EXPIRED_KHR, EGL_FALSE])
291         annotation class EGLClientWaitResult
292 
293         /**
294          * Return value used in [eglClientWaitSyncKHR] to indicate that the specified timeout period
295          * had expired before a sync object was signalled.
296          */
297         const val EGL_TIMEOUT_EXPIRED_KHR = 0x30F5
298 
299         /**
300          * Return value used in [eglClientWaitSyncKHR] to indicate that the sync object had
301          * signalled before the timeout expired. This includes the case where the sync object had
302          * already signalled before [eglClientWaitSyncKHR] was called.
303          */
304         const val EGL_CONDITION_SATISFIED_KHR = 0x30F6
305 
306         /**
307          * Accepted in the flags parameter of [eglClientWaitSyncKHR]. This will implicitly ensure
308          * pending commands are flushed to prevent [eglClientWaitSyncKHR] from potentially blocking
309          * forever. See [eglClientWaitSyncKHR] for details.
310          */
311         const val EGL_SYNC_FLUSH_COMMANDS_BIT_KHR = 0x0001
312 
313         /** Constant indicating true within EGL. This is often returned in success cases. */
314         const val EGL_TRUE = 1
315 
316         /** Constant indicating false within EGL. This is often returned in failure cases. */
317         const val EGL_FALSE = 0
318 
319         /**
320          * Creates an EGLImage from the provided [HardwareBuffer]. This handles internally creating
321          * an EGLClientBuffer and an [EGLImageKHR] from the client buffer.
322          *
323          * When this [EGLImageKHR] instance is no longer necessary, consumers should be sure to call
324          * the corresponding method [eglDestroyImageKHR] to deallocate the resource.
325          *
326          * @param eglDisplay EGLDisplay connection associated with the EGLImage to create
327          * @param hardwareBuffer Backing [HardwareBuffer] for the generated EGLImage instance
328          * @return an [EGLImageKHR] instance representing the [EGLImageKHR] created from the
329          *   HardwareBuffer. Because this is created internally through EGL's eglCreateImageKR
330          *   method, this has the KHR suffix.
331          *
332          * This can return null if the EGL_ANDROID_image_native_buffer and EGL_KHR_image_base
333          * extensions are not supported or if allocation of the buffer fails.
334          *
335          * See
336          * www.khronos.org/registry/EGL/extensions/ANDROID/EGL_ANDROID_get_native_client_buffer.txt
337          */
338         @JvmStatic
339         @RequiresApi(Build.VERSION_CODES.O)
eglCreateImageFromHardwareBuffernull340         fun eglCreateImageFromHardwareBuffer(
341             eglDisplay: EGLDisplay,
342             hardwareBuffer: HardwareBuffer
343         ): EGLImageKHR? {
344             val handle =
345                 EGLBindings.nCreateImageFromHardwareBuffer(eglDisplay.nativeHandle, hardwareBuffer)
346             return if (handle == 0L) {
347                 null
348             } else {
349                 EGLImageKHR(handle)
350             }
351         }
352 
353         /**
354          * Destroy the given [EGLImageKHR] instance. Once destroyed, the image may not be used to
355          * create any additional [EGLImageKHR] target resources within any client API contexts,
356          * although existing [EGLImageKHR] siblings may continue to be used. `True` is returned if
357          * DestroyImageKHR succeeds, `false` indicates failure. This can return `false` if the
358          * [EGLImageKHR] is not associated with the default display.
359          *
360          * See: https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_image_base.txt
361          *
362          * @param eglDisplay EGLDisplay that this EGLImage is connected to
363          * @param image EGLImageKHR to be destroyed
364          * @return True if the destruction of the EGLImageKHR object was successful, false otherwise
365          */
366         @JvmStatic
eglDestroyImageKHRnull367         fun eglDestroyImageKHR(eglDisplay: EGLDisplay, image: EGLImageKHR): Boolean =
368             EGLBindings.nDestroyImageKHR(eglDisplay.nativeHandle, image.nativeHandle)
369 
370         /**
371          * Upload a given EGLImage to the currently bound GLTexture
372          *
373          * This method requires either of the following EGL extensions to be supported:
374          * EGL_KHR_image_base or EGL_KHR_image
375          *
376          * See: https://www.khronos.org/registry/OpenGL/extensions/OES/OES_EGL_image_external.txt
377          */
378         @JvmStatic
379         @Suppress("AcronymName")
380         fun glEGLImageTargetTexture2DOES(target: Int, image: EGLImageKHR) {
381             EGLBindings.nImageTargetTexture2DOES(target, image.nativeHandle)
382         }
383 
384         /**
385          * Creates a sync object of the specified type associated with the specified display, and
386          * returns a handle to the new object. The configuration of the returned [EGLSyncKHR] object
387          * is specified by the provided attributes.
388          *
389          * Consumers should ensure that the EGL_KHR_fence_sync EGL extension is supported before
390          * invoking this method otherwise a null EGLSyncFenceKHR object is returned.
391          *
392          * Additionally when the [EGLSyncKHR] instance is no longer necessary, consumers are
393          * encouraged to call [eglDestroySyncKHR] to deallocate this resource.
394          *
395          * See: https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_fence_sync.txt
396          *
397          * @param eglDisplay EGLDisplay to associate the sync object with
398          * @param type Indicates the type of sync object that is returned
399          * @param attributes Specifies the configuration of the sync object returned
400          * @return the EGLSyncKHR object to be used as a fence or null if this extension is not
401          *   supported
402          */
403         @JvmStatic
eglCreateSyncKHRnull404         fun eglCreateSyncKHR(
405             eglDisplay: EGLDisplay,
406             @EGLFenceType type: Int,
407             attributes: EGLConfigAttributes?
408         ): EGLSyncKHR? {
409             val handle =
410                 EGLBindings.nCreateSyncKHR(eglDisplay.nativeHandle, type, attributes?.attrs)
411             return if (handle == 0L) {
412                 null
413             } else {
414                 EGLSyncKHR(handle)
415             }
416         }
417 
418         /**
419          * Query attributes of the provided sync object. Accepted attributes to query depend on the
420          * type of sync object. If no errors are generated, this returns true and the value of the
421          * queried attribute is stored in the value array at the offset position. If this method
422          * returns false, the provided value array is unmodified.
423          *
424          * See: https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_fence_sync.txt
425          *
426          * @param eglDisplay EGLDisplay to associate the sync object with
427          * @param sync EGLSyncKHR object to query attributes
428          * @param attribute Corresponding EGLSyncKHR attribute to query on [sync]
429          * @param value Integer array used to store the result of the query
430          * @param offset Index within the value array to store the result of the attribute query
431          * @return True if the attribute was queried successfully, false otherwise. Failure cases
432          *   include attempting to call this method on an invalid sync object, or the display
433          *   provided not matching the display that was used to create this sync object.
434          *   Additionally if the queried attribute is not supported for the sync object, false is
435          *   returned.
436          */
437         @JvmStatic
eglGetSyncAttribKHRnull438         fun eglGetSyncAttribKHR(
439             eglDisplay: EGLDisplay,
440             sync: EGLSyncKHR,
441             @EGLSyncAttribute attribute: Int,
442             value: IntArray,
443             offset: Int
444         ): Boolean =
445             EGLBindings.nGetSyncAttribKHR(
446                 eglDisplay.nativeHandle,
447                 sync.nativeHandle,
448                 attribute,
449                 value,
450                 offset
451             )
452 
453         /**
454          * Blocks the calling thread until the specified sync object is signalled or until
455          * [timeoutNanos] nanoseconds have passed. More than one [eglClientWaitSyncKHR] may be
456          * outstanding on the same [sync] at any given time. When there are multiple threads blocked
457          * on the same [sync] and the [sync] object has signalled, all such threads are released,
458          * but the order in which they are released is not defined.
459          *
460          * If the value of [timeoutNanos] is zero, then [eglClientWaitSyncKHR] simply tests the
461          * current status of sync. If the value of [timeoutNanos] is the special value
462          * [EGL_FOREVER_KHR], then [eglClientWaitSyncKHR] does not time out. For all other values,
463          * [timeoutNanos] is adjusted to the closest value allowed by the implementation-dependent
464          * timeout accuracy, which may be substantially longer than one nanosecond.
465          *
466          * [eglClientWaitSyncKHR] returns one of three status values describing the reason for
467          * returning. A return value of [EGL_TIMEOUT_EXPIRED_KHR] indicates that the specified
468          * timeout period expired before [sync] was signalled, or if [timeoutNanos] is zero,
469          * indicates that [sync] is not signaled. A return value of [EGL_CONDITION_SATISFIED_KHR]
470          * indicates that [sync] was signaled before the timeout expired, which includes the case
471          * when [sync] was already signaled when [eglClientWaitSyncKHR] was called. If an error
472          * occurs then an error is generated and [EGL_FALSE] is returned.
473          *
474          * If the sync object being blocked upon will not be signaled in finite time (for example by
475          * an associated fence command issued previously, but not yet flushed to the graphics
476          * pipeline), then [eglClientWaitSyncKHR] may wait forever. To help prevent this behavior,
477          * if the [EGL_SYNC_FLUSH_COMMANDS_BIT_KHR] is set on the flags parameter and the [sync] is
478          * unsignaled when [eglClientWaitSyncKHR] is called, then the equivalent flush will be
479          * performed for the current EGL context before blocking on sync. If no context is current
480          * bound for the API, the [EGL_SYNC_FLUSH_COMMANDS_BIT_KHR] bit is ignored.
481          *
482          * @param eglDisplay EGLDisplay to associate the sync object with
483          * @param sync EGLSyncKHR object to wait on
484          * @param flags Optional flags to provide to handle flushing of pending commands
485          * @param timeoutNanos Optional timeout value to wait before this method returns, measured
486          *   in nanoseconds. This value is always consumed as an unsigned long value so even
487          *   negative values will be converted to their unsigned equivalent.
488          * @return Result code indicating the status of the wait request. Either
489          *   [EGL_CONDITION_SATISFIED_KHR], if the sync did signal within the specified timeout,
490          *   [EGL_TIMEOUT_EXPIRED_KHR] if the sync did not signal within the specified timeout, or
491          *   [EGL_FALSE] if an error occurs.
492          */
493         @JvmStatic
494         fun eglClientWaitSyncKHR(
495             eglDisplay: EGLDisplay,
496             sync: EGLSyncKHR,
497             flags: Int,
498             timeoutNanos: Long
499         ): @EGLClientWaitResult Int =
500             EGLBindings.nClientWaitSyncKHR(
501                 eglDisplay.nativeHandle,
502                 sync.nativeHandle,
503                 flags,
504                 timeoutNanos
505             )
506 
507         /**
508          * Creates a native synchronization fence referenced through a file descriptor that is
509          * associated with an EGL fence sync object.
510          *
511          * See:
512          * https://www.khronos.org/registry/EGL/extensions/ANDROID/EGL_ANDROID_native_fence_sync.txt
513          *
514          * @param display The EGLDisplay connection
515          * @param sync The EGLSyncKHR to fetch the [SyncFenceCompat] from
516          * @return A [SyncFenceCompat] representing the native fence. If [sync] is not a valid sync
517          *   object for [display], an invalid [SyncFenceCompat] instance is returned and an
518          *   EGL_BAD_PARAMETER error is generated. If the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute
519          *   of [sync] is EGL_NO_NATIVE_FENCE_FD_ANDROID, an invalid [SyncFenceCompat] is returned
520          *   and an EGL_BAD_PARAMETER error is generated. If [display] does not match the display
521          *   passed to [eglCreateSyncKHR] when [sync] was created, the behavior is undefined.
522          */
523         @JvmStatic
524         @Suppress("AcronymName")
525         internal fun eglDupNativeFenceFDANDROID(
526             display: EGLDisplay,
527             sync: EGLSyncKHR
528         ): SyncFenceCompat {
529             val fd = EGLBindings.nDupNativeFenceFDANDROID(display.nativeHandle, sync.nativeHandle)
530             return if (fd >= 0) {
531                 SyncFenceCompat(SyncFenceV19(fd))
532             } else {
533                 SyncFenceCompat(SyncFenceV19(-1))
534             }
535         }
536 
537         /**
538          * Destroys the given sync object associated with the specified display
539          *
540          * Consumers should ensure that the EGL_KHR_fence_sync EGL extension is supported before
541          * invoking this method otherwise a null EGLSyncFenceKHR object is returned. See:
542          * https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_fence_sync.txt
543          *
544          * @param eglDisplay EGLDisplay instance associated with the fence
545          * @param eglSync Fence object to be destroyed
546          * @return true if the EGLSyncKHR object was destroyed successfully false otherwise. This
547          *   can return false if the sync object is not a valid sync object for the provided display
548          *   or if the display provided in this method does not match the display used to create
549          *   this sync in eglCreateSyncKHR.
550          */
551         @JvmStatic
eglDestroySyncKHRnull552         fun eglDestroySyncKHR(eglDisplay: EGLDisplay, eglSync: EGLSyncKHR): Boolean =
553             EGLBindings.nDestroySyncKHR(eglDisplay.nativeHandle, eglSync.nativeHandle)
554 
555         /**
556          * Returns a set of supported supported extensions from a space separated string that
557          * represents the set of OpenGL extensions supported
558          */
559         @JvmStatic
560         fun parseExtensions(queryString: String): Set<String> =
561             HashSet<String>().apply { addAll(queryString.split(' ')) }
562     }
563 }
564 
565 /**
566  * Helper class to configure JNI bindings to be invoked within the EGLUtils public API. This class
567  * is provided to separate responsibilities of jni method registration and helps to avoid synthetic
568  * accessor warnings
569  */
570 @JniVisible
571 internal class EGLBindings {
572     companion object {
573         @JvmStatic
574         @JniVisible
nCreateImageFromHardwareBuffernull575         external fun nCreateImageFromHardwareBuffer(
576             eglDisplayPtr: Long,
577             hardwareBuffer: HardwareBuffer
578         ): Long
579 
580         // Note this API is explicitly a GL API and not an EGL API which is the reason
581         // why this has the GL prefix vs EGL
582         @JvmStatic @JniVisible external fun nImageTargetTexture2DOES(target: Int, eglImagePtr: Long)
583 
584         @JvmStatic
585         @JniVisible
586         external fun nDupNativeFenceFDANDROID(eglDisplayPtr: Long, syncPtr: Long): Int
587 
588         @JvmStatic
589         @JniVisible
590         external fun nCreateSyncKHR(eglDisplayPtr: Long, type: Int, attrs: IntArray?): Long
591 
592         @JvmStatic
593         @JniVisible
594         external fun nGetSyncAttribKHR(
595             eglDisplayPtr: Long,
596             syncPtr: Long,
597             attrib: Int,
598             result: IntArray,
599             offset: Int
600         ): Boolean
601 
602         @JvmStatic
603         @JniVisible
604         external fun nClientWaitSyncKHR(
605             eglDisplayPtr: Long,
606             syncPtr: Long,
607             flags: Int,
608             timeout: Long
609         ): Int
610 
611         @JvmStatic
612         @JniVisible
613         external fun nDestroySyncKHR(eglDisplayPtr: Long, syncPtr: Long): Boolean
614 
615         @JvmStatic
616         @JniVisible
617         external fun nDestroyImageKHR(eglDisplayPtr: Long, eglImagePtr: Long): Boolean
618 
619         @JvmStatic @JniVisible external fun nSupportsEglGetNativeClientBufferAndroid(): Boolean
620 
621         @JvmStatic @JniVisible external fun nSupportsDupNativeFenceFDANDROID(): Boolean
622 
623         @JvmStatic @JniVisible external fun nSupportsEglCreateImageKHR(): Boolean
624 
625         @JvmStatic @JniVisible external fun nSupportsEglDestroyImageKHR(): Boolean
626 
627         @JvmStatic @JniVisible external fun nSupportsGlImageTargetTexture2DOES(): Boolean
628 
629         @JvmStatic @JniVisible external fun nSupportsEglCreateSyncKHR(): Boolean
630 
631         @JvmStatic @JniVisible external fun nSupportsEglGetSyncAttribKHR(): Boolean
632 
633         @JvmStatic @JniVisible external fun nSupportsEglClientWaitSyncKHR(): Boolean
634 
635         @JvmStatic @JniVisible external fun nSupportsEglDestroySyncKHR(): Boolean
636 
637         @JvmStatic
638         @JniVisible
639         external fun nEqualToNativeForeverTimeout(timeoutNanos: Long): Boolean
640 
641         init {
642             System.loadLibrary("graphics-core")
643         }
644     }
645 }
646