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