eglApi.cpp revision f4486c6ea4bcb728ee0f38df7a8ec75c389d9d2e
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#define ATRACE_TAG ATRACE_TAG_GRAPHICS
18
19#include <dlfcn.h>
20#include <ctype.h>
21#include <stdlib.h>
22#include <string.h>
23
24#include <hardware/gralloc.h>
25#include <system/window.h>
26
27#include <EGL/egl.h>
28#include <EGL/eglext.h>
29
30#include <cutils/log.h>
31#include <cutils/atomic.h>
32#include <cutils/compiler.h>
33#include <cutils/properties.h>
34#include <cutils/memory.h>
35
36#include <utils/KeyedVector.h>
37#include <utils/SortedVector.h>
38#include <utils/String8.h>
39#include <utils/Trace.h>
40
41#include "../egl_impl.h"
42#include "../glestrace.h"
43#include "../hooks.h"
44
45#include "egl_display.h"
46#include "egl_object.h"
47#include "egl_tls.h"
48#include "egldefs.h"
49
50using namespace android;
51
52// ----------------------------------------------------------------------------
53
54namespace android {
55
56struct extention_map_t {
57    const char* name;
58    __eglMustCastToProperFunctionPointerType address;
59};
60
61/*
62 * This is the list of EGL extensions exposed to applications.
63 *
64 * Some of them (gBuiltinExtensionString) are implemented entirely in this EGL
65 * wrapper and are always available.
66 *
67 * The rest (gExtensionString) depend on support in the EGL driver, and are
68 * only available if the driver supports them. However, some of these must be
69 * supported because they are used by the Android system itself; these are
70 * listd as mandatory below and are required by the CDD. The system *assumes*
71 * the mandatory extensions are present and may not function properly if some
72 * are missing.
73 *
74 * NOTE: Both strings MUST have a single space as the last character.
75 */
76extern char const * const gBuiltinExtensionString =
77        "EGL_KHR_get_all_proc_addresses "
78        "EGL_ANDROID_presentation_time "
79        ;
80extern char const * const gExtensionString  =
81        "EGL_KHR_image "                        // mandatory
82        "EGL_KHR_image_base "                   // mandatory
83        "EGL_KHR_image_pixmap "
84        "EGL_KHR_lock_surface "
85        "EGL_KHR_gl_colorspace "
86        "EGL_KHR_gl_texture_2D_image "
87        "EGL_KHR_gl_texture_cubemap_image "
88        "EGL_KHR_gl_renderbuffer_image "
89        "EGL_KHR_reusable_sync "
90        "EGL_KHR_fence_sync "
91        "EGL_KHR_create_context "
92        "EGL_EXT_create_context_robustness "
93        "EGL_NV_system_time "
94        "EGL_ANDROID_image_native_buffer "      // mandatory
95        "EGL_KHR_wait_sync "                    // strongly recommended
96        ;
97
98// extensions not exposed to applications but used by the ANDROID system
99//      "EGL_ANDROID_blob_cache "               // strongly recommended
100//      "EGL_IMG_hibernate_process "            // optional
101//      "EGL_ANDROID_native_fence_sync "        // strongly recommended
102//      "EGL_ANDROID_framebuffer_target "       // mandatory for HWC 1.1
103//      "EGL_ANDROID_recordable "               // mandatory
104
105
106/*
107 * EGL Extensions entry-points exposed to 3rd party applications
108 * (keep in sync with gExtensionString above)
109 *
110 */
111static const extention_map_t sExtensionMap[] = {
112    // EGL_KHR_lock_surface
113    { "eglLockSurfaceKHR",
114            (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
115    { "eglUnlockSurfaceKHR",
116            (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
117
118    // EGL_KHR_image, EGL_KHR_image_base
119    { "eglCreateImageKHR",
120            (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
121    { "eglDestroyImageKHR",
122            (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
123
124    // EGL_KHR_reusable_sync, EGL_KHR_fence_sync
125    { "eglCreateSyncKHR",
126            (__eglMustCastToProperFunctionPointerType)&eglCreateSyncKHR },
127    { "eglDestroySyncKHR",
128            (__eglMustCastToProperFunctionPointerType)&eglDestroySyncKHR },
129    { "eglClientWaitSyncKHR",
130            (__eglMustCastToProperFunctionPointerType)&eglClientWaitSyncKHR },
131    { "eglSignalSyncKHR",
132            (__eglMustCastToProperFunctionPointerType)&eglSignalSyncKHR },
133    { "eglGetSyncAttribKHR",
134            (__eglMustCastToProperFunctionPointerType)&eglGetSyncAttribKHR },
135
136    // EGL_NV_system_time
137    { "eglGetSystemTimeFrequencyNV",
138            (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeFrequencyNV },
139    { "eglGetSystemTimeNV",
140            (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeNV },
141
142    // EGL_KHR_wait_sync
143    { "eglWaitSyncKHR",
144            (__eglMustCastToProperFunctionPointerType)&eglWaitSyncKHR },
145
146    // EGL_ANDROID_presentation_time
147    { "eglPresentationTimeANDROID",
148            (__eglMustCastToProperFunctionPointerType)&eglPresentationTimeANDROID },
149};
150
151/*
152 * These extensions entry-points should not be exposed to applications.
153 * They're used internally by the Android EGL layer.
154 */
155#define FILTER_EXTENSIONS(procname) \
156        (!strcmp((procname), "eglSetBlobCacheFuncsANDROID") ||    \
157         !strcmp((procname), "eglHibernateProcessIMG")      ||    \
158         !strcmp((procname), "eglAwakenProcessIMG")         ||    \
159         !strcmp((procname), "eglDupNativeFenceFDANDROID"))
160
161
162
163// accesses protected by sExtensionMapMutex
164static DefaultKeyedVector<String8, __eglMustCastToProperFunctionPointerType> sGLExtentionMap;
165static int sGLExtentionSlot = 0;
166static pthread_mutex_t sExtensionMapMutex = PTHREAD_MUTEX_INITIALIZER;
167
168static void(*findProcAddress(const char* name,
169        const extention_map_t* map, size_t n))() {
170    for (uint32_t i=0 ; i<n ; i++) {
171        if (!strcmp(name, map[i].name)) {
172            return map[i].address;
173        }
174    }
175    return NULL;
176}
177
178// ----------------------------------------------------------------------------
179
180extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
181extern EGLBoolean egl_init_drivers();
182extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS];
183extern int getEGLDebugLevel();
184extern void setEGLDebugLevel(int level);
185extern gl_hooks_t gHooksTrace;
186
187} // namespace android;
188
189
190// ----------------------------------------------------------------------------
191
192static inline void clearError() { egl_tls_t::clearError(); }
193static inline EGLContext getContext() { return egl_tls_t::getContext(); }
194
195// ----------------------------------------------------------------------------
196
197EGLDisplay eglGetDisplay(EGLNativeDisplayType display)
198{
199    clearError();
200
201    uint32_t index = uint32_t(display);
202    if (index >= NUM_DISPLAYS) {
203        return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
204    }
205
206    if (egl_init_drivers() == EGL_FALSE) {
207        return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
208    }
209
210    EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display);
211    return dpy;
212}
213
214// ----------------------------------------------------------------------------
215// Initialization
216// ----------------------------------------------------------------------------
217
218EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
219{
220    clearError();
221
222    egl_display_ptr dp = get_display(dpy);
223    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
224
225    EGLBoolean res = dp->initialize(major, minor);
226
227    return res;
228}
229
230EGLBoolean eglTerminate(EGLDisplay dpy)
231{
232    // NOTE: don't unload the drivers b/c some APIs can be called
233    // after eglTerminate() has been called. eglTerminate() only
234    // terminates an EGLDisplay, not a EGL itself.
235
236    clearError();
237
238    egl_display_ptr dp = get_display(dpy);
239    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
240
241    EGLBoolean res = dp->terminate();
242
243    return res;
244}
245
246// ----------------------------------------------------------------------------
247// configuration
248// ----------------------------------------------------------------------------
249
250EGLBoolean eglGetConfigs(   EGLDisplay dpy,
251                            EGLConfig *configs,
252                            EGLint config_size, EGLint *num_config)
253{
254    clearError();
255
256    const egl_display_ptr dp = validate_display(dpy);
257    if (!dp) return EGL_FALSE;
258
259    if (num_config==0) {
260        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
261    }
262
263    EGLBoolean res = EGL_FALSE;
264    *num_config = 0;
265
266    egl_connection_t* const cnx = &gEGLImpl;
267    if (cnx->dso) {
268        res = cnx->egl.eglGetConfigs(
269                dp->disp.dpy, configs, config_size, num_config);
270    }
271
272    return res;
273}
274
275EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
276                            EGLConfig *configs, EGLint config_size,
277                            EGLint *num_config)
278{
279    clearError();
280
281    const egl_display_ptr dp = validate_display(dpy);
282    if (!dp) return EGL_FALSE;
283
284    if (num_config==0) {
285        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
286    }
287
288    EGLBoolean res = EGL_FALSE;
289    *num_config = 0;
290
291    egl_connection_t* const cnx = &gEGLImpl;
292    if (cnx->dso) {
293        if (attrib_list) {
294            char value[PROPERTY_VALUE_MAX];
295            property_get("debug.egl.force_msaa", value, "false");
296
297            if (!strcmp(value, "true")) {
298                size_t attribCount = 0;
299                EGLint attrib = attrib_list[0];
300
301                // Only enable MSAA if the context is OpenGL ES 2.0 and
302                // if no caveat is requested
303                const EGLint *attribRendererable = NULL;
304                const EGLint *attribCaveat = NULL;
305
306                // Count the number of attributes and look for
307                // EGL_RENDERABLE_TYPE and EGL_CONFIG_CAVEAT
308                while (attrib != EGL_NONE) {
309                    attrib = attrib_list[attribCount];
310                    switch (attrib) {
311                        case EGL_RENDERABLE_TYPE:
312                            attribRendererable = &attrib_list[attribCount];
313                            break;
314                        case EGL_CONFIG_CAVEAT:
315                            attribCaveat = &attrib_list[attribCount];
316                            break;
317                    }
318                    attribCount++;
319                }
320
321                if (attribRendererable && attribRendererable[1] == EGL_OPENGL_ES2_BIT &&
322                        (!attribCaveat || attribCaveat[1] != EGL_NONE)) {
323
324                    // Insert 2 extra attributes to force-enable MSAA 4x
325                    EGLint aaAttribs[attribCount + 4];
326                    aaAttribs[0] = EGL_SAMPLE_BUFFERS;
327                    aaAttribs[1] = 1;
328                    aaAttribs[2] = EGL_SAMPLES;
329                    aaAttribs[3] = 4;
330
331                    memcpy(&aaAttribs[4], attrib_list, attribCount * sizeof(EGLint));
332
333                    EGLint numConfigAA;
334                    EGLBoolean resAA = cnx->egl.eglChooseConfig(
335                            dp->disp.dpy, aaAttribs, configs, config_size, &numConfigAA);
336
337                    if (resAA == EGL_TRUE && numConfigAA > 0) {
338                        ALOGD("Enabling MSAA 4x");
339                        *num_config = numConfigAA;
340                        return resAA;
341                    }
342                }
343            }
344        }
345
346        res = cnx->egl.eglChooseConfig(
347                dp->disp.dpy, attrib_list, configs, config_size, num_config);
348    }
349    return res;
350}
351
352EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
353        EGLint attribute, EGLint *value)
354{
355    clearError();
356
357    egl_connection_t* cnx = NULL;
358    const egl_display_ptr dp = validate_display_connection(dpy, cnx);
359    if (!dp) return EGL_FALSE;
360
361    return cnx->egl.eglGetConfigAttrib(
362            dp->disp.dpy, config, attribute, value);
363}
364
365// ----------------------------------------------------------------------------
366// surfaces
367// ----------------------------------------------------------------------------
368
369// The EGL_KHR_gl_colorspace spec hasn't been published yet, so these haven't
370// been added to the Khronos egl.h.
371#define EGL_GL_COLORSPACE_KHR           EGL_VG_COLORSPACE
372#define EGL_GL_COLORSPACE_SRGB_KHR      EGL_VG_COLORSPACE_sRGB
373#define EGL_GL_COLORSPACE_LINEAR_KHR    EGL_VG_COLORSPACE_LINEAR
374
375// Turn linear formats into corresponding sRGB formats when colorspace is
376// EGL_GL_COLORSPACE_SRGB_KHR, or turn sRGB formats into corresponding linear
377// formats when colorspace is EGL_GL_COLORSPACE_LINEAR_KHR. In any cases where
378// the modification isn't possible, the original format is returned.
379static int modifyFormatColorspace(int fmt, EGLint colorspace) {
380    if (colorspace == EGL_GL_COLORSPACE_LINEAR_KHR) {
381        switch (fmt) {
382            case HAL_PIXEL_FORMAT_sRGB_A_8888: return HAL_PIXEL_FORMAT_RGBA_8888;
383            case HAL_PIXEL_FORMAT_sRGB_X_8888: return HAL_PIXEL_FORMAT_RGBX_8888;
384        }
385    } else if (colorspace == EGL_GL_COLORSPACE_SRGB_KHR) {
386        switch (fmt) {
387            case HAL_PIXEL_FORMAT_RGBA_8888: return HAL_PIXEL_FORMAT_sRGB_A_8888;
388            case HAL_PIXEL_FORMAT_RGBX_8888: return HAL_PIXEL_FORMAT_sRGB_X_8888;
389        }
390    }
391    return fmt;
392}
393
394EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
395                                    NativeWindowType window,
396                                    const EGLint *attrib_list)
397{
398    clearError();
399
400    egl_connection_t* cnx = NULL;
401    egl_display_ptr dp = validate_display_connection(dpy, cnx);
402    if (dp) {
403        EGLDisplay iDpy = dp->disp.dpy;
404
405        if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) != OK) {
406            ALOGE("EGLNativeWindowType %p already connected to another API",
407                    window);
408            return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
409        }
410
411        // Set the native window's buffers format to match what this config requests.
412        // Whether to use sRGB gamma is not part of the EGLconfig, but is part
413        // of our native format. So if sRGB gamma is requested, we have to
414        // modify the EGLconfig's format before setting the native window's
415        // format.
416#if WORKAROUND_BUG_10194508
417#warning "WORKAROUND_10194508 enabled"
418        EGLint format;
419        if (!cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_NATIVE_VISUAL_ID,
420                &format)) {
421            ALOGE("eglGetConfigAttrib(EGL_NATIVE_VISUAL_ID) failed: %#x",
422                    eglGetError());
423            format = 0;
424        }
425        if (attrib_list) {
426            for (const EGLint* attr = attrib_list; *attr != EGL_NONE;
427                    attr += 2) {
428                if (*attr == EGL_GL_COLORSPACE_KHR &&
429                        dp->haveExtension("EGL_KHR_gl_colorspace")) {
430                    format = modifyFormatColorspace(format, *(attr+1));
431                }
432            }
433        }
434#else
435        // by default, just pick RGBA_8888
436        EGLint format = HAL_PIXEL_FORMAT_RGBA_8888;
437
438        EGLint a = 0;
439        cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_ALPHA_SIZE, &a);
440        if (a > 0) {
441            // alpha-channel requested, there's really only one suitable format
442            format = HAL_PIXEL_FORMAT_RGBA_8888;
443        } else {
444            EGLint r, g, b;
445            r = g = b = 0;
446            cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_RED_SIZE,   &r);
447            cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_GREEN_SIZE, &g);
448            cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_BLUE_SIZE,  &b);
449            EGLint colorDepth = r + g + b;
450            if (colorDepth <= 16) {
451                format = HAL_PIXEL_FORMAT_RGB_565;
452            } else {
453                format = HAL_PIXEL_FORMAT_RGBX_8888;
454            }
455        }
456
457        // now select a corresponding sRGB format if needed
458        if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) {
459            for (const EGLint* attr = attrib_list; *attr != EGL_NONE; attr += 2) {
460                if (*attr == EGL_GL_COLORSPACE_KHR) {
461                    format = modifyFormatColorspace(format, attr[1]);
462                }
463            }
464        }
465#endif
466        if (format != 0) {
467            int err = native_window_set_buffers_format(window, format);
468            if (err != 0) {
469                ALOGE("error setting native window pixel format: %s (%d)",
470                        strerror(-err), err);
471                native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
472                return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
473            }
474        }
475
476        // the EGL spec requires that a new EGLSurface default to swap interval
477        // 1, so explicitly set that on the window here.
478        ANativeWindow* anw = reinterpret_cast<ANativeWindow*>(window);
479        anw->setSwapInterval(anw, 1);
480
481        EGLSurface surface = cnx->egl.eglCreateWindowSurface(
482                iDpy, config, window, attrib_list);
483        if (surface != EGL_NO_SURFACE) {
484            egl_surface_t* s = new egl_surface_t(dp.get(), config, window,
485                    surface, cnx);
486            return s;
487        }
488
489        // EGLSurface creation failed
490        native_window_set_buffers_format(window, 0);
491        native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
492    }
493    return EGL_NO_SURFACE;
494}
495
496EGLSurface eglCreatePixmapSurface(  EGLDisplay dpy, EGLConfig config,
497                                    NativePixmapType pixmap,
498                                    const EGLint *attrib_list)
499{
500    clearError();
501
502    egl_connection_t* cnx = NULL;
503    egl_display_ptr dp = validate_display_connection(dpy, cnx);
504    if (dp) {
505        EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
506                dp->disp.dpy, config, pixmap, attrib_list);
507        if (surface != EGL_NO_SURFACE) {
508            egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL,
509                    surface, cnx);
510            return s;
511        }
512    }
513    return EGL_NO_SURFACE;
514}
515
516EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
517                                    const EGLint *attrib_list)
518{
519    clearError();
520
521    egl_connection_t* cnx = NULL;
522    egl_display_ptr dp = validate_display_connection(dpy, cnx);
523    if (dp) {
524        EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
525                dp->disp.dpy, config, attrib_list);
526        if (surface != EGL_NO_SURFACE) {
527            egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL,
528                    surface, cnx);
529            return s;
530        }
531    }
532    return EGL_NO_SURFACE;
533}
534
535EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
536{
537    clearError();
538
539    const egl_display_ptr dp = validate_display(dpy);
540    if (!dp) return EGL_FALSE;
541
542    SurfaceRef _s(dp.get(), surface);
543    if (!_s.get())
544        return setError(EGL_BAD_SURFACE, EGL_FALSE);
545
546    egl_surface_t * const s = get_surface(surface);
547    EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface);
548    if (result == EGL_TRUE) {
549        _s.terminate();
550    }
551    return result;
552}
553
554EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
555                            EGLint attribute, EGLint *value)
556{
557    clearError();
558
559    const egl_display_ptr dp = validate_display(dpy);
560    if (!dp) return EGL_FALSE;
561
562    SurfaceRef _s(dp.get(), surface);
563    if (!_s.get())
564        return setError(EGL_BAD_SURFACE, EGL_FALSE);
565
566    egl_surface_t const * const s = get_surface(surface);
567    return s->cnx->egl.eglQuerySurface(
568            dp->disp.dpy, s->surface, attribute, value);
569}
570
571void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) {
572    ATRACE_CALL();
573    clearError();
574
575    const egl_display_ptr dp = validate_display(dpy);
576    if (!dp) {
577        return;
578    }
579
580    SurfaceRef _s(dp.get(), surface);
581    if (!_s.get()) {
582        setError(EGL_BAD_SURFACE, EGL_FALSE);
583        return;
584    }
585}
586
587// ----------------------------------------------------------------------------
588// Contexts
589// ----------------------------------------------------------------------------
590
591EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
592                            EGLContext share_list, const EGLint *attrib_list)
593{
594    clearError();
595
596    egl_connection_t* cnx = NULL;
597    const egl_display_ptr dp = validate_display_connection(dpy, cnx);
598    if (dp) {
599        if (share_list != EGL_NO_CONTEXT) {
600            if (!ContextRef(dp.get(), share_list).get()) {
601                return setError(EGL_BAD_CONTEXT, EGL_NO_CONTEXT);
602            }
603            egl_context_t* const c = get_context(share_list);
604            share_list = c->context;
605        }
606        EGLContext context = cnx->egl.eglCreateContext(
607                dp->disp.dpy, config, share_list, attrib_list);
608        if (context != EGL_NO_CONTEXT) {
609            // figure out if it's a GLESv1 or GLESv2
610            int version = 0;
611            if (attrib_list) {
612                while (*attrib_list != EGL_NONE) {
613                    GLint attr = *attrib_list++;
614                    GLint value = *attrib_list++;
615                    if (attr == EGL_CONTEXT_CLIENT_VERSION) {
616                        if (value == 1) {
617                            version = egl_connection_t::GLESv1_INDEX;
618                        } else if (value == 2 || value == 3) {
619                            version = egl_connection_t::GLESv2_INDEX;
620                        }
621                    }
622                };
623            }
624            egl_context_t* c = new egl_context_t(dpy, context, config, cnx,
625                    version);
626#if EGL_TRACE
627            if (getEGLDebugLevel() > 0)
628                GLTrace_eglCreateContext(version, c);
629#endif
630            return c;
631        }
632    }
633    return EGL_NO_CONTEXT;
634}
635
636EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
637{
638    clearError();
639
640    const egl_display_ptr dp = validate_display(dpy);
641    if (!dp)
642        return EGL_FALSE;
643
644    ContextRef _c(dp.get(), ctx);
645    if (!_c.get())
646        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
647
648    egl_context_t * const c = get_context(ctx);
649    EGLBoolean result = c->cnx->egl.eglDestroyContext(dp->disp.dpy, c->context);
650    if (result == EGL_TRUE) {
651        _c.terminate();
652    }
653    return result;
654}
655
656EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
657                            EGLSurface read, EGLContext ctx)
658{
659    clearError();
660
661    egl_display_ptr dp = validate_display(dpy);
662    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
663
664    // If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not
665    // EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is
666    // a valid but uninitialized display.
667    if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) ||
668         (draw != EGL_NO_SURFACE) ) {
669        if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
670    }
671
672    // get a reference to the object passed in
673    ContextRef _c(dp.get(), ctx);
674    SurfaceRef _d(dp.get(), draw);
675    SurfaceRef _r(dp.get(), read);
676
677    // validate the context (if not EGL_NO_CONTEXT)
678    if ((ctx != EGL_NO_CONTEXT) && !_c.get()) {
679        // EGL_NO_CONTEXT is valid
680        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
681    }
682
683    // these are the underlying implementation's object
684    EGLContext impl_ctx  = EGL_NO_CONTEXT;
685    EGLSurface impl_draw = EGL_NO_SURFACE;
686    EGLSurface impl_read = EGL_NO_SURFACE;
687
688    // these are our objects structs passed in
689    egl_context_t       * c = NULL;
690    egl_surface_t const * d = NULL;
691    egl_surface_t const * r = NULL;
692
693    // these are the current objects structs
694    egl_context_t * cur_c = get_context(getContext());
695
696    if (ctx != EGL_NO_CONTEXT) {
697        c = get_context(ctx);
698        impl_ctx = c->context;
699    } else {
700        // no context given, use the implementation of the current context
701        if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
702            // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT);
703            return setError(EGL_BAD_MATCH, EGL_FALSE);
704        }
705        if (cur_c == NULL) {
706            // no current context
707            // not an error, there is just no current context.
708            return EGL_TRUE;
709        }
710    }
711
712    // retrieve the underlying implementation's draw EGLSurface
713    if (draw != EGL_NO_SURFACE) {
714        if (!_d.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
715        d = get_surface(draw);
716        impl_draw = d->surface;
717    }
718
719    // retrieve the underlying implementation's read EGLSurface
720    if (read != EGL_NO_SURFACE) {
721        if (!_r.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
722        r = get_surface(read);
723        impl_read = r->surface;
724    }
725
726
727    EGLBoolean result = dp->makeCurrent(c, cur_c,
728            draw, read, ctx,
729            impl_draw, impl_read, impl_ctx);
730
731    if (result == EGL_TRUE) {
732        if (c) {
733            setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
734            egl_tls_t::setContext(ctx);
735#if EGL_TRACE
736            if (getEGLDebugLevel() > 0)
737                GLTrace_eglMakeCurrent(c->version, c->cnx->hooks[c->version], ctx);
738#endif
739            _c.acquire();
740            _r.acquire();
741            _d.acquire();
742        } else {
743            setGLHooksThreadSpecific(&gHooksNoContext);
744            egl_tls_t::setContext(EGL_NO_CONTEXT);
745        }
746    } else {
747        // this will ALOGE the error
748        result = setError(c->cnx->egl.eglGetError(), EGL_FALSE);
749    }
750    return result;
751}
752
753
754EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
755                            EGLint attribute, EGLint *value)
756{
757    clearError();
758
759    const egl_display_ptr dp = validate_display(dpy);
760    if (!dp) return EGL_FALSE;
761
762    ContextRef _c(dp.get(), ctx);
763    if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
764
765    egl_context_t * const c = get_context(ctx);
766    return c->cnx->egl.eglQueryContext(
767            dp->disp.dpy, c->context, attribute, value);
768
769}
770
771EGLContext eglGetCurrentContext(void)
772{
773    // could be called before eglInitialize(), but we wouldn't have a context
774    // then, and this function would correctly return EGL_NO_CONTEXT.
775
776    clearError();
777
778    EGLContext ctx = getContext();
779    return ctx;
780}
781
782EGLSurface eglGetCurrentSurface(EGLint readdraw)
783{
784    // could be called before eglInitialize(), but we wouldn't have a context
785    // then, and this function would correctly return EGL_NO_SURFACE.
786
787    clearError();
788
789    EGLContext ctx = getContext();
790    if (ctx) {
791        egl_context_t const * const c = get_context(ctx);
792        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
793        switch (readdraw) {
794            case EGL_READ: return c->read;
795            case EGL_DRAW: return c->draw;
796            default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
797        }
798    }
799    return EGL_NO_SURFACE;
800}
801
802EGLDisplay eglGetCurrentDisplay(void)
803{
804    // could be called before eglInitialize(), but we wouldn't have a context
805    // then, and this function would correctly return EGL_NO_DISPLAY.
806
807    clearError();
808
809    EGLContext ctx = getContext();
810    if (ctx) {
811        egl_context_t const * const c = get_context(ctx);
812        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
813        return c->dpy;
814    }
815    return EGL_NO_DISPLAY;
816}
817
818EGLBoolean eglWaitGL(void)
819{
820    clearError();
821
822    egl_connection_t* const cnx = &gEGLImpl;
823    if (!cnx->dso)
824        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
825
826    return cnx->egl.eglWaitGL();
827}
828
829EGLBoolean eglWaitNative(EGLint engine)
830{
831    clearError();
832
833    egl_connection_t* const cnx = &gEGLImpl;
834    if (!cnx->dso)
835        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
836
837    return cnx->egl.eglWaitNative(engine);
838}
839
840EGLint eglGetError(void)
841{
842    EGLint err = EGL_SUCCESS;
843    egl_connection_t* const cnx = &gEGLImpl;
844    if (cnx->dso) {
845        err = cnx->egl.eglGetError();
846    }
847    if (err == EGL_SUCCESS) {
848        err = egl_tls_t::getError();
849    }
850    return err;
851}
852
853static __eglMustCastToProperFunctionPointerType findBuiltinGLWrapper(
854        const char* procname) {
855    const egl_connection_t* cnx = &gEGLImpl;
856    void* proc = NULL;
857
858    proc = dlsym(cnx->libGles2, procname);
859    if (proc) return (__eglMustCastToProperFunctionPointerType)proc;
860
861    proc = dlsym(cnx->libGles1, procname);
862    if (proc) return (__eglMustCastToProperFunctionPointerType)proc;
863
864    return NULL;
865}
866
867__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
868{
869    // eglGetProcAddress() could be the very first function called
870    // in which case we must make sure we've initialized ourselves, this
871    // happens the first time egl_get_display() is called.
872
873    clearError();
874
875    if (egl_init_drivers() == EGL_FALSE) {
876        setError(EGL_BAD_PARAMETER, NULL);
877        return  NULL;
878    }
879
880    if (FILTER_EXTENSIONS(procname)) {
881        return NULL;
882    }
883
884    __eglMustCastToProperFunctionPointerType addr;
885    addr = findProcAddress(procname, sExtensionMap, NELEM(sExtensionMap));
886    if (addr) return addr;
887
888    addr = findBuiltinGLWrapper(procname);
889    if (addr) return addr;
890
891    // this protects accesses to sGLExtentionMap and sGLExtentionSlot
892    pthread_mutex_lock(&sExtensionMapMutex);
893
894        /*
895         * Since eglGetProcAddress() is not associated to anything, it needs
896         * to return a function pointer that "works" regardless of what
897         * the current context is.
898         *
899         * For this reason, we return a "forwarder", a small stub that takes
900         * care of calling the function associated with the context
901         * currently bound.
902         *
903         * We first look for extensions we've already resolved, if we're seeing
904         * this extension for the first time, we go through all our
905         * implementations and call eglGetProcAddress() and record the
906         * result in the appropriate implementation hooks and return the
907         * address of the forwarder corresponding to that hook set.
908         *
909         */
910
911        const String8 name(procname);
912        addr = sGLExtentionMap.valueFor(name);
913        const int slot = sGLExtentionSlot;
914
915        ALOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS,
916                "no more slots for eglGetProcAddress(\"%s\")",
917                procname);
918
919#if EGL_TRACE
920        gl_hooks_t *debugHooks = GLTrace_getGLHooks();
921#endif
922
923        if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) {
924            bool found = false;
925
926            egl_connection_t* const cnx = &gEGLImpl;
927            if (cnx->dso && cnx->egl.eglGetProcAddress) {
928                // Extensions are independent of the bound context
929                addr =
930                cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] =
931                cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] =
932#if EGL_TRACE
933                debugHooks->ext.extensions[slot] =
934                gHooksTrace.ext.extensions[slot] =
935#endif
936                        cnx->egl.eglGetProcAddress(procname);
937                if (addr) found = true;
938            }
939
940            if (found) {
941                addr = gExtensionForwarders[slot];
942                sGLExtentionMap.add(name, addr);
943                sGLExtentionSlot++;
944            }
945        }
946
947    pthread_mutex_unlock(&sExtensionMapMutex);
948    return addr;
949}
950
951class FrameCompletionThread : public Thread {
952public:
953
954    static void queueSync(EGLSyncKHR sync) {
955        static sp<FrameCompletionThread> thread(new FrameCompletionThread);
956        static bool running = false;
957        if (!running) {
958            thread->run("GPUFrameCompletion");
959            running = true;
960        }
961        {
962            Mutex::Autolock lock(thread->mMutex);
963            ScopedTrace st(ATRACE_TAG, String8::format("kicked off frame %d",
964                    thread->mFramesQueued).string());
965            thread->mQueue.push_back(sync);
966            thread->mCondition.signal();
967            thread->mFramesQueued++;
968            ATRACE_INT("GPU Frames Outstanding", thread->mQueue.size());
969        }
970    }
971
972private:
973    FrameCompletionThread() : mFramesQueued(0), mFramesCompleted(0) {}
974
975    virtual bool threadLoop() {
976        EGLSyncKHR sync;
977        uint32_t frameNum;
978        {
979            Mutex::Autolock lock(mMutex);
980            while (mQueue.isEmpty()) {
981                mCondition.wait(mMutex);
982            }
983            sync = mQueue[0];
984            frameNum = mFramesCompleted;
985        }
986        EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
987        {
988            ScopedTrace st(ATRACE_TAG, String8::format("waiting for frame %d",
989                    frameNum).string());
990            EGLint result = eglClientWaitSyncKHR(dpy, sync, 0, EGL_FOREVER_KHR);
991            if (result == EGL_FALSE) {
992                ALOGE("FrameCompletion: error waiting for fence: %#x", eglGetError());
993            } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
994                ALOGE("FrameCompletion: timeout waiting for fence");
995            }
996            eglDestroySyncKHR(dpy, sync);
997        }
998        {
999            Mutex::Autolock lock(mMutex);
1000            mQueue.removeAt(0);
1001            mFramesCompleted++;
1002            ATRACE_INT("GPU Frames Outstanding", mQueue.size());
1003        }
1004        return true;
1005    }
1006
1007    uint32_t mFramesQueued;
1008    uint32_t mFramesCompleted;
1009    Vector<EGLSyncKHR> mQueue;
1010    Condition mCondition;
1011    Mutex mMutex;
1012};
1013
1014EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1015{
1016    ATRACE_CALL();
1017    clearError();
1018
1019    const egl_display_ptr dp = validate_display(dpy);
1020    if (!dp) return EGL_FALSE;
1021
1022    SurfaceRef _s(dp.get(), draw);
1023    if (!_s.get())
1024        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1025
1026#if EGL_TRACE
1027    gl_hooks_t const *trace_hooks = getGLTraceThreadSpecific();
1028    if (getEGLDebugLevel() > 0) {
1029        if (trace_hooks == NULL) {
1030            if (GLTrace_start() < 0) {
1031                ALOGE("Disabling Tracer for OpenGL ES");
1032                setEGLDebugLevel(0);
1033            } else {
1034                // switch over to the trace version of hooks
1035                EGLContext ctx = egl_tls_t::getContext();
1036                egl_context_t * const c = get_context(ctx);
1037                if (c) {
1038                    setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
1039                    GLTrace_eglMakeCurrent(c->version, c->cnx->hooks[c->version], ctx);
1040                }
1041            }
1042        }
1043
1044        GLTrace_eglSwapBuffers(dpy, draw);
1045    } else if (trace_hooks != NULL) {
1046        // tracing is now disabled, so switch back to the non trace version
1047        EGLContext ctx = egl_tls_t::getContext();
1048        egl_context_t * const c = get_context(ctx);
1049        if (c) setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
1050        GLTrace_stop();
1051    }
1052#endif
1053
1054    egl_surface_t const * const s = get_surface(draw);
1055
1056    if (CC_UNLIKELY(dp->traceGpuCompletion)) {
1057        EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
1058        if (sync != EGL_NO_SYNC_KHR) {
1059            FrameCompletionThread::queueSync(sync);
1060        }
1061    }
1062
1063    if (CC_UNLIKELY(dp->finishOnSwap)) {
1064        uint32_t pixel;
1065        egl_context_t * const c = get_context( egl_tls_t::getContext() );
1066        if (c) {
1067            // glReadPixels() ensures that the frame is complete
1068            s->cnx->hooks[c->version]->gl.glReadPixels(0,0,1,1,
1069                    GL_RGBA,GL_UNSIGNED_BYTE,&pixel);
1070        }
1071    }
1072
1073    return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface);
1074}
1075
1076EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
1077                            NativePixmapType target)
1078{
1079    clearError();
1080
1081    const egl_display_ptr dp = validate_display(dpy);
1082    if (!dp) return EGL_FALSE;
1083
1084    SurfaceRef _s(dp.get(), surface);
1085    if (!_s.get())
1086        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1087
1088    egl_surface_t const * const s = get_surface(surface);
1089    return s->cnx->egl.eglCopyBuffers(dp->disp.dpy, s->surface, target);
1090}
1091
1092const char* eglQueryString(EGLDisplay dpy, EGLint name)
1093{
1094    clearError();
1095
1096    const egl_display_ptr dp = validate_display(dpy);
1097    if (!dp) return (const char *) NULL;
1098
1099    switch (name) {
1100        case EGL_VENDOR:
1101            return dp->getVendorString();
1102        case EGL_VERSION:
1103            return dp->getVersionString();
1104        case EGL_EXTENSIONS:
1105            return dp->getExtensionString();
1106        case EGL_CLIENT_APIS:
1107            return dp->getClientApiString();
1108    }
1109    return setError(EGL_BAD_PARAMETER, (const char *)0);
1110}
1111
1112EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name)
1113{
1114    clearError();
1115
1116    const egl_display_ptr dp = validate_display(dpy);
1117    if (!dp) return (const char *) NULL;
1118
1119    switch (name) {
1120        case EGL_VENDOR:
1121            return dp->disp.queryString.vendor;
1122        case EGL_VERSION:
1123            return dp->disp.queryString.version;
1124        case EGL_EXTENSIONS:
1125            return dp->disp.queryString.extensions;
1126        case EGL_CLIENT_APIS:
1127            return dp->disp.queryString.clientApi;
1128    }
1129    return setError(EGL_BAD_PARAMETER, (const char *)0);
1130}
1131
1132// ----------------------------------------------------------------------------
1133// EGL 1.1
1134// ----------------------------------------------------------------------------
1135
1136EGLBoolean eglSurfaceAttrib(
1137        EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1138{
1139    clearError();
1140
1141    const egl_display_ptr dp = validate_display(dpy);
1142    if (!dp) return EGL_FALSE;
1143
1144    SurfaceRef _s(dp.get(), surface);
1145    if (!_s.get())
1146        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1147
1148    egl_surface_t const * const s = get_surface(surface);
1149    if (s->cnx->egl.eglSurfaceAttrib) {
1150        return s->cnx->egl.eglSurfaceAttrib(
1151                dp->disp.dpy, s->surface, attribute, value);
1152    }
1153    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1154}
1155
1156EGLBoolean eglBindTexImage(
1157        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1158{
1159    clearError();
1160
1161    const egl_display_ptr dp = validate_display(dpy);
1162    if (!dp) return EGL_FALSE;
1163
1164    SurfaceRef _s(dp.get(), surface);
1165    if (!_s.get())
1166        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1167
1168    egl_surface_t const * const s = get_surface(surface);
1169    if (s->cnx->egl.eglBindTexImage) {
1170        return s->cnx->egl.eglBindTexImage(
1171                dp->disp.dpy, s->surface, buffer);
1172    }
1173    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1174}
1175
1176EGLBoolean eglReleaseTexImage(
1177        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1178{
1179    clearError();
1180
1181    const egl_display_ptr dp = validate_display(dpy);
1182    if (!dp) return EGL_FALSE;
1183
1184    SurfaceRef _s(dp.get(), surface);
1185    if (!_s.get())
1186        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1187
1188    egl_surface_t const * const s = get_surface(surface);
1189    if (s->cnx->egl.eglReleaseTexImage) {
1190        return s->cnx->egl.eglReleaseTexImage(
1191                dp->disp.dpy, s->surface, buffer);
1192    }
1193    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1194}
1195
1196EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1197{
1198    clearError();
1199
1200    const egl_display_ptr dp = validate_display(dpy);
1201    if (!dp) return EGL_FALSE;
1202
1203    EGLBoolean res = EGL_TRUE;
1204    egl_connection_t* const cnx = &gEGLImpl;
1205    if (cnx->dso && cnx->egl.eglSwapInterval) {
1206        res = cnx->egl.eglSwapInterval(dp->disp.dpy, interval);
1207    }
1208
1209    return res;
1210}
1211
1212
1213// ----------------------------------------------------------------------------
1214// EGL 1.2
1215// ----------------------------------------------------------------------------
1216
1217EGLBoolean eglWaitClient(void)
1218{
1219    clearError();
1220
1221    egl_connection_t* const cnx = &gEGLImpl;
1222    if (!cnx->dso)
1223        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1224
1225    EGLBoolean res;
1226    if (cnx->egl.eglWaitClient) {
1227        res = cnx->egl.eglWaitClient();
1228    } else {
1229        res = cnx->egl.eglWaitGL();
1230    }
1231    return res;
1232}
1233
1234EGLBoolean eglBindAPI(EGLenum api)
1235{
1236    clearError();
1237
1238    if (egl_init_drivers() == EGL_FALSE) {
1239        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1240    }
1241
1242    // bind this API on all EGLs
1243    EGLBoolean res = EGL_TRUE;
1244    egl_connection_t* const cnx = &gEGLImpl;
1245    if (cnx->dso && cnx->egl.eglBindAPI) {
1246        res = cnx->egl.eglBindAPI(api);
1247    }
1248    return res;
1249}
1250
1251EGLenum eglQueryAPI(void)
1252{
1253    clearError();
1254
1255    if (egl_init_drivers() == EGL_FALSE) {
1256        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1257    }
1258
1259    egl_connection_t* const cnx = &gEGLImpl;
1260    if (cnx->dso && cnx->egl.eglQueryAPI) {
1261        return cnx->egl.eglQueryAPI();
1262    }
1263
1264    // or, it can only be OpenGL ES
1265    return EGL_OPENGL_ES_API;
1266}
1267
1268EGLBoolean eglReleaseThread(void)
1269{
1270    clearError();
1271
1272#if EGL_TRACE
1273    if (getEGLDebugLevel() > 0)
1274        GLTrace_eglReleaseThread();
1275#endif
1276
1277    // If there is context bound to the thread, release it
1278    egl_display_t::loseCurrent(get_context(getContext()));
1279
1280    egl_connection_t* const cnx = &gEGLImpl;
1281    if (cnx->dso && cnx->egl.eglReleaseThread) {
1282        cnx->egl.eglReleaseThread();
1283    }
1284    egl_tls_t::clearTLS();
1285    return EGL_TRUE;
1286}
1287
1288EGLSurface eglCreatePbufferFromClientBuffer(
1289          EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1290          EGLConfig config, const EGLint *attrib_list)
1291{
1292    clearError();
1293
1294    egl_connection_t* cnx = NULL;
1295    const egl_display_ptr dp = validate_display_connection(dpy, cnx);
1296    if (!dp) return EGL_FALSE;
1297    if (cnx->egl.eglCreatePbufferFromClientBuffer) {
1298        return cnx->egl.eglCreatePbufferFromClientBuffer(
1299                dp->disp.dpy, buftype, buffer, config, attrib_list);
1300    }
1301    return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1302}
1303
1304// ----------------------------------------------------------------------------
1305// EGL_EGLEXT_VERSION 3
1306// ----------------------------------------------------------------------------
1307
1308EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1309        const EGLint *attrib_list)
1310{
1311    clearError();
1312
1313    const egl_display_ptr dp = validate_display(dpy);
1314    if (!dp) return EGL_FALSE;
1315
1316    SurfaceRef _s(dp.get(), surface);
1317    if (!_s.get())
1318        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1319
1320    egl_surface_t const * const s = get_surface(surface);
1321    if (s->cnx->egl.eglLockSurfaceKHR) {
1322        return s->cnx->egl.eglLockSurfaceKHR(
1323                dp->disp.dpy, s->surface, attrib_list);
1324    }
1325    return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1326}
1327
1328EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
1329{
1330    clearError();
1331
1332    const egl_display_ptr dp = validate_display(dpy);
1333    if (!dp) return EGL_FALSE;
1334
1335    SurfaceRef _s(dp.get(), surface);
1336    if (!_s.get())
1337        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1338
1339    egl_surface_t const * const s = get_surface(surface);
1340    if (s->cnx->egl.eglUnlockSurfaceKHR) {
1341        return s->cnx->egl.eglUnlockSurfaceKHR(dp->disp.dpy, s->surface);
1342    }
1343    return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1344}
1345
1346EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1347        EGLClientBuffer buffer, const EGLint *attrib_list)
1348{
1349    clearError();
1350
1351    const egl_display_ptr dp = validate_display(dpy);
1352    if (!dp) return EGL_NO_IMAGE_KHR;
1353
1354    ContextRef _c(dp.get(), ctx);
1355    egl_context_t * const c = _c.get();
1356
1357    EGLImageKHR result = EGL_NO_IMAGE_KHR;
1358    egl_connection_t* const cnx = &gEGLImpl;
1359    if (cnx->dso && cnx->egl.eglCreateImageKHR) {
1360        result = cnx->egl.eglCreateImageKHR(
1361                dp->disp.dpy,
1362                c ? c->context : EGL_NO_CONTEXT,
1363                target, buffer, attrib_list);
1364    }
1365    return result;
1366}
1367
1368EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1369{
1370    clearError();
1371
1372    const egl_display_ptr dp = validate_display(dpy);
1373    if (!dp) return EGL_FALSE;
1374
1375    EGLBoolean result = EGL_FALSE;
1376    egl_connection_t* const cnx = &gEGLImpl;
1377    if (cnx->dso && cnx->egl.eglDestroyImageKHR) {
1378        result = cnx->egl.eglDestroyImageKHR(dp->disp.dpy, img);
1379    }
1380    return result;
1381}
1382
1383// ----------------------------------------------------------------------------
1384// EGL_EGLEXT_VERSION 5
1385// ----------------------------------------------------------------------------
1386
1387
1388EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
1389{
1390    clearError();
1391
1392    const egl_display_ptr dp = validate_display(dpy);
1393    if (!dp) return EGL_NO_SYNC_KHR;
1394
1395    EGLSyncKHR result = EGL_NO_SYNC_KHR;
1396    egl_connection_t* const cnx = &gEGLImpl;
1397    if (cnx->dso && cnx->egl.eglCreateSyncKHR) {
1398        result = cnx->egl.eglCreateSyncKHR(dp->disp.dpy, type, attrib_list);
1399    }
1400    return result;
1401}
1402
1403EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
1404{
1405    clearError();
1406
1407    const egl_display_ptr dp = validate_display(dpy);
1408    if (!dp) return EGL_FALSE;
1409
1410    EGLBoolean result = EGL_FALSE;
1411    egl_connection_t* const cnx = &gEGLImpl;
1412    if (cnx->dso && cnx->egl.eglDestroySyncKHR) {
1413        result = cnx->egl.eglDestroySyncKHR(dp->disp.dpy, sync);
1414    }
1415    return result;
1416}
1417
1418EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) {
1419    clearError();
1420
1421    const egl_display_ptr dp = validate_display(dpy);
1422    if (!dp) return EGL_FALSE;
1423
1424    EGLBoolean result = EGL_FALSE;
1425    egl_connection_t* const cnx = &gEGLImpl;
1426    if (cnx->dso && cnx->egl.eglSignalSyncKHR) {
1427        result = cnx->egl.eglSignalSyncKHR(
1428                dp->disp.dpy, sync, mode);
1429    }
1430    return result;
1431}
1432
1433EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync,
1434        EGLint flags, EGLTimeKHR timeout)
1435{
1436    clearError();
1437
1438    const egl_display_ptr dp = validate_display(dpy);
1439    if (!dp) return EGL_FALSE;
1440
1441    EGLBoolean result = EGL_FALSE;
1442    egl_connection_t* const cnx = &gEGLImpl;
1443    if (cnx->dso && cnx->egl.eglClientWaitSyncKHR) {
1444        result = cnx->egl.eglClientWaitSyncKHR(
1445                dp->disp.dpy, sync, flags, timeout);
1446    }
1447    return result;
1448}
1449
1450EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync,
1451        EGLint attribute, EGLint *value)
1452{
1453    clearError();
1454
1455    const egl_display_ptr dp = validate_display(dpy);
1456    if (!dp) return EGL_FALSE;
1457
1458    EGLBoolean result = EGL_FALSE;
1459    egl_connection_t* const cnx = &gEGLImpl;
1460    if (cnx->dso && cnx->egl.eglGetSyncAttribKHR) {
1461        result = cnx->egl.eglGetSyncAttribKHR(
1462                dp->disp.dpy, sync, attribute, value);
1463    }
1464    return result;
1465}
1466
1467// ----------------------------------------------------------------------------
1468// EGL_EGLEXT_VERSION 15
1469// ----------------------------------------------------------------------------
1470
1471EGLint eglWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) {
1472    clearError();
1473    const egl_display_ptr dp = validate_display(dpy);
1474    if (!dp) return EGL_FALSE;
1475    EGLint result = EGL_FALSE;
1476    egl_connection_t* const cnx = &gEGLImpl;
1477    if (cnx->dso && cnx->egl.eglWaitSyncKHR) {
1478        result = cnx->egl.eglWaitSyncKHR(dp->disp.dpy, sync, flags);
1479    }
1480    return result;
1481}
1482
1483// ----------------------------------------------------------------------------
1484// ANDROID extensions
1485// ----------------------------------------------------------------------------
1486
1487EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync)
1488{
1489    clearError();
1490
1491    const egl_display_ptr dp = validate_display(dpy);
1492    if (!dp) return EGL_NO_NATIVE_FENCE_FD_ANDROID;
1493
1494    EGLint result = EGL_NO_NATIVE_FENCE_FD_ANDROID;
1495    egl_connection_t* const cnx = &gEGLImpl;
1496    if (cnx->dso && cnx->egl.eglDupNativeFenceFDANDROID) {
1497        result = cnx->egl.eglDupNativeFenceFDANDROID(dp->disp.dpy, sync);
1498    }
1499    return result;
1500}
1501
1502EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface,
1503        EGLnsecsANDROID time)
1504{
1505    clearError();
1506
1507    const egl_display_ptr dp = validate_display(dpy);
1508    if (!dp) {
1509        return EGL_FALSE;
1510    }
1511
1512    SurfaceRef _s(dp.get(), surface);
1513    if (!_s.get()) {
1514        setError(EGL_BAD_SURFACE, EGL_FALSE);
1515        return EGL_FALSE;
1516    }
1517
1518    egl_surface_t const * const s = get_surface(surface);
1519    native_window_set_buffers_timestamp(s->win.get(), time);
1520
1521    return EGL_TRUE;
1522}
1523
1524// ----------------------------------------------------------------------------
1525// NVIDIA extensions
1526// ----------------------------------------------------------------------------
1527EGLuint64NV eglGetSystemTimeFrequencyNV()
1528{
1529    clearError();
1530
1531    if (egl_init_drivers() == EGL_FALSE) {
1532        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1533    }
1534
1535    EGLuint64NV ret = 0;
1536    egl_connection_t* const cnx = &gEGLImpl;
1537
1538    if (cnx->dso && cnx->egl.eglGetSystemTimeFrequencyNV) {
1539        return cnx->egl.eglGetSystemTimeFrequencyNV();
1540    }
1541
1542    return setErrorQuiet(EGL_BAD_DISPLAY, 0);
1543}
1544
1545EGLuint64NV eglGetSystemTimeNV()
1546{
1547    clearError();
1548
1549    if (egl_init_drivers() == EGL_FALSE) {
1550        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1551    }
1552
1553    EGLuint64NV ret = 0;
1554    egl_connection_t* const cnx = &gEGLImpl;
1555
1556    if (cnx->dso && cnx->egl.eglGetSystemTimeNV) {
1557        return cnx->egl.eglGetSystemTimeNV();
1558    }
1559
1560    return setErrorQuiet(EGL_BAD_DISPLAY, 0);
1561}
1562