OSDN Git Service

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