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