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