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