eglApi.cpp revision 4b9511c16195a646242eff833b0af212933b6eca
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
21#include <hardware/gralloc.h>
22#include <system/window.h>
23
24#include <EGL/egl.h>
25#include <EGL/eglext.h>
26#include <GLES/gl.h>
27#include <GLES/glext.h>
28
29#include <cutils/log.h>
30#include <cutils/atomic.h>
31#include <cutils/properties.h>
32#include <cutils/memory.h>
33
34#include <utils/KeyedVector.h>
35#include <utils/SortedVector.h>
36#include <utils/String8.h>
37
38#include "egl_impl.h"
39#include "egl_tls.h"
40#include "glesv2dbg.h"
41#include "hooks.h"
42
43#include "egl_display.h"
44#include "egl_impl.h"
45#include "egl_object.h"
46#include "egl_tls.h"
47
48using namespace android;
49
50// ----------------------------------------------------------------------------
51
52struct extention_map_t {
53    const char* name;
54    __eglMustCastToProperFunctionPointerType address;
55};
56
57static const extention_map_t sExtentionMap[] = {
58    { "eglLockSurfaceKHR",
59            (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
60    { "eglUnlockSurfaceKHR",
61            (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
62    { "eglCreateImageKHR",
63            (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
64    { "eglDestroyImageKHR",
65            (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
66    { "eglGetSystemTimeFrequencyNV",
67            (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeFrequencyNV },
68    { "eglGetSystemTimeNV",
69            (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeNV },
70};
71
72// accesses protected by sExtensionMapMutex
73static DefaultKeyedVector<String8, __eglMustCastToProperFunctionPointerType> sGLExtentionMap;
74static int sGLExtentionSlot = 0;
75static pthread_mutex_t sExtensionMapMutex = PTHREAD_MUTEX_INITIALIZER;
76
77static void(*findProcAddress(const char* name,
78        const extention_map_t* map, size_t n))() {
79    for (uint32_t i=0 ; i<n ; i++) {
80        if (!strcmp(name, map[i].name)) {
81            return map[i].address;
82        }
83    }
84    return NULL;
85}
86
87// ----------------------------------------------------------------------------
88
89template<typename T>
90static __attribute__((noinline))
91int binarySearch(T const sortedArray[], int first, int last, T key) {
92    while (first <= last) {
93        int mid = (first + last) / 2;
94        if (sortedArray[mid] < key) {
95            first = mid + 1;
96        } else if (key < sortedArray[mid]) {
97            last = mid - 1;
98        } else {
99            return mid;
100        }
101    }
102    return -1;
103}
104
105// ----------------------------------------------------------------------------
106
107namespace android {
108extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
109extern EGLBoolean egl_init_drivers();
110extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS];
111extern int gEGLDebugLevel;
112extern gl_hooks_t gHooksTrace;
113extern gl_hooks_t gHooksDebug;
114} // namespace android;
115
116// ----------------------------------------------------------------------------
117
118static inline void clearError() { egl_tls_t::clearError(); }
119static inline EGLContext getContext() { return egl_tls_t::getContext(); }
120
121// ----------------------------------------------------------------------------
122
123EGLDisplay eglGetDisplay(EGLNativeDisplayType display)
124{
125    clearError();
126
127    uint32_t index = uint32_t(display);
128    if (index >= NUM_DISPLAYS) {
129        return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
130    }
131
132    if (egl_init_drivers() == EGL_FALSE) {
133        return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
134    }
135
136    EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display);
137    return dpy;
138}
139
140// ----------------------------------------------------------------------------
141// Initialization
142// ----------------------------------------------------------------------------
143
144EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
145{
146    clearError();
147
148    egl_display_t * const dp = get_display(dpy);
149    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
150
151    EGLBoolean res = dp->initialize(major, minor);
152
153    return res;
154}
155
156EGLBoolean eglTerminate(EGLDisplay dpy)
157{
158    // NOTE: don't unload the drivers b/c some APIs can be called
159    // after eglTerminate() has been called. eglTerminate() only
160    // terminates an EGLDisplay, not a EGL itself.
161
162    clearError();
163
164    egl_display_t* const dp = get_display(dpy);
165    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
166
167    EGLBoolean res = dp->terminate();
168
169    return res;
170}
171
172// ----------------------------------------------------------------------------
173// configuration
174// ----------------------------------------------------------------------------
175
176EGLBoolean eglGetConfigs(   EGLDisplay dpy,
177                            EGLConfig *configs,
178                            EGLint config_size, EGLint *num_config)
179{
180    clearError();
181
182    egl_display_t const * const dp = validate_display(dpy);
183    if (!dp) return EGL_FALSE;
184
185    GLint numConfigs = dp->numTotalConfigs;
186    if (!configs) {
187        *num_config = numConfigs;
188        return EGL_TRUE;
189    }
190
191    GLint n = 0;
192    for (intptr_t i=0 ; i<dp->numTotalConfigs && config_size ; i++) {
193        *configs++ = EGLConfig(i);
194        config_size--;
195        n++;
196    }
197
198    *num_config = n;
199    return EGL_TRUE;
200}
201
202EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
203                            EGLConfig *configs, EGLint config_size,
204                            EGLint *num_config)
205{
206    clearError();
207
208    egl_display_t const * const dp = validate_display(dpy);
209    if (!dp) return EGL_FALSE;
210
211    if (num_config==0) {
212        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
213    }
214
215    EGLint n;
216    EGLBoolean res = EGL_FALSE;
217    *num_config = 0;
218
219
220    // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
221    // to do this, we have to go through the attrib_list array once
222    // to figure out both its size and if it contains an EGL_CONFIG_ID
223    // key. If so, the full array is copied and patched.
224    // NOTE: we assume that there can be only one occurrence
225    // of EGL_CONFIG_ID.
226
227    EGLint patch_index = -1;
228    GLint attr;
229    size_t size = 0;
230    if (attrib_list) {
231        while ((attr=attrib_list[size]) != EGL_NONE) {
232            if (attr == EGL_CONFIG_ID)
233                patch_index = size;
234            size += 2;
235        }
236    }
237    if (patch_index >= 0) {
238        size += 2; // we need copy the sentinel as well
239        EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
240        if (new_list == 0)
241            return setError(EGL_BAD_ALLOC, EGL_FALSE);
242        memcpy(new_list, attrib_list, size*sizeof(EGLint));
243
244        // patch the requested EGL_CONFIG_ID
245        bool found = false;
246        EGLConfig ourConfig(0);
247        EGLint& configId(new_list[patch_index+1]);
248        for (intptr_t i=0 ; i<dp->numTotalConfigs ; i++) {
249            if (dp->configs[i].configId == configId) {
250                ourConfig = EGLConfig(i);
251                configId = dp->configs[i].implConfigId;
252                found = true;
253                break;
254            }
255        }
256
257        egl_connection_t* const cnx = &gEGLImpl[dp->configs[intptr_t(ourConfig)].impl];
258        if (found && cnx->dso) {
259            // and switch to the new list
260            attrib_list = const_cast<const EGLint *>(new_list);
261
262            // At this point, the only configuration that can match is
263            // dp->configs[i][index], however, we don't know if it would be
264            // rejected because of the other attributes, so we do have to call
265            // cnx->egl.eglChooseConfig() -- but we don't have to loop
266            // through all the EGLimpl[].
267            // We also know we can only get a single config back, and we know
268            // which one.
269
270            res = cnx->egl.eglChooseConfig(
271                    dp->disp[ dp->configs[intptr_t(ourConfig)].impl ].dpy,
272                    attrib_list, configs, config_size, &n);
273            if (res && n>0) {
274                // n has to be 0 or 1, by construction, and we already know
275                // which config it will return (since there can be only one).
276                if (configs) {
277                    configs[0] = ourConfig;
278                }
279                *num_config = 1;
280            }
281        }
282
283        free(const_cast<EGLint *>(attrib_list));
284        return res;
285    }
286
287
288    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
289        egl_connection_t* const cnx = &gEGLImpl[i];
290        if (cnx->dso) {
291            if (cnx->egl.eglChooseConfig(
292                    dp->disp[i].dpy, attrib_list, configs, config_size, &n)) {
293                if (configs) {
294                    // now we need to convert these client EGLConfig to our
295                    // internal EGLConfig format.
296                    // This is done in O(n Log(n)) time.
297                    for (int j=0 ; j<n ; j++) {
298                        egl_config_t key(i, configs[j]);
299                        intptr_t index = binarySearch<egl_config_t>(
300                                dp->configs, 0, dp->numTotalConfigs, key);
301                        if (index >= 0) {
302                            configs[j] = EGLConfig(index);
303                        } else {
304                            return setError(EGL_BAD_CONFIG, EGL_FALSE);
305                        }
306                    }
307                    configs += n;
308                    config_size -= n;
309                }
310                *num_config += n;
311                res = EGL_TRUE;
312            }
313        }
314    }
315    return res;
316}
317
318EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
319        EGLint attribute, EGLint *value)
320{
321    clearError();
322
323    egl_display_t const* dp = 0;
324    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
325    if (!cnx) return EGL_FALSE;
326
327    if (attribute == EGL_CONFIG_ID) {
328        *value = dp->configs[intptr_t(config)].configId;
329        return EGL_TRUE;
330    }
331    return cnx->egl.eglGetConfigAttrib(
332            dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
333            dp->configs[intptr_t(config)].config, attribute, value);
334}
335
336// ----------------------------------------------------------------------------
337// surfaces
338// ----------------------------------------------------------------------------
339
340EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
341                                    NativeWindowType window,
342                                    const EGLint *attrib_list)
343{
344    clearError();
345
346    egl_display_t const* dp = 0;
347    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
348    if (cnx) {
349        EGLDisplay iDpy = dp->disp[ dp->configs[intptr_t(config)].impl ].dpy;
350        EGLConfig iConfig = dp->configs[intptr_t(config)].config;
351        EGLint format;
352
353        if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) != OK) {
354            LOGE("EGLNativeWindowType %p already connected to another API",
355                    window);
356            return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
357        }
358
359        // set the native window's buffers format to match this config
360        if (cnx->egl.eglGetConfigAttrib(iDpy,
361                iConfig, EGL_NATIVE_VISUAL_ID, &format)) {
362            if (format != 0) {
363                int err = native_window_set_buffers_format(window, format);
364                if (err != 0) {
365                    LOGE("error setting native window pixel format: %s (%d)",
366                            strerror(-err), err);
367                    native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
368                    return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
369                }
370            }
371        }
372
373        EGLSurface surface = cnx->egl.eglCreateWindowSurface(
374                iDpy, iConfig, window, attrib_list);
375        if (surface != EGL_NO_SURFACE) {
376            egl_surface_t* s = new egl_surface_t(dpy, config, window, surface,
377                    dp->configs[intptr_t(config)].impl, cnx);
378            return s;
379        }
380
381        // EGLSurface creation failed
382        native_window_set_buffers_format(window, 0);
383        native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
384    }
385    return EGL_NO_SURFACE;
386}
387
388EGLSurface eglCreatePixmapSurface(  EGLDisplay dpy, EGLConfig config,
389                                    NativePixmapType pixmap,
390                                    const EGLint *attrib_list)
391{
392    clearError();
393
394    egl_display_t const* dp = 0;
395    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
396    if (cnx) {
397        EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
398                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
399                dp->configs[intptr_t(config)].config, pixmap, attrib_list);
400        if (surface != EGL_NO_SURFACE) {
401            egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface,
402                    dp->configs[intptr_t(config)].impl, cnx);
403            return s;
404        }
405    }
406    return EGL_NO_SURFACE;
407}
408
409EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
410                                    const EGLint *attrib_list)
411{
412    clearError();
413
414    egl_display_t const* dp = 0;
415    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
416    if (cnx) {
417        EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
418                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
419                dp->configs[intptr_t(config)].config, attrib_list);
420        if (surface != EGL_NO_SURFACE) {
421            egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface,
422                    dp->configs[intptr_t(config)].impl, cnx);
423            return s;
424        }
425    }
426    return EGL_NO_SURFACE;
427}
428
429EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
430{
431    clearError();
432
433    egl_display_t const * const dp = validate_display(dpy);
434    if (!dp) return EGL_FALSE;
435
436    SurfaceRef _s(dp, surface);
437    if (!_s.get())
438        return setError(EGL_BAD_SURFACE, EGL_FALSE);
439
440    egl_surface_t * const s = get_surface(surface);
441    EGLBoolean result = s->cnx->egl.eglDestroySurface(
442            dp->disp[s->impl].dpy, s->surface);
443    if (result == EGL_TRUE) {
444        _s.terminate();
445    }
446    return result;
447}
448
449EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
450                            EGLint attribute, EGLint *value)
451{
452    clearError();
453
454    egl_display_t const * const dp = validate_display(dpy);
455    if (!dp) return EGL_FALSE;
456
457    SurfaceRef _s(dp, surface);
458    if (!_s.get())
459        return setError(EGL_BAD_SURFACE, EGL_FALSE);
460
461    egl_surface_t const * const s = get_surface(surface);
462    EGLBoolean result(EGL_TRUE);
463    if (attribute == EGL_CONFIG_ID) {
464        // We need to remap EGL_CONFIG_IDs
465        *value = dp->configs[intptr_t(s->config)].configId;
466    } else {
467        result = s->cnx->egl.eglQuerySurface(
468                dp->disp[s->impl].dpy, s->surface, attribute, value);
469    }
470
471    return result;
472}
473
474// ----------------------------------------------------------------------------
475// Contexts
476// ----------------------------------------------------------------------------
477
478EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
479                            EGLContext share_list, const EGLint *attrib_list)
480{
481    clearError();
482
483    egl_display_t const* dp = 0;
484    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
485    if (cnx) {
486        if (share_list != EGL_NO_CONTEXT) {
487            egl_context_t* const c = get_context(share_list);
488            share_list = c->context;
489        }
490        EGLContext context = cnx->egl.eglCreateContext(
491                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
492                dp->configs[intptr_t(config)].config,
493                share_list, attrib_list);
494        if (context != EGL_NO_CONTEXT) {
495            // figure out if it's a GLESv1 or GLESv2
496            int version = 0;
497            if (attrib_list) {
498                while (*attrib_list != EGL_NONE) {
499                    GLint attr = *attrib_list++;
500                    GLint value = *attrib_list++;
501                    if (attr == EGL_CONTEXT_CLIENT_VERSION) {
502                        if (value == 1) {
503                            version = GLESv1_INDEX;
504                        } else if (value == 2) {
505                            version = GLESv2_INDEX;
506                        }
507                    }
508                };
509            }
510            egl_context_t* c = new egl_context_t(dpy, context, config,
511                    dp->configs[intptr_t(config)].impl, cnx, version);
512            return c;
513        }
514    }
515    return EGL_NO_CONTEXT;
516}
517
518EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
519{
520    clearError();
521
522    egl_display_t const * const dp = validate_display(dpy);
523    if (!dp)
524        return EGL_FALSE;
525
526    ContextRef _c(dp, ctx);
527    if (!_c.get())
528        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
529
530    egl_context_t * const c = get_context(ctx);
531    EGLBoolean result = c->cnx->egl.eglDestroyContext(
532            dp->disp[c->impl].dpy, c->context);
533    if (result == EGL_TRUE) {
534        _c.terminate();
535    }
536    return result;
537}
538
539static void loseCurrent(egl_context_t * cur_c)
540{
541    if (cur_c) {
542        egl_surface_t * cur_r = get_surface(cur_c->read);
543        egl_surface_t * cur_d = get_surface(cur_c->draw);
544
545        // by construction, these are either 0 or valid (possibly terminated)
546        // it should be impossible for these to be invalid
547        ContextRef _cur_c(cur_c);
548        SurfaceRef _cur_r(cur_r);
549        SurfaceRef _cur_d(cur_d);
550
551        cur_c->read = NULL;
552        cur_c->draw = NULL;
553
554        _cur_c.release();
555        _cur_r.release();
556        _cur_d.release();
557    }
558}
559
560EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
561                            EGLSurface read, EGLContext ctx)
562{
563    clearError();
564
565    egl_display_t const * const dp = get_display(dpy);
566    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
567
568    // If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not
569    // EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is
570    // a valid but uninitialized display.
571    if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) ||
572         (draw != EGL_NO_SURFACE) ) {
573        if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
574    }
575
576    // get a reference to the object passed in
577    ContextRef _c(dp, ctx);
578    SurfaceRef _d(dp, draw);
579    SurfaceRef _r(dp, read);
580
581    // validate the context (if not EGL_NO_CONTEXT)
582    if ((ctx != EGL_NO_CONTEXT) && !_c.get()) {
583        // EGL_NO_CONTEXT is valid
584        return EGL_FALSE;
585    }
586
587    // these are the underlying implementation's object
588    EGLContext impl_ctx  = EGL_NO_CONTEXT;
589    EGLSurface impl_draw = EGL_NO_SURFACE;
590    EGLSurface impl_read = EGL_NO_SURFACE;
591
592    // these are our objects structs passed in
593    egl_context_t       * c = NULL;
594    egl_surface_t const * d = NULL;
595    egl_surface_t const * r = NULL;
596
597    // these are the current objects structs
598    egl_context_t * cur_c = get_context(getContext());
599
600    if (ctx != EGL_NO_CONTEXT) {
601        c = get_context(ctx);
602        impl_ctx = c->context;
603    } else {
604        // no context given, use the implementation of the current context
605        if (cur_c == NULL) {
606            // no current context
607            if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
608                // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT);
609                return setError(EGL_BAD_MATCH, EGL_FALSE);
610            }
611            // not an error, there is just no current context.
612            return EGL_TRUE;
613        }
614    }
615
616    // retrieve the underlying implementation's draw EGLSurface
617    if (draw != EGL_NO_SURFACE) {
618        d = get_surface(draw);
619        // make sure the EGLContext and EGLSurface passed in are for
620        // the same driver
621        if (c && d->impl != c->impl)
622            return setError(EGL_BAD_MATCH, EGL_FALSE);
623        impl_draw = d->surface;
624    }
625
626    // retrieve the underlying implementation's read EGLSurface
627    if (read != EGL_NO_SURFACE) {
628        r = get_surface(read);
629        // make sure the EGLContext and EGLSurface passed in are for
630        // the same driver
631        if (c && r->impl != c->impl)
632            return setError(EGL_BAD_MATCH, EGL_FALSE);
633        impl_read = r->surface;
634    }
635
636    EGLBoolean result;
637
638    if (c) {
639        result = c->cnx->egl.eglMakeCurrent(
640                dp->disp[c->impl].dpy, impl_draw, impl_read, impl_ctx);
641    } else {
642        result = cur_c->cnx->egl.eglMakeCurrent(
643                dp->disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx);
644    }
645
646    if (result == EGL_TRUE) {
647
648        loseCurrent(cur_c);
649
650        if (ctx != EGL_NO_CONTEXT) {
651            setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
652            egl_tls_t::setContext(ctx);
653            if (gEGLDebugLevel > 0) {
654                CreateDbgContext(c->version, c->cnx->hooks[c->version]);
655            }
656            _c.acquire();
657            _r.acquire();
658            _d.acquire();
659            c->read = read;
660            c->draw = draw;
661        } else {
662            setGLHooksThreadSpecific(&gHooksNoContext);
663            egl_tls_t::setContext(EGL_NO_CONTEXT);
664        }
665    } else {
666        // this will LOGE the error
667        result = setError(c->cnx->egl.eglGetError(), EGL_FALSE);
668    }
669    return result;
670}
671
672
673EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
674                            EGLint attribute, EGLint *value)
675{
676    clearError();
677
678    egl_display_t const * const dp = validate_display(dpy);
679    if (!dp) return EGL_FALSE;
680
681    ContextRef _c(dp, ctx);
682    if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
683
684    egl_context_t * const c = get_context(ctx);
685
686    EGLBoolean result(EGL_TRUE);
687    if (attribute == EGL_CONFIG_ID) {
688        *value = dp->configs[intptr_t(c->config)].configId;
689    } else {
690        // We need to remap EGL_CONFIG_IDs
691        result = c->cnx->egl.eglQueryContext(
692                dp->disp[c->impl].dpy, c->context, attribute, value);
693    }
694
695    return result;
696}
697
698EGLContext eglGetCurrentContext(void)
699{
700    // could be called before eglInitialize(), but we wouldn't have a context
701    // then, and this function would correctly return EGL_NO_CONTEXT.
702
703    clearError();
704
705    EGLContext ctx = getContext();
706    return ctx;
707}
708
709EGLSurface eglGetCurrentSurface(EGLint readdraw)
710{
711    // could be called before eglInitialize(), but we wouldn't have a context
712    // then, and this function would correctly return EGL_NO_SURFACE.
713
714    clearError();
715
716    EGLContext ctx = getContext();
717    if (ctx) {
718        egl_context_t const * const c = get_context(ctx);
719        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
720        switch (readdraw) {
721            case EGL_READ: return c->read;
722            case EGL_DRAW: return c->draw;
723            default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
724        }
725    }
726    return EGL_NO_SURFACE;
727}
728
729EGLDisplay eglGetCurrentDisplay(void)
730{
731    // could be called before eglInitialize(), but we wouldn't have a context
732    // then, and this function would correctly return EGL_NO_DISPLAY.
733
734    clearError();
735
736    EGLContext ctx = getContext();
737    if (ctx) {
738        egl_context_t const * const c = get_context(ctx);
739        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
740        return c->dpy;
741    }
742    return EGL_NO_DISPLAY;
743}
744
745EGLBoolean eglWaitGL(void)
746{
747    // could be called before eglInitialize(), but we wouldn't have a context
748    // then, and this function would return GL_TRUE, which isn't wrong.
749
750    clearError();
751
752    EGLBoolean res = EGL_TRUE;
753    EGLContext ctx = getContext();
754    if (ctx) {
755        egl_context_t const * const c = get_context(ctx);
756        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
757        if (uint32_t(c->impl)>=2)
758            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
759        egl_connection_t* const cnx = &gEGLImpl[c->impl];
760        if (!cnx->dso)
761            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
762        res = cnx->egl.eglWaitGL();
763    }
764    return res;
765}
766
767EGLBoolean eglWaitNative(EGLint engine)
768{
769    // could be called before eglInitialize(), but we wouldn't have a context
770    // then, and this function would return GL_TRUE, which isn't wrong.
771
772    clearError();
773
774    EGLBoolean res = EGL_TRUE;
775    EGLContext ctx = getContext();
776    if (ctx) {
777        egl_context_t const * const c = get_context(ctx);
778        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
779        if (uint32_t(c->impl)>=2)
780            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
781        egl_connection_t* const cnx = &gEGLImpl[c->impl];
782        if (!cnx->dso)
783            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
784        res = cnx->egl.eglWaitNative(engine);
785    }
786    return res;
787}
788
789EGLint eglGetError(void)
790{
791    EGLint result = EGL_SUCCESS;
792    EGLint err;
793    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
794        err = EGL_SUCCESS;
795        egl_connection_t* const cnx = &gEGLImpl[i];
796        if (cnx->dso)
797            err = cnx->egl.eglGetError();
798        if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
799            result = err;
800    }
801    err = egl_tls_t::getError();
802    if (result == EGL_SUCCESS)
803        result = err;
804    return result;
805}
806
807// Note: Similar implementations of these functions also exist in
808// gl2.cpp and gl.cpp, and are used by applications that call the
809// exported entry points directly.
810typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
811typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
812
813static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_impl = NULL;
814static PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES_impl = NULL;
815
816static void glEGLImageTargetTexture2DOES_wrapper(GLenum target, GLeglImageOES image)
817{
818    GLeglImageOES implImage =
819        (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
820    glEGLImageTargetTexture2DOES_impl(target, implImage);
821}
822
823static void glEGLImageTargetRenderbufferStorageOES_wrapper(GLenum target, GLeglImageOES image)
824{
825    GLeglImageOES implImage =
826        (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
827    glEGLImageTargetRenderbufferStorageOES_impl(target, implImage);
828}
829
830__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
831{
832    // eglGetProcAddress() could be the very first function called
833    // in which case we must make sure we've initialized ourselves, this
834    // happens the first time egl_get_display() is called.
835
836    clearError();
837
838    if (egl_init_drivers() == EGL_FALSE) {
839        setError(EGL_BAD_PARAMETER, NULL);
840        return  NULL;
841    }
842
843    // The EGL_ANDROID_blob_cache extension should not be exposed to
844    // applications.  It is used internally by the Android EGL layer.
845    if (!strcmp(procname, "eglSetBlobCacheFuncsANDROID")) {
846        return NULL;
847    }
848
849    __eglMustCastToProperFunctionPointerType addr;
850    addr = findProcAddress(procname, sExtentionMap, NELEM(sExtentionMap));
851    if (addr) return addr;
852
853
854    // this protects accesses to sGLExtentionMap and sGLExtentionSlot
855    pthread_mutex_lock(&sExtensionMapMutex);
856
857        /*
858         * Since eglGetProcAddress() is not associated to anything, it needs
859         * to return a function pointer that "works" regardless of what
860         * the current context is.
861         *
862         * For this reason, we return a "forwarder", a small stub that takes
863         * care of calling the function associated with the context
864         * currently bound.
865         *
866         * We first look for extensions we've already resolved, if we're seeing
867         * this extension for the first time, we go through all our
868         * implementations and call eglGetProcAddress() and record the
869         * result in the appropriate implementation hooks and return the
870         * address of the forwarder corresponding to that hook set.
871         *
872         */
873
874        const String8 name(procname);
875        addr = sGLExtentionMap.valueFor(name);
876        const int slot = sGLExtentionSlot;
877
878        LOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS,
879                "no more slots for eglGetProcAddress(\"%s\")",
880                procname);
881
882        if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) {
883            bool found = false;
884            for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
885                egl_connection_t* const cnx = &gEGLImpl[i];
886                if (cnx->dso && cnx->egl.eglGetProcAddress) {
887                    found = true;
888                    // Extensions are independent of the bound context
889                    cnx->hooks[GLESv1_INDEX]->ext.extensions[slot] =
890                    cnx->hooks[GLESv2_INDEX]->ext.extensions[slot] =
891#if EGL_TRACE
892                    gHooksDebug.ext.extensions[slot] = gHooksTrace.ext.extensions[slot] =
893#endif
894                            cnx->egl.eglGetProcAddress(procname);
895                }
896            }
897            if (found) {
898                addr = gExtensionForwarders[slot];
899
900                if (!strcmp(procname, "glEGLImageTargetTexture2DOES")) {
901                    glEGLImageTargetTexture2DOES_impl = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)addr;
902                    addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetTexture2DOES_wrapper;
903                }
904                if (!strcmp(procname, "glEGLImageTargetRenderbufferStorageOES")) {
905                    glEGLImageTargetRenderbufferStorageOES_impl = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)addr;
906                    addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetRenderbufferStorageOES_wrapper;
907                }
908
909                sGLExtentionMap.add(name, addr);
910                sGLExtentionSlot++;
911            }
912        }
913
914    pthread_mutex_unlock(&sExtensionMapMutex);
915    return addr;
916}
917
918EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
919{
920    EGLBoolean Debug_eglSwapBuffers(EGLDisplay dpy, EGLSurface draw);
921    if (gEGLDebugLevel > 0)
922        Debug_eglSwapBuffers(dpy, draw);
923
924    clearError();
925
926    egl_display_t const * const dp = validate_display(dpy);
927    if (!dp) return EGL_FALSE;
928
929    SurfaceRef _s(dp, draw);
930    if (!_s.get())
931        return setError(EGL_BAD_SURFACE, EGL_FALSE);
932
933    egl_surface_t const * const s = get_surface(draw);
934    return s->cnx->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface);
935}
936
937EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
938                            NativePixmapType target)
939{
940    clearError();
941
942    egl_display_t const * const dp = validate_display(dpy);
943    if (!dp) return EGL_FALSE;
944
945    SurfaceRef _s(dp, surface);
946    if (!_s.get())
947        return setError(EGL_BAD_SURFACE, EGL_FALSE);
948
949    egl_surface_t const * const s = get_surface(surface);
950    return s->cnx->egl.eglCopyBuffers(
951            dp->disp[s->impl].dpy, s->surface, target);
952}
953
954const char* eglQueryString(EGLDisplay dpy, EGLint name)
955{
956    clearError();
957
958    egl_display_t const * const dp = validate_display(dpy);
959    if (!dp) return (const char *) NULL;
960
961    switch (name) {
962        case EGL_VENDOR:
963            return dp->getVendorString();
964        case EGL_VERSION:
965            return dp->getVersionString();
966        case EGL_EXTENSIONS:
967            return dp->getExtensionString();
968        case EGL_CLIENT_APIS:
969            return dp->getClientApiString();
970    }
971    return setError(EGL_BAD_PARAMETER, (const char *)0);
972}
973
974
975// ----------------------------------------------------------------------------
976// EGL 1.1
977// ----------------------------------------------------------------------------
978
979EGLBoolean eglSurfaceAttrib(
980        EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
981{
982    clearError();
983
984    egl_display_t const * const dp = validate_display(dpy);
985    if (!dp) return EGL_FALSE;
986
987    SurfaceRef _s(dp, surface);
988    if (!_s.get())
989        return setError(EGL_BAD_SURFACE, EGL_FALSE);
990
991    egl_surface_t const * const s = get_surface(surface);
992    if (s->cnx->egl.eglSurfaceAttrib) {
993        return s->cnx->egl.eglSurfaceAttrib(
994                dp->disp[s->impl].dpy, s->surface, attribute, value);
995    }
996    return setError(EGL_BAD_SURFACE, EGL_FALSE);
997}
998
999EGLBoolean eglBindTexImage(
1000        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1001{
1002    clearError();
1003
1004    egl_display_t const * const dp = validate_display(dpy);
1005    if (!dp) return EGL_FALSE;
1006
1007    SurfaceRef _s(dp, surface);
1008    if (!_s.get())
1009        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1010
1011    egl_surface_t const * const s = get_surface(surface);
1012    if (s->cnx->egl.eglBindTexImage) {
1013        return s->cnx->egl.eglBindTexImage(
1014                dp->disp[s->impl].dpy, s->surface, buffer);
1015    }
1016    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1017}
1018
1019EGLBoolean eglReleaseTexImage(
1020        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1021{
1022    clearError();
1023
1024    egl_display_t const * const dp = validate_display(dpy);
1025    if (!dp) return EGL_FALSE;
1026
1027    SurfaceRef _s(dp, surface);
1028    if (!_s.get())
1029        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1030
1031    egl_surface_t const * const s = get_surface(surface);
1032    if (s->cnx->egl.eglReleaseTexImage) {
1033        return s->cnx->egl.eglReleaseTexImage(
1034                dp->disp[s->impl].dpy, s->surface, buffer);
1035    }
1036    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1037}
1038
1039EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1040{
1041    clearError();
1042
1043    egl_display_t const * const dp = validate_display(dpy);
1044    if (!dp) return EGL_FALSE;
1045
1046    EGLBoolean res = EGL_TRUE;
1047    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1048        egl_connection_t* const cnx = &gEGLImpl[i];
1049        if (cnx->dso) {
1050            if (cnx->egl.eglSwapInterval) {
1051                if (cnx->egl.eglSwapInterval(
1052                        dp->disp[i].dpy, interval) == EGL_FALSE) {
1053                    res = EGL_FALSE;
1054                }
1055            }
1056        }
1057    }
1058    return res;
1059}
1060
1061
1062// ----------------------------------------------------------------------------
1063// EGL 1.2
1064// ----------------------------------------------------------------------------
1065
1066EGLBoolean eglWaitClient(void)
1067{
1068    clearError();
1069
1070    // could be called before eglInitialize(), but we wouldn't have a context
1071    // then, and this function would return GL_TRUE, which isn't wrong.
1072    EGLBoolean res = EGL_TRUE;
1073    EGLContext ctx = getContext();
1074    if (ctx) {
1075        egl_context_t const * const c = get_context(ctx);
1076        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1077        if (uint32_t(c->impl)>=2)
1078            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1079        egl_connection_t* const cnx = &gEGLImpl[c->impl];
1080        if (!cnx->dso)
1081            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1082        if (cnx->egl.eglWaitClient) {
1083            res = cnx->egl.eglWaitClient();
1084        } else {
1085            res = cnx->egl.eglWaitGL();
1086        }
1087    }
1088    return res;
1089}
1090
1091EGLBoolean eglBindAPI(EGLenum api)
1092{
1093    clearError();
1094
1095    if (egl_init_drivers() == EGL_FALSE) {
1096        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1097    }
1098
1099    // bind this API on all EGLs
1100    EGLBoolean res = EGL_TRUE;
1101    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1102        egl_connection_t* const cnx = &gEGLImpl[i];
1103        if (cnx->dso) {
1104            if (cnx->egl.eglBindAPI) {
1105                if (cnx->egl.eglBindAPI(api) == EGL_FALSE) {
1106                    res = EGL_FALSE;
1107                }
1108            }
1109        }
1110    }
1111    return res;
1112}
1113
1114EGLenum eglQueryAPI(void)
1115{
1116    clearError();
1117
1118    if (egl_init_drivers() == EGL_FALSE) {
1119        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1120    }
1121
1122    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1123        egl_connection_t* const cnx = &gEGLImpl[i];
1124        if (cnx->dso) {
1125            if (cnx->egl.eglQueryAPI) {
1126                // the first one we find is okay, because they all
1127                // should be the same
1128                return cnx->egl.eglQueryAPI();
1129            }
1130        }
1131    }
1132    // or, it can only be OpenGL ES
1133    return EGL_OPENGL_ES_API;
1134}
1135
1136EGLBoolean eglReleaseThread(void)
1137{
1138    clearError();
1139
1140    // If there is context bound to the thread, release it
1141    loseCurrent(get_context(getContext()));
1142
1143    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1144        egl_connection_t* const cnx = &gEGLImpl[i];
1145        if (cnx->dso) {
1146            if (cnx->egl.eglReleaseThread) {
1147                cnx->egl.eglReleaseThread();
1148            }
1149        }
1150    }
1151    egl_tls_t::clearTLS();
1152    dbgReleaseThread();
1153    return EGL_TRUE;
1154}
1155
1156EGLSurface eglCreatePbufferFromClientBuffer(
1157          EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1158          EGLConfig config, const EGLint *attrib_list)
1159{
1160    clearError();
1161
1162    egl_display_t const* dp = 0;
1163    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
1164    if (!cnx) return EGL_FALSE;
1165    if (cnx->egl.eglCreatePbufferFromClientBuffer) {
1166        return cnx->egl.eglCreatePbufferFromClientBuffer(
1167                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
1168                buftype, buffer,
1169                dp->configs[intptr_t(config)].config, attrib_list);
1170    }
1171    return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1172}
1173
1174// ----------------------------------------------------------------------------
1175// EGL_EGLEXT_VERSION 3
1176// ----------------------------------------------------------------------------
1177
1178EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1179        const EGLint *attrib_list)
1180{
1181    clearError();
1182
1183    egl_display_t const * const dp = validate_display(dpy);
1184    if (!dp) return EGL_FALSE;
1185
1186    SurfaceRef _s(dp, surface);
1187    if (!_s.get())
1188        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1189
1190    egl_surface_t const * const s = get_surface(surface);
1191    if (s->cnx->egl.eglLockSurfaceKHR) {
1192        return s->cnx->egl.eglLockSurfaceKHR(
1193                dp->disp[s->impl].dpy, s->surface, attrib_list);
1194    }
1195    return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1196}
1197
1198EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
1199{
1200    clearError();
1201
1202    egl_display_t const * const dp = validate_display(dpy);
1203    if (!dp) return EGL_FALSE;
1204
1205    SurfaceRef _s(dp, surface);
1206    if (!_s.get())
1207        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1208
1209    egl_surface_t const * const s = get_surface(surface);
1210    if (s->cnx->egl.eglUnlockSurfaceKHR) {
1211        return s->cnx->egl.eglUnlockSurfaceKHR(
1212                dp->disp[s->impl].dpy, s->surface);
1213    }
1214    return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1215}
1216
1217EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1218        EGLClientBuffer buffer, const EGLint *attrib_list)
1219{
1220    clearError();
1221
1222    egl_display_t const * const dp = validate_display(dpy);
1223    if (!dp) return EGL_NO_IMAGE_KHR;
1224
1225    if (ctx != EGL_NO_CONTEXT) {
1226        ContextRef _c(dp, ctx);
1227        if (!_c.get())
1228            return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
1229        egl_context_t * const c = get_context(ctx);
1230        // since we have an EGLContext, we know which implementation to use
1231        EGLImageKHR image = c->cnx->egl.eglCreateImageKHR(
1232                dp->disp[c->impl].dpy, c->context, target, buffer, attrib_list);
1233        if (image == EGL_NO_IMAGE_KHR)
1234            return image;
1235
1236        egl_image_t* result = new egl_image_t(dpy, ctx);
1237        result->images[c->impl] = image;
1238        return (EGLImageKHR)result;
1239    } else {
1240        // EGL_NO_CONTEXT is a valid parameter
1241
1242        /* Since we don't have a way to know which implementation to call,
1243         * we're calling all of them. If at least one of the implementation
1244         * succeeded, this is a success.
1245         */
1246
1247        EGLint currentError = eglGetError();
1248
1249        EGLImageKHR implImages[IMPL_NUM_IMPLEMENTATIONS];
1250        bool success = false;
1251        for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1252            egl_connection_t* const cnx = &gEGLImpl[i];
1253            implImages[i] = EGL_NO_IMAGE_KHR;
1254            if (cnx->dso) {
1255                if (cnx->egl.eglCreateImageKHR) {
1256                    implImages[i] = cnx->egl.eglCreateImageKHR(
1257                            dp->disp[i].dpy, ctx, target, buffer, attrib_list);
1258                    if (implImages[i] != EGL_NO_IMAGE_KHR) {
1259                        success = true;
1260                    }
1261                }
1262            }
1263        }
1264
1265        if (!success) {
1266            // failure, if there was an error when we entered this function,
1267            // the error flag must not be updated.
1268            // Otherwise, the error is whatever happened in the implementation
1269            // that faulted.
1270            if (currentError != EGL_SUCCESS) {
1271                setError(currentError, EGL_NO_IMAGE_KHR);
1272            }
1273            return EGL_NO_IMAGE_KHR;
1274        } else {
1275            // In case of success, we need to clear all error flags
1276            // (especially those caused by the implementation that didn't
1277            // succeed). TODO: we could avoid this if we knew this was
1278            // a "full" success (all implementation succeeded).
1279            eglGetError();
1280        }
1281
1282        egl_image_t* result = new egl_image_t(dpy, ctx);
1283        memcpy(result->images, implImages, sizeof(implImages));
1284        return (EGLImageKHR)result;
1285    }
1286}
1287
1288EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1289{
1290    clearError();
1291
1292    egl_display_t const * const dp = validate_display(dpy);
1293    if (!dp) return EGL_FALSE;
1294
1295    ImageRef _i(dp, img);
1296    if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1297
1298    egl_image_t* image = get_image(img);
1299    bool success = false;
1300    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1301        egl_connection_t* const cnx = &gEGLImpl[i];
1302        if (image->images[i] != EGL_NO_IMAGE_KHR) {
1303            if (cnx->dso) {
1304                if (cnx->egl.eglDestroyImageKHR) {
1305                    if (cnx->egl.eglDestroyImageKHR(
1306                            dp->disp[i].dpy, image->images[i])) {
1307                        success = true;
1308                    }
1309                }
1310            }
1311        }
1312    }
1313    if (!success)
1314        return EGL_FALSE;
1315
1316    _i.terminate();
1317
1318    return EGL_TRUE;
1319}
1320
1321// ----------------------------------------------------------------------------
1322// EGL_EGLEXT_VERSION 5
1323// ----------------------------------------------------------------------------
1324
1325
1326EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
1327{
1328    clearError();
1329
1330    egl_display_t const * const dp = validate_display(dpy);
1331    if (!dp) return EGL_NO_SYNC_KHR;
1332
1333    EGLContext ctx = eglGetCurrentContext();
1334    ContextRef _c(dp, ctx);
1335    if (!_c.get())
1336        return setError(EGL_BAD_CONTEXT, EGL_NO_SYNC_KHR);
1337
1338    egl_context_t * const c = get_context(ctx);
1339    EGLSyncKHR result = EGL_NO_SYNC_KHR;
1340    if (c->cnx->egl.eglCreateSyncKHR) {
1341        EGLSyncKHR sync = c->cnx->egl.eglCreateSyncKHR(
1342                dp->disp[c->impl].dpy, type, attrib_list);
1343        if (sync == EGL_NO_SYNC_KHR)
1344            return sync;
1345        result = (egl_sync_t*)new egl_sync_t(dpy, ctx, sync);
1346    }
1347    return (EGLSyncKHR)result;
1348}
1349
1350EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
1351{
1352    clearError();
1353
1354    egl_display_t const * const dp = validate_display(dpy);
1355    if (!dp) return EGL_FALSE;
1356
1357    SyncRef _s(dp, sync);
1358    if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1359    egl_sync_t* syncObject = get_sync(sync);
1360
1361    EGLContext ctx = syncObject->context;
1362    ContextRef _c(dp, ctx);
1363    if (!_c.get())
1364        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1365
1366    EGLBoolean result = EGL_FALSE;
1367    egl_context_t * const c = get_context(ctx);
1368    if (c->cnx->egl.eglDestroySyncKHR) {
1369        result = c->cnx->egl.eglDestroySyncKHR(
1370                dp->disp[c->impl].dpy, syncObject->sync);
1371        if (result)
1372            _s.terminate();
1373    }
1374    return result;
1375}
1376
1377EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout)
1378{
1379    clearError();
1380
1381    egl_display_t const * const dp = validate_display(dpy);
1382    if (!dp) return EGL_FALSE;
1383
1384    SyncRef _s(dp, sync);
1385    if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1386    egl_sync_t* syncObject = get_sync(sync);
1387
1388    EGLContext ctx = syncObject->context;
1389    ContextRef _c(dp, ctx);
1390    if (!_c.get())
1391        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1392
1393    egl_context_t * const c = get_context(ctx);
1394    if (c->cnx->egl.eglClientWaitSyncKHR) {
1395        return c->cnx->egl.eglClientWaitSyncKHR(
1396                dp->disp[c->impl].dpy, syncObject->sync, flags, timeout);
1397    }
1398
1399    return EGL_FALSE;
1400}
1401
1402EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value)
1403{
1404    clearError();
1405
1406    egl_display_t const * const dp = validate_display(dpy);
1407    if (!dp) return EGL_FALSE;
1408
1409    SyncRef _s(dp, sync);
1410    if (!_s.get())
1411        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1412
1413    egl_sync_t* syncObject = get_sync(sync);
1414    EGLContext ctx = syncObject->context;
1415    ContextRef _c(dp, ctx);
1416    if (!_c.get())
1417        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1418
1419    egl_context_t * const c = get_context(ctx);
1420    if (c->cnx->egl.eglGetSyncAttribKHR) {
1421        return c->cnx->egl.eglGetSyncAttribKHR(
1422                dp->disp[c->impl].dpy, syncObject->sync, attribute, value);
1423    }
1424
1425    return EGL_FALSE;
1426}
1427
1428// ----------------------------------------------------------------------------
1429// ANDROID extensions
1430// ----------------------------------------------------------------------------
1431
1432/* ANDROID extensions entry-point go here */
1433
1434// ----------------------------------------------------------------------------
1435// NVIDIA extensions
1436// ----------------------------------------------------------------------------
1437EGLuint64NV eglGetSystemTimeFrequencyNV()
1438{
1439    clearError();
1440
1441    if (egl_init_drivers() == EGL_FALSE) {
1442        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1443    }
1444
1445    EGLuint64NV ret = 0;
1446    egl_connection_t* const cnx = &gEGLImpl[IMPL_HARDWARE];
1447
1448    if (cnx->dso) {
1449        if (cnx->egl.eglGetSystemTimeFrequencyNV) {
1450            return cnx->egl.eglGetSystemTimeFrequencyNV();
1451        }
1452    }
1453
1454    return setErrorQuiet(EGL_BAD_DISPLAY, 0);
1455}
1456
1457EGLuint64NV eglGetSystemTimeNV()
1458{
1459    clearError();
1460
1461    if (egl_init_drivers() == EGL_FALSE) {
1462        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1463    }
1464
1465    EGLuint64NV ret = 0;
1466    egl_connection_t* const cnx = &gEGLImpl[IMPL_HARDWARE];
1467
1468    if (cnx->dso) {
1469        if (cnx->egl.eglGetSystemTimeNV) {
1470            return cnx->egl.eglGetSystemTimeNV();
1471        }
1472    }
1473
1474    return setErrorQuiet(EGL_BAD_DISPLAY, 0);
1475}
1476