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 }