blob: 687c8bc1f7a81e1458e50a1b510bc22a8904c548 [file] [log] [blame]
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001/*
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#define LOG_TAG "GLLogger"
18
19#include <ctype.h>
20#include <string.h>
21#include <errno.h>
22#include <dlfcn.h>
23
24#include <sys/ioctl.h>
25
26#if HAVE_ANDROID_OS
27#include <linux/android_pmem.h>
28#endif
29
30#include <EGL/egl.h>
31#include <EGL/eglext.h>
32#include <GLES/gl.h>
33#include <GLES/glext.h>
34
35#include <cutils/log.h>
36#include <cutils/atomic.h>
37#include <cutils/properties.h>
38#include <cutils/memory.h>
39
40#include <utils/RefBase.h>
41
42#include "hooks.h"
43#include "egl_impl.h"
44
45
46#define MAKE_CONFIG(_impl, _index) ((EGLConfig)(((_impl)<<24) | (_index)))
47#define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
48
49// ----------------------------------------------------------------------------
50namespace android {
51// ----------------------------------------------------------------------------
52
53#define VERSION_MAJOR 1
54#define VERSION_MINOR 4
55static char const * const gVendorString = "Android";
56static char const * const gVersionString = "1.31 Android META-EGL";
57static char const * const gClientApiString = "OpenGL ES";
58static char const * const gExtensionString = "";
59
60template <int MAGIC>
61struct egl_object_t
62{
63 egl_object_t() : magic(MAGIC) { }
64 ~egl_object_t() { magic = 0; }
65 bool isValid() const { return magic == MAGIC; }
66private:
67 uint32_t magic;
68};
69
70struct egl_display_t : public egl_object_t<'_dpy'>
71{
72 EGLDisplay dpys[2];
73 EGLConfig* configs[2];
74 EGLint numConfigs[2];
75 EGLint numTotalConfigs;
76 char const* extensionsString;
77 volatile int32_t refs;
78 struct strings_t {
79 char const * vendor;
80 char const * version;
81 char const * clientApi;
82 char const * extensions;
83 };
84 strings_t queryString[2];
85};
86
87struct egl_surface_t : public egl_object_t<'_srf'>
88{
89 egl_surface_t(EGLDisplay dpy, EGLSurface surface,
90 NativeWindowType window, int impl, egl_connection_t const* cnx)
91 : dpy(dpy), surface(surface), window(window), impl(impl), cnx(cnx)
92 {
93 // NOTE: window must be incRef'ed and connected already
94 }
95 ~egl_surface_t() {
96 if (window) {
97 if (window->disconnect)
98 window->disconnect(window);
99 window->decRef(window);
100 }
101 }
102 EGLDisplay dpy;
103 EGLSurface surface;
104 NativeWindowType window;
105 int impl;
106 egl_connection_t const* cnx;
107};
108
109struct egl_context_t : public egl_object_t<'_ctx'>
110{
111 egl_context_t(EGLDisplay dpy, EGLContext context,
112 int impl, egl_connection_t const* cnx)
113 : dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx)
114 {
115 }
116 EGLDisplay dpy;
117 EGLContext context;
118 EGLSurface read;
119 EGLSurface draw;
120 int impl;
121 egl_connection_t const* cnx;
122};
123
124struct tls_t
125{
126 tls_t() : error(EGL_SUCCESS), ctx(0) { }
127 EGLint error;
128 EGLContext ctx;
129};
130
131static void gl_unimplemented() {
132 LOGE("called unimplemented OpenGL ES API");
133}
134
135// ----------------------------------------------------------------------------
136// GL / EGL hooks
137// ----------------------------------------------------------------------------
138
139#undef GL_ENTRY
140#undef EGL_ENTRY
141#define GL_ENTRY(_r, _api, ...) #_api,
142#define EGL_ENTRY(_r, _api, ...) #_api,
143
144static char const * const gl_names[] = {
145 #include "gl_entries.in"
146 NULL
147};
148
149static char const * const egl_names[] = {
150 #include "egl_entries.in"
151 NULL
152};
153
154#undef GL_ENTRY
155#undef EGL_ENTRY
156
157// ----------------------------------------------------------------------------
158
159egl_connection_t gEGLImpl[2];
160static egl_display_t gDisplay[NUM_DISPLAYS];
161static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
162static pthread_key_t gEGLThreadLocalStorageKey = -1;
163
164// ----------------------------------------------------------------------------
165
166gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS];
167pthread_key_t gGLWrapperKey = -1;
168
169// ----------------------------------------------------------------------------
170
171static __attribute__((noinline))
172const char *egl_strerror(EGLint err)
173{
174 switch (err){
175 case EGL_SUCCESS: return "EGL_SUCCESS";
176 case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
177 case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
178 case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
179 case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
180 case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
181 case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
182 case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
183 case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
184 case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
185 case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
186 case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
187 case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
188 case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
189 case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
190 default: return "UNKNOWN";
191 }
192}
193
194static __attribute__((noinline))
195void clearTLS() {
196 if (gEGLThreadLocalStorageKey != -1) {
197 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
198 if (tls) {
199 delete tls;
200 pthread_setspecific(gEGLThreadLocalStorageKey, 0);
201 }
202 }
203}
204
205static tls_t* getTLS()
206{
207 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
208 if (tls == 0) {
209 tls = new tls_t;
210 pthread_setspecific(gEGLThreadLocalStorageKey, tls);
211 }
212 return tls;
213}
214
215template<typename T>
216static __attribute__((noinline))
217T setErrorEtc(const char* caller, int line, EGLint error, T returnValue) {
218 if (gEGLThreadLocalStorageKey == -1) {
219 pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
220 if (gEGLThreadLocalStorageKey == -1)
221 pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
222 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
223 }
224 tls_t* tls = getTLS();
225 if (tls->error != error) {
226 LOGE("%s:%d error %x (%s)", caller, line, error, egl_strerror(error));
227 tls->error = error;
228 }
229 return returnValue;
230}
231
232static __attribute__((noinline))
233GLint getError() {
234 if (gEGLThreadLocalStorageKey == -1)
235 return EGL_SUCCESS;
236 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
237 if (!tls) return EGL_SUCCESS;
238 GLint error = tls->error;
239 tls->error = EGL_SUCCESS;
240 return error;
241}
242
243static __attribute__((noinline))
244void setContext(EGLContext ctx) {
245 if (gEGLThreadLocalStorageKey == -1) {
246 pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
247 if (gEGLThreadLocalStorageKey == -1)
248 pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
249 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
250 }
251 tls_t* tls = getTLS();
252 tls->ctx = ctx;
253}
254
255static __attribute__((noinline))
256EGLContext getContext() {
257 if (gEGLThreadLocalStorageKey == -1)
258 return EGL_NO_CONTEXT;
259 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
260 if (!tls) return EGL_NO_CONTEXT;
261 return tls->ctx;
262}
263
264
265/*****************************************************************************/
266
267class ISurfaceComposer;
268const sp<ISurfaceComposer>& getSurfaceFlinger();
269request_gpu_t* gpu_acquire(void* user);
270int gpu_release(void*, request_gpu_t* gpu);
271
272static __attribute__((noinline))
273void *load_driver(const char* driver, gl_hooks_t* hooks)
274{
275 void* dso = dlopen(driver, RTLD_NOW | RTLD_LOCAL);
276 LOGE_IF(!dso,
277 "couldn't load <%s> library (%s)",
278 driver, dlerror());
279
280 if (dso) {
281 void** curr;
282 char const * const * api;
283 gl_hooks_t::gl_t* gl = &hooks->gl;
284 curr = (void**)gl;
285 api = gl_names;
286 while (*api) {
287 void* f = dlsym(dso, *api);
288 //LOGD("<%s> @ 0x%p", *api, f);
289 if (f == NULL) {
290 //LOGW("<%s> not found in %s", *api, driver);
291 f = (void*)gl_unimplemented;
292 }
293 *curr++ = f;
294 api++;
295 }
296 gl_hooks_t::egl_t* egl = &hooks->egl;
297 curr = (void**)egl;
298 api = egl_names;
299 while (*api) {
300 void* f = dlsym(dso, *api);
301 if (f == NULL) {
302 //LOGW("<%s> not found in %s", *api, driver);
303 f = (void*)0;
304 }
305 *curr++ = f;
306 api++;
307 }
308
309 // hook this driver up with surfaceflinger if needed
310 register_gpu_t register_gpu =
311 (register_gpu_t)dlsym(dso, "oem_register_gpu");
312
313 if (register_gpu != NULL) {
314 if (getSurfaceFlinger() != 0) {
315 register_gpu(dso, gpu_acquire, gpu_release);
316 }
317 }
318 }
319 return dso;
320}
321
322template<typename T>
323static __attribute__((noinline))
324int binarySearch(
325 T const sortedArray[], int first, int last, T key)
326{
327 while (first <= last) {
328 int mid = (first + last) / 2;
329 if (key > sortedArray[mid]) {
330 first = mid + 1;
331 } else if (key < sortedArray[mid]) {
332 last = mid - 1;
333 } else {
334 return mid;
335 }
336 }
337 return -1;
338}
339
340static EGLint configToUniqueId(egl_display_t const* dp, int i, int index)
341{
342 // NOTE: this mapping works only if we have no more than two EGLimpl
343 return (i>0 ? dp->numConfigs[0] : 0) + index;
344}
345
346static void uniqueIdToConfig(egl_display_t const* dp, EGLint configId,
347 int& i, int& index)
348{
349 // NOTE: this mapping works only if we have no more than two EGLimpl
350 size_t numConfigs = dp->numConfigs[0];
351 i = configId / numConfigs;
352 index = configId % numConfigs;
353}
354
355static int cmp_configs(const void* a, const void *b)
356{
357 EGLConfig c0 = *(EGLConfig const *)a;
358 EGLConfig c1 = *(EGLConfig const *)b;
359 return c0<c1 ? -1 : (c0>c1 ? 1 : 0);
360}
361
362struct extention_map_t {
363 const char* name;
364 __eglMustCastToProperFunctionPointerType address;
365};
366
367static const extention_map_t gExtentionMap[] = {
368};
369
370static extention_map_t gGLExtentionMap[MAX_NUMBER_OF_GL_EXTENSIONS];
371
372static void(*findProcAddress(const char* name,
373 const extention_map_t* map, size_t n))()
374{
375 for (uint32_t i=0 ; i<n ; i++) {
376 if (!strcmp(name, map[i].name)) {
377 return map[i].address;
378 }
379 }
380 return NULL;
381}
382
383// ----------------------------------------------------------------------------
384
385static int gl_context_lost() {
386 setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
387 return 0;
388}
389static int egl_context_lost() {
390 setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
391 return EGL_FALSE;
392}
393static EGLBoolean egl_context_lost_swap_buffers(void*, void*) {
394 usleep(100000); // don't use all the CPU
395 setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
396 return EGL_FALSE;
397}
398static GLint egl_context_lost_get_error() {
399 return EGL_CONTEXT_LOST;
400}
401static int ext_context_lost() {
402 return 0;
403}
404
405static void gl_no_context() {
406 LOGE("call to OpenGL ES API with no current context");
407}
408static void early_egl_init(void)
409{
410#if !USE_FAST_TLS_KEY
411 pthread_key_create(&gGLWrapperKey, NULL);
412#endif
413 uint32_t addr = (uint32_t)((void*)gl_no_context);
414 android_memset32(
415 (uint32_t*)(void*)&gHooks[IMPL_NO_CONTEXT],
416 addr,
417 sizeof(gHooks[IMPL_NO_CONTEXT]));
418 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
419}
420
421static pthread_once_t once_control = PTHREAD_ONCE_INIT;
422static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
423
424
425static inline
426egl_display_t* get_display(EGLDisplay dpy)
427{
428 uintptr_t index = uintptr_t(dpy)-1U;
429 return (index >= NUM_DISPLAYS) ? NULL : &gDisplay[index];
430}
431
432static inline
433egl_surface_t* get_surface(EGLSurface surface)
434{
435 egl_surface_t* s = (egl_surface_t *)surface;
436 return s;
437}
438
439static inline
440egl_context_t* get_context(EGLContext context)
441{
442 egl_context_t* c = (egl_context_t *)context;
443 return c;
444}
445
446static egl_connection_t* validate_display_config(
447 EGLDisplay dpy, EGLConfig config,
448 egl_display_t const*& dp, int& impl, int& index)
449{
450 dp = get_display(dpy);
451 if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
452
453 impl = uintptr_t(config)>>24;
454 if (uint32_t(impl) >= 2) {
455 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
456 }
457 index = uintptr_t(config) & 0xFFFFFF;
458 if (index >= dp->numConfigs[impl]) {
459 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
460 }
461 egl_connection_t* const cnx = &gEGLImpl[impl];
462 if (cnx->dso == 0) {
463 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
464 }
465 return cnx;
466}
467
468static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
469{
470 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
471 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
472 if (!get_display(dpy)->isValid())
473 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
474 if (!ctx) // TODO: make sure context is a valid object
475 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
476 if (!get_context(ctx)->isValid())
477 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
478 return EGL_TRUE;
479}
480
481static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
482{
483 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
484 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
485 if (!get_display(dpy)->isValid())
486 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
487 if (!surface) // TODO: make sure surface is a valid object
488 return setError(EGL_BAD_SURFACE, EGL_FALSE);
489 if (!get_surface(surface)->isValid())
490 return setError(EGL_BAD_SURFACE, EGL_FALSE);
491 return EGL_TRUE;
492}
493
494// ----------------------------------------------------------------------------
495}; // namespace android
496// ----------------------------------------------------------------------------
497
498using namespace android;
499
500EGLDisplay eglGetDisplay(NativeDisplayType display)
501{
502 if (sEarlyInitState) {
503 return EGL_NO_DISPLAY;
504 }
505
506 uint32_t index = uint32_t(display);
507 if (index >= NUM_DISPLAYS) {
508 return EGL_NO_DISPLAY;
509 }
510
511 EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
512 egl_display_t* d = &gDisplay[index];
513
514 // dynamically load all our EGL implementations for that display
515 // and call into the real eglGetGisplay()
516 egl_connection_t* cnx = &gEGLImpl[IMPL_SOFTWARE];
517 if (cnx->dso == 0) {
518 cnx->hooks = &gHooks[IMPL_SOFTWARE];
519 cnx->dso = load_driver("libagl.so", cnx->hooks);
520 }
521 if (cnx->dso && d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY) {
522 d->dpys[IMPL_SOFTWARE] = cnx->hooks->egl.eglGetDisplay(display);
523 LOGE_IF(d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY,
524 "No EGLDisplay for software EGL!");
525 }
526
527 cnx = &gEGLImpl[IMPL_HARDWARE];
528 if (cnx->dso == 0 && cnx->unavailable == 0) {
529 char value[PROPERTY_VALUE_MAX];
530 property_get("debug.egl.hw", value, "1");
531 if (atoi(value) != 0) {
532 cnx->hooks = &gHooks[IMPL_HARDWARE];
533 cnx->dso = load_driver("libhgl.so", cnx->hooks);
534 } else {
535 LOGD("3D hardware acceleration is disabled");
536 }
537 }
538 if (cnx->dso && d->dpys[IMPL_HARDWARE]==EGL_NO_DISPLAY) {
539 android_memset32(
540 (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].gl,
541 (uint32_t)((void*)gl_context_lost),
542 sizeof(gHooks[IMPL_CONTEXT_LOST].gl));
543 android_memset32(
544 (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].egl,
545 (uint32_t)((void*)egl_context_lost),
546 sizeof(gHooks[IMPL_CONTEXT_LOST].egl));
547 android_memset32(
548 (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].ext,
549 (uint32_t)((void*)ext_context_lost),
550 sizeof(gHooks[IMPL_CONTEXT_LOST].ext));
551
552 gHooks[IMPL_CONTEXT_LOST].egl.eglSwapBuffers =
553 egl_context_lost_swap_buffers;
554
555 gHooks[IMPL_CONTEXT_LOST].egl.eglGetError =
556 egl_context_lost_get_error;
557
558 gHooks[IMPL_CONTEXT_LOST].egl.eglTerminate =
559 gHooks[IMPL_HARDWARE].egl.eglTerminate;
560
561 d->dpys[IMPL_HARDWARE] = cnx->hooks->egl.eglGetDisplay(display);
562 if (d->dpys[IMPL_HARDWARE] == EGL_NO_DISPLAY) {
563 LOGE("h/w accelerated eglGetDisplay() failed (%s)",
564 egl_strerror(cnx->hooks->egl.eglGetError()));
565 dlclose((void*)cnx->dso);
566 cnx->dso = 0;
567 // in case of failure, we want to make sure we don't try again
568 // as it's expensive.
569 cnx->unavailable = 1;
570 }
571 }
572
573 return dpy;
574}
575
576// ----------------------------------------------------------------------------
577// Initialization
578// ----------------------------------------------------------------------------
579
580EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
581{
582 egl_display_t * const dp = get_display(dpy);
583 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
584
585 if (android_atomic_inc(&dp->refs) > 0) {
586 if (major != NULL) *major = VERSION_MAJOR;
587 if (minor != NULL) *minor = VERSION_MINOR;
588 return EGL_TRUE;
589 }
590
591 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
592
593 // initialize each EGL and
594 // build our own extension string first, based on the extension we know
595 // and the extension supported by our client implementation
596 dp->extensionsString = strdup(gExtensionString);
597 for (int i=0 ; i<2 ; i++) {
598 egl_connection_t* const cnx = &gEGLImpl[i];
599 cnx->major = -1;
600 cnx->minor = -1;
601 if (!cnx->dso)
602 continue;
603
604 if (cnx->hooks->egl.eglInitialize(
605 dp->dpys[i], &cnx->major, &cnx->minor)) {
606
607 //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
608 // i, dp->dpys[i], cnx->major, cnx->minor, cnx);
609
610 // get the query-strings for this display for each implementation
611 dp->queryString[i].vendor =
612 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VENDOR);
613 dp->queryString[i].version =
614 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VERSION);
615 dp->queryString[i].extensions = strdup(
616 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_EXTENSIONS));
617 dp->queryString[i].clientApi =
618 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_CLIENT_APIS);
619
620 } else {
621 LOGD("%d: eglInitialize() failed (%s)",
622 i, egl_strerror(cnx->hooks->egl.eglGetError()));
623 }
624 }
625
626 EGLBoolean res = EGL_FALSE;
627 for (int i=0 ; i<2 ; i++) {
628 egl_connection_t* const cnx = &gEGLImpl[i];
629 if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
630 EGLint n;
631 if (cnx->hooks->egl.eglGetConfigs(dp->dpys[i], 0, 0, &n)) {
632 dp->configs[i] = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
633 if (dp->configs[i]) {
634 if (cnx->hooks->egl.eglGetConfigs(
635 dp->dpys[i], dp->configs[i], n, &dp->numConfigs[i]))
636 {
637 // sort the configurations so we can do binary searches
638 qsort( dp->configs[i],
639 dp->numConfigs[i],
640 sizeof(EGLConfig), cmp_configs);
641
642 dp->numTotalConfigs += n;
643 res = EGL_TRUE;
644 }
645 }
646 }
647 }
648 }
649
650 if (res == EGL_TRUE) {
651 if (major != NULL) *major = VERSION_MAJOR;
652 if (minor != NULL) *minor = VERSION_MINOR;
653 return EGL_TRUE;
654 }
655 return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
656}
657
658EGLBoolean eglTerminate(EGLDisplay dpy)
659{
660 egl_display_t* const dp = get_display(dpy);
661 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
662 if (android_atomic_dec(&dp->refs) != 1)
663 return EGL_TRUE;
664
665 EGLBoolean res = EGL_FALSE;
666 for (int i=0 ; i<2 ; i++) {
667 egl_connection_t* const cnx = &gEGLImpl[i];
668 if (cnx->dso) {
669 cnx->hooks->egl.eglTerminate(dp->dpys[i]);
670
671 /* REVISIT: it's unclear what to do if eglTerminate() fails,
672 * on one end we shouldn't care, on the other end if it fails
673 * it might not be safe to call dlclose() (there could be some
674 * threads around). */
675
676 free(dp->configs[i]);
677 free((void*)dp->queryString[i].extensions);
678 dp->numConfigs[i] = 0;
679 dp->dpys[i] = EGL_NO_DISPLAY;
680 dlclose((void*)cnx->dso);
681 cnx->dso = 0;
682 res = EGL_TRUE;
683 }
684 }
685 free((void*)dp->extensionsString);
686 dp->extensionsString = 0;
687 dp->numTotalConfigs = 0;
688 clearTLS();
689 return res;
690}
691
692// ----------------------------------------------------------------------------
693// configuration
694// ----------------------------------------------------------------------------
695
696EGLBoolean eglGetConfigs( EGLDisplay dpy,
697 EGLConfig *configs,
698 EGLint config_size, EGLint *num_config)
699{
700 egl_display_t const * const dp = get_display(dpy);
701 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
702
703 GLint numConfigs = dp->numTotalConfigs;
704 if (!configs) {
705 *num_config = numConfigs;
706 return EGL_TRUE;
707 }
708 GLint n = 0;
709 for (int j=0 ; j<2 ; j++) {
710 for (int i=0 ; i<dp->numConfigs[j] && config_size ; i++) {
711 *configs++ = MAKE_CONFIG(j, i);
712 config_size--;
713 n++;
714 }
715 }
716
717 *num_config = n;
718 return EGL_TRUE;
719}
720
721EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
722 EGLConfig *configs, EGLint config_size,
723 EGLint *num_config)
724{
725 egl_display_t const * const dp = get_display(dpy);
726 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
727
728 if (configs == 0) {
729 *num_config = 0;
730 return EGL_TRUE;
731 }
732
733 EGLint n;
734 EGLBoolean res = EGL_FALSE;
735 *num_config = 0;
736
737
738 // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
739 // to do this, we have to go through the attrib_list array once
740 // to figure out both its size and if it contains an EGL_CONFIG_ID
741 // key. If so, the full array is copied and patched.
742 // NOTE: we assume that there can be only one occurrence
743 // of EGL_CONFIG_ID.
744
745 EGLint patch_index = -1;
746 GLint attr;
747 size_t size = 0;
748 while ((attr=attrib_list[size])) {
749 if (attr == EGL_CONFIG_ID)
750 patch_index = size;
751 size += 2;
752 }
753 if (patch_index >= 0) {
754 size += 2; // we need copy the sentinel as well
755 EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
756 if (new_list == 0)
757 return setError(EGL_BAD_ALLOC, EGL_FALSE);
758 memcpy(new_list, attrib_list, size*sizeof(EGLint));
759
760 // patch the requested EGL_CONFIG_ID
761 int i, index;
762 EGLint& configId(new_list[patch_index+1]);
763 uniqueIdToConfig(dp, configId, i, index);
764
765 egl_connection_t* const cnx = &gEGLImpl[i];
766 if (cnx->dso) {
767 cnx->hooks->egl.eglGetConfigAttrib(
768 dp->dpys[i], dp->configs[i][index],
769 EGL_CONFIG_ID, &configId);
770
771 // and switch to the new list
772 attrib_list = const_cast<const EGLint *>(new_list);
773
774 // At this point, the only configuration that can match is
775 // dp->configs[i][index], however, we don't know if it would be
776 // rejected because of the other attributes, so we do have to call
777 // cnx->hooks->egl.eglChooseConfig() -- but we don't have to loop
778 // through all the EGLimpl[].
779 // We also know we can only get a single config back, and we know
780 // which one.
781
782 res = cnx->hooks->egl.eglChooseConfig(
783 dp->dpys[i], attrib_list, configs, config_size, &n);
784 if (res && n>0) {
785 // n has to be 0 or 1, by construction, and we already know
786 // which config it will return (since there can be only one).
787 configs[0] = MAKE_CONFIG(i, index);
788 *num_config = 1;
789 }
790 }
791
792 free(const_cast<EGLint *>(attrib_list));
793 return res;
794 }
795
796 for (int i=0 ; i<2 ; i++) {
797 egl_connection_t* const cnx = &gEGLImpl[i];
798 if (cnx->dso) {
799 if (cnx->hooks->egl.eglChooseConfig(
800 dp->dpys[i], attrib_list, configs, config_size, &n)) {
801 // now we need to convert these client EGLConfig to our
802 // internal EGLConfig format. This is done in O(n log n).
803 for (int j=0 ; j<n ; j++) {
804 int index = binarySearch<EGLConfig>(
805 dp->configs[i], 0, dp->numConfigs[i]-1, configs[j]);
806 if (index >= 0) {
807 configs[j] = MAKE_CONFIG(i, index);
808 } else {
809 return setError(EGL_BAD_CONFIG, EGL_FALSE);
810 }
811 }
812 configs += n;
813 config_size -= n;
814 *num_config += n;
815 res = EGL_TRUE;
816 }
817 }
818 }
819 return res;
820}
821
822EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
823 EGLint attribute, EGLint *value)
824{
825 egl_display_t const* dp = 0;
826 int i=0, index=0;
827 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
828 if (!cnx) return EGL_FALSE;
829
830 if (attribute == EGL_CONFIG_ID) {
831 // EGL_CONFIG_IDs must be unique, just use the order of the selected
832 // EGLConfig.
833 *value = configToUniqueId(dp, i, index);
834 return EGL_TRUE;
835 }
836 return cnx->hooks->egl.eglGetConfigAttrib(
837 dp->dpys[i], dp->configs[i][index], attribute, value);
838}
839
840// ----------------------------------------------------------------------------
841// surfaces
842// ----------------------------------------------------------------------------
843
844EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
845 NativeWindowType window,
846 const EGLint *attrib_list)
847{
848 egl_display_t const* dp = 0;
849 int i=0, index=0;
850 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
851 if (cnx) {
852 // window must be connected upon calling underlying
853 // eglCreateWindowSurface
854 if (window) {
855 window->incRef(window);
856 if (window->connect)
857 window->connect(window);
858 }
859
860 EGLSurface surface = cnx->hooks->egl.eglCreateWindowSurface(
861 dp->dpys[i], dp->configs[i][index], window, attrib_list);
862 if (surface != EGL_NO_SURFACE) {
863 egl_surface_t* s = new egl_surface_t(dpy, surface, window, i, cnx);
864 return s;
865 }
866
867 // something went wrong, disconnect and free window
868 // (will disconnect() automatically)
869 if (window) {
870 window->decRef(window);
871 }
872 }
873 return EGL_NO_SURFACE;
874}
875
876EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
877 NativePixmapType pixmap,
878 const EGLint *attrib_list)
879{
880 egl_display_t const* dp = 0;
881 int i=0, index=0;
882 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
883 if (cnx) {
884 EGLSurface surface = cnx->hooks->egl.eglCreatePixmapSurface(
885 dp->dpys[i], dp->configs[i][index], pixmap, attrib_list);
886 if (surface != EGL_NO_SURFACE) {
887 egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
888 return s;
889 }
890 }
891 return EGL_NO_SURFACE;
892}
893
894EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
895 const EGLint *attrib_list)
896{
897 egl_display_t const* dp = 0;
898 int i=0, index=0;
899 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
900 if (cnx) {
901 EGLSurface surface = cnx->hooks->egl.eglCreatePbufferSurface(
902 dp->dpys[i], dp->configs[i][index], attrib_list);
903 if (surface != EGL_NO_SURFACE) {
904 egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
905 return s;
906 }
907 }
908 return EGL_NO_SURFACE;
909}
910
911EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
912{
913 if (!validate_display_surface(dpy, surface))
914 return EGL_FALSE;
915 egl_display_t const * const dp = get_display(dpy);
916 egl_surface_t const * const s = get_surface(surface);
917
918 EGLBoolean result = s->cnx->hooks->egl.eglDestroySurface(
919 dp->dpys[s->impl], s->surface);
920
921 delete s;
922 return result;
923}
924
925EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
926 EGLint attribute, EGLint *value)
927{
928 if (!validate_display_surface(dpy, surface))
929 return EGL_FALSE;
930 egl_display_t const * const dp = get_display(dpy);
931 egl_surface_t const * const s = get_surface(surface);
932
933 return s->cnx->hooks->egl.eglQuerySurface(
934 dp->dpys[s->impl], s->surface, attribute, value);
935}
936
937// ----------------------------------------------------------------------------
938// contextes
939// ----------------------------------------------------------------------------
940
941EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
942 EGLContext share_list, const EGLint *attrib_list)
943{
944 egl_display_t const* dp = 0;
945 int i=0, index=0;
946 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
947 if (cnx) {
948 EGLContext context = cnx->hooks->egl.eglCreateContext(
949 dp->dpys[i], dp->configs[i][index], share_list, attrib_list);
950 if (context != EGL_NO_CONTEXT) {
951 egl_context_t* c = new egl_context_t(dpy, context, i, cnx);
952 return c;
953 }
954 }
955 return EGL_NO_CONTEXT;
956}
957
958EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
959{
960 if (!validate_display_context(dpy, ctx))
961 return EGL_FALSE;
962 egl_display_t const * const dp = get_display(dpy);
963 egl_context_t * const c = get_context(ctx);
964 EGLBoolean result = c->cnx->hooks->egl.eglDestroyContext(
965 dp->dpys[c->impl], c->context);
966 delete c;
967 return result;
968}
969
970EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
971 EGLSurface read, EGLContext ctx)
972{
973 egl_display_t const * const dp = get_display(dpy);
974 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
975
976 if (read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE &&
977 ctx == EGL_NO_CONTEXT)
978 {
979 EGLBoolean result = EGL_TRUE;
980 ctx = getContext();
981 if (ctx) {
982 egl_context_t * const c = get_context(ctx);
983 result = c->cnx->hooks->egl.eglMakeCurrent(dp->dpys[c->impl], 0, 0, 0);
984 if (result == EGL_TRUE) {
985 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
986 setContext(EGL_NO_CONTEXT);
987 }
988 }
989 return result;
990 }
991
992 if (!validate_display_context(dpy, ctx))
993 return EGL_FALSE;
994
995 egl_context_t * const c = get_context(ctx);
996 if (draw != EGL_NO_SURFACE) {
997 egl_surface_t const * d = get_surface(draw);
998 if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE);
999 if (d->impl != c->impl)
1000 return setError(EGL_BAD_MATCH, EGL_FALSE);
1001 draw = d->surface;
1002 }
1003 if (read != EGL_NO_SURFACE) {
1004 egl_surface_t const * r = get_surface(read);
1005 if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1006 if (r->impl != c->impl)
1007 return setError(EGL_BAD_MATCH, EGL_FALSE);
1008 read = r->surface;
1009 }
1010 EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent(
1011 dp->dpys[c->impl], draw, read, c->context);
1012
1013 if (result == EGL_TRUE) {
1014 setGlThreadSpecific(c->cnx->hooks);
1015 setContext(ctx);
1016 c->read = read;
1017 c->draw = draw;
1018 }
1019 return result;
1020}
1021
1022
1023EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1024 EGLint attribute, EGLint *value)
1025{
1026 if (!validate_display_context(dpy, ctx))
1027 return EGL_FALSE;
1028
1029 egl_display_t const * const dp = get_display(dpy);
1030 egl_context_t * const c = get_context(ctx);
1031
1032 return c->cnx->hooks->egl.eglQueryContext(
1033 dp->dpys[c->impl], c->context, attribute, value);
1034}
1035
1036EGLContext eglGetCurrentContext(void)
1037{
1038 EGLContext ctx = getContext();
1039 return ctx;
1040}
1041
1042EGLSurface eglGetCurrentSurface(EGLint readdraw)
1043{
1044 EGLContext ctx = getContext();
1045 if (ctx) {
1046 egl_context_t const * const c = get_context(ctx);
1047 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1048 switch (readdraw) {
1049 case EGL_READ: return c->read;
1050 case EGL_DRAW: return c->draw;
1051 default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1052 }
1053 }
1054 return EGL_NO_SURFACE;
1055}
1056
1057EGLDisplay eglGetCurrentDisplay(void)
1058{
1059 EGLContext ctx = getContext();
1060 if (ctx) {
1061 egl_context_t const * const c = get_context(ctx);
1062 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1063 return c->dpy;
1064 }
1065 return EGL_NO_DISPLAY;
1066}
1067
1068EGLBoolean eglWaitGL(void)
1069{
1070 EGLBoolean res = EGL_TRUE;
1071 EGLContext ctx = getContext();
1072 if (ctx) {
1073 egl_context_t const * const c = get_context(ctx);
1074 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1075 if (uint32_t(c->impl)>=2)
1076 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1077 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1078 if (!cnx->dso)
1079 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1080 res = cnx->hooks->egl.eglWaitGL();
1081 }
1082 return res;
1083}
1084
1085EGLBoolean eglWaitNative(EGLint engine)
1086{
1087 EGLBoolean res = EGL_TRUE;
1088 EGLContext ctx = getContext();
1089 if (ctx) {
1090 egl_context_t const * const c = get_context(ctx);
1091 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1092 if (uint32_t(c->impl)>=2)
1093 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1094 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1095 if (!cnx->dso)
1096 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1097 res = cnx->hooks->egl.eglWaitNative(engine);
1098 }
1099 return res;
1100}
1101
1102EGLint eglGetError(void)
1103{
1104 EGLint result = EGL_SUCCESS;
1105 for (int i=0 ; i<2 ; i++) {
1106 EGLint err = EGL_SUCCESS;
1107 egl_connection_t* const cnx = &gEGLImpl[i];
1108 if (cnx->dso)
1109 err = cnx->hooks->egl.eglGetError();
1110 if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
1111 result = err;
1112 }
1113 if (result == EGL_SUCCESS)
1114 result = getError();
1115 return result;
1116}
1117
1118void (*eglGetProcAddress(const char *procname))()
1119{
1120 __eglMustCastToProperFunctionPointerType addr;
1121 addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
1122 if (addr) return addr;
1123
1124 return NULL; // TODO: finish implementation below
1125
1126 addr = findProcAddress(procname, gGLExtentionMap, NELEM(gGLExtentionMap));
1127 if (addr) return addr;
1128
1129 addr = 0;
1130 int slot = -1;
1131 for (int i=0 ; i<2 ; i++) {
1132 egl_connection_t* const cnx = &gEGLImpl[i];
1133 if (cnx->dso) {
1134 if (cnx->hooks->egl.eglGetProcAddress) {
1135 addr = cnx->hooks->egl.eglGetProcAddress(procname);
1136 if (addr) {
1137 if (slot == -1) {
1138 slot = 0; // XXX: find free slot
1139 if (slot == -1) {
1140 addr = 0;
1141 break;
1142 }
1143 }
1144 cnx->hooks->ext.extensions[slot] = addr;
1145 }
1146 }
1147 }
1148 }
1149
1150 if (slot >= 0) {
1151 addr = 0; // XXX: address of stub 'slot'
1152 gGLExtentionMap[slot].name = strdup(procname);
1153 gGLExtentionMap[slot].address = addr;
1154 }
1155
1156 return addr;
1157
1158
1159 /*
1160 * TODO: For OpenGL ES extensions, we must generate a stub
1161 * that looks like
1162 * mov r12, #0xFFFF0FFF
1163 * ldr r12, [r12, #-15]
1164 * ldr r12, [r12, #TLS_SLOT_OPENGL_API*4]
1165 * mov r12, [r12, #api_offset]
1166 * ldrne pc, r12
1167 * mov pc, #unsupported_extension
1168 *
1169 * and write the address of the extension in *all*
1170 * gl_hooks_t::gl_ext_t at offset "api_offset" from gl_hooks_t
1171 *
1172 */
1173}
1174
1175EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1176{
1177 if (!validate_display_surface(dpy, draw))
1178 return EGL_FALSE;
1179 egl_display_t const * const dp = get_display(dpy);
1180 egl_surface_t const * const s = get_surface(draw);
1181 return s->cnx->hooks->egl.eglSwapBuffers(dp->dpys[s->impl], s->surface);
1182}
1183
1184EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
1185 NativePixmapType target)
1186{
1187 if (!validate_display_surface(dpy, surface))
1188 return EGL_FALSE;
1189 egl_display_t const * const dp = get_display(dpy);
1190 egl_surface_t const * const s = get_surface(surface);
1191 return s->cnx->hooks->egl.eglCopyBuffers(
1192 dp->dpys[s->impl], s->surface, target);
1193}
1194
1195const char* eglQueryString(EGLDisplay dpy, EGLint name)
1196{
1197 egl_display_t const * const dp = get_display(dpy);
1198 switch (name) {
1199 case EGL_VENDOR:
1200 return gVendorString;
1201 case EGL_VERSION:
1202 return gVersionString;
1203 case EGL_EXTENSIONS:
1204 return gExtensionString;
1205 case EGL_CLIENT_APIS:
1206 return gClientApiString;
1207 }
1208 return setError(EGL_BAD_PARAMETER, (const char *)0);
1209}
1210
1211
1212// ----------------------------------------------------------------------------
1213// EGL 1.1
1214// ----------------------------------------------------------------------------
1215
1216EGLBoolean eglSurfaceAttrib(
1217 EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1218{
1219 if (!validate_display_surface(dpy, surface))
1220 return EGL_FALSE;
1221 egl_display_t const * const dp = get_display(dpy);
1222 egl_surface_t const * const s = get_surface(surface);
1223 if (s->cnx->hooks->egl.eglSurfaceAttrib) {
1224 return s->cnx->hooks->egl.eglSurfaceAttrib(
1225 dp->dpys[s->impl], s->surface, attribute, value);
1226 }
1227 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1228}
1229
1230EGLBoolean eglBindTexImage(
1231 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1232{
1233 if (!validate_display_surface(dpy, surface))
1234 return EGL_FALSE;
1235 egl_display_t const * const dp = get_display(dpy);
1236 egl_surface_t const * const s = get_surface(surface);
1237 if (s->cnx->hooks->egl.eglBindTexImage) {
1238 return s->cnx->hooks->egl.eglBindTexImage(
1239 dp->dpys[s->impl], s->surface, buffer);
1240 }
1241 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1242}
1243
1244EGLBoolean eglReleaseTexImage(
1245 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1246{
1247 if (!validate_display_surface(dpy, surface))
1248 return EGL_FALSE;
1249 egl_display_t const * const dp = get_display(dpy);
1250 egl_surface_t const * const s = get_surface(surface);
1251 if (s->cnx->hooks->egl.eglReleaseTexImage) {
1252 return s->cnx->hooks->egl.eglReleaseTexImage(
1253 dp->dpys[s->impl], s->surface, buffer);
1254 }
1255 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1256}
1257
1258EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1259{
1260 egl_display_t * const dp = get_display(dpy);
1261 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1262
1263 EGLBoolean res = EGL_TRUE;
1264 for (int i=0 ; i<2 ; i++) {
1265 egl_connection_t* const cnx = &gEGLImpl[i];
1266 if (cnx->dso) {
1267 if (cnx->hooks->egl.eglSwapInterval) {
1268 if (cnx->hooks->egl.eglSwapInterval(dp->dpys[i], interval) == EGL_FALSE) {
1269 res = EGL_FALSE;
1270 }
1271 }
1272 }
1273 }
1274 return res;
1275}
1276
1277
1278// ----------------------------------------------------------------------------
1279// EGL 1.2
1280// ----------------------------------------------------------------------------
1281
1282EGLBoolean eglWaitClient(void)
1283{
1284 EGLBoolean res = EGL_TRUE;
1285 EGLContext ctx = getContext();
1286 if (ctx) {
1287 egl_context_t const * const c = get_context(ctx);
1288 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1289 if (uint32_t(c->impl)>=2)
1290 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1291 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1292 if (!cnx->dso)
1293 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1294 if (cnx->hooks->egl.eglWaitClient) {
1295 res = cnx->hooks->egl.eglWaitClient();
1296 } else {
1297 res = cnx->hooks->egl.eglWaitGL();
1298 }
1299 }
1300 return res;
1301}
1302
1303EGLBoolean eglBindAPI(EGLenum api)
1304{
1305 // bind this API on all EGLs
1306 EGLBoolean res = EGL_TRUE;
1307 for (int i=0 ; i<2 ; i++) {
1308 egl_connection_t* const cnx = &gEGLImpl[i];
1309 if (cnx->dso) {
1310 if (cnx->hooks->egl.eglBindAPI) {
1311 if (cnx->hooks->egl.eglBindAPI(api) == EGL_FALSE) {
1312 res = EGL_FALSE;
1313 }
1314 }
1315 }
1316 }
1317 return res;
1318}
1319
1320EGLenum eglQueryAPI(void)
1321{
1322 for (int i=0 ; i<2 ; i++) {
1323 egl_connection_t* const cnx = &gEGLImpl[i];
1324 if (cnx->dso) {
1325 if (cnx->hooks->egl.eglQueryAPI) {
1326 // the first one we find is okay, because they all
1327 // should be the same
1328 return cnx->hooks->egl.eglQueryAPI();
1329 }
1330 }
1331 }
1332 // or, it can only be OpenGL ES
1333 return EGL_OPENGL_ES_API;
1334}
1335
1336EGLBoolean eglReleaseThread(void)
1337{
1338 for (int i=0 ; i<2 ; i++) {
1339 egl_connection_t* const cnx = &gEGLImpl[i];
1340 if (cnx->dso) {
1341 if (cnx->hooks->egl.eglReleaseThread) {
1342 cnx->hooks->egl.eglReleaseThread();
1343 }
1344 }
1345 }
1346 clearTLS();
1347 return EGL_TRUE;
1348}
1349
1350EGLSurface eglCreatePbufferFromClientBuffer(
1351 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1352 EGLConfig config, const EGLint *attrib_list)
1353{
1354 egl_display_t const* dp = 0;
1355 int i=0, index=0;
1356 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1357 if (!cnx) return EGL_FALSE;
1358 if (cnx->hooks->egl.eglCreatePbufferFromClientBuffer) {
1359 return cnx->hooks->egl.eglCreatePbufferFromClientBuffer(
1360 dp->dpys[i], buftype, buffer, dp->configs[i][index], attrib_list);
1361 }
1362 return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1363}