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 #include <jni.h>
17 #include <string>
18 #include <poll.h>
19 #include <unistd.h>
20 #include <EGL/egl.h>
21 #include <EGL/eglext.h>
22 #include <android/log.h>
23 #include <EGL/eglplatform.h>
24 #include <GLES2/gl2.h>
25 #include <GLES2/gl2ext.h>
26 #include <android/sync.h>
27 #include <android/hardware_buffer_jni.h>
28 #include <mutex>
29 #include "egl_utils.h"
30 
31 #define EGL_UTILS "EglUtils"
32 #define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, EGL_UTILS, __VA_ARGS__)
33 
34 /**
35  * Cached reference to the eglGetNativeClientBufferANDROID egl extension method
36  * On first invocation within the corresponding JNI method, a call to eglGetProcAddress
37  * is made to determine if this method exists. If it does then this function pointer
38  * is persisted for subsequent method calls.
39  */
40 PFNEGLGETNATIVECLIENTBUFFERANDROIDPROC eglGetNativeClientBufferANDROID = nullptr;
41 
42 /**
43  * Cached reference to the eglImageTargetTexture2DOES egl extension method.
44  * On first invocation within the corresponding JNI method, a call to eglGetProcAddress
45  * is made to determine if this method exists. If it does then this function pointer
46  * is persisted for subsequent method calls.
47  */
48 PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = nullptr;
49 
50 /**
51  * Cached reference to the eglCreateImageKHR egl extension method.
52  * On first invocation within the corresponding JNI method, a call to eglGetProcAddress
53  * is made to determine if this method exists. If it does then this function pointer
54  * is persisted for subsequent method calls.
55  */
56 PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = nullptr;
57 
58 /**
59  * Cached reference to the eglDestroyImageKHR egl extension method.
60  * On first invocation within the corresponding JNI method, a call to eglGetProcAddress
61  * is made to determine if this method exists. If it does then this function pointer
62  * is persisted for subsequent method calls.
63  */
64 PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = nullptr;
65 
66 /**
67  * Cached reference to the eglCreateSyncKHR egl extension method.
68  * On first invocation within the corresponding JNI method, a call to eglGetProcAddress
69  * is made to determine if this method exists. If it does then this function pointer
70  * is persisted for subsequent method calls.
71  */
72 PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR = nullptr;
73 
74 /**
75  * Cached reference to the eglGetSyncAttribKHR egl extension method.
76  * On first invocation within the corresponding JNI method, a call to eglGetProcAddress
77  * is made to determine if this method exists. If it does then this function pointer
78  * is persisted for subsequent method calls.
79  */
80 PFNEGLGETSYNCATTRIBKHRPROC eglGetSyncAttribKHR = nullptr;
81 
82 /**
83  * Cached reference to the eglClientWaitSyncKHR egl extension method.
84  * On first invocation within the corresponding JNI method, a call to eglGetProcAddress
85  * is made to determine if this method exists. If it does then this function pointer
86  * is persisted for subsequent method calls.
87  */
88 PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR = nullptr;
89 
90 /**
91  * Cached reference to the eglDestroySyncKHR egl extension method.
92  * On first invocation within the corresponding JNI method, a call to eglGetProcAddress
93  * is made to determine if this method exists. If it does then this function pointer
94  * is persisted for subsequent method calls.
95  */
96 PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR = nullptr;
97 
98 /**
99  * Cached reference to the eglDupNativeFenceFDANDROID egl extension method.
100  * On first invocation within the corresponding JNI method, a call to eglGetProcAddress
101  * is made to determine if this method exists. If it does then this function pointer
102  * is persisted for subsequent method calls.
103  */
104 PFNEGLDUPNATIVEFENCEFDANDROIDPROC eglDupNativeFenceFDANDROID = nullptr;
105 
106 /**
107  * Helper method for querying the EGL extension method eglGetNativeClientBufferANDROID.
108  * This is used in initial invocations of the corresponding JNI method to obtain
109  * an EGLClientBuffer instance from a HardwareBuffer as well as for testing purposes
110  * to guarantee that Android devices that advertise support for the corresponding
111  * extensions actually expose this API.
112  */
obtainEglGetNativeClientBufferANDROID()113 static PFNEGLGETNATIVECLIENTBUFFERANDROIDPROC obtainEglGetNativeClientBufferANDROID() {
114     return reinterpret_cast<PFNEGLGETNATIVECLIENTBUFFERANDROIDPROC>(
115             eglGetProcAddress("eglGetNativeClientBufferANDROID"));
116 }
117 
118 /**
119  * Helper method for querying the EGL extension method eglCreateImageKHR.
120  * This is used in initial invocations of the corresponding JNI method to obtain
121  * an EGLImage from an EGLClientBuffer as well as for testing purposes
122  * to guarantee that Android devices that advertise support for the corresponding
123  * extensions actually expose this API.
124  */
obtainEglCreateImageKHR()125 static PFNEGLCREATEIMAGEKHRPROC obtainEglCreateImageKHR() {
126     return reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(
127             eglGetProcAddress("eglCreateImageKHR"));
128 }
129 
130 /**
131  * Helper method for querying the EGL extension method eglDestroyImageKHR.
132  * This is used in initial invocations of the corresponding JNI method to destroy
133  * an EGLImage as well as for testing purposes to guarantee that Android devices
134  * that advertise support for the corresponding extensions actually expose this API.
135  */
obtainEglDestroyImageKHR()136 static PFNEGLDESTROYIMAGEKHRPROC obtainEglDestroyImageKHR() {
137     return reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(
138             eglGetProcAddress("eglDestroyImageKHR"));
139 }
140 
141 /**
142  * Helper method for querying the EGL extension method glImageTargetTexture2DOES.
143  * This is used in initial invocations of the corresponding JNI method to load
144  * an EGLImage instance into a caller defined GL Texture as well as for testing
145  * purposes to guarantee that Android devices that advertise support for the
146  * corresponding extensions actually expose this API.
147  */
obtainGlImageTargetTexture2DOES()148 static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC obtainGlImageTargetTexture2DOES() {
149     return reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(
150             eglGetProcAddress("glEGLImageTargetTexture2DOES"));
151 }
152 
153 /**
154  * Helper method for querying the EGL extension method eglDupNativeFenceFDANDROID.
155  * This is used in initial invocations of the corresponding JNI method to to create EGL  fence sync
156  * objects that are associated with a native synchronization fence object that are referenced using
157  * a file descriptor. Additionally this is used for testing purposes to guarantee that Android
158  * devices that advertise support for the corresponding extensions actually expose this API.
159  */
obtainEglDupNativeFenceFDANDROID()160 static PFNEGLDUPNATIVEFENCEFDANDROIDPROC obtainEglDupNativeFenceFDANDROID() {
161     return reinterpret_cast<PFNEGLDUPNATIVEFENCEFDANDROIDPROC>(
162             eglGetProcAddress("eglDupNativeFenceFDANDROID"));
163 }
164 
165 /**
166  * Helper method for querying the EGL extension method eglCreateSyncKHR.
167  * This is used in initial invocations of the corresponding JNI method to to create EGL fence sync
168  * object. Additionally this is used for testing purposes to guarantee that Android
169  * devices that advertise support for the corresponding extensions actually expose this API.
170  */
obtainEglCreateSyncKHR()171 static PFNEGLCREATESYNCKHRPROC obtainEglCreateSyncKHR() {
172     return reinterpret_cast<PFNEGLCREATESYNCKHRPROC>(
173             eglGetProcAddress("eglCreateSyncKHR"));
174 }
175 
176 /**
177  * Helper method for querying the EGL extension method eglGetSyncAttribKHR.
178  * This is used in initial invocations of the corresponding JNI method to query
179  * properties of an EGLSync object returned by eglCreateSyncKHR as well as for
180  * testing purposes to guarantee that Android devices that advertise support for
181  * the corresponding extensions actually expose this API.
182  */
obtainEglGetSyncAttribKHR()183 static PFNEGLGETSYNCATTRIBKHRPROC obtainEglGetSyncAttribKHR() {
184     return reinterpret_cast<PFNEGLGETSYNCATTRIBKHRPROC>(
185             eglGetProcAddress("eglGetSyncAttribKHR"));
186 }
187 
188 /**
189  * Helper method for querying the EGL extension method eglClientWaitSyncKHR.
190  * This is used in initial invocations of the corresponding JNI method to block
191  * the current thread until the specified sync object is signalled or until a timeout
192  * has passed. Additionally this is used for testing purposes to guarantee that Android devices
193  * that advertise support for the corresponding extensions actually expose this API.
194  */
obtainEglClientWaitSyncKHR()195 static PFNEGLCLIENTWAITSYNCKHRPROC obtainEglClientWaitSyncKHR() {
196     return reinterpret_cast<PFNEGLCLIENTWAITSYNCKHRPROC>(
197             eglGetProcAddress("eglClientWaitSyncKHR"));
198 }
199 
200 /**
201  * Helper method for querying the EGL extension method eglDestroySyncKHR.
202  * This is used in initial invocations of the corresponding JNI method to destroy an EGL fence sync
203  * object. Additionally this is used for testing purposes to guarantee that Android devices that
204  * advertise support for corresponding extensions actually expose this API.
205  */
obtainEglDestroySyncKHR()206 static PFNEGLDESTROYSYNCKHRPROC obtainEglDestroySyncKHR() {
207     return reinterpret_cast<PFNEGLDESTROYSYNCKHRPROC>(
208             eglGetProcAddress("eglDestroySyncKHR"));
209 }
210 
EGLBindings_nCreateImageFromHardwareBuffer(JNIEnv * env,jclass,jlong egl_display_ptr,jobject hardware_buffer)211 jlong EGLBindings_nCreateImageFromHardwareBuffer(
212         JNIEnv *env, jclass , jlong egl_display_ptr, jobject hardware_buffer) {
213     static std::once_flag eglGetNativeClientBufferANDROIDFlag;
214     static std::once_flag eglCreateImageKHRFlag;
215     std::call_once(eglGetNativeClientBufferANDROIDFlag, [](){
216         eglGetNativeClientBufferANDROID = obtainEglGetNativeClientBufferANDROID();
217     });
218     if (!eglGetNativeClientBufferANDROID) {
219         ALOGE("Unable to resolve eglGetNativeClientBufferANDROID");
220         return 0;
221     }
222 
223     std::call_once(eglCreateImageKHRFlag, [](){
224         eglCreateImageKHR = obtainEglCreateImageKHR();
225     });
226     if (!eglCreateImageKHR) {
227         ALOGE("Unable to resolve eglCreateImageKHR");
228         return 0;
229     }
230 
231     AHardwareBuffer *buffer =
232             AHardwareBuffer_fromHardwareBuffer(env, hardware_buffer);
233     EGLClientBuffer eglClientBuffer = eglGetNativeClientBufferANDROID(buffer);
234 
235     EGLint imageAttrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
236     auto display = reinterpret_cast<EGLDisplay *>(egl_display_ptr);
237     EGLImage image = eglCreateImageKHR(
238             display,
239             EGL_NO_CONTEXT,
240             EGL_NATIVE_BUFFER_ANDROID,
241             eglClientBuffer,
242             imageAttrs
243     );
244 
245     return reinterpret_cast<jlong>(image);
246 }
247 
EGLBindings_nDestroyImageKHR(JNIEnv * env,jclass,jlong egl_display_ptr,jlong egl_image_ptr)248 jboolean EGLBindings_nDestroyImageKHR(
249         JNIEnv *env, jclass, jlong egl_display_ptr, jlong egl_image_ptr) {
250     static std::once_flag eglDestroyImageKHRFlag;
251     std::call_once(eglDestroyImageKHRFlag, [](){
252         eglDestroyImageKHR = obtainEglDestroyImageKHR();
253     });
254     if (!eglDestroyImageKHR) {
255         ALOGE("Unable to resolve eglDestroyImageKHR");
256         return static_cast<jboolean>(false);
257     }
258 
259     auto display = reinterpret_cast<EGLDisplay *>(egl_display_ptr);
260     auto eglImage = reinterpret_cast<EGLImage>(egl_image_ptr);
261     return static_cast<jboolean>(eglDestroyImageKHR(display, eglImage));
262 }
263 
EGLBindings_nImageTargetTexture2DOES(JNIEnv * env,jclass,jint target,jlong egl_image_ptr)264 void EGLBindings_nImageTargetTexture2DOES(JNIEnv *env, jclass, jint target, jlong egl_image_ptr) {
265     static std::once_flag glEGLImageTargetTexture2DOESFlag;
266     std::call_once(glEGLImageTargetTexture2DOESFlag, [](){
267         glEGLImageTargetTexture2DOES = obtainGlImageTargetTexture2DOES();
268     });
269     if (!glEGLImageTargetTexture2DOES) {
270         ALOGE("Unable to resolve glEGLImageTargetTexture2DOES");
271         return;
272     }
273 
274     glEGLImageTargetTexture2DOES(target, reinterpret_cast<EGLImage>(egl_image_ptr));
275 }
276 
EGLBindings_nDupNativeFenceFDANDROID(JNIEnv * env,jclass,jlong egl_display_ptr,jlong sync_ptr)277 jint EGLBindings_nDupNativeFenceFDANDROID(JNIEnv *env, jclass, jlong egl_display_ptr,
278                                           jlong sync_ptr) {
279     static std::once_flag eglDupNativeFenceFDANDROIDflag;
280     std::call_once(eglDupNativeFenceFDANDROIDflag, [](){
281         eglDupNativeFenceFDANDROID = obtainEglDupNativeFenceFDANDROID();
282     });
283     if (!eglDupNativeFenceFDANDROID) {
284         ALOGE("Unable to resolve eglDupNativeFenceFDAndroid");
285         return EGL_NO_NATIVE_FENCE_FD_ANDROID;
286     }
287 
288     auto display = reinterpret_cast<EGLDisplay *>(egl_display_ptr);
289     auto sync = reinterpret_cast<EGLSync>(sync_ptr);
290     return (jint)eglDupNativeFenceFDANDROID(display, sync);
291 }
292 
EGLBindings_nCreateSyncKHR(JNIEnv * env,jclass,jlong egl_display_ptr,jint type,jintArray attrs)293 jlong EGLBindings_nCreateSyncKHR(JNIEnv *env, jclass, jlong egl_display_ptr, jint type,
294                                  jintArray attrs) {
295     static std::once_flag eglCreateSyncKHRFlag;
296     std::call_once(eglCreateSyncKHRFlag, [](){
297         eglCreateSyncKHR = obtainEglCreateSyncKHR();
298     });
299     if (!eglCreateSyncKHR) {
300         ALOGE("Unable to resolve eglCreateSyncKHR");
301         return 0;
302     }
303 
304     auto display = reinterpret_cast<EGLDisplay *>(egl_display_ptr);
305     auto attrib_list = reinterpret_cast<EGLint *>(attrs);
306     return reinterpret_cast<jlong>(eglCreateSyncKHR(display, type, attrib_list));
307 }
308 
createIllegalArgumentException(JNIEnv * env,jstring message)309 static jobject createIllegalArgumentException(JNIEnv* env, jstring message) {
310     jclass exceptionClass = env->FindClass("java/lang/IllegalArgumentException");
311     if (exceptionClass != nullptr) {
312         jmethodID init = env->GetMethodID(exceptionClass, "<init>", "(Ljava/lang/String;)V");
313         jobject instance;
314         if (init != nullptr) {
315             instance = env->NewObject(exceptionClass, init, message);
316         } else {
317             ALOGE("Unable to find constructor for IllegalArgumentException");
318             instance = nullptr;
319         }
320         env->DeleteLocalRef(exceptionClass);
321         return instance;
322     } else {
323         ALOGE("Unable to find IllegalArgumentException class");
324         return nullptr;
325     }
326 }
327 
jniThrowIllegalArgumentException(JNIEnv * env,const char * msg)328 static int jniThrowIllegalArgumentException(JNIEnv* env, const char* msg) {
329     jstring message = env->NewStringUTF(msg);
330     if (message != nullptr) {
331         jobject exception = createIllegalArgumentException(env, message);
332         int status = 0;
333         if (exception != nullptr) {
334             if (env->Throw((jthrowable) exception) != JNI_OK) {
335                 ALOGE("Unable to throw IllegalArgumentException");
336                 status = -1;
337             }
338         } else {
339             status = -1;
340         }
341         env->DeleteLocalRef(message);
342         return status;
343     } else {
344         env->ExceptionClear();
345         return -1;
346     }
347 }
348 
EGLBindings_nGetSyncAttribKHR(JNIEnv * env,jclass,jlong egl_display_ptr,jlong sync_ptr,jint attrib,jintArray result_ref,jint offset)349 jboolean EGLBindings_nGetSyncAttribKHR(
350         JNIEnv *env,
351         jclass,
352         jlong egl_display_ptr,
353         jlong sync_ptr,
354         jint attrib,
355         jintArray result_ref,
356         jint offset
357         ) {
358     static std::once_flag eglGetSyncAttribKHRFlag;
359     std::call_once(eglGetSyncAttribKHRFlag, []() {
360         eglGetSyncAttribKHR = obtainEglGetSyncAttribKHR();
361     });
362     if (!eglGetSyncAttribKHR) {
363         ALOGE("Unable to resolve eglGetSyncAttribKHR");
364         return static_cast<jboolean>(false);
365     }
366 
367     if (!result_ref) {
368         jniThrowIllegalArgumentException(env,
369             "Null pointer received, invalid array provided to store eglGetSyncAttribKHR result");
370         return static_cast<jboolean>(false);
371     }
372 
373     if (offset < 0) {
374         jniThrowIllegalArgumentException(env,
375             "Invalid offset provided, must be greater than or equal to 0");
376         return static_cast<jboolean>(false);
377     }
378 
379     jint remaining = env->GetArrayLength(result_ref) - offset;
380     if (remaining < 1) {
381         jniThrowIllegalArgumentException(env, "length - offset is out of bounds");
382         return static_cast<jboolean>(false);
383     }
384 
385     auto result_base = (GLint *)env->GetIntArrayElements(result_ref, (jboolean *)nullptr);
386     auto result = (GLint *)(result_base + offset);
387     auto display = reinterpret_cast<EGLDisplay *>(egl_display_ptr);
388     auto sync = reinterpret_cast<EGLSync>(sync_ptr);
389     auto success = static_cast<jboolean>(eglGetSyncAttribKHR(display, sync, attrib, result));
390     env->ReleaseIntArrayElements(result_ref, (jint*) result_base, 0);
391     return success;
392 }
393 
EGLBindings_nClientWaitSyncKHR(JNIEnv * env,jclass,jlong egl_display_ptr,jlong sync_ptr,jint flags,jlong timeout)394 jint EGLBindings_nClientWaitSyncKHR(
395         JNIEnv *env,
396         jclass,
397         jlong egl_display_ptr,
398         jlong sync_ptr,
399         jint flags,
400         jlong timeout
401         ) {
402     static std::once_flag eglClientWaitKRFlag;
403     std::call_once(eglClientWaitKRFlag, []() {
404         eglClientWaitSyncKHR = obtainEglClientWaitSyncKHR();
405     });
406 
407     auto display = reinterpret_cast<EGLDisplay *>(egl_display_ptr);
408     auto sync = reinterpret_cast<EGLSync>(sync_ptr);
409     auto wait_flags = static_cast<EGLint>(flags);
410     auto wait_timeout = static_cast<EGLTimeKHR>(timeout);
411     return static_cast<jint>(eglClientWaitSyncKHR(display, sync, wait_flags, wait_timeout));
412 }
413 
EGLBindings_nDestroySyncKHR(JNIEnv * env,jclass,jlong egl_display_ptr,jlong sync_ptr)414 jboolean EGLBindings_nDestroySyncKHR(
415         JNIEnv *env,
416         jclass,
417         jlong egl_display_ptr,
418         jlong sync_ptr
419         ) {
420     static std::once_flag eglDestroySyncKHRFlag;
421     std::call_once(eglDestroySyncKHRFlag, [](){
422         eglDestroySyncKHR = obtainEglDestroySyncKHR();
423     });
424     if (!eglDestroySyncKHR) {
425         ALOGE("Unable to resolve eglDestroySyncKHR");
426         return static_cast<jboolean>(false);
427     }
428 
429     auto display = reinterpret_cast<EGLDisplay *>(egl_display_ptr);
430     auto sync = reinterpret_cast<EGLSync>(sync_ptr);
431     return static_cast<jboolean>(eglDestroySyncKHR(display, sync));
432 }
433 
434 /**
435  * Helper method used in testing to verify if the eglGetNativeClientBufferANDROID method
436  * is actually supported on the Android device.
437  */
EGLBindings_nSupportsEglGetNativeClientBufferAndroid(JNIEnv * env,jclass)438 jboolean EGLBindings_nSupportsEglGetNativeClientBufferAndroid(
439         JNIEnv *env, jclass) {
440     return obtainEglGetNativeClientBufferANDROID() != nullptr;
441 }
442 
443 /**
444  * Helper method used in testing to verify if the eglCreateImageKHR method
445  * is actually supported on the Android device.
446  */
EGLBindings_nSupportsEglCreateImageKHR(JNIEnv * env,jclass)447 jboolean EGLBindings_nSupportsEglCreateImageKHR(JNIEnv *env, jclass) {
448     return obtainEglCreateImageKHR() != nullptr;
449 }
450 
451 /**
452  * Helper method used in testing to verify if the eglDestroyImageKHR method
453  * is actually supported on the Android device.
454  */
EGLBindings_nSupportsEglDestroyImageKHR(JNIEnv * env,jclass)455 jboolean EGLBindings_nSupportsEglDestroyImageKHR(JNIEnv *env, jclass) {
456     return obtainEglDestroyImageKHR() != nullptr;
457 }
458 
459 /**
460  * Helper method used in testing to verify if the glImageTargetTexture2DOES method
461  * is actually supported on the Android device.
462  */
EGLBindings_nSupportsGlImageTargetTexture2DOES(JNIEnv * env,jclass)463 jboolean EGLBindings_nSupportsGlImageTargetTexture2DOES(JNIEnv *env, jclass) {
464     return obtainGlImageTargetTexture2DOES() != nullptr;
465 }
466 
467 /**
468  * Helper method used in testing to verify if the eglCreateSyncKHR method is actually supported
469  * on the Android device
470  */
EGLBindings_nSupportsEglCreateSyncKHR(JNIEnv * env,jclass)471 jboolean EGLBindings_nSupportsEglCreateSyncKHR(JNIEnv *env, jclass) {
472     return obtainEglCreateSyncKHR() != nullptr;
473 }
474 
475 /**
476  * Helper method used in testing to verify if the eglDestroySyncKHR method is actually supported
477  * on the Android device
478  */
EGLBindings_nSupportsEglDestroySyncKHR(JNIEnv * env,jclass)479 jboolean EGLBindings_nSupportsEglDestroySyncKHR(JNIEnv *env, jclass) {
480     return obtainEglDestroySyncKHR() != nullptr;
481 }
482 
483 /**
484  * Helper method used in testing to verify if the eglDupNativeFenceFDAndroid methid is actually
485  * supported on the Android device
486  */
EGLBindings_nSupportsDupNativeFenceFDANDROID(JNIEnv * env,jclass)487 jboolean EGLBindings_nSupportsDupNativeFenceFDANDROID(JNIEnv *env, jclass) {
488     return obtainEglDupNativeFenceFDANDROID() != nullptr;
489 }
490 
491 /**
492  * Helper method used in testing to verify if the eglGetSyncAttribKHR method is actually supported
493  * on the Android device
494  */
EGLBindings_nSupportsEglGetSyncAttribKHR(JNIEnv * env,jclass)495 jboolean EGLBindings_nSupportsEglGetSyncAttribKHR(JNIEnv *env, jclass) {
496     return obtainEglGetSyncAttribKHR() != nullptr;
497 }
498 
499 /**
500  * Helper method used in testing to verify if the eglClientWaitSyncKHR method is actually supported
501  * on the Android device
502  */
EGLBindings_nSupportsEglClientWaitSyncKHR(JNIEnv * env,jclass)503 jboolean EGLBindings_nSupportsEglClientWaitSyncKHR(JNIEnv *env, jclass) {
504     return obtainEglClientWaitSyncKHR() != nullptr;
505 }
506 
507 /**
508  * Java does not support unsigned long types. Ensure that our casting of Java types the native
509  * equivalent matches.
510  */
EGLBindings_nEqualToNativeForeverTimeout(JNIEnv * env,jclass,jlong timeout_nanos)511 jboolean EGLBindings_nEqualToNativeForeverTimeout(JNIEnv *env, jclass, jlong timeout_nanos) {
512     return static_cast<EGLTimeKHR>(timeout_nanos) == EGL_FOREVER_KHR;
513 }
514 
515 static const JNINativeMethod EGL_METHOD_TABLE[] = {
516         {
517             "nCreateImageFromHardwareBuffer",
518             "(JLandroid/hardware/HardwareBuffer;)J",
519             (void*)EGLBindings_nCreateImageFromHardwareBuffer
520         },
521         {
522             "nDestroyImageKHR",
523             "(JJ)Z",
524             (void*)EGLBindings_nDestroyImageKHR
525         },
526         {
527             "nImageTargetTexture2DOES",
528             "(IJ)V",
529             (void*)EGLBindings_nImageTargetTexture2DOES
530         },
531         {
532             "nDupNativeFenceFDANDROID",
533             "(JJ)I",
534             (void*)EGLBindings_nDupNativeFenceFDANDROID
535         },
536         {
537             "nCreateSyncKHR",
538             "(JI[I)J",
539             (void*)EGLBindings_nCreateSyncKHR
540         },
541         {
542             "nGetSyncAttribKHR",
543             "(JJI[II)Z",
544             (void*)EGLBindings_nGetSyncAttribKHR
545         },
546         {
547             "nClientWaitSyncKHR",
548             "(JJIJ)I",
549             (void*)EGLBindings_nClientWaitSyncKHR
550         },
551         {
552             "nDestroySyncKHR",
553             "(JJ)Z",
554             (void*)EGLBindings_nDestroySyncKHR
555         },
556         {
557             "nSupportsEglGetNativeClientBufferAndroid",
558             "()Z",
559             (void*)EGLBindings_nSupportsEglGetNativeClientBufferAndroid
560         },
561         {
562             "nSupportsEglCreateImageKHR",
563             "()Z",
564             (void*)EGLBindings_nSupportsEglCreateImageKHR
565         },
566         {
567             "nSupportsEglDestroyImageKHR",
568             "()Z",
569             (void*)EGLBindings_nSupportsEglDestroyImageKHR
570         },
571         {
572             "nSupportsGlImageTargetTexture2DOES",
573             "()Z",
574             (void*)EGLBindings_nSupportsGlImageTargetTexture2DOES
575         },
576         {
577             "nSupportsEglCreateSyncKHR",
578             "()Z",
579             (void*)EGLBindings_nSupportsEglCreateSyncKHR
580         },
581         {
582             "nSupportsEglDestroySyncKHR",
583             "()Z",
584             (void*)EGLBindings_nSupportsEglDestroySyncKHR
585         },
586         {
587             "nSupportsDupNativeFenceFDANDROID",
588             "()Z",
589             (void*)EGLBindings_nSupportsDupNativeFenceFDANDROID
590         },
591         {
592             "nSupportsEglGetSyncAttribKHR",
593             "()Z",
594             (void*)EGLBindings_nSupportsEglGetSyncAttribKHR
595         },
596         {
597             "nSupportsEglClientWaitSyncKHR",
598             "()Z",
599             (void*)EGLBindings_nSupportsEglClientWaitSyncKHR
600         },
601         {
602             "nEqualToNativeForeverTimeout",
603             "(J)Z",
604             (void*)EGLBindings_nEqualToNativeForeverTimeout
605         }
606 };
607 
loadEGLMethods(JNIEnv * env)608 jint loadEGLMethods(JNIEnv* env) {
609     jclass eglBindingsClass = env->FindClass("androidx/opengl/EGLBindings");
610     if (eglBindingsClass == nullptr) {
611         return JNI_ERR;
612     }
613     if (env->RegisterNatives(eglBindingsClass, EGL_METHOD_TABLE,
614                              sizeof(EGL_METHOD_TABLE) / sizeof(JNINativeMethod)) != JNI_OK) {
615         return JNI_ERR;
616     }
617     return JNI_OK;
618 }