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