OSDN Git Service

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