eglApi.cpp revision 0f288fcc9c1b2d23b1cff2f5c59689aef76b77ae
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
417        // by default, just pick RGBA_8888
418        EGLint format = HAL_PIXEL_FORMAT_RGBA_8888;
419
420        EGLint a = 0;
421        cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_ALPHA_SIZE, &a);
422        if (a > 0) {
423            // alpha-channel requested, there's really only one suitable format
424            format = HAL_PIXEL_FORMAT_RGBA_8888;
425        } else {
426            EGLint r, g, b;
427            r = g = b = 0;
428            cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_RED_SIZE,   &r);
429            cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_GREEN_SIZE, &g);
430            cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_BLUE_SIZE,  &b);
431            EGLint colorDepth = r + g + b;
432            if (colorDepth <= 16) {
433                format = HAL_PIXEL_FORMAT_RGB_565;
434            } else {
435                format = HAL_PIXEL_FORMAT_RGBX_8888;
436            }
437        }
438
439        // now select a corresponding sRGB format if needed
440        if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) {
441            for (const EGLint* attr = attrib_list; *attr != EGL_NONE; attr += 2) {
442                if (*attr == EGL_GL_COLORSPACE_KHR) {
443                    format = modifyFormatColorspace(format, attr[1]);
444                }
445            }
446        }
447        if (format != 0) {
448            int err = native_window_set_buffers_format(window, format);
449            if (err != 0) {
450                ALOGE("error setting native window pixel format: %s (%d)",
451                        strerror(-err), err);
452                native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
453                return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
454            }
455        }
456
457        // the EGL spec requires that a new EGLSurface default to swap interval
458        // 1, so explicitly set that on the window here.
459        ANativeWindow* anw = reinterpret_cast<ANativeWindow*>(window);
460        anw->setSwapInterval(anw, 1);
461
462        EGLSurface surface = cnx->egl.eglCreateWindowSurface(
463                iDpy, config, window, attrib_list);
464        if (surface != EGL_NO_SURFACE) {
465            egl_surface_t* s = new egl_surface_t(dp.get(), config, window,
466                    surface, cnx);
467            return s;
468        }
469
470        // EGLSurface creation failed
471        native_window_set_buffers_format(window, 0);
472        native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
473    }
474    return EGL_NO_SURFACE;
475}
476
477EGLSurface eglCreatePixmapSurface(  EGLDisplay dpy, EGLConfig config,
478                                    NativePixmapType pixmap,
479                                    const EGLint *attrib_list)
480{
481    clearError();
482
483    egl_connection_t* cnx = NULL;
484    egl_display_ptr dp = validate_display_connection(dpy, cnx);
485    if (dp) {
486        EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
487                dp->disp.dpy, config, pixmap, attrib_list);
488        if (surface != EGL_NO_SURFACE) {
489            egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL,
490                    surface, cnx);
491            return s;
492        }
493    }
494    return EGL_NO_SURFACE;
495}
496
497EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
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.eglCreatePbufferSurface(
506                dp->disp.dpy, config, 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
516EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
517{
518    clearError();
519
520    const egl_display_ptr dp = validate_display(dpy);
521    if (!dp) return EGL_FALSE;
522
523    SurfaceRef _s(dp.get(), surface);
524    if (!_s.get())
525        return setError(EGL_BAD_SURFACE, EGL_FALSE);
526
527    egl_surface_t * const s = get_surface(surface);
528    EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface);
529    if (result == EGL_TRUE) {
530        _s.terminate();
531    }
532    return result;
533}
534
535EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
536                            EGLint attribute, EGLint *value)
537{
538    clearError();
539
540    const egl_display_ptr dp = validate_display(dpy);
541    if (!dp) return EGL_FALSE;
542
543    SurfaceRef _s(dp.get(), surface);
544    if (!_s.get())
545        return setError(EGL_BAD_SURFACE, EGL_FALSE);
546
547    egl_surface_t const * const s = get_surface(surface);
548    return s->cnx->egl.eglQuerySurface(
549            dp->disp.dpy, s->surface, attribute, value);
550}
551
552void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) {
553    ATRACE_CALL();
554    clearError();
555
556    const egl_display_ptr dp = validate_display(dpy);
557    if (!dp) {
558        return;
559    }
560
561    SurfaceRef _s(dp.get(), surface);
562    if (!_s.get()) {
563        setError(EGL_BAD_SURFACE, EGL_FALSE);
564        return;
565    }
566}
567
568// ----------------------------------------------------------------------------
569// Contexts
570// ----------------------------------------------------------------------------
571
572EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
573                            EGLContext share_list, const EGLint *attrib_list)
574{
575    clearError();
576
577    egl_connection_t* cnx = NULL;
578    const egl_display_ptr dp = validate_display_connection(dpy, cnx);
579    if (dp) {
580        if (share_list != EGL_NO_CONTEXT) {
581            if (!ContextRef(dp.get(), share_list).get()) {
582                return setError(EGL_BAD_CONTEXT, EGL_NO_CONTEXT);
583            }
584            egl_context_t* const c = get_context(share_list);
585            share_list = c->context;
586        }
587        EGLContext context = cnx->egl.eglCreateContext(
588                dp->disp.dpy, config, share_list, attrib_list);
589        if (context != EGL_NO_CONTEXT) {
590            // figure out if it's a GLESv1 or GLESv2
591            int version = 0;
592            if (attrib_list) {
593                while (*attrib_list != EGL_NONE) {
594                    GLint attr = *attrib_list++;
595                    GLint value = *attrib_list++;
596                    if (attr == EGL_CONTEXT_CLIENT_VERSION) {
597                        if (value == 1) {
598                            version = egl_connection_t::GLESv1_INDEX;
599                        } else if (value == 2 || value == 3) {
600                            version = egl_connection_t::GLESv2_INDEX;
601                        }
602                    }
603                };
604            }
605            egl_context_t* c = new egl_context_t(dpy, context, config, cnx,
606                    version);
607#if EGL_TRACE
608            if (getEGLDebugLevel() > 0)
609                GLTrace_eglCreateContext(version, c);
610#endif
611            return c;
612        }
613    }
614    return EGL_NO_CONTEXT;
615}
616
617EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
618{
619    clearError();
620
621    const egl_display_ptr dp = validate_display(dpy);
622    if (!dp)
623        return EGL_FALSE;
624
625    ContextRef _c(dp.get(), ctx);
626    if (!_c.get())
627        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
628
629    egl_context_t * const c = get_context(ctx);
630    EGLBoolean result = c->cnx->egl.eglDestroyContext(dp->disp.dpy, c->context);
631    if (result == EGL_TRUE) {
632        _c.terminate();
633    }
634    return result;
635}
636
637EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
638                            EGLSurface read, EGLContext ctx)
639{
640    clearError();
641
642    egl_display_ptr dp = validate_display(dpy);
643    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
644
645    // If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not
646    // EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is
647    // a valid but uninitialized display.
648    if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) ||
649         (draw != EGL_NO_SURFACE) ) {
650        if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
651    }
652
653    // get a reference to the object passed in
654    ContextRef _c(dp.get(), ctx);
655    SurfaceRef _d(dp.get(), draw);
656    SurfaceRef _r(dp.get(), read);
657
658    // validate the context (if not EGL_NO_CONTEXT)
659    if ((ctx != EGL_NO_CONTEXT) && !_c.get()) {
660        // EGL_NO_CONTEXT is valid
661        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
662    }
663
664    // these are the underlying implementation's object
665    EGLContext impl_ctx  = EGL_NO_CONTEXT;
666    EGLSurface impl_draw = EGL_NO_SURFACE;
667    EGLSurface impl_read = EGL_NO_SURFACE;
668
669    // these are our objects structs passed in
670    egl_context_t       * c = NULL;
671    egl_surface_t const * d = NULL;
672    egl_surface_t const * r = NULL;
673
674    // these are the current objects structs
675    egl_context_t * cur_c = get_context(getContext());
676
677    if (ctx != EGL_NO_CONTEXT) {
678        c = get_context(ctx);
679        impl_ctx = c->context;
680    } else {
681        // no context given, use the implementation of the current context
682        if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
683            // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT);
684            return setError(EGL_BAD_MATCH, EGL_FALSE);
685        }
686        if (cur_c == NULL) {
687            // no current context
688            // not an error, there is just no current context.
689            return EGL_TRUE;
690        }
691    }
692
693    // retrieve the underlying implementation's draw EGLSurface
694    if (draw != EGL_NO_SURFACE) {
695        if (!_d.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
696        d = get_surface(draw);
697        impl_draw = d->surface;
698    }
699
700    // retrieve the underlying implementation's read EGLSurface
701    if (read != EGL_NO_SURFACE) {
702        if (!_r.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
703        r = get_surface(read);
704        impl_read = r->surface;
705    }
706
707
708    EGLBoolean result = dp->makeCurrent(c, cur_c,
709            draw, read, ctx,
710            impl_draw, impl_read, impl_ctx);
711
712    if (result == EGL_TRUE) {
713        if (c) {
714            setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
715            egl_tls_t::setContext(ctx);
716#if EGL_TRACE
717            if (getEGLDebugLevel() > 0)
718                GLTrace_eglMakeCurrent(c->version, c->cnx->hooks[c->version], ctx);
719#endif
720            _c.acquire();
721            _r.acquire();
722            _d.acquire();
723        } else {
724            setGLHooksThreadSpecific(&gHooksNoContext);
725            egl_tls_t::setContext(EGL_NO_CONTEXT);
726        }
727    } else {
728        // this will ALOGE the error
729        result = setError(c->cnx->egl.eglGetError(), EGL_FALSE);
730    }
731    return result;
732}
733
734
735EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
736                            EGLint attribute, EGLint *value)
737{
738    clearError();
739
740    const egl_display_ptr dp = validate_display(dpy);
741    if (!dp) return EGL_FALSE;
742
743    ContextRef _c(dp.get(), ctx);
744    if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
745
746    egl_context_t * const c = get_context(ctx);
747    return c->cnx->egl.eglQueryContext(
748            dp->disp.dpy, c->context, attribute, value);
749
750}
751
752EGLContext eglGetCurrentContext(void)
753{
754    // could be called before eglInitialize(), but we wouldn't have a context
755    // then, and this function would correctly return EGL_NO_CONTEXT.
756
757    clearError();
758
759    EGLContext ctx = getContext();
760    return ctx;
761}
762
763EGLSurface eglGetCurrentSurface(EGLint readdraw)
764{
765    // could be called before eglInitialize(), but we wouldn't have a context
766    // then, and this function would correctly return EGL_NO_SURFACE.
767
768    clearError();
769
770    EGLContext ctx = getContext();
771    if (ctx) {
772        egl_context_t const * const c = get_context(ctx);
773        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
774        switch (readdraw) {
775            case EGL_READ: return c->read;
776            case EGL_DRAW: return c->draw;
777            default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
778        }
779    }
780    return EGL_NO_SURFACE;
781}
782
783EGLDisplay eglGetCurrentDisplay(void)
784{
785    // could be called before eglInitialize(), but we wouldn't have a context
786    // then, and this function would correctly return EGL_NO_DISPLAY.
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        return c->dpy;
795    }
796    return EGL_NO_DISPLAY;
797}
798
799EGLBoolean eglWaitGL(void)
800{
801    clearError();
802
803    egl_connection_t* const cnx = &gEGLImpl;
804    if (!cnx->dso)
805        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
806
807    return cnx->egl.eglWaitGL();
808}
809
810EGLBoolean eglWaitNative(EGLint engine)
811{
812    clearError();
813
814    egl_connection_t* const cnx = &gEGLImpl;
815    if (!cnx->dso)
816        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
817
818    return cnx->egl.eglWaitNative(engine);
819}
820
821EGLint eglGetError(void)
822{
823    EGLint err = EGL_SUCCESS;
824    egl_connection_t* const cnx = &gEGLImpl;
825    if (cnx->dso) {
826        err = cnx->egl.eglGetError();
827    }
828    if (err == EGL_SUCCESS) {
829        err = egl_tls_t::getError();
830    }
831    return err;
832}
833
834static __eglMustCastToProperFunctionPointerType findBuiltinGLWrapper(
835        const char* procname) {
836    const egl_connection_t* cnx = &gEGLImpl;
837    void* proc = NULL;
838
839    proc = dlsym(cnx->libGles2, procname);
840    if (proc) return (__eglMustCastToProperFunctionPointerType)proc;
841
842    proc = dlsym(cnx->libGles1, procname);
843    if (proc) return (__eglMustCastToProperFunctionPointerType)proc;
844
845    return NULL;
846}
847
848__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
849{
850    // eglGetProcAddress() could be the very first function called
851    // in which case we must make sure we've initialized ourselves, this
852    // happens the first time egl_get_display() is called.
853
854    clearError();
855
856    if (egl_init_drivers() == EGL_FALSE) {
857        setError(EGL_BAD_PARAMETER, NULL);
858        return  NULL;
859    }
860
861    if (FILTER_EXTENSIONS(procname)) {
862        return NULL;
863    }
864
865    __eglMustCastToProperFunctionPointerType addr;
866    addr = findProcAddress(procname, sExtensionMap, NELEM(sExtensionMap));
867    if (addr) return addr;
868
869    addr = findBuiltinGLWrapper(procname);
870    if (addr) return addr;
871
872    // this protects accesses to sGLExtentionMap and sGLExtentionSlot
873    pthread_mutex_lock(&sExtensionMapMutex);
874
875        /*
876         * Since eglGetProcAddress() is not associated to anything, it needs
877         * to return a function pointer that "works" regardless of what
878         * the current context is.
879         *
880         * For this reason, we return a "forwarder", a small stub that takes
881         * care of calling the function associated with the context
882         * currently bound.
883         *
884         * We first look for extensions we've already resolved, if we're seeing
885         * this extension for the first time, we go through all our
886         * implementations and call eglGetProcAddress() and record the
887         * result in the appropriate implementation hooks and return the
888         * address of the forwarder corresponding to that hook set.
889         *
890         */
891
892        const String8 name(procname);
893        addr = sGLExtentionMap.valueFor(name);
894        const int slot = sGLExtentionSlot;
895
896        ALOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS,
897                "no more slots for eglGetProcAddress(\"%s\")",
898                procname);
899
900#if EGL_TRACE
901        gl_hooks_t *debugHooks = GLTrace_getGLHooks();
902#endif
903
904        if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) {
905            bool found = false;
906
907            egl_connection_t* const cnx = &gEGLImpl;
908            if (cnx->dso && cnx->egl.eglGetProcAddress) {
909                // Extensions are independent of the bound context
910                addr =
911                cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] =
912                cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] =
913#if EGL_TRACE
914                debugHooks->ext.extensions[slot] =
915                gHooksTrace.ext.extensions[slot] =
916#endif
917                        cnx->egl.eglGetProcAddress(procname);
918                if (addr) found = true;
919            }
920
921            if (found) {
922                addr = gExtensionForwarders[slot];
923                sGLExtentionMap.add(name, addr);
924                sGLExtentionSlot++;
925            }
926        }
927
928    pthread_mutex_unlock(&sExtensionMapMutex);
929    return addr;
930}
931
932class FrameCompletionThread : public Thread {
933public:
934
935    static void queueSync(EGLSyncKHR sync) {
936        static sp<FrameCompletionThread> thread(new FrameCompletionThread);
937        static bool running = false;
938        if (!running) {
939            thread->run("GPUFrameCompletion");
940            running = true;
941        }
942        {
943            Mutex::Autolock lock(thread->mMutex);
944            ScopedTrace st(ATRACE_TAG, String8::format("kicked off frame %d",
945                    thread->mFramesQueued).string());
946            thread->mQueue.push_back(sync);
947            thread->mCondition.signal();
948            thread->mFramesQueued++;
949            ATRACE_INT("GPU Frames Outstanding", thread->mQueue.size());
950        }
951    }
952
953private:
954    FrameCompletionThread() : mFramesQueued(0), mFramesCompleted(0) {}
955
956    virtual bool threadLoop() {
957        EGLSyncKHR sync;
958        uint32_t frameNum;
959        {
960            Mutex::Autolock lock(mMutex);
961            while (mQueue.isEmpty()) {
962                mCondition.wait(mMutex);
963            }
964            sync = mQueue[0];
965            frameNum = mFramesCompleted;
966        }
967        EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
968        {
969            ScopedTrace st(ATRACE_TAG, String8::format("waiting for frame %d",
970                    frameNum).string());
971            EGLint result = eglClientWaitSyncKHR(dpy, sync, 0, EGL_FOREVER_KHR);
972            if (result == EGL_FALSE) {
973                ALOGE("FrameCompletion: error waiting for fence: %#x", eglGetError());
974            } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
975                ALOGE("FrameCompletion: timeout waiting for fence");
976            }
977            eglDestroySyncKHR(dpy, sync);
978        }
979        {
980            Mutex::Autolock lock(mMutex);
981            mQueue.removeAt(0);
982            mFramesCompleted++;
983            ATRACE_INT("GPU Frames Outstanding", mQueue.size());
984        }
985        return true;
986    }
987
988    uint32_t mFramesQueued;
989    uint32_t mFramesCompleted;
990    Vector<EGLSyncKHR> mQueue;
991    Condition mCondition;
992    Mutex mMutex;
993};
994
995EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
996{
997    ATRACE_CALL();
998    clearError();
999
1000    const egl_display_ptr dp = validate_display(dpy);
1001    if (!dp) return EGL_FALSE;
1002
1003    SurfaceRef _s(dp.get(), draw);
1004    if (!_s.get())
1005        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1006
1007#if EGL_TRACE
1008    gl_hooks_t const *trace_hooks = getGLTraceThreadSpecific();
1009    if (getEGLDebugLevel() > 0) {
1010        if (trace_hooks == NULL) {
1011            if (GLTrace_start() < 0) {
1012                ALOGE("Disabling Tracer for OpenGL ES");
1013                setEGLDebugLevel(0);
1014            } else {
1015                // switch over to the trace version of hooks
1016                EGLContext ctx = egl_tls_t::getContext();
1017                egl_context_t * const c = get_context(ctx);
1018                if (c) {
1019                    setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
1020                    GLTrace_eglMakeCurrent(c->version, c->cnx->hooks[c->version], ctx);
1021                }
1022            }
1023        }
1024
1025        GLTrace_eglSwapBuffers(dpy, draw);
1026    } else if (trace_hooks != NULL) {
1027        // tracing is now disabled, so switch back to the non trace version
1028        EGLContext ctx = egl_tls_t::getContext();
1029        egl_context_t * const c = get_context(ctx);
1030        if (c) setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
1031        GLTrace_stop();
1032    }
1033#endif
1034
1035    egl_surface_t const * const s = get_surface(draw);
1036
1037    if (CC_UNLIKELY(dp->traceGpuCompletion)) {
1038        EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
1039        if (sync != EGL_NO_SYNC_KHR) {
1040            FrameCompletionThread::queueSync(sync);
1041        }
1042    }
1043
1044    if (CC_UNLIKELY(dp->finishOnSwap)) {
1045        uint32_t pixel;
1046        egl_context_t * const c = get_context( egl_tls_t::getContext() );
1047        if (c) {
1048            // glReadPixels() ensures that the frame is complete
1049            s->cnx->hooks[c->version]->gl.glReadPixels(0,0,1,1,
1050                    GL_RGBA,GL_UNSIGNED_BYTE,&pixel);
1051        }
1052    }
1053
1054    return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface);
1055}
1056
1057EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
1058                            NativePixmapType target)
1059{
1060    clearError();
1061
1062    const egl_display_ptr dp = validate_display(dpy);
1063    if (!dp) return EGL_FALSE;
1064
1065    SurfaceRef _s(dp.get(), surface);
1066    if (!_s.get())
1067        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1068
1069    egl_surface_t const * const s = get_surface(surface);
1070    return s->cnx->egl.eglCopyBuffers(dp->disp.dpy, s->surface, target);
1071}
1072
1073const char* eglQueryString(EGLDisplay dpy, EGLint name)
1074{
1075    clearError();
1076
1077    const egl_display_ptr dp = validate_display(dpy);
1078    if (!dp) return (const char *) NULL;
1079
1080    switch (name) {
1081        case EGL_VENDOR:
1082            return dp->getVendorString();
1083        case EGL_VERSION:
1084            return dp->getVersionString();
1085        case EGL_EXTENSIONS:
1086            return dp->getExtensionString();
1087        case EGL_CLIENT_APIS:
1088            return dp->getClientApiString();
1089    }
1090    return setError(EGL_BAD_PARAMETER, (const char *)0);
1091}
1092
1093EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name)
1094{
1095    clearError();
1096
1097    const egl_display_ptr dp = validate_display(dpy);
1098    if (!dp) return (const char *) NULL;
1099
1100    switch (name) {
1101        case EGL_VENDOR:
1102            return dp->disp.queryString.vendor;
1103        case EGL_VERSION:
1104            return dp->disp.queryString.version;
1105        case EGL_EXTENSIONS:
1106            return dp->disp.queryString.extensions;
1107        case EGL_CLIENT_APIS:
1108            return dp->disp.queryString.clientApi;
1109    }
1110    return setError(EGL_BAD_PARAMETER, (const char *)0);
1111}
1112
1113// ----------------------------------------------------------------------------
1114// EGL 1.1
1115// ----------------------------------------------------------------------------
1116
1117EGLBoolean eglSurfaceAttrib(
1118        EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1119{
1120    clearError();
1121
1122    const egl_display_ptr dp = validate_display(dpy);
1123    if (!dp) return EGL_FALSE;
1124
1125    SurfaceRef _s(dp.get(), surface);
1126    if (!_s.get())
1127        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1128
1129    egl_surface_t const * const s = get_surface(surface);
1130    if (s->cnx->egl.eglSurfaceAttrib) {
1131        return s->cnx->egl.eglSurfaceAttrib(
1132                dp->disp.dpy, s->surface, attribute, value);
1133    }
1134    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1135}
1136
1137EGLBoolean eglBindTexImage(
1138        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1139{
1140    clearError();
1141
1142    const egl_display_ptr dp = validate_display(dpy);
1143    if (!dp) return EGL_FALSE;
1144
1145    SurfaceRef _s(dp.get(), surface);
1146    if (!_s.get())
1147        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1148
1149    egl_surface_t const * const s = get_surface(surface);
1150    if (s->cnx->egl.eglBindTexImage) {
1151        return s->cnx->egl.eglBindTexImage(
1152                dp->disp.dpy, s->surface, buffer);
1153    }
1154    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1155}
1156
1157EGLBoolean eglReleaseTexImage(
1158        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1159{
1160    clearError();
1161
1162    const egl_display_ptr dp = validate_display(dpy);
1163    if (!dp) return EGL_FALSE;
1164
1165    SurfaceRef _s(dp.get(), surface);
1166    if (!_s.get())
1167        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1168
1169    egl_surface_t const * const s = get_surface(surface);
1170    if (s->cnx->egl.eglReleaseTexImage) {
1171        return s->cnx->egl.eglReleaseTexImage(
1172                dp->disp.dpy, s->surface, buffer);
1173    }
1174    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1175}
1176
1177EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1178{
1179    clearError();
1180
1181    const egl_display_ptr dp = validate_display(dpy);
1182    if (!dp) return EGL_FALSE;
1183
1184    EGLBoolean res = EGL_TRUE;
1185    egl_connection_t* const cnx = &gEGLImpl;
1186    if (cnx->dso && cnx->egl.eglSwapInterval) {
1187        res = cnx->egl.eglSwapInterval(dp->disp.dpy, interval);
1188    }
1189
1190    return res;
1191}
1192
1193
1194// ----------------------------------------------------------------------------
1195// EGL 1.2
1196// ----------------------------------------------------------------------------
1197
1198EGLBoolean eglWaitClient(void)
1199{
1200    clearError();
1201
1202    egl_connection_t* const cnx = &gEGLImpl;
1203    if (!cnx->dso)
1204        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1205
1206    EGLBoolean res;
1207    if (cnx->egl.eglWaitClient) {
1208        res = cnx->egl.eglWaitClient();
1209    } else {
1210        res = cnx->egl.eglWaitGL();
1211    }
1212    return res;
1213}
1214
1215EGLBoolean eglBindAPI(EGLenum api)
1216{
1217    clearError();
1218
1219    if (egl_init_drivers() == EGL_FALSE) {
1220        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1221    }
1222
1223    // bind this API on all EGLs
1224    EGLBoolean res = EGL_TRUE;
1225    egl_connection_t* const cnx = &gEGLImpl;
1226    if (cnx->dso && cnx->egl.eglBindAPI) {
1227        res = cnx->egl.eglBindAPI(api);
1228    }
1229    return res;
1230}
1231
1232EGLenum eglQueryAPI(void)
1233{
1234    clearError();
1235
1236    if (egl_init_drivers() == EGL_FALSE) {
1237        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1238    }
1239
1240    egl_connection_t* const cnx = &gEGLImpl;
1241    if (cnx->dso && cnx->egl.eglQueryAPI) {
1242        return cnx->egl.eglQueryAPI();
1243    }
1244
1245    // or, it can only be OpenGL ES
1246    return EGL_OPENGL_ES_API;
1247}
1248
1249EGLBoolean eglReleaseThread(void)
1250{
1251    clearError();
1252
1253#if EGL_TRACE
1254    if (getEGLDebugLevel() > 0)
1255        GLTrace_eglReleaseThread();
1256#endif
1257
1258    // If there is context bound to the thread, release it
1259    egl_display_t::loseCurrent(get_context(getContext()));
1260
1261    egl_connection_t* const cnx = &gEGLImpl;
1262    if (cnx->dso && cnx->egl.eglReleaseThread) {
1263        cnx->egl.eglReleaseThread();
1264    }
1265    egl_tls_t::clearTLS();
1266    return EGL_TRUE;
1267}
1268
1269EGLSurface eglCreatePbufferFromClientBuffer(
1270          EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1271          EGLConfig config, const EGLint *attrib_list)
1272{
1273    clearError();
1274
1275    egl_connection_t* cnx = NULL;
1276    const egl_display_ptr dp = validate_display_connection(dpy, cnx);
1277    if (!dp) return EGL_FALSE;
1278    if (cnx->egl.eglCreatePbufferFromClientBuffer) {
1279        return cnx->egl.eglCreatePbufferFromClientBuffer(
1280                dp->disp.dpy, buftype, buffer, config, attrib_list);
1281    }
1282    return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1283}
1284
1285// ----------------------------------------------------------------------------
1286// EGL_EGLEXT_VERSION 3
1287// ----------------------------------------------------------------------------
1288
1289EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1290        const EGLint *attrib_list)
1291{
1292    clearError();
1293
1294    const egl_display_ptr dp = validate_display(dpy);
1295    if (!dp) return EGL_FALSE;
1296
1297    SurfaceRef _s(dp.get(), surface);
1298    if (!_s.get())
1299        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1300
1301    egl_surface_t const * const s = get_surface(surface);
1302    if (s->cnx->egl.eglLockSurfaceKHR) {
1303        return s->cnx->egl.eglLockSurfaceKHR(
1304                dp->disp.dpy, s->surface, attrib_list);
1305    }
1306    return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1307}
1308
1309EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
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.eglUnlockSurfaceKHR) {
1322        return s->cnx->egl.eglUnlockSurfaceKHR(dp->disp.dpy, s->surface);
1323    }
1324    return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1325}
1326
1327EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1328        EGLClientBuffer buffer, const EGLint *attrib_list)
1329{
1330    clearError();
1331
1332    const egl_display_ptr dp = validate_display(dpy);
1333    if (!dp) return EGL_NO_IMAGE_KHR;
1334
1335    ContextRef _c(dp.get(), ctx);
1336    egl_context_t * const c = _c.get();
1337
1338    EGLImageKHR result = EGL_NO_IMAGE_KHR;
1339    egl_connection_t* const cnx = &gEGLImpl;
1340    if (cnx->dso && cnx->egl.eglCreateImageKHR) {
1341        result = cnx->egl.eglCreateImageKHR(
1342                dp->disp.dpy,
1343                c ? c->context : EGL_NO_CONTEXT,
1344                target, buffer, attrib_list);
1345    }
1346    return result;
1347}
1348
1349EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1350{
1351    clearError();
1352
1353    const egl_display_ptr dp = validate_display(dpy);
1354    if (!dp) return EGL_FALSE;
1355
1356    EGLBoolean result = EGL_FALSE;
1357    egl_connection_t* const cnx = &gEGLImpl;
1358    if (cnx->dso && cnx->egl.eglDestroyImageKHR) {
1359        result = cnx->egl.eglDestroyImageKHR(dp->disp.dpy, img);
1360    }
1361    return result;
1362}
1363
1364// ----------------------------------------------------------------------------
1365// EGL_EGLEXT_VERSION 5
1366// ----------------------------------------------------------------------------
1367
1368
1369EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
1370{
1371    clearError();
1372
1373    const egl_display_ptr dp = validate_display(dpy);
1374    if (!dp) return EGL_NO_SYNC_KHR;
1375
1376    EGLSyncKHR result = EGL_NO_SYNC_KHR;
1377    egl_connection_t* const cnx = &gEGLImpl;
1378    if (cnx->dso && cnx->egl.eglCreateSyncKHR) {
1379        result = cnx->egl.eglCreateSyncKHR(dp->disp.dpy, type, attrib_list);
1380    }
1381    return result;
1382}
1383
1384EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
1385{
1386    clearError();
1387
1388    const egl_display_ptr dp = validate_display(dpy);
1389    if (!dp) return EGL_FALSE;
1390
1391    EGLBoolean result = EGL_FALSE;
1392    egl_connection_t* const cnx = &gEGLImpl;
1393    if (cnx->dso && cnx->egl.eglDestroySyncKHR) {
1394        result = cnx->egl.eglDestroySyncKHR(dp->disp.dpy, sync);
1395    }
1396    return result;
1397}
1398
1399EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) {
1400    clearError();
1401
1402    const egl_display_ptr dp = validate_display(dpy);
1403    if (!dp) return EGL_FALSE;
1404
1405    EGLBoolean result = EGL_FALSE;
1406    egl_connection_t* const cnx = &gEGLImpl;
1407    if (cnx->dso && cnx->egl.eglSignalSyncKHR) {
1408        result = cnx->egl.eglSignalSyncKHR(
1409                dp->disp.dpy, sync, mode);
1410    }
1411    return result;
1412}
1413
1414EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync,
1415        EGLint flags, EGLTimeKHR timeout)
1416{
1417    clearError();
1418
1419    const egl_display_ptr dp = validate_display(dpy);
1420    if (!dp) return EGL_FALSE;
1421
1422    EGLBoolean result = EGL_FALSE;
1423    egl_connection_t* const cnx = &gEGLImpl;
1424    if (cnx->dso && cnx->egl.eglClientWaitSyncKHR) {
1425        result = cnx->egl.eglClientWaitSyncKHR(
1426                dp->disp.dpy, sync, flags, timeout);
1427    }
1428    return result;
1429}
1430
1431EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync,
1432        EGLint attribute, EGLint *value)
1433{
1434    clearError();
1435
1436    const egl_display_ptr dp = validate_display(dpy);
1437    if (!dp) return EGL_FALSE;
1438
1439    EGLBoolean result = EGL_FALSE;
1440    egl_connection_t* const cnx = &gEGLImpl;
1441    if (cnx->dso && cnx->egl.eglGetSyncAttribKHR) {
1442        result = cnx->egl.eglGetSyncAttribKHR(
1443                dp->disp.dpy, sync, attribute, value);
1444    }
1445    return result;
1446}
1447
1448// ----------------------------------------------------------------------------
1449// EGL_EGLEXT_VERSION 15
1450// ----------------------------------------------------------------------------
1451
1452EGLint eglWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) {
1453    clearError();
1454    const egl_display_ptr dp = validate_display(dpy);
1455    if (!dp) return EGL_FALSE;
1456    EGLint result = EGL_FALSE;
1457    egl_connection_t* const cnx = &gEGLImpl;
1458    if (cnx->dso && cnx->egl.eglWaitSyncKHR) {
1459        result = cnx->egl.eglWaitSyncKHR(dp->disp.dpy, sync, flags);
1460    }
1461    return result;
1462}
1463
1464// ----------------------------------------------------------------------------
1465// ANDROID extensions
1466// ----------------------------------------------------------------------------
1467
1468EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync)
1469{
1470    clearError();
1471
1472    const egl_display_ptr dp = validate_display(dpy);
1473    if (!dp) return EGL_NO_NATIVE_FENCE_FD_ANDROID;
1474
1475    EGLint result = EGL_NO_NATIVE_FENCE_FD_ANDROID;
1476    egl_connection_t* const cnx = &gEGLImpl;
1477    if (cnx->dso && cnx->egl.eglDupNativeFenceFDANDROID) {
1478        result = cnx->egl.eglDupNativeFenceFDANDROID(dp->disp.dpy, sync);
1479    }
1480    return result;
1481}
1482
1483EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface,
1484        EGLnsecsANDROID time)
1485{
1486    clearError();
1487
1488    const egl_display_ptr dp = validate_display(dpy);
1489    if (!dp) {
1490        return EGL_FALSE;
1491    }
1492
1493    SurfaceRef _s(dp.get(), surface);
1494    if (!_s.get()) {
1495        setError(EGL_BAD_SURFACE, EGL_FALSE);
1496        return EGL_FALSE;
1497    }
1498
1499    egl_surface_t const * const s = get_surface(surface);
1500    native_window_set_buffers_timestamp(s->win.get(), time);
1501
1502    return EGL_TRUE;
1503}
1504
1505// ----------------------------------------------------------------------------
1506// NVIDIA extensions
1507// ----------------------------------------------------------------------------
1508EGLuint64NV eglGetSystemTimeFrequencyNV()
1509{
1510    clearError();
1511
1512    if (egl_init_drivers() == EGL_FALSE) {
1513        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1514    }
1515
1516    EGLuint64NV ret = 0;
1517    egl_connection_t* const cnx = &gEGLImpl;
1518
1519    if (cnx->dso && cnx->egl.eglGetSystemTimeFrequencyNV) {
1520        return cnx->egl.eglGetSystemTimeFrequencyNV();
1521    }
1522
1523    return setErrorQuiet(EGL_BAD_DISPLAY, 0);
1524}
1525
1526EGLuint64NV eglGetSystemTimeNV()
1527{
1528    clearError();
1529
1530    if (egl_init_drivers() == EGL_FALSE) {
1531        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1532    }
1533
1534    EGLuint64NV ret = 0;
1535    egl_connection_t* const cnx = &gEGLImpl;
1536
1537    if (cnx->dso && cnx->egl.eglGetSystemTimeNV) {
1538        return cnx->egl.eglGetSystemTimeNV();
1539    }
1540
1541    return setErrorQuiet(EGL_BAD_DISPLAY, 0);
1542}
1543