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