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