1 /*
2 ** Copyright 2007, 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 #include <ctype.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <dlfcn.h>
22
23 #include <sys/ioctl.h>
24
25 #if HAVE_ANDROID_OS
26 #include <linux/android_pmem.h>
27 #endif
28
29 #include <EGL/egl.h>
30 #include <EGL/eglext.h>
31 #include <GLES/gl.h>
32 #include <GLES/glext.h>
33
34 #include <cutils/log.h>
35 #include <cutils/atomic.h>
36 #include <cutils/properties.h>
37 #include <cutils/memory.h>
38
39 #include <utils/SortedVector.h>
40
41 #include "hooks.h"
42 #include "egl_impl.h"
43 #include "Loader.h"
44
45 #define MAKE_CONFIG(_impl, _index) ((EGLConfig)(((_impl)<<24) | (_index)))
46 #define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
47
48 // ----------------------------------------------------------------------------
49 namespace android {
50 // ----------------------------------------------------------------------------
51
52 #define VERSION_MAJOR 1
53 #define VERSION_MINOR 4
54 static char const * const gVendorString = "Android";
55 static char const * const gVersionString = "1.4 Android META-EGL";
56 static char const * const gClientApiString = "OpenGL ES";
57 static char const * const gExtensionString =
58 "EGL_KHR_image "
59 "EGL_KHR_image_base "
60 "EGL_KHR_image_pixmap "
61 "EGL_ANDROID_image_native_buffer "
62 "EGL_ANDROID_swap_rectangle "
63 "EGL_ANDROID_get_render_buffer "
64 ;
65
66 // ----------------------------------------------------------------------------
67
68 class egl_object_t {
69 static SortedVector<egl_object_t*> sObjects;
70 static Mutex sLock;
71
72 volatile int32_t terminated;
73 mutable volatile int32_t count;
74
75 public:
egl_object_t()76 egl_object_t() : terminated(0), count(1) {
77 Mutex::Autolock _l(sLock);
78 sObjects.add(this);
79 }
80
isAlive() const81 inline bool isAlive() const { return !terminated; }
82
83 private:
get()84 bool get() {
85 Mutex::Autolock _l(sLock);
86 if (egl_object_t::sObjects.indexOf(this) >= 0) {
87 android_atomic_inc(&count);
88 return true;
89 }
90 return false;
91 }
92
put()93 bool put() {
94 Mutex::Autolock _l(sLock);
95 if (android_atomic_dec(&count) == 1) {
96 sObjects.remove(this);
97 return true;
98 }
99 return false;
100 }
101
102 public:
103 template <typename N, typename T>
104 struct LocalRef {
105 N* ref;
LocalRefandroid::egl_object_t::LocalRef106 LocalRef(T o) : ref(0) {
107 N* native = reinterpret_cast<N*>(o);
108 if (o && native->get()) {
109 ref = native;
110 }
111 }
~LocalRefandroid::egl_object_t::LocalRef112 ~LocalRef() {
113 if (ref && ref->put()) {
114 delete ref;
115 }
116 }
getandroid::egl_object_t::LocalRef117 inline N* get() {
118 return ref;
119 }
acquireandroid::egl_object_t::LocalRef120 void acquire() const {
121 if (ref) {
122 android_atomic_inc(&ref->count);
123 }
124 }
releaseandroid::egl_object_t::LocalRef125 void release() const {
126 if (ref) {
127 int32_t c = android_atomic_dec(&ref->count);
128 // ref->count cannot be 1 prior atomic_dec because we have
129 // a reference, and if we have one, it means there was
130 // already one before us.
131 LOGE_IF(c==1, "refcount is now 0 in release()");
132 }
133 }
terminateandroid::egl_object_t::LocalRef134 void terminate() {
135 if (ref) {
136 ref->terminated = 1;
137 release();
138 }
139 }
140 };
141 };
142
143 SortedVector<egl_object_t*> egl_object_t::sObjects;
144 Mutex egl_object_t::sLock;
145
146 struct egl_display_t {
147 enum { NOT_INITIALIZED, INITIALIZED, TERMINATED };
148
149 struct strings_t {
150 char const * vendor;
151 char const * version;
152 char const * clientApi;
153 char const * extensions;
154 };
155
156 struct DisplayImpl {
DisplayImplandroid::egl_display_t::DisplayImpl157 DisplayImpl() : dpy(EGL_NO_DISPLAY), config(0),
158 state(NOT_INITIALIZED), numConfigs(0) { }
159 EGLDisplay dpy;
160 EGLConfig* config;
161 EGLint state;
162 EGLint numConfigs;
163 strings_t queryString;
164 };
165
166 uint32_t magic;
167 DisplayImpl disp[IMPL_NUM_IMPLEMENTATIONS];
168 EGLint numTotalConfigs;
169 volatile int32_t refs;
170
egl_display_tandroid::egl_display_t171 egl_display_t() : magic('_dpy'), numTotalConfigs(0) { }
~egl_display_tandroid::egl_display_t172 ~egl_display_t() { magic = 0; }
isValidandroid::egl_display_t173 inline bool isValid() const { return magic == '_dpy'; }
isAliveandroid::egl_display_t174 inline bool isAlive() const { return isValid(); }
175 };
176
177 struct egl_surface_t : public egl_object_t
178 {
179 typedef egl_object_t::LocalRef<egl_surface_t, EGLSurface> Ref;
180
egl_surface_tandroid::egl_surface_t181 egl_surface_t(EGLDisplay dpy, EGLSurface surface,
182 int impl, egl_connection_t const* cnx)
183 : dpy(dpy), surface(surface), impl(impl), cnx(cnx) {
184 }
~egl_surface_tandroid::egl_surface_t185 ~egl_surface_t() {
186 }
187 EGLDisplay dpy;
188 EGLSurface surface;
189 int impl;
190 egl_connection_t const* cnx;
191 };
192
193 struct egl_context_t : public egl_object_t
194 {
195 typedef egl_object_t::LocalRef<egl_context_t, EGLContext> Ref;
196
egl_context_tandroid::egl_context_t197 egl_context_t(EGLDisplay dpy, EGLContext context,
198 int impl, egl_connection_t const* cnx, int version)
199 : dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx),
200 version(version)
201 {
202 }
203 EGLDisplay dpy;
204 EGLContext context;
205 EGLSurface read;
206 EGLSurface draw;
207 int impl;
208 egl_connection_t const* cnx;
209 int version;
210 };
211
212 struct egl_image_t : public egl_object_t
213 {
214 typedef egl_object_t::LocalRef<egl_image_t, EGLImageKHR> Ref;
215
egl_image_tandroid::egl_image_t216 egl_image_t(EGLDisplay dpy, EGLContext context)
217 : dpy(dpy), context(context)
218 {
219 memset(images, 0, sizeof(images));
220 }
221 EGLDisplay dpy;
222 EGLConfig context;
223 EGLImageKHR images[IMPL_NUM_IMPLEMENTATIONS];
224 };
225
226 typedef egl_surface_t::Ref SurfaceRef;
227 typedef egl_context_t::Ref ContextRef;
228 typedef egl_image_t::Ref ImageRef;
229
230 struct tls_t
231 {
tls_tandroid::tls_t232 tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE) { }
233 EGLint error;
234 EGLContext ctx;
235 EGLBoolean logCallWithNoContext;
236 };
237
238
239 // ----------------------------------------------------------------------------
240
241 egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
242 static egl_display_t gDisplay[NUM_DISPLAYS];
243 static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
244 static pthread_key_t gEGLThreadLocalStorageKey = -1;
245
246 // ----------------------------------------------------------------------------
247
248 EGLAPI gl_hooks_t gHooks[2][IMPL_NUM_IMPLEMENTATIONS];
249 EGLAPI gl_hooks_t gHooksNoContext;
250 EGLAPI pthread_key_t gGLWrapperKey = -1;
251
252 // ----------------------------------------------------------------------------
253
254 static __attribute__((noinline))
egl_strerror(EGLint err)255 const char *egl_strerror(EGLint err)
256 {
257 switch (err){
258 case EGL_SUCCESS: return "EGL_SUCCESS";
259 case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
260 case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
261 case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
262 case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
263 case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
264 case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
265 case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
266 case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
267 case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
268 case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
269 case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
270 case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
271 case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
272 case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
273 default: return "UNKNOWN";
274 }
275 }
276
277 static __attribute__((noinline))
clearTLS()278 void clearTLS() {
279 if (gEGLThreadLocalStorageKey != -1) {
280 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
281 if (tls) {
282 delete tls;
283 pthread_setspecific(gEGLThreadLocalStorageKey, 0);
284 }
285 }
286 }
287
getTLS()288 static tls_t* getTLS()
289 {
290 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
291 if (tls == 0) {
292 tls = new tls_t;
293 pthread_setspecific(gEGLThreadLocalStorageKey, tls);
294 }
295 return tls;
296 }
297
298 template<typename T>
299 static __attribute__((noinline))
setErrorEtc(const char * caller,int line,EGLint error,T returnValue)300 T setErrorEtc(const char* caller, int line, EGLint error, T returnValue) {
301 if (gEGLThreadLocalStorageKey == -1) {
302 pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
303 if (gEGLThreadLocalStorageKey == -1)
304 pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
305 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
306 }
307 tls_t* tls = getTLS();
308 if (tls->error != error) {
309 LOGE("%s:%d error %x (%s)", caller, line, error, egl_strerror(error));
310 tls->error = error;
311 }
312 return returnValue;
313 }
314
315 static __attribute__((noinline))
getError()316 GLint getError() {
317 if (gEGLThreadLocalStorageKey == -1)
318 return EGL_SUCCESS;
319 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
320 if (!tls) return EGL_SUCCESS;
321 GLint error = tls->error;
322 tls->error = EGL_SUCCESS;
323 return error;
324 }
325
326 static __attribute__((noinline))
setContext(EGLContext ctx)327 void setContext(EGLContext ctx) {
328 if (gEGLThreadLocalStorageKey == -1) {
329 pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
330 if (gEGLThreadLocalStorageKey == -1)
331 pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
332 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
333 }
334 tls_t* tls = getTLS();
335 tls->ctx = ctx;
336 }
337
338 static __attribute__((noinline))
getContext()339 EGLContext getContext() {
340 if (gEGLThreadLocalStorageKey == -1)
341 return EGL_NO_CONTEXT;
342 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
343 if (!tls) return EGL_NO_CONTEXT;
344 return tls->ctx;
345 }
346
347 /*****************************************************************************/
348
349 template<typename T>
350 static __attribute__((noinline))
binarySearch(T const sortedArray[],int first,int last,T key)351 int binarySearch(
352 T const sortedArray[], int first, int last, T key)
353 {
354 while (first <= last) {
355 int mid = (first + last) / 2;
356 if (key > sortedArray[mid]) {
357 first = mid + 1;
358 } else if (key < sortedArray[mid]) {
359 last = mid - 1;
360 } else {
361 return mid;
362 }
363 }
364 return -1;
365 }
366
configToUniqueId(egl_display_t const * dp,int i,int index)367 static EGLint configToUniqueId(egl_display_t const* dp, int i, int index)
368 {
369 // NOTE: this mapping works only if we have no more than two EGLimpl
370 return (i>0 ? dp->disp[0].numConfigs : 0) + index;
371 }
372
uniqueIdToConfig(egl_display_t const * dp,EGLint configId,int & i,int & index)373 static void uniqueIdToConfig(egl_display_t const* dp, EGLint configId,
374 int& i, int& index)
375 {
376 // NOTE: this mapping works only if we have no more than two EGLimpl
377 size_t numConfigs = dp->disp[0].numConfigs;
378 i = configId / numConfigs;
379 index = configId % numConfigs;
380 }
381
cmp_configs(const void * a,const void * b)382 static int cmp_configs(const void* a, const void *b)
383 {
384 EGLConfig c0 = *(EGLConfig const *)a;
385 EGLConfig c1 = *(EGLConfig const *)b;
386 return c0<c1 ? -1 : (c0>c1 ? 1 : 0);
387 }
388
389 struct extention_map_t {
390 const char* name;
391 __eglMustCastToProperFunctionPointerType address;
392 };
393
394 static const extention_map_t gExtentionMap[] = {
395 { "eglLockSurfaceKHR",
396 (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
397 { "eglUnlockSurfaceKHR",
398 (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
399 { "eglCreateImageKHR",
400 (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
401 { "eglDestroyImageKHR",
402 (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
403 { "eglSetSwapRectangleANDROID",
404 (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
405 { "eglGetRenderBufferANDROID",
406 (__eglMustCastToProperFunctionPointerType)&eglGetRenderBufferANDROID },
407 };
408
409 static extention_map_t gGLExtentionMap[MAX_NUMBER_OF_GL_EXTENSIONS];
410
findProcAddress(const char * name,const extention_map_t * map,size_t n)411 static void(*findProcAddress(const char* name,
412 const extention_map_t* map, size_t n))()
413 {
414 for (uint32_t i=0 ; i<n ; i++) {
415 if (!strcmp(name, map[i].name)) {
416 return map[i].address;
417 }
418 }
419 return NULL;
420 }
421
422 // ----------------------------------------------------------------------------
423
gl_no_context()424 static void gl_no_context() {
425 tls_t* tls = getTLS();
426 if (tls->logCallWithNoContext == EGL_TRUE) {
427 tls->logCallWithNoContext = EGL_FALSE;
428 LOGE("call to OpenGL ES API with no current context "
429 "(logged once per thread)");
430 }
431 }
432
early_egl_init(void)433 static void early_egl_init(void)
434 {
435 #if !USE_FAST_TLS_KEY
436 pthread_key_create(&gGLWrapperKey, NULL);
437 #endif
438 uint32_t addr = (uint32_t)((void*)gl_no_context);
439 android_memset32(
440 (uint32_t*)(void*)&gHooksNoContext,
441 addr,
442 sizeof(gHooksNoContext));
443 setGlThreadSpecific(&gHooksNoContext);
444 }
445
446 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
447 static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
448
449
450 static inline
get_display(EGLDisplay dpy)451 egl_display_t* get_display(EGLDisplay dpy)
452 {
453 uintptr_t index = uintptr_t(dpy)-1U;
454 return (index >= NUM_DISPLAYS) ? NULL : &gDisplay[index];
455 }
456
457 template<typename NATIVE, typename EGL>
egl_to_native_cast(EGL arg)458 static inline NATIVE* egl_to_native_cast(EGL arg) {
459 return reinterpret_cast<NATIVE*>(arg);
460 }
461
462 static inline
get_surface(EGLSurface surface)463 egl_surface_t* get_surface(EGLSurface surface) {
464 return egl_to_native_cast<egl_surface_t>(surface);
465 }
466
467 static inline
get_context(EGLContext context)468 egl_context_t* get_context(EGLContext context) {
469 return egl_to_native_cast<egl_context_t>(context);
470 }
471
472 static inline
get_image(EGLImageKHR image)473 egl_image_t* get_image(EGLImageKHR image) {
474 return egl_to_native_cast<egl_image_t>(image);
475 }
476
validate_display_config(EGLDisplay dpy,EGLConfig config,egl_display_t const * & dp,int & impl,int & index)477 static egl_connection_t* validate_display_config(
478 EGLDisplay dpy, EGLConfig config,
479 egl_display_t const*& dp, int& impl, int& index)
480 {
481 dp = get_display(dpy);
482 if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
483
484 impl = uintptr_t(config)>>24;
485 if (uint32_t(impl) >= IMPL_NUM_IMPLEMENTATIONS) {
486 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
487 }
488 index = uintptr_t(config) & 0xFFFFFF;
489 if (index >= dp->disp[impl].numConfigs) {
490 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
491 }
492 egl_connection_t* const cnx = &gEGLImpl[impl];
493 if (cnx->dso == 0) {
494 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
495 }
496 return cnx;
497 }
498
validate_display_context(EGLDisplay dpy,EGLContext ctx)499 static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
500 {
501 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
502 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
503 if (!get_display(dpy)->isAlive())
504 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
505 if (!get_context(ctx)->isAlive())
506 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
507 return EGL_TRUE;
508 }
509
validate_display_surface(EGLDisplay dpy,EGLSurface surface)510 static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
511 {
512 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
513 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
514 if (!get_display(dpy)->isAlive())
515 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
516 if (!get_surface(surface)->isAlive())
517 return setError(EGL_BAD_SURFACE, EGL_FALSE);
518 return EGL_TRUE;
519 }
520
egl_get_image_for_current_context(EGLImageKHR image)521 EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image)
522 {
523 ImageRef _i(image);
524 if (!_i.get()) return EGL_NO_IMAGE_KHR;
525
526 EGLContext context = getContext();
527 if (context == EGL_NO_CONTEXT || image == EGL_NO_IMAGE_KHR)
528 return EGL_NO_IMAGE_KHR;
529
530 egl_context_t const * const c = get_context(context);
531 if (!c->isAlive())
532 return EGL_NO_IMAGE_KHR;
533
534 egl_image_t const * const i = get_image(image);
535 return i->images[c->impl];
536 }
537
538 // ----------------------------------------------------------------------------
539
540 // this mutex protects:
541 // d->disp[]
542 // egl_init_drivers_locked()
543 //
544 static pthread_mutex_t gInitDriverMutex = PTHREAD_MUTEX_INITIALIZER;
545
egl_init_drivers_locked()546 EGLBoolean egl_init_drivers_locked()
547 {
548 if (sEarlyInitState) {
549 // initialized by static ctor. should be set here.
550 return EGL_FALSE;
551 }
552
553 // get our driver loader
554 Loader& loader(Loader::getInstance());
555
556 // dynamically load all our EGL implementations for all displays
557 // and retrieve the corresponding EGLDisplay
558 // if that fails, don't use this driver.
559 // TODO: currently we only deal with EGL_DEFAULT_DISPLAY
560 egl_connection_t* cnx;
561 egl_display_t* d = &gDisplay[0];
562
563 cnx = &gEGLImpl[IMPL_SOFTWARE];
564 if (cnx->dso == 0) {
565 cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_SOFTWARE];
566 cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_SOFTWARE];
567 cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 0, cnx);
568 if (cnx->dso) {
569 EGLDisplay dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
570 LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for software EGL!");
571 d->disp[IMPL_SOFTWARE].dpy = dpy;
572 if (dpy == EGL_NO_DISPLAY) {
573 loader.close(cnx->dso);
574 cnx->dso = NULL;
575 }
576 }
577 }
578
579 cnx = &gEGLImpl[IMPL_HARDWARE];
580 if (cnx->dso == 0) {
581 char value[PROPERTY_VALUE_MAX];
582 property_get("debug.egl.hw", value, "1");
583 if (atoi(value) != 0) {
584 cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_HARDWARE];
585 cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_HARDWARE];
586 cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 1, cnx);
587 if (cnx->dso) {
588 EGLDisplay dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
589 LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for hardware EGL!");
590 d->disp[IMPL_HARDWARE].dpy = dpy;
591 if (dpy == EGL_NO_DISPLAY) {
592 loader.close(cnx->dso);
593 cnx->dso = NULL;
594 }
595 }
596 } else {
597 LOGD("3D hardware acceleration is disabled");
598 }
599 }
600
601 if (!gEGLImpl[IMPL_SOFTWARE].dso && !gEGLImpl[IMPL_HARDWARE].dso) {
602 return EGL_FALSE;
603 }
604
605 return EGL_TRUE;
606 }
607
egl_init_drivers()608 EGLBoolean egl_init_drivers()
609 {
610 EGLBoolean res;
611 pthread_mutex_lock(&gInitDriverMutex);
612 res = egl_init_drivers_locked();
613 pthread_mutex_unlock(&gInitDriverMutex);
614 return res;
615 }
616
617 // ----------------------------------------------------------------------------
618 }; // namespace android
619 // ----------------------------------------------------------------------------
620
621 using namespace android;
622
eglGetDisplay(NativeDisplayType display)623 EGLDisplay eglGetDisplay(NativeDisplayType display)
624 {
625 uint32_t index = uint32_t(display);
626 if (index >= NUM_DISPLAYS) {
627 return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
628 }
629
630 if (egl_init_drivers() == EGL_FALSE) {
631 return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
632 }
633
634 EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
635 return dpy;
636 }
637
638 // ----------------------------------------------------------------------------
639 // Initialization
640 // ----------------------------------------------------------------------------
641
eglInitialize(EGLDisplay dpy,EGLint * major,EGLint * minor)642 EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
643 {
644 egl_display_t * const dp = get_display(dpy);
645 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
646
647 if (android_atomic_inc(&dp->refs) > 0) {
648 if (major != NULL) *major = VERSION_MAJOR;
649 if (minor != NULL) *minor = VERSION_MINOR;
650 return EGL_TRUE;
651 }
652
653 setGlThreadSpecific(&gHooksNoContext);
654
655 // initialize each EGL and
656 // build our own extension string first, based on the extension we know
657 // and the extension supported by our client implementation
658 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
659 egl_connection_t* const cnx = &gEGLImpl[i];
660 cnx->major = -1;
661 cnx->minor = -1;
662 if (!cnx->dso)
663 continue;
664
665 #if defined(ADRENO130)
666 #warning "Adreno-130 eglInitialize() workaround"
667 /*
668 * The ADRENO 130 driver returns a different EGLDisplay each time
669 * eglGetDisplay() is called, but also makes the EGLDisplay invalid
670 * after eglTerminate() has been called, so that eglInitialize()
671 * cannot be called again. Therefore, we need to make sure to call
672 * eglGetDisplay() before calling eglInitialize();
673 */
674 if (i == IMPL_HARDWARE) {
675 dp->disp[i].dpy =
676 cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
677 }
678 #endif
679
680
681 EGLDisplay idpy = dp->disp[i].dpy;
682 if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) {
683 //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
684 // i, idpy, cnx->major, cnx->minor, cnx);
685
686 // display is now initialized
687 dp->disp[i].state = egl_display_t::INITIALIZED;
688
689 // get the query-strings for this display for each implementation
690 dp->disp[i].queryString.vendor =
691 cnx->egl.eglQueryString(idpy, EGL_VENDOR);
692 dp->disp[i].queryString.version =
693 cnx->egl.eglQueryString(idpy, EGL_VERSION);
694 dp->disp[i].queryString.extensions =
695 cnx->egl.eglQueryString(idpy, EGL_EXTENSIONS);
696 dp->disp[i].queryString.clientApi =
697 cnx->egl.eglQueryString(idpy, EGL_CLIENT_APIS);
698
699 } else {
700 LOGW("%d: eglInitialize(%p) failed (%s)", i, idpy,
701 egl_strerror(cnx->egl.eglGetError()));
702 }
703 }
704
705 EGLBoolean res = EGL_FALSE;
706 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
707 egl_connection_t* const cnx = &gEGLImpl[i];
708 if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
709 EGLint n;
710 if (cnx->egl.eglGetConfigs(dp->disp[i].dpy, 0, 0, &n)) {
711 dp->disp[i].config = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
712 if (dp->disp[i].config) {
713 if (cnx->egl.eglGetConfigs(
714 dp->disp[i].dpy, dp->disp[i].config, n,
715 &dp->disp[i].numConfigs))
716 {
717 // sort the configurations so we can do binary searches
718 qsort( dp->disp[i].config,
719 dp->disp[i].numConfigs,
720 sizeof(EGLConfig), cmp_configs);
721
722 dp->numTotalConfigs += n;
723 res = EGL_TRUE;
724 }
725 }
726 }
727 }
728 }
729
730 if (res == EGL_TRUE) {
731 if (major != NULL) *major = VERSION_MAJOR;
732 if (minor != NULL) *minor = VERSION_MINOR;
733 return EGL_TRUE;
734 }
735 return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
736 }
737
eglTerminate(EGLDisplay dpy)738 EGLBoolean eglTerminate(EGLDisplay dpy)
739 {
740 // NOTE: don't unload the drivers b/c some APIs can be called
741 // after eglTerminate() has been called. eglTerminate() only
742 // terminates an EGLDisplay, not a EGL itself.
743
744 egl_display_t* const dp = get_display(dpy);
745 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
746 if (android_atomic_dec(&dp->refs) != 1)
747 return EGL_TRUE;
748
749 EGLBoolean res = EGL_FALSE;
750 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
751 egl_connection_t* const cnx = &gEGLImpl[i];
752 if (cnx->dso && dp->disp[i].state == egl_display_t::INITIALIZED) {
753 if (cnx->egl.eglTerminate(dp->disp[i].dpy) == EGL_FALSE) {
754 LOGW("%d: eglTerminate(%p) failed (%s)", i, dp->disp[i].dpy,
755 egl_strerror(cnx->egl.eglGetError()));
756 }
757 // REVISIT: it's unclear what to do if eglTerminate() fails
758 free(dp->disp[i].config);
759
760 dp->disp[i].numConfigs = 0;
761 dp->disp[i].config = 0;
762 dp->disp[i].state = egl_display_t::TERMINATED;
763
764 res = EGL_TRUE;
765 }
766 }
767
768 // TODO: all egl_object_t should be marked for termination
769
770 dp->numTotalConfigs = 0;
771 clearTLS();
772 return res;
773 }
774
775 // ----------------------------------------------------------------------------
776 // configuration
777 // ----------------------------------------------------------------------------
778
eglGetConfigs(EGLDisplay dpy,EGLConfig * configs,EGLint config_size,EGLint * num_config)779 EGLBoolean eglGetConfigs( EGLDisplay dpy,
780 EGLConfig *configs,
781 EGLint config_size, EGLint *num_config)
782 {
783 egl_display_t const * const dp = get_display(dpy);
784 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
785
786 GLint numConfigs = dp->numTotalConfigs;
787 if (!configs) {
788 *num_config = numConfigs;
789 return EGL_TRUE;
790 }
791 GLint n = 0;
792 for (int j=0 ; j<IMPL_NUM_IMPLEMENTATIONS ; j++) {
793 for (int i=0 ; i<dp->disp[j].numConfigs && config_size ; i++) {
794 *configs++ = MAKE_CONFIG(j, i);
795 config_size--;
796 n++;
797 }
798 }
799
800 *num_config = n;
801 return EGL_TRUE;
802 }
803
eglChooseConfig(EGLDisplay dpy,const EGLint * attrib_list,EGLConfig * configs,EGLint config_size,EGLint * num_config)804 EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
805 EGLConfig *configs, EGLint config_size,
806 EGLint *num_config)
807 {
808 egl_display_t const * const dp = get_display(dpy);
809 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
810
811 if (num_config==0) {
812 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
813 }
814
815 EGLint n;
816 EGLBoolean res = EGL_FALSE;
817 *num_config = 0;
818
819
820 // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
821 // to do this, we have to go through the attrib_list array once
822 // to figure out both its size and if it contains an EGL_CONFIG_ID
823 // key. If so, the full array is copied and patched.
824 // NOTE: we assume that there can be only one occurrence
825 // of EGL_CONFIG_ID.
826
827 EGLint patch_index = -1;
828 GLint attr;
829 size_t size = 0;
830 while ((attr=attrib_list[size]) != EGL_NONE) {
831 if (attr == EGL_CONFIG_ID)
832 patch_index = size;
833 size += 2;
834 }
835 if (patch_index >= 0) {
836 size += 2; // we need copy the sentinel as well
837 EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
838 if (new_list == 0)
839 return setError(EGL_BAD_ALLOC, EGL_FALSE);
840 memcpy(new_list, attrib_list, size*sizeof(EGLint));
841
842 // patch the requested EGL_CONFIG_ID
843 int i, index;
844 EGLint& configId(new_list[patch_index+1]);
845 uniqueIdToConfig(dp, configId, i, index);
846
847 egl_connection_t* const cnx = &gEGLImpl[i];
848 if (cnx->dso) {
849 cnx->egl.eglGetConfigAttrib(
850 dp->disp[i].dpy, dp->disp[i].config[index],
851 EGL_CONFIG_ID, &configId);
852
853 // and switch to the new list
854 attrib_list = const_cast<const EGLint *>(new_list);
855
856 // At this point, the only configuration that can match is
857 // dp->configs[i][index], however, we don't know if it would be
858 // rejected because of the other attributes, so we do have to call
859 // cnx->egl.eglChooseConfig() -- but we don't have to loop
860 // through all the EGLimpl[].
861 // We also know we can only get a single config back, and we know
862 // which one.
863
864 res = cnx->egl.eglChooseConfig(
865 dp->disp[i].dpy, attrib_list, configs, config_size, &n);
866 if (res && n>0) {
867 // n has to be 0 or 1, by construction, and we already know
868 // which config it will return (since there can be only one).
869 if (configs) {
870 configs[0] = MAKE_CONFIG(i, index);
871 }
872 *num_config = 1;
873 }
874 }
875
876 free(const_cast<EGLint *>(attrib_list));
877 return res;
878 }
879
880 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
881 egl_connection_t* const cnx = &gEGLImpl[i];
882 if (cnx->dso) {
883 if (cnx->egl.eglChooseConfig(
884 dp->disp[i].dpy, attrib_list, configs, config_size, &n)) {
885 if (configs) {
886 // now we need to convert these client EGLConfig to our
887 // internal EGLConfig format. This is done in O(n log n).
888 for (int j=0 ; j<n ; j++) {
889 int index = binarySearch<EGLConfig>(
890 dp->disp[i].config, 0,
891 dp->disp[i].numConfigs-1, configs[j]);
892 if (index >= 0) {
893 if (configs) {
894 configs[j] = MAKE_CONFIG(i, index);
895 }
896 } else {
897 return setError(EGL_BAD_CONFIG, EGL_FALSE);
898 }
899 }
900 configs += n;
901 config_size -= n;
902 }
903 *num_config += n;
904 res = EGL_TRUE;
905 }
906 }
907 }
908 return res;
909 }
910
eglGetConfigAttrib(EGLDisplay dpy,EGLConfig config,EGLint attribute,EGLint * value)911 EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
912 EGLint attribute, EGLint *value)
913 {
914 egl_display_t const* dp = 0;
915 int i=0, index=0;
916 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
917 if (!cnx) return EGL_FALSE;
918
919 if (attribute == EGL_CONFIG_ID) {
920 // EGL_CONFIG_IDs must be unique, just use the order of the selected
921 // EGLConfig.
922 *value = configToUniqueId(dp, i, index);
923 return EGL_TRUE;
924 }
925 return cnx->egl.eglGetConfigAttrib(
926 dp->disp[i].dpy, dp->disp[i].config[index], attribute, value);
927 }
928
929 // ----------------------------------------------------------------------------
930 // surfaces
931 // ----------------------------------------------------------------------------
932
eglCreateWindowSurface(EGLDisplay dpy,EGLConfig config,NativeWindowType window,const EGLint * attrib_list)933 EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
934 NativeWindowType window,
935 const EGLint *attrib_list)
936 {
937 egl_display_t const* dp = 0;
938 int i=0, index=0;
939 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
940 if (cnx) {
941 EGLSurface surface = cnx->egl.eglCreateWindowSurface(
942 dp->disp[i].dpy, dp->disp[i].config[index], window, attrib_list);
943 if (surface != EGL_NO_SURFACE) {
944 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
945 return s;
946 }
947 }
948 return EGL_NO_SURFACE;
949 }
950
eglCreatePixmapSurface(EGLDisplay dpy,EGLConfig config,NativePixmapType pixmap,const EGLint * attrib_list)951 EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
952 NativePixmapType pixmap,
953 const EGLint *attrib_list)
954 {
955 egl_display_t const* dp = 0;
956 int i=0, index=0;
957 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
958 if (cnx) {
959 EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
960 dp->disp[i].dpy, dp->disp[i].config[index], pixmap, attrib_list);
961 if (surface != EGL_NO_SURFACE) {
962 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
963 return s;
964 }
965 }
966 return EGL_NO_SURFACE;
967 }
968
eglCreatePbufferSurface(EGLDisplay dpy,EGLConfig config,const EGLint * attrib_list)969 EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
970 const EGLint *attrib_list)
971 {
972 egl_display_t const* dp = 0;
973 int i=0, index=0;
974 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
975 if (cnx) {
976 EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
977 dp->disp[i].dpy, dp->disp[i].config[index], attrib_list);
978 if (surface != EGL_NO_SURFACE) {
979 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
980 return s;
981 }
982 }
983 return EGL_NO_SURFACE;
984 }
985
eglDestroySurface(EGLDisplay dpy,EGLSurface surface)986 EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
987 {
988 SurfaceRef _s(surface);
989 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
990
991 if (!validate_display_surface(dpy, surface))
992 return EGL_FALSE;
993 egl_display_t const * const dp = get_display(dpy);
994
995 egl_surface_t * const s = get_surface(surface);
996 EGLBoolean result = s->cnx->egl.eglDestroySurface(
997 dp->disp[s->impl].dpy, s->surface);
998 if (result == EGL_TRUE) {
999 _s.terminate();
1000 }
1001 return result;
1002 }
1003
eglQuerySurface(EGLDisplay dpy,EGLSurface surface,EGLint attribute,EGLint * value)1004 EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
1005 EGLint attribute, EGLint *value)
1006 {
1007 SurfaceRef _s(surface);
1008 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1009
1010 if (!validate_display_surface(dpy, surface))
1011 return EGL_FALSE;
1012 egl_display_t const * const dp = get_display(dpy);
1013 egl_surface_t const * const s = get_surface(surface);
1014
1015 return s->cnx->egl.eglQuerySurface(
1016 dp->disp[s->impl].dpy, s->surface, attribute, value);
1017 }
1018
1019 // ----------------------------------------------------------------------------
1020 // contextes
1021 // ----------------------------------------------------------------------------
1022
eglCreateContext(EGLDisplay dpy,EGLConfig config,EGLContext share_list,const EGLint * attrib_list)1023 EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
1024 EGLContext share_list, const EGLint *attrib_list)
1025 {
1026 egl_display_t const* dp = 0;
1027 int i=0, index=0;
1028 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1029 if (cnx) {
1030 EGLContext context = cnx->egl.eglCreateContext(
1031 dp->disp[i].dpy, dp->disp[i].config[index],
1032 share_list, attrib_list);
1033 if (context != EGL_NO_CONTEXT) {
1034 // figure out if it's a GLESv1 or GLESv2
1035 int version = 0;
1036 if (attrib_list) {
1037 while (*attrib_list != EGL_NONE) {
1038 GLint attr = *attrib_list++;
1039 GLint value = *attrib_list++;
1040 if (attr == EGL_CONTEXT_CLIENT_VERSION) {
1041 if (value == 1) {
1042 version = GLESv1_INDEX;
1043 } else if (value == 2) {
1044 version = GLESv2_INDEX;
1045 }
1046 }
1047 };
1048 }
1049 egl_context_t* c = new egl_context_t(dpy, context, i, cnx, version);
1050 return c;
1051 }
1052 }
1053 return EGL_NO_CONTEXT;
1054 }
1055
eglDestroyContext(EGLDisplay dpy,EGLContext ctx)1056 EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
1057 {
1058 ContextRef _c(ctx);
1059 if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1060
1061 if (!validate_display_context(dpy, ctx))
1062 return EGL_FALSE;
1063 egl_display_t const * const dp = get_display(dpy);
1064 egl_context_t * const c = get_context(ctx);
1065 EGLBoolean result = c->cnx->egl.eglDestroyContext(
1066 dp->disp[c->impl].dpy, c->context);
1067 if (result == EGL_TRUE) {
1068 _c.terminate();
1069 }
1070 return result;
1071 }
1072
eglMakeCurrent(EGLDisplay dpy,EGLSurface draw,EGLSurface read,EGLContext ctx)1073 EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
1074 EGLSurface read, EGLContext ctx)
1075 {
1076 // get a reference to the object passed in
1077 ContextRef _c(ctx);
1078 SurfaceRef _d(draw);
1079 SurfaceRef _r(read);
1080
1081 // validate the display and the context (if not EGL_NO_CONTEXT)
1082 egl_display_t const * const dp = get_display(dpy);
1083 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1084 if ((ctx != EGL_NO_CONTEXT) && (!validate_display_context(dpy, ctx))) {
1085 // EGL_NO_CONTEXT is valid
1086 return EGL_FALSE;
1087 }
1088
1089 // these are the underlying implementation's object
1090 EGLContext impl_ctx = EGL_NO_CONTEXT;
1091 EGLSurface impl_draw = EGL_NO_SURFACE;
1092 EGLSurface impl_read = EGL_NO_SURFACE;
1093
1094 // these are our objects structs passed in
1095 egl_context_t * c = NULL;
1096 egl_surface_t const * d = NULL;
1097 egl_surface_t const * r = NULL;
1098
1099 // these are the current objects structs
1100 egl_context_t * cur_c = get_context(getContext());
1101 egl_surface_t * cur_r = NULL;
1102 egl_surface_t * cur_d = NULL;
1103
1104 if (ctx != EGL_NO_CONTEXT) {
1105 c = get_context(ctx);
1106 cur_r = get_surface(c->read);
1107 cur_d = get_surface(c->draw);
1108 impl_ctx = c->context;
1109 } else {
1110 // no context given, use the implementation of the current context
1111 if (cur_c == NULL) {
1112 // no current context
1113 if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
1114 // calling eglMakeCurrent( ..., EGL_NO_CONTEXT, !=0, !=0);
1115 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1116 }
1117 // not an error, there is just not current context.
1118 return EGL_TRUE;
1119 }
1120 }
1121
1122 // retrieve the underlying implementation's draw EGLSurface
1123 if (draw != EGL_NO_SURFACE) {
1124 d = get_surface(draw);
1125 // make sure the EGLContext and EGLSurface passed in are for
1126 // the same driver
1127 if (c && d->impl != c->impl)
1128 return setError(EGL_BAD_MATCH, EGL_FALSE);
1129 impl_draw = d->surface;
1130 }
1131
1132 // retrieve the underlying implementation's read EGLSurface
1133 if (read != EGL_NO_SURFACE) {
1134 r = get_surface(read);
1135 // make sure the EGLContext and EGLSurface passed in are for
1136 // the same driver
1137 if (c && r->impl != c->impl)
1138 return setError(EGL_BAD_MATCH, EGL_FALSE);
1139 impl_read = r->surface;
1140 }
1141
1142 EGLBoolean result;
1143
1144 if (c) {
1145 result = c->cnx->egl.eglMakeCurrent(
1146 dp->disp[c->impl].dpy, impl_draw, impl_read, impl_ctx);
1147 } else {
1148 result = cur_c->cnx->egl.eglMakeCurrent(
1149 dp->disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx);
1150 }
1151
1152 if (result == EGL_TRUE) {
1153 // by construction, these are either 0 or valid (possibly terminated)
1154 // it should be impossible for these to be invalid
1155 ContextRef _cur_c(cur_c);
1156 SurfaceRef _cur_r(cur_r);
1157 SurfaceRef _cur_d(cur_d);
1158
1159 // cur_c has to be valid here (but could be terminated)
1160 if (ctx != EGL_NO_CONTEXT) {
1161 setGlThreadSpecific(c->cnx->hooks[c->version]);
1162 setContext(ctx);
1163 _c.acquire();
1164 } else {
1165 setGlThreadSpecific(&gHooksNoContext);
1166 setContext(EGL_NO_CONTEXT);
1167 }
1168 _cur_c.release();
1169
1170 _r.acquire();
1171 _cur_r.release();
1172 if (c) c->read = read;
1173
1174 _d.acquire();
1175 _cur_d.release();
1176 if (c) c->draw = draw;
1177 }
1178 return result;
1179 }
1180
1181
eglQueryContext(EGLDisplay dpy,EGLContext ctx,EGLint attribute,EGLint * value)1182 EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1183 EGLint attribute, EGLint *value)
1184 {
1185 ContextRef _c(ctx);
1186 if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1187
1188 if (!validate_display_context(dpy, ctx))
1189 return EGL_FALSE;
1190
1191 egl_display_t const * const dp = get_display(dpy);
1192 egl_context_t * const c = get_context(ctx);
1193
1194 return c->cnx->egl.eglQueryContext(
1195 dp->disp[c->impl].dpy, c->context, attribute, value);
1196 }
1197
eglGetCurrentContext(void)1198 EGLContext eglGetCurrentContext(void)
1199 {
1200 // could be called before eglInitialize(), but we wouldn't have a context
1201 // then, and this function would correctly return EGL_NO_CONTEXT.
1202
1203 EGLContext ctx = getContext();
1204 return ctx;
1205 }
1206
eglGetCurrentSurface(EGLint readdraw)1207 EGLSurface eglGetCurrentSurface(EGLint readdraw)
1208 {
1209 // could be called before eglInitialize(), but we wouldn't have a context
1210 // then, and this function would correctly return EGL_NO_SURFACE.
1211
1212 EGLContext ctx = getContext();
1213 if (ctx) {
1214 egl_context_t const * const c = get_context(ctx);
1215 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1216 switch (readdraw) {
1217 case EGL_READ: return c->read;
1218 case EGL_DRAW: return c->draw;
1219 default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1220 }
1221 }
1222 return EGL_NO_SURFACE;
1223 }
1224
eglGetCurrentDisplay(void)1225 EGLDisplay eglGetCurrentDisplay(void)
1226 {
1227 // could be called before eglInitialize(), but we wouldn't have a context
1228 // then, and this function would correctly return EGL_NO_DISPLAY.
1229
1230 EGLContext ctx = getContext();
1231 if (ctx) {
1232 egl_context_t const * const c = get_context(ctx);
1233 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1234 return c->dpy;
1235 }
1236 return EGL_NO_DISPLAY;
1237 }
1238
eglWaitGL(void)1239 EGLBoolean eglWaitGL(void)
1240 {
1241 // could be called before eglInitialize(), but we wouldn't have a context
1242 // then, and this function would return GL_TRUE, which isn't wrong.
1243
1244 EGLBoolean res = EGL_TRUE;
1245 EGLContext ctx = getContext();
1246 if (ctx) {
1247 egl_context_t const * const c = get_context(ctx);
1248 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1249 if (uint32_t(c->impl)>=2)
1250 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1251 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1252 if (!cnx->dso)
1253 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1254 res = cnx->egl.eglWaitGL();
1255 }
1256 return res;
1257 }
1258
eglWaitNative(EGLint engine)1259 EGLBoolean eglWaitNative(EGLint engine)
1260 {
1261 // could be called before eglInitialize(), but we wouldn't have a context
1262 // then, and this function would return GL_TRUE, which isn't wrong.
1263
1264 EGLBoolean res = EGL_TRUE;
1265 EGLContext ctx = getContext();
1266 if (ctx) {
1267 egl_context_t const * const c = get_context(ctx);
1268 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1269 if (uint32_t(c->impl)>=2)
1270 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1271 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1272 if (!cnx->dso)
1273 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1274 res = cnx->egl.eglWaitNative(engine);
1275 }
1276 return res;
1277 }
1278
eglGetError(void)1279 EGLint eglGetError(void)
1280 {
1281 EGLint result = EGL_SUCCESS;
1282 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1283 EGLint err = EGL_SUCCESS;
1284 egl_connection_t* const cnx = &gEGLImpl[i];
1285 if (cnx->dso)
1286 err = cnx->egl.eglGetError();
1287 if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
1288 result = err;
1289 }
1290 if (result == EGL_SUCCESS)
1291 result = getError();
1292 return result;
1293 }
1294
eglGetProcAddress(const char * procname)1295 __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
1296 {
1297 // eglGetProcAddress() could be the very first function called
1298 // in which case we must make sure we've initialized ourselves, this
1299 // happens the first time egl_get_display() is called.
1300
1301 if (egl_init_drivers() == EGL_FALSE) {
1302 setError(EGL_BAD_PARAMETER, NULL);
1303 return NULL;
1304 }
1305
1306 __eglMustCastToProperFunctionPointerType addr;
1307 addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
1308 if (addr) return addr;
1309
1310 return NULL; // TODO: finish implementation below
1311
1312 addr = findProcAddress(procname, gGLExtentionMap, NELEM(gGLExtentionMap));
1313 if (addr) return addr;
1314
1315 addr = 0;
1316 int slot = -1;
1317 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1318 egl_connection_t* const cnx = &gEGLImpl[i];
1319 if (cnx->dso) {
1320 if (cnx->egl.eglGetProcAddress) {
1321 addr = cnx->egl.eglGetProcAddress(procname);
1322 if (addr) {
1323 if (slot == -1) {
1324 slot = 0; // XXX: find free slot
1325 if (slot == -1) {
1326 addr = 0;
1327 break;
1328 }
1329 }
1330 //cnx->hooks->ext.extensions[slot] = addr;
1331 }
1332 }
1333 }
1334 }
1335
1336 if (slot >= 0) {
1337 addr = 0; // XXX: address of stub 'slot'
1338 gGLExtentionMap[slot].name = strdup(procname);
1339 gGLExtentionMap[slot].address = addr;
1340 }
1341
1342 return addr;
1343
1344
1345 /*
1346 * TODO: For OpenGL ES extensions, we must generate a stub
1347 * that looks like
1348 * mov r12, #0xFFFF0FFF
1349 * ldr r12, [r12, #-15]
1350 * ldr r12, [r12, #TLS_SLOT_OPENGL_API*4]
1351 * mov r12, [r12, #api_offset]
1352 * ldrne pc, r12
1353 * mov pc, #unsupported_extension
1354 *
1355 * and write the address of the extension in *all*
1356 * gl_hooks_t::gl_ext_t at offset "api_offset" from gl_hooks_t
1357 *
1358 */
1359 }
1360
eglSwapBuffers(EGLDisplay dpy,EGLSurface draw)1361 EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1362 {
1363 SurfaceRef _s(draw);
1364 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1365
1366 if (!validate_display_surface(dpy, draw))
1367 return EGL_FALSE;
1368 egl_display_t const * const dp = get_display(dpy);
1369 egl_surface_t const * const s = get_surface(draw);
1370 return s->cnx->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface);
1371 }
1372
eglCopyBuffers(EGLDisplay dpy,EGLSurface surface,NativePixmapType target)1373 EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
1374 NativePixmapType target)
1375 {
1376 SurfaceRef _s(surface);
1377 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1378
1379 if (!validate_display_surface(dpy, surface))
1380 return EGL_FALSE;
1381 egl_display_t const * const dp = get_display(dpy);
1382 egl_surface_t const * const s = get_surface(surface);
1383 return s->cnx->egl.eglCopyBuffers(
1384 dp->disp[s->impl].dpy, s->surface, target);
1385 }
1386
eglQueryString(EGLDisplay dpy,EGLint name)1387 const char* eglQueryString(EGLDisplay dpy, EGLint name)
1388 {
1389 egl_display_t const * const dp = get_display(dpy);
1390 switch (name) {
1391 case EGL_VENDOR:
1392 return gVendorString;
1393 case EGL_VERSION:
1394 return gVersionString;
1395 case EGL_EXTENSIONS:
1396 return gExtensionString;
1397 case EGL_CLIENT_APIS:
1398 return gClientApiString;
1399 }
1400 return setError(EGL_BAD_PARAMETER, (const char *)0);
1401 }
1402
1403
1404 // ----------------------------------------------------------------------------
1405 // EGL 1.1
1406 // ----------------------------------------------------------------------------
1407
eglSurfaceAttrib(EGLDisplay dpy,EGLSurface surface,EGLint attribute,EGLint value)1408 EGLBoolean eglSurfaceAttrib(
1409 EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1410 {
1411 SurfaceRef _s(surface);
1412 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1413
1414 if (!validate_display_surface(dpy, surface))
1415 return EGL_FALSE;
1416 egl_display_t const * const dp = get_display(dpy);
1417 egl_surface_t const * const s = get_surface(surface);
1418 if (s->cnx->egl.eglSurfaceAttrib) {
1419 return s->cnx->egl.eglSurfaceAttrib(
1420 dp->disp[s->impl].dpy, s->surface, attribute, value);
1421 }
1422 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1423 }
1424
eglBindTexImage(EGLDisplay dpy,EGLSurface surface,EGLint buffer)1425 EGLBoolean eglBindTexImage(
1426 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1427 {
1428 SurfaceRef _s(surface);
1429 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1430
1431 if (!validate_display_surface(dpy, surface))
1432 return EGL_FALSE;
1433 egl_display_t const * const dp = get_display(dpy);
1434 egl_surface_t const * const s = get_surface(surface);
1435 if (s->cnx->egl.eglBindTexImage) {
1436 return s->cnx->egl.eglBindTexImage(
1437 dp->disp[s->impl].dpy, s->surface, buffer);
1438 }
1439 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1440 }
1441
eglReleaseTexImage(EGLDisplay dpy,EGLSurface surface,EGLint buffer)1442 EGLBoolean eglReleaseTexImage(
1443 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1444 {
1445 SurfaceRef _s(surface);
1446 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1447
1448 if (!validate_display_surface(dpy, surface))
1449 return EGL_FALSE;
1450 egl_display_t const * const dp = get_display(dpy);
1451 egl_surface_t const * const s = get_surface(surface);
1452 if (s->cnx->egl.eglReleaseTexImage) {
1453 return s->cnx->egl.eglReleaseTexImage(
1454 dp->disp[s->impl].dpy, s->surface, buffer);
1455 }
1456 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1457 }
1458
eglSwapInterval(EGLDisplay dpy,EGLint interval)1459 EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1460 {
1461 egl_display_t * const dp = get_display(dpy);
1462 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1463
1464 EGLBoolean res = EGL_TRUE;
1465 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1466 egl_connection_t* const cnx = &gEGLImpl[i];
1467 if (cnx->dso) {
1468 if (cnx->egl.eglSwapInterval) {
1469 if (cnx->egl.eglSwapInterval(
1470 dp->disp[i].dpy, interval) == EGL_FALSE) {
1471 res = EGL_FALSE;
1472 }
1473 }
1474 }
1475 }
1476 return res;
1477 }
1478
1479
1480 // ----------------------------------------------------------------------------
1481 // EGL 1.2
1482 // ----------------------------------------------------------------------------
1483
eglWaitClient(void)1484 EGLBoolean eglWaitClient(void)
1485 {
1486 // could be called before eglInitialize(), but we wouldn't have a context
1487 // then, and this function would return GL_TRUE, which isn't wrong.
1488 EGLBoolean res = EGL_TRUE;
1489 EGLContext ctx = getContext();
1490 if (ctx) {
1491 egl_context_t const * const c = get_context(ctx);
1492 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1493 if (uint32_t(c->impl)>=2)
1494 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1495 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1496 if (!cnx->dso)
1497 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1498 if (cnx->egl.eglWaitClient) {
1499 res = cnx->egl.eglWaitClient();
1500 } else {
1501 res = cnx->egl.eglWaitGL();
1502 }
1503 }
1504 return res;
1505 }
1506
eglBindAPI(EGLenum api)1507 EGLBoolean eglBindAPI(EGLenum api)
1508 {
1509 if (egl_init_drivers() == EGL_FALSE) {
1510 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1511 }
1512
1513 // bind this API on all EGLs
1514 EGLBoolean res = EGL_TRUE;
1515 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1516 egl_connection_t* const cnx = &gEGLImpl[i];
1517 if (cnx->dso) {
1518 if (cnx->egl.eglBindAPI) {
1519 if (cnx->egl.eglBindAPI(api) == EGL_FALSE) {
1520 res = EGL_FALSE;
1521 }
1522 }
1523 }
1524 }
1525 return res;
1526 }
1527
eglQueryAPI(void)1528 EGLenum eglQueryAPI(void)
1529 {
1530 if (egl_init_drivers() == EGL_FALSE) {
1531 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1532 }
1533
1534 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1535 egl_connection_t* const cnx = &gEGLImpl[i];
1536 if (cnx->dso) {
1537 if (cnx->egl.eglQueryAPI) {
1538 // the first one we find is okay, because they all
1539 // should be the same
1540 return cnx->egl.eglQueryAPI();
1541 }
1542 }
1543 }
1544 // or, it can only be OpenGL ES
1545 return EGL_OPENGL_ES_API;
1546 }
1547
eglReleaseThread(void)1548 EGLBoolean eglReleaseThread(void)
1549 {
1550 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1551 egl_connection_t* const cnx = &gEGLImpl[i];
1552 if (cnx->dso) {
1553 if (cnx->egl.eglReleaseThread) {
1554 cnx->egl.eglReleaseThread();
1555 }
1556 }
1557 }
1558 clearTLS();
1559 return EGL_TRUE;
1560 }
1561
eglCreatePbufferFromClientBuffer(EGLDisplay dpy,EGLenum buftype,EGLClientBuffer buffer,EGLConfig config,const EGLint * attrib_list)1562 EGLSurface eglCreatePbufferFromClientBuffer(
1563 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1564 EGLConfig config, const EGLint *attrib_list)
1565 {
1566 egl_display_t const* dp = 0;
1567 int i=0, index=0;
1568 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1569 if (!cnx) return EGL_FALSE;
1570 if (cnx->egl.eglCreatePbufferFromClientBuffer) {
1571 return cnx->egl.eglCreatePbufferFromClientBuffer(
1572 dp->disp[i].dpy, buftype, buffer,
1573 dp->disp[i].config[index], attrib_list);
1574 }
1575 return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1576 }
1577
1578 // ----------------------------------------------------------------------------
1579 // EGL_EGLEXT_VERSION 3
1580 // ----------------------------------------------------------------------------
1581
eglLockSurfaceKHR(EGLDisplay dpy,EGLSurface surface,const EGLint * attrib_list)1582 EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1583 const EGLint *attrib_list)
1584 {
1585 SurfaceRef _s(surface);
1586 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1587
1588 if (!validate_display_surface(dpy, surface))
1589 return EGL_FALSE;
1590
1591 egl_display_t const * const dp = get_display(dpy);
1592 egl_surface_t const * const s = get_surface(surface);
1593
1594 if (s->cnx->egl.eglLockSurfaceKHR) {
1595 return s->cnx->egl.eglLockSurfaceKHR(
1596 dp->disp[s->impl].dpy, s->surface, attrib_list);
1597 }
1598 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1599 }
1600
eglUnlockSurfaceKHR(EGLDisplay dpy,EGLSurface surface)1601 EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
1602 {
1603 SurfaceRef _s(surface);
1604 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1605
1606 if (!validate_display_surface(dpy, surface))
1607 return EGL_FALSE;
1608
1609 egl_display_t const * const dp = get_display(dpy);
1610 egl_surface_t const * const s = get_surface(surface);
1611
1612 if (s->cnx->egl.eglUnlockSurfaceKHR) {
1613 return s->cnx->egl.eglUnlockSurfaceKHR(
1614 dp->disp[s->impl].dpy, s->surface);
1615 }
1616 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1617 }
1618
eglCreateImageKHR(EGLDisplay dpy,EGLContext ctx,EGLenum target,EGLClientBuffer buffer,const EGLint * attrib_list)1619 EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1620 EGLClientBuffer buffer, const EGLint *attrib_list)
1621 {
1622 if (ctx != EGL_NO_CONTEXT) {
1623 ContextRef _c(ctx);
1624 if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
1625 if (!validate_display_context(dpy, ctx))
1626 return EGL_NO_IMAGE_KHR;
1627 egl_display_t const * const dp = get_display(dpy);
1628 egl_context_t * const c = get_context(ctx);
1629 // since we have an EGLContext, we know which implementation to use
1630 EGLImageKHR image = c->cnx->egl.eglCreateImageKHR(
1631 dp->disp[c->impl].dpy, c->context, target, buffer, attrib_list);
1632 if (image == EGL_NO_IMAGE_KHR)
1633 return image;
1634
1635 egl_image_t* result = new egl_image_t(dpy, ctx);
1636 result->images[c->impl] = image;
1637 return (EGLImageKHR)result;
1638 } else {
1639 // EGL_NO_CONTEXT is a valid parameter
1640 egl_display_t const * const dp = get_display(dpy);
1641 if (dp == 0) {
1642 return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
1643 }
1644
1645 /* Since we don't have a way to know which implementation to call,
1646 * we're calling all of them. If at least one of the implementation
1647 * succeeded, this is a success.
1648 */
1649
1650 EGLint currentError = eglGetError();
1651
1652 EGLImageKHR implImages[IMPL_NUM_IMPLEMENTATIONS];
1653 bool success = false;
1654 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1655 egl_connection_t* const cnx = &gEGLImpl[i];
1656 implImages[i] = EGL_NO_IMAGE_KHR;
1657 if (cnx->dso) {
1658 if (cnx->egl.eglCreateImageKHR) {
1659 implImages[i] = cnx->egl.eglCreateImageKHR(
1660 dp->disp[i].dpy, ctx, target, buffer, attrib_list);
1661 if (implImages[i] != EGL_NO_IMAGE_KHR) {
1662 success = true;
1663 }
1664 }
1665 }
1666 }
1667
1668 if (!success) {
1669 // failure, if there was an error when we entered this function,
1670 // the error flag must not be updated.
1671 // Otherwise, the error is whatever happened in the implementation
1672 // that faulted.
1673 if (currentError != EGL_SUCCESS) {
1674 setError(currentError, EGL_NO_IMAGE_KHR);
1675 }
1676 return EGL_NO_IMAGE_KHR;
1677 } else {
1678 // In case of success, we need to clear all error flags
1679 // (especially those caused by the implementation that didn't
1680 // succeed). TODO: we could avoid this if we knew this was
1681 // a "full" success (all implementation succeeded).
1682 eglGetError();
1683 }
1684
1685 egl_image_t* result = new egl_image_t(dpy, ctx);
1686 memcpy(result->images, implImages, sizeof(implImages));
1687 return (EGLImageKHR)result;
1688 }
1689 }
1690
eglDestroyImageKHR(EGLDisplay dpy,EGLImageKHR img)1691 EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1692 {
1693 egl_display_t const * const dp = get_display(dpy);
1694 if (dp == 0) {
1695 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1696 }
1697
1698 ImageRef _i(img);
1699 if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1700
1701 egl_image_t* image = get_image(img);
1702 bool success = false;
1703 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1704 egl_connection_t* const cnx = &gEGLImpl[i];
1705 if (image->images[i] != EGL_NO_IMAGE_KHR) {
1706 if (cnx->dso) {
1707 if (cnx->egl.eglCreateImageKHR) {
1708 if (cnx->egl.eglDestroyImageKHR(
1709 dp->disp[i].dpy, image->images[i])) {
1710 success = true;
1711 }
1712 }
1713 }
1714 }
1715 }
1716 if (!success)
1717 return EGL_FALSE;
1718
1719 _i.terminate();
1720
1721 return EGL_TRUE;
1722 }
1723
1724
1725 // ----------------------------------------------------------------------------
1726 // ANDROID extensions
1727 // ----------------------------------------------------------------------------
1728
eglSetSwapRectangleANDROID(EGLDisplay dpy,EGLSurface draw,EGLint left,EGLint top,EGLint width,EGLint height)1729 EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
1730 EGLint left, EGLint top, EGLint width, EGLint height)
1731 {
1732 SurfaceRef _s(draw);
1733 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1734
1735 if (!validate_display_surface(dpy, draw))
1736 return EGL_FALSE;
1737 egl_display_t const * const dp = get_display(dpy);
1738 egl_surface_t const * const s = get_surface(draw);
1739 if (s->cnx->egl.eglSetSwapRectangleANDROID) {
1740 return s->cnx->egl.eglSetSwapRectangleANDROID(
1741 dp->disp[s->impl].dpy, s->surface, left, top, width, height);
1742 }
1743 return setError(EGL_BAD_DISPLAY, NULL);
1744 }
1745
eglGetRenderBufferANDROID(EGLDisplay dpy,EGLSurface draw)1746 EGLClientBuffer eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw)
1747 {
1748 SurfaceRef _s(draw);
1749 if (!_s.get()) return setError(EGL_BAD_SURFACE, (EGLClientBuffer*)0);
1750
1751 if (!validate_display_surface(dpy, draw))
1752 return 0;
1753 egl_display_t const * const dp = get_display(dpy);
1754 egl_surface_t const * const s = get_surface(draw);
1755 if (s->cnx->egl.eglGetRenderBufferANDROID) {
1756 return s->cnx->egl.eglGetRenderBufferANDROID(
1757 dp->disp[s->impl].dpy, s->surface);
1758 }
1759 return setError(EGL_BAD_DISPLAY, (EGLClientBuffer*)0);
1760 }
1761