blob: 0b4bcce9eae5264512fcde8380a6975a04f2338e [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
Jack Palevich87d80222009-03-24 22:48:26 -0700728 if (num_config==0) {
729 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800730 }
731
732 EGLint n;
733 EGLBoolean res = EGL_FALSE;
734 *num_config = 0;
735
736
737 // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
738 // to do this, we have to go through the attrib_list array once
739 // to figure out both its size and if it contains an EGL_CONFIG_ID
740 // key. If so, the full array is copied and patched.
741 // NOTE: we assume that there can be only one occurrence
742 // of EGL_CONFIG_ID.
743
744 EGLint patch_index = -1;
745 GLint attr;
746 size_t size = 0;
747 while ((attr=attrib_list[size])) {
748 if (attr == EGL_CONFIG_ID)
749 patch_index = size;
750 size += 2;
751 }
752 if (patch_index >= 0) {
753 size += 2; // we need copy the sentinel as well
754 EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
755 if (new_list == 0)
756 return setError(EGL_BAD_ALLOC, EGL_FALSE);
757 memcpy(new_list, attrib_list, size*sizeof(EGLint));
758
759 // patch the requested EGL_CONFIG_ID
760 int i, index;
761 EGLint& configId(new_list[patch_index+1]);
762 uniqueIdToConfig(dp, configId, i, index);
763
764 egl_connection_t* const cnx = &gEGLImpl[i];
765 if (cnx->dso) {
766 cnx->hooks->egl.eglGetConfigAttrib(
767 dp->dpys[i], dp->configs[i][index],
768 EGL_CONFIG_ID, &configId);
769
770 // and switch to the new list
771 attrib_list = const_cast<const EGLint *>(new_list);
772
773 // At this point, the only configuration that can match is
774 // dp->configs[i][index], however, we don't know if it would be
775 // rejected because of the other attributes, so we do have to call
776 // cnx->hooks->egl.eglChooseConfig() -- but we don't have to loop
777 // through all the EGLimpl[].
778 // We also know we can only get a single config back, and we know
779 // which one.
780
781 res = cnx->hooks->egl.eglChooseConfig(
782 dp->dpys[i], attrib_list, configs, config_size, &n);
783 if (res && n>0) {
784 // n has to be 0 or 1, by construction, and we already know
785 // which config it will return (since there can be only one).
Jack Palevich87d80222009-03-24 22:48:26 -0700786 if (configs) {
787 configs[0] = MAKE_CONFIG(i, index);
788 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800789 *num_config = 1;
790 }
791 }
792
793 free(const_cast<EGLint *>(attrib_list));
794 return res;
795 }
796
797 for (int i=0 ; i<2 ; i++) {
798 egl_connection_t* const cnx = &gEGLImpl[i];
799 if (cnx->dso) {
800 if (cnx->hooks->egl.eglChooseConfig(
801 dp->dpys[i], attrib_list, configs, config_size, &n)) {
Jack Palevich87d80222009-03-24 22:48:26 -0700802 if (configs) {
803 // now we need to convert these client EGLConfig to our
804 // internal EGLConfig format. This is done in O(n log n).
805 for (int j=0 ; j<n ; j++) {
806 int index = binarySearch<EGLConfig>(
807 dp->configs[i], 0, dp->numConfigs[i]-1, configs[j]);
808 if (index >= 0) {
809 if (configs) {
810 configs[j] = MAKE_CONFIG(i, index);
811 }
812 } else {
813 return setError(EGL_BAD_CONFIG, EGL_FALSE);
814 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800815 }
Jack Palevich87d80222009-03-24 22:48:26 -0700816 configs += n;
817 config_size -= n;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800818 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800819 *num_config += n;
820 res = EGL_TRUE;
821 }
822 }
823 }
824 return res;
825}
826
827EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
828 EGLint attribute, EGLint *value)
829{
830 egl_display_t const* dp = 0;
831 int i=0, index=0;
832 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
833 if (!cnx) return EGL_FALSE;
834
835 if (attribute == EGL_CONFIG_ID) {
836 // EGL_CONFIG_IDs must be unique, just use the order of the selected
837 // EGLConfig.
838 *value = configToUniqueId(dp, i, index);
839 return EGL_TRUE;
840 }
841 return cnx->hooks->egl.eglGetConfigAttrib(
842 dp->dpys[i], dp->configs[i][index], attribute, value);
843}
844
845// ----------------------------------------------------------------------------
846// surfaces
847// ----------------------------------------------------------------------------
848
849EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
850 NativeWindowType window,
851 const EGLint *attrib_list)
852{
853 egl_display_t const* dp = 0;
854 int i=0, index=0;
855 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
856 if (cnx) {
857 // window must be connected upon calling underlying
858 // eglCreateWindowSurface
859 if (window) {
860 window->incRef(window);
861 if (window->connect)
862 window->connect(window);
863 }
864
865 EGLSurface surface = cnx->hooks->egl.eglCreateWindowSurface(
866 dp->dpys[i], dp->configs[i][index], window, attrib_list);
867 if (surface != EGL_NO_SURFACE) {
868 egl_surface_t* s = new egl_surface_t(dpy, surface, window, i, cnx);
869 return s;
870 }
871
872 // something went wrong, disconnect and free window
873 // (will disconnect() automatically)
874 if (window) {
875 window->decRef(window);
876 }
877 }
878 return EGL_NO_SURFACE;
879}
880
881EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
882 NativePixmapType pixmap,
883 const EGLint *attrib_list)
884{
885 egl_display_t const* dp = 0;
886 int i=0, index=0;
887 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
888 if (cnx) {
889 EGLSurface surface = cnx->hooks->egl.eglCreatePixmapSurface(
890 dp->dpys[i], dp->configs[i][index], pixmap, attrib_list);
891 if (surface != EGL_NO_SURFACE) {
892 egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
893 return s;
894 }
895 }
896 return EGL_NO_SURFACE;
897}
898
899EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
900 const EGLint *attrib_list)
901{
902 egl_display_t const* dp = 0;
903 int i=0, index=0;
904 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
905 if (cnx) {
906 EGLSurface surface = cnx->hooks->egl.eglCreatePbufferSurface(
907 dp->dpys[i], dp->configs[i][index], attrib_list);
908 if (surface != EGL_NO_SURFACE) {
909 egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
910 return s;
911 }
912 }
913 return EGL_NO_SURFACE;
914}
915
916EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
917{
918 if (!validate_display_surface(dpy, surface))
919 return EGL_FALSE;
920 egl_display_t const * const dp = get_display(dpy);
921 egl_surface_t const * const s = get_surface(surface);
922
923 EGLBoolean result = s->cnx->hooks->egl.eglDestroySurface(
924 dp->dpys[s->impl], s->surface);
925
926 delete s;
927 return result;
928}
929
930EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
931 EGLint attribute, EGLint *value)
932{
933 if (!validate_display_surface(dpy, surface))
934 return EGL_FALSE;
935 egl_display_t const * const dp = get_display(dpy);
936 egl_surface_t const * const s = get_surface(surface);
937
938 return s->cnx->hooks->egl.eglQuerySurface(
939 dp->dpys[s->impl], s->surface, attribute, value);
940}
941
942// ----------------------------------------------------------------------------
943// contextes
944// ----------------------------------------------------------------------------
945
946EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
947 EGLContext share_list, const EGLint *attrib_list)
948{
949 egl_display_t const* dp = 0;
950 int i=0, index=0;
951 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
952 if (cnx) {
953 EGLContext context = cnx->hooks->egl.eglCreateContext(
954 dp->dpys[i], dp->configs[i][index], share_list, attrib_list);
955 if (context != EGL_NO_CONTEXT) {
956 egl_context_t* c = new egl_context_t(dpy, context, i, cnx);
957 return c;
958 }
959 }
960 return EGL_NO_CONTEXT;
961}
962
963EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
964{
965 if (!validate_display_context(dpy, ctx))
966 return EGL_FALSE;
967 egl_display_t const * const dp = get_display(dpy);
968 egl_context_t * const c = get_context(ctx);
969 EGLBoolean result = c->cnx->hooks->egl.eglDestroyContext(
970 dp->dpys[c->impl], c->context);
971 delete c;
972 return result;
973}
974
975EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
976 EGLSurface read, EGLContext ctx)
977{
978 egl_display_t const * const dp = get_display(dpy);
979 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
980
981 if (read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE &&
982 ctx == EGL_NO_CONTEXT)
983 {
984 EGLBoolean result = EGL_TRUE;
985 ctx = getContext();
986 if (ctx) {
987 egl_context_t * const c = get_context(ctx);
988 result = c->cnx->hooks->egl.eglMakeCurrent(dp->dpys[c->impl], 0, 0, 0);
989 if (result == EGL_TRUE) {
990 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
991 setContext(EGL_NO_CONTEXT);
992 }
993 }
994 return result;
995 }
996
997 if (!validate_display_context(dpy, ctx))
998 return EGL_FALSE;
999
1000 egl_context_t * const c = get_context(ctx);
1001 if (draw != EGL_NO_SURFACE) {
1002 egl_surface_t const * d = get_surface(draw);
1003 if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1004 if (d->impl != c->impl)
1005 return setError(EGL_BAD_MATCH, EGL_FALSE);
1006 draw = d->surface;
1007 }
1008 if (read != EGL_NO_SURFACE) {
1009 egl_surface_t const * r = get_surface(read);
1010 if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1011 if (r->impl != c->impl)
1012 return setError(EGL_BAD_MATCH, EGL_FALSE);
1013 read = r->surface;
1014 }
1015 EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent(
1016 dp->dpys[c->impl], draw, read, c->context);
1017
1018 if (result == EGL_TRUE) {
1019 setGlThreadSpecific(c->cnx->hooks);
1020 setContext(ctx);
1021 c->read = read;
1022 c->draw = draw;
1023 }
1024 return result;
1025}
1026
1027
1028EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1029 EGLint attribute, EGLint *value)
1030{
1031 if (!validate_display_context(dpy, ctx))
1032 return EGL_FALSE;
1033
1034 egl_display_t const * const dp = get_display(dpy);
1035 egl_context_t * const c = get_context(ctx);
1036
1037 return c->cnx->hooks->egl.eglQueryContext(
1038 dp->dpys[c->impl], c->context, attribute, value);
1039}
1040
1041EGLContext eglGetCurrentContext(void)
1042{
1043 EGLContext ctx = getContext();
1044 return ctx;
1045}
1046
1047EGLSurface eglGetCurrentSurface(EGLint readdraw)
1048{
1049 EGLContext ctx = getContext();
1050 if (ctx) {
1051 egl_context_t const * const c = get_context(ctx);
1052 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1053 switch (readdraw) {
1054 case EGL_READ: return c->read;
1055 case EGL_DRAW: return c->draw;
1056 default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1057 }
1058 }
1059 return EGL_NO_SURFACE;
1060}
1061
1062EGLDisplay eglGetCurrentDisplay(void)
1063{
1064 EGLContext ctx = getContext();
1065 if (ctx) {
1066 egl_context_t const * const c = get_context(ctx);
1067 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1068 return c->dpy;
1069 }
1070 return EGL_NO_DISPLAY;
1071}
1072
1073EGLBoolean eglWaitGL(void)
1074{
1075 EGLBoolean res = EGL_TRUE;
1076 EGLContext ctx = getContext();
1077 if (ctx) {
1078 egl_context_t const * const c = get_context(ctx);
1079 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1080 if (uint32_t(c->impl)>=2)
1081 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1082 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1083 if (!cnx->dso)
1084 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1085 res = cnx->hooks->egl.eglWaitGL();
1086 }
1087 return res;
1088}
1089
1090EGLBoolean eglWaitNative(EGLint engine)
1091{
1092 EGLBoolean res = EGL_TRUE;
1093 EGLContext ctx = getContext();
1094 if (ctx) {
1095 egl_context_t const * const c = get_context(ctx);
1096 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1097 if (uint32_t(c->impl)>=2)
1098 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1099 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1100 if (!cnx->dso)
1101 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1102 res = cnx->hooks->egl.eglWaitNative(engine);
1103 }
1104 return res;
1105}
1106
1107EGLint eglGetError(void)
1108{
1109 EGLint result = EGL_SUCCESS;
1110 for (int i=0 ; i<2 ; i++) {
1111 EGLint err = EGL_SUCCESS;
1112 egl_connection_t* const cnx = &gEGLImpl[i];
1113 if (cnx->dso)
1114 err = cnx->hooks->egl.eglGetError();
1115 if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
1116 result = err;
1117 }
1118 if (result == EGL_SUCCESS)
1119 result = getError();
1120 return result;
1121}
1122
1123void (*eglGetProcAddress(const char *procname))()
1124{
1125 __eglMustCastToProperFunctionPointerType addr;
1126 addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
1127 if (addr) return addr;
1128
1129 return NULL; // TODO: finish implementation below
1130
1131 addr = findProcAddress(procname, gGLExtentionMap, NELEM(gGLExtentionMap));
1132 if (addr) return addr;
1133
1134 addr = 0;
1135 int slot = -1;
1136 for (int i=0 ; i<2 ; i++) {
1137 egl_connection_t* const cnx = &gEGLImpl[i];
1138 if (cnx->dso) {
1139 if (cnx->hooks->egl.eglGetProcAddress) {
1140 addr = cnx->hooks->egl.eglGetProcAddress(procname);
1141 if (addr) {
1142 if (slot == -1) {
1143 slot = 0; // XXX: find free slot
1144 if (slot == -1) {
1145 addr = 0;
1146 break;
1147 }
1148 }
1149 cnx->hooks->ext.extensions[slot] = addr;
1150 }
1151 }
1152 }
1153 }
1154
1155 if (slot >= 0) {
1156 addr = 0; // XXX: address of stub 'slot'
1157 gGLExtentionMap[slot].name = strdup(procname);
1158 gGLExtentionMap[slot].address = addr;
1159 }
1160
1161 return addr;
1162
1163
1164 /*
1165 * TODO: For OpenGL ES extensions, we must generate a stub
1166 * that looks like
1167 * mov r12, #0xFFFF0FFF
1168 * ldr r12, [r12, #-15]
1169 * ldr r12, [r12, #TLS_SLOT_OPENGL_API*4]
1170 * mov r12, [r12, #api_offset]
1171 * ldrne pc, r12
1172 * mov pc, #unsupported_extension
1173 *
1174 * and write the address of the extension in *all*
1175 * gl_hooks_t::gl_ext_t at offset "api_offset" from gl_hooks_t
1176 *
1177 */
1178}
1179
1180EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1181{
1182 if (!validate_display_surface(dpy, draw))
1183 return EGL_FALSE;
1184 egl_display_t const * const dp = get_display(dpy);
1185 egl_surface_t const * const s = get_surface(draw);
1186 return s->cnx->hooks->egl.eglSwapBuffers(dp->dpys[s->impl], s->surface);
1187}
1188
1189EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
1190 NativePixmapType target)
1191{
1192 if (!validate_display_surface(dpy, surface))
1193 return EGL_FALSE;
1194 egl_display_t const * const dp = get_display(dpy);
1195 egl_surface_t const * const s = get_surface(surface);
1196 return s->cnx->hooks->egl.eglCopyBuffers(
1197 dp->dpys[s->impl], s->surface, target);
1198}
1199
1200const char* eglQueryString(EGLDisplay dpy, EGLint name)
1201{
1202 egl_display_t const * const dp = get_display(dpy);
1203 switch (name) {
1204 case EGL_VENDOR:
1205 return gVendorString;
1206 case EGL_VERSION:
1207 return gVersionString;
1208 case EGL_EXTENSIONS:
1209 return gExtensionString;
1210 case EGL_CLIENT_APIS:
1211 return gClientApiString;
1212 }
1213 return setError(EGL_BAD_PARAMETER, (const char *)0);
1214}
1215
1216
1217// ----------------------------------------------------------------------------
1218// EGL 1.1
1219// ----------------------------------------------------------------------------
1220
1221EGLBoolean eglSurfaceAttrib(
1222 EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1223{
1224 if (!validate_display_surface(dpy, surface))
1225 return EGL_FALSE;
1226 egl_display_t const * const dp = get_display(dpy);
1227 egl_surface_t const * const s = get_surface(surface);
1228 if (s->cnx->hooks->egl.eglSurfaceAttrib) {
1229 return s->cnx->hooks->egl.eglSurfaceAttrib(
1230 dp->dpys[s->impl], s->surface, attribute, value);
1231 }
1232 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1233}
1234
1235EGLBoolean eglBindTexImage(
1236 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1237{
1238 if (!validate_display_surface(dpy, surface))
1239 return EGL_FALSE;
1240 egl_display_t const * const dp = get_display(dpy);
1241 egl_surface_t const * const s = get_surface(surface);
1242 if (s->cnx->hooks->egl.eglBindTexImage) {
1243 return s->cnx->hooks->egl.eglBindTexImage(
1244 dp->dpys[s->impl], s->surface, buffer);
1245 }
1246 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1247}
1248
1249EGLBoolean eglReleaseTexImage(
1250 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1251{
1252 if (!validate_display_surface(dpy, surface))
1253 return EGL_FALSE;
1254 egl_display_t const * const dp = get_display(dpy);
1255 egl_surface_t const * const s = get_surface(surface);
1256 if (s->cnx->hooks->egl.eglReleaseTexImage) {
1257 return s->cnx->hooks->egl.eglReleaseTexImage(
1258 dp->dpys[s->impl], s->surface, buffer);
1259 }
1260 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1261}
1262
1263EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1264{
1265 egl_display_t * const dp = get_display(dpy);
1266 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1267
1268 EGLBoolean res = EGL_TRUE;
1269 for (int i=0 ; i<2 ; i++) {
1270 egl_connection_t* const cnx = &gEGLImpl[i];
1271 if (cnx->dso) {
1272 if (cnx->hooks->egl.eglSwapInterval) {
1273 if (cnx->hooks->egl.eglSwapInterval(dp->dpys[i], interval) == EGL_FALSE) {
1274 res = EGL_FALSE;
1275 }
1276 }
1277 }
1278 }
1279 return res;
1280}
1281
1282
1283// ----------------------------------------------------------------------------
1284// EGL 1.2
1285// ----------------------------------------------------------------------------
1286
1287EGLBoolean eglWaitClient(void)
1288{
1289 EGLBoolean res = EGL_TRUE;
1290 EGLContext ctx = getContext();
1291 if (ctx) {
1292 egl_context_t const * const c = get_context(ctx);
1293 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1294 if (uint32_t(c->impl)>=2)
1295 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1296 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1297 if (!cnx->dso)
1298 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1299 if (cnx->hooks->egl.eglWaitClient) {
1300 res = cnx->hooks->egl.eglWaitClient();
1301 } else {
1302 res = cnx->hooks->egl.eglWaitGL();
1303 }
1304 }
1305 return res;
1306}
1307
1308EGLBoolean eglBindAPI(EGLenum api)
1309{
1310 // bind this API on all EGLs
1311 EGLBoolean res = EGL_TRUE;
1312 for (int i=0 ; i<2 ; i++) {
1313 egl_connection_t* const cnx = &gEGLImpl[i];
1314 if (cnx->dso) {
1315 if (cnx->hooks->egl.eglBindAPI) {
1316 if (cnx->hooks->egl.eglBindAPI(api) == EGL_FALSE) {
1317 res = EGL_FALSE;
1318 }
1319 }
1320 }
1321 }
1322 return res;
1323}
1324
1325EGLenum eglQueryAPI(void)
1326{
1327 for (int i=0 ; i<2 ; i++) {
1328 egl_connection_t* const cnx = &gEGLImpl[i];
1329 if (cnx->dso) {
1330 if (cnx->hooks->egl.eglQueryAPI) {
1331 // the first one we find is okay, because they all
1332 // should be the same
1333 return cnx->hooks->egl.eglQueryAPI();
1334 }
1335 }
1336 }
1337 // or, it can only be OpenGL ES
1338 return EGL_OPENGL_ES_API;
1339}
1340
1341EGLBoolean eglReleaseThread(void)
1342{
1343 for (int i=0 ; i<2 ; i++) {
1344 egl_connection_t* const cnx = &gEGLImpl[i];
1345 if (cnx->dso) {
1346 if (cnx->hooks->egl.eglReleaseThread) {
1347 cnx->hooks->egl.eglReleaseThread();
1348 }
1349 }
1350 }
1351 clearTLS();
1352 return EGL_TRUE;
1353}
1354
1355EGLSurface eglCreatePbufferFromClientBuffer(
1356 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1357 EGLConfig config, const EGLint *attrib_list)
1358{
1359 egl_display_t const* dp = 0;
1360 int i=0, index=0;
1361 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1362 if (!cnx) return EGL_FALSE;
1363 if (cnx->hooks->egl.eglCreatePbufferFromClientBuffer) {
1364 return cnx->hooks->egl.eglCreatePbufferFromClientBuffer(
1365 dp->dpys[i], buftype, buffer, dp->configs[i][index], attrib_list);
1366 }
1367 return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1368}