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