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