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