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