• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <ctype.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <dlfcn.h>
22 
23 #include <sys/ioctl.h>
24 
25 #if HAVE_ANDROID_OS
26 #include <linux/android_pmem.h>
27 #endif
28 
29 #include <EGL/egl.h>
30 #include <EGL/eglext.h>
31 #include <GLES/gl.h>
32 #include <GLES/glext.h>
33 
34 #include <cutils/log.h>
35 #include <cutils/atomic.h>
36 #include <cutils/properties.h>
37 #include <cutils/memory.h>
38 
39 #include <utils/SortedVector.h>
40 
41 #include "hooks.h"
42 #include "egl_impl.h"
43 #include "Loader.h"
44 
45 #define MAKE_CONFIG(_impl, _index)  ((EGLConfig)(((_impl)<<24) | (_index)))
46 #define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
47 
48 // ----------------------------------------------------------------------------
49 namespace android {
50 // ----------------------------------------------------------------------------
51 
52 #define VERSION_MAJOR 1
53 #define VERSION_MINOR 4
54 static char const * const gVendorString     = "Android";
55 static char const * const gVersionString    = "1.4 Android META-EGL";
56 static char const * const gClientApiString  = "OpenGL ES";
57 static char const * const gExtensionString  =
58         "EGL_KHR_image "
59         "EGL_KHR_image_base "
60         "EGL_KHR_image_pixmap "
61         "EGL_ANDROID_image_native_buffer "
62         "EGL_ANDROID_swap_rectangle "
63         "EGL_ANDROID_get_render_buffer "
64         ;
65 
66 // ----------------------------------------------------------------------------
67 
68 class egl_object_t {
69     static SortedVector<egl_object_t*> sObjects;
70     static Mutex sLock;
71 
72             volatile int32_t  terminated;
73     mutable volatile int32_t  count;
74 
75 public:
egl_object_t()76     egl_object_t() : terminated(0), count(1) {
77         Mutex::Autolock _l(sLock);
78         sObjects.add(this);
79     }
80 
isAlive() const81     inline bool isAlive() const { return !terminated; }
82 
83 private:
get()84     bool get() {
85         Mutex::Autolock _l(sLock);
86         if (egl_object_t::sObjects.indexOf(this) >= 0) {
87             android_atomic_inc(&count);
88             return true;
89         }
90         return false;
91     }
92 
put()93     bool put() {
94         Mutex::Autolock _l(sLock);
95         if (android_atomic_dec(&count) == 1) {
96             sObjects.remove(this);
97             return true;
98         }
99         return false;
100     }
101 
102 public:
103     template <typename N, typename T>
104     struct LocalRef {
105         N* ref;
LocalRefandroid::egl_object_t::LocalRef106         LocalRef(T o) : ref(0) {
107             N* native = reinterpret_cast<N*>(o);
108             if (o && native->get()) {
109                 ref = native;
110             }
111         }
~LocalRefandroid::egl_object_t::LocalRef112         ~LocalRef() {
113             if (ref && ref->put()) {
114                 delete ref;
115             }
116         }
getandroid::egl_object_t::LocalRef117         inline N* get() {
118             return ref;
119         }
acquireandroid::egl_object_t::LocalRef120         void acquire() const {
121             if (ref) {
122                 android_atomic_inc(&ref->count);
123             }
124         }
releaseandroid::egl_object_t::LocalRef125         void release() const {
126             if (ref) {
127                 int32_t c = android_atomic_dec(&ref->count);
128                 // ref->count cannot be 1 prior atomic_dec because we have
129                 // a reference, and if we have one, it means there was
130                 // already one before us.
131                 LOGE_IF(c==1, "refcount is now 0 in release()");
132             }
133         }
terminateandroid::egl_object_t::LocalRef134         void terminate() {
135             if (ref) {
136                 ref->terminated = 1;
137                 release();
138             }
139         }
140     };
141 };
142 
143 SortedVector<egl_object_t*> egl_object_t::sObjects;
144 Mutex egl_object_t::sLock;
145 
146 struct egl_display_t {
147     enum { NOT_INITIALIZED, INITIALIZED, TERMINATED };
148 
149     struct strings_t {
150         char const * vendor;
151         char const * version;
152         char const * clientApi;
153         char const * extensions;
154     };
155 
156     struct DisplayImpl {
DisplayImplandroid::egl_display_t::DisplayImpl157         DisplayImpl() : dpy(EGL_NO_DISPLAY), config(0),
158                         state(NOT_INITIALIZED), numConfigs(0) { }
159         EGLDisplay  dpy;
160         EGLConfig*  config;
161         EGLint      state;
162         EGLint      numConfigs;
163         strings_t   queryString;
164     };
165 
166     uint32_t    magic;
167     DisplayImpl disp[IMPL_NUM_IMPLEMENTATIONS];
168     EGLint      numTotalConfigs;
169     volatile int32_t refs;
170 
egl_display_tandroid::egl_display_t171     egl_display_t() : magic('_dpy'), numTotalConfigs(0) { }
~egl_display_tandroid::egl_display_t172     ~egl_display_t() { magic = 0; }
isValidandroid::egl_display_t173     inline bool isValid() const { return magic == '_dpy'; }
isAliveandroid::egl_display_t174     inline bool isAlive() const { return isValid(); }
175 };
176 
177 struct egl_surface_t : public egl_object_t
178 {
179     typedef egl_object_t::LocalRef<egl_surface_t, EGLSurface> Ref;
180 
egl_surface_tandroid::egl_surface_t181     egl_surface_t(EGLDisplay dpy, EGLSurface surface,
182             int impl, egl_connection_t const* cnx)
183     : dpy(dpy), surface(surface), impl(impl), cnx(cnx) {
184     }
~egl_surface_tandroid::egl_surface_t185     ~egl_surface_t() {
186     }
187     EGLDisplay                  dpy;
188     EGLSurface                  surface;
189     int                         impl;
190     egl_connection_t const*     cnx;
191 };
192 
193 struct egl_context_t : public egl_object_t
194 {
195     typedef egl_object_t::LocalRef<egl_context_t, EGLContext> Ref;
196 
egl_context_tandroid::egl_context_t197     egl_context_t(EGLDisplay dpy, EGLContext context,
198             int impl, egl_connection_t const* cnx, int version)
199     : dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx),
200       version(version)
201     {
202     }
203     EGLDisplay                  dpy;
204     EGLContext                  context;
205     EGLSurface                  read;
206     EGLSurface                  draw;
207     int                         impl;
208     egl_connection_t const*     cnx;
209     int                         version;
210 };
211 
212 struct egl_image_t : public egl_object_t
213 {
214     typedef egl_object_t::LocalRef<egl_image_t, EGLImageKHR> Ref;
215 
egl_image_tandroid::egl_image_t216     egl_image_t(EGLDisplay dpy, EGLContext context)
217         : dpy(dpy), context(context)
218     {
219         memset(images, 0, sizeof(images));
220     }
221     EGLDisplay dpy;
222     EGLConfig context;
223     EGLImageKHR images[IMPL_NUM_IMPLEMENTATIONS];
224 };
225 
226 typedef egl_surface_t::Ref  SurfaceRef;
227 typedef egl_context_t::Ref  ContextRef;
228 typedef egl_image_t::Ref    ImageRef;
229 
230 struct tls_t
231 {
tls_tandroid::tls_t232     tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE) { }
233     EGLint      error;
234     EGLContext  ctx;
235     EGLBoolean  logCallWithNoContext;
236 };
237 
238 
239 // ----------------------------------------------------------------------------
240 
241 egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
242 static egl_display_t gDisplay[NUM_DISPLAYS];
243 static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
244 static pthread_key_t gEGLThreadLocalStorageKey = -1;
245 
246 // ----------------------------------------------------------------------------
247 
248 EGLAPI gl_hooks_t gHooks[2][IMPL_NUM_IMPLEMENTATIONS];
249 EGLAPI gl_hooks_t gHooksNoContext;
250 EGLAPI pthread_key_t gGLWrapperKey = -1;
251 
252 // ----------------------------------------------------------------------------
253 
254 static __attribute__((noinline))
egl_strerror(EGLint err)255 const char *egl_strerror(EGLint err)
256 {
257     switch (err){
258         case EGL_SUCCESS:               return "EGL_SUCCESS";
259         case EGL_NOT_INITIALIZED:       return "EGL_NOT_INITIALIZED";
260         case EGL_BAD_ACCESS:            return "EGL_BAD_ACCESS";
261         case EGL_BAD_ALLOC:             return "EGL_BAD_ALLOC";
262         case EGL_BAD_ATTRIBUTE:         return "EGL_BAD_ATTRIBUTE";
263         case EGL_BAD_CONFIG:            return "EGL_BAD_CONFIG";
264         case EGL_BAD_CONTEXT:           return "EGL_BAD_CONTEXT";
265         case EGL_BAD_CURRENT_SURFACE:   return "EGL_BAD_CURRENT_SURFACE";
266         case EGL_BAD_DISPLAY:           return "EGL_BAD_DISPLAY";
267         case EGL_BAD_MATCH:             return "EGL_BAD_MATCH";
268         case EGL_BAD_NATIVE_PIXMAP:     return "EGL_BAD_NATIVE_PIXMAP";
269         case EGL_BAD_NATIVE_WINDOW:     return "EGL_BAD_NATIVE_WINDOW";
270         case EGL_BAD_PARAMETER:         return "EGL_BAD_PARAMETER";
271         case EGL_BAD_SURFACE:           return "EGL_BAD_SURFACE";
272         case EGL_CONTEXT_LOST:          return "EGL_CONTEXT_LOST";
273         default: return "UNKNOWN";
274     }
275 }
276 
277 static __attribute__((noinline))
clearTLS()278 void clearTLS() {
279     if (gEGLThreadLocalStorageKey != -1) {
280         tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
281         if (tls) {
282             delete tls;
283             pthread_setspecific(gEGLThreadLocalStorageKey, 0);
284         }
285     }
286 }
287 
getTLS()288 static tls_t* getTLS()
289 {
290     tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
291     if (tls == 0) {
292         tls = new tls_t;
293         pthread_setspecific(gEGLThreadLocalStorageKey, tls);
294     }
295     return tls;
296 }
297 
298 template<typename T>
299 static __attribute__((noinline))
setErrorEtc(const char * caller,int line,EGLint error,T returnValue)300 T setErrorEtc(const char* caller, int line, EGLint error, T returnValue) {
301     if (gEGLThreadLocalStorageKey == -1) {
302         pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
303         if (gEGLThreadLocalStorageKey == -1)
304             pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
305         pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
306     }
307     tls_t* tls = getTLS();
308     if (tls->error != error) {
309         LOGE("%s:%d error %x (%s)", caller, line, error, egl_strerror(error));
310         tls->error = error;
311     }
312     return returnValue;
313 }
314 
315 static __attribute__((noinline))
getError()316 GLint getError() {
317     if (gEGLThreadLocalStorageKey == -1)
318         return EGL_SUCCESS;
319     tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
320     if (!tls) return EGL_SUCCESS;
321     GLint error = tls->error;
322     tls->error = EGL_SUCCESS;
323     return error;
324 }
325 
326 static __attribute__((noinline))
setContext(EGLContext ctx)327 void setContext(EGLContext ctx) {
328     if (gEGLThreadLocalStorageKey == -1) {
329         pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
330         if (gEGLThreadLocalStorageKey == -1)
331             pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
332         pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
333     }
334     tls_t* tls = getTLS();
335     tls->ctx = ctx;
336 }
337 
338 static __attribute__((noinline))
getContext()339 EGLContext getContext() {
340     if (gEGLThreadLocalStorageKey == -1)
341         return EGL_NO_CONTEXT;
342     tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
343     if (!tls) return EGL_NO_CONTEXT;
344     return tls->ctx;
345 }
346 
347 /*****************************************************************************/
348 
349 template<typename T>
350 static __attribute__((noinline))
binarySearch(T const sortedArray[],int first,int last,T key)351 int binarySearch(
352         T const sortedArray[], int first, int last, T key)
353 {
354     while (first <= last) {
355         int mid = (first + last) / 2;
356         if (key > sortedArray[mid]) {
357             first = mid + 1;
358         } else if (key < sortedArray[mid]) {
359             last = mid - 1;
360         } else {
361             return mid;
362         }
363     }
364     return -1;
365 }
366 
configToUniqueId(egl_display_t const * dp,int i,int index)367 static EGLint configToUniqueId(egl_display_t const* dp, int i, int index)
368 {
369     // NOTE: this mapping works only if we have no more than two EGLimpl
370     return (i>0 ? dp->disp[0].numConfigs : 0) + index;
371 }
372 
uniqueIdToConfig(egl_display_t const * dp,EGLint configId,int & i,int & index)373 static void uniqueIdToConfig(egl_display_t const* dp, EGLint configId,
374         int& i, int& index)
375 {
376     // NOTE: this mapping works only if we have no more than two EGLimpl
377     size_t numConfigs = dp->disp[0].numConfigs;
378     i = configId / numConfigs;
379     index = configId % numConfigs;
380 }
381 
cmp_configs(const void * a,const void * b)382 static int cmp_configs(const void* a, const void *b)
383 {
384     EGLConfig c0 = *(EGLConfig const *)a;
385     EGLConfig c1 = *(EGLConfig const *)b;
386     return c0<c1 ? -1 : (c0>c1 ? 1 : 0);
387 }
388 
389 struct extention_map_t {
390     const char* name;
391     __eglMustCastToProperFunctionPointerType address;
392 };
393 
394 static const extention_map_t gExtentionMap[] = {
395     { "eglLockSurfaceKHR",
396             (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
397     { "eglUnlockSurfaceKHR",
398             (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
399     { "eglCreateImageKHR",
400             (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
401     { "eglDestroyImageKHR",
402             (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
403     { "eglSetSwapRectangleANDROID",
404             (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
405     { "eglGetRenderBufferANDROID",
406             (__eglMustCastToProperFunctionPointerType)&eglGetRenderBufferANDROID },
407 };
408 
409 static extention_map_t gGLExtentionMap[MAX_NUMBER_OF_GL_EXTENSIONS];
410 
findProcAddress(const char * name,const extention_map_t * map,size_t n)411 static void(*findProcAddress(const char* name,
412         const extention_map_t* map, size_t n))()
413 {
414     for (uint32_t i=0 ; i<n ; i++) {
415         if (!strcmp(name, map[i].name)) {
416             return map[i].address;
417         }
418     }
419     return NULL;
420 }
421 
422 // ----------------------------------------------------------------------------
423 
gl_no_context()424 static void gl_no_context() {
425     tls_t* tls = getTLS();
426     if (tls->logCallWithNoContext == EGL_TRUE) {
427         tls->logCallWithNoContext = EGL_FALSE;
428         LOGE("call to OpenGL ES API with no current context "
429              "(logged once per thread)");
430     }
431 }
432 
early_egl_init(void)433 static void early_egl_init(void)
434 {
435 #if !USE_FAST_TLS_KEY
436     pthread_key_create(&gGLWrapperKey, NULL);
437 #endif
438     uint32_t addr = (uint32_t)((void*)gl_no_context);
439     android_memset32(
440             (uint32_t*)(void*)&gHooksNoContext,
441             addr,
442             sizeof(gHooksNoContext));
443     setGlThreadSpecific(&gHooksNoContext);
444 }
445 
446 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
447 static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
448 
449 
450 static inline
get_display(EGLDisplay dpy)451 egl_display_t* get_display(EGLDisplay dpy)
452 {
453     uintptr_t index = uintptr_t(dpy)-1U;
454     return (index >= NUM_DISPLAYS) ? NULL : &gDisplay[index];
455 }
456 
457 template<typename NATIVE, typename EGL>
egl_to_native_cast(EGL arg)458 static inline NATIVE* egl_to_native_cast(EGL arg) {
459     return reinterpret_cast<NATIVE*>(arg);
460 }
461 
462 static inline
get_surface(EGLSurface surface)463 egl_surface_t* get_surface(EGLSurface surface) {
464     return egl_to_native_cast<egl_surface_t>(surface);
465 }
466 
467 static inline
get_context(EGLContext context)468 egl_context_t* get_context(EGLContext context) {
469     return egl_to_native_cast<egl_context_t>(context);
470 }
471 
472 static inline
get_image(EGLImageKHR image)473 egl_image_t* get_image(EGLImageKHR image) {
474     return egl_to_native_cast<egl_image_t>(image);
475 }
476 
validate_display_config(EGLDisplay dpy,EGLConfig config,egl_display_t const * & dp,int & impl,int & index)477 static egl_connection_t* validate_display_config(
478         EGLDisplay dpy, EGLConfig config,
479         egl_display_t const*& dp, int& impl, int& index)
480 {
481     dp = get_display(dpy);
482     if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
483 
484     impl = uintptr_t(config)>>24;
485     if (uint32_t(impl) >= IMPL_NUM_IMPLEMENTATIONS) {
486         return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
487     }
488     index = uintptr_t(config) & 0xFFFFFF;
489     if (index >= dp->disp[impl].numConfigs) {
490         return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
491     }
492     egl_connection_t* const cnx = &gEGLImpl[impl];
493     if (cnx->dso == 0) {
494         return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
495     }
496     return cnx;
497 }
498 
validate_display_context(EGLDisplay dpy,EGLContext ctx)499 static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
500 {
501     if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
502         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
503     if (!get_display(dpy)->isAlive())
504         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
505     if (!get_context(ctx)->isAlive())
506         return setError(EGL_BAD_CONTEXT, EGL_FALSE);
507     return EGL_TRUE;
508 }
509 
validate_display_surface(EGLDisplay dpy,EGLSurface surface)510 static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
511 {
512     if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
513         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
514     if (!get_display(dpy)->isAlive())
515         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
516     if (!get_surface(surface)->isAlive())
517         return setError(EGL_BAD_SURFACE, EGL_FALSE);
518     return EGL_TRUE;
519 }
520 
egl_get_image_for_current_context(EGLImageKHR image)521 EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image)
522 {
523     ImageRef _i(image);
524     if (!_i.get()) return EGL_NO_IMAGE_KHR;
525 
526     EGLContext context = getContext();
527     if (context == EGL_NO_CONTEXT || image == EGL_NO_IMAGE_KHR)
528         return EGL_NO_IMAGE_KHR;
529 
530     egl_context_t const * const c = get_context(context);
531     if (!c->isAlive())
532         return EGL_NO_IMAGE_KHR;
533 
534     egl_image_t const * const i = get_image(image);
535     return i->images[c->impl];
536 }
537 
538 // ----------------------------------------------------------------------------
539 
540 // this mutex protects:
541 //    d->disp[]
542 //    egl_init_drivers_locked()
543 //
544 static pthread_mutex_t gInitDriverMutex = PTHREAD_MUTEX_INITIALIZER;
545 
egl_init_drivers_locked()546 EGLBoolean egl_init_drivers_locked()
547 {
548     if (sEarlyInitState) {
549         // initialized by static ctor. should be set here.
550         return EGL_FALSE;
551     }
552 
553     // get our driver loader
554     Loader& loader(Loader::getInstance());
555 
556     // dynamically load all our EGL implementations for all displays
557     // and retrieve the corresponding EGLDisplay
558     // if that fails, don't use this driver.
559     // TODO: currently we only deal with EGL_DEFAULT_DISPLAY
560     egl_connection_t* cnx;
561     egl_display_t* d = &gDisplay[0];
562 
563     cnx = &gEGLImpl[IMPL_SOFTWARE];
564     if (cnx->dso == 0) {
565         cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_SOFTWARE];
566         cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_SOFTWARE];
567         cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 0, cnx);
568         if (cnx->dso) {
569             EGLDisplay dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
570             LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for software EGL!");
571             d->disp[IMPL_SOFTWARE].dpy = dpy;
572             if (dpy == EGL_NO_DISPLAY) {
573                 loader.close(cnx->dso);
574                 cnx->dso = NULL;
575             }
576         }
577     }
578 
579     cnx = &gEGLImpl[IMPL_HARDWARE];
580     if (cnx->dso == 0) {
581         char value[PROPERTY_VALUE_MAX];
582         property_get("debug.egl.hw", value, "1");
583         if (atoi(value) != 0) {
584             cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_HARDWARE];
585             cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_HARDWARE];
586             cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 1, cnx);
587             if (cnx->dso) {
588                 EGLDisplay dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
589                 LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for hardware EGL!");
590                 d->disp[IMPL_HARDWARE].dpy = dpy;
591                 if (dpy == EGL_NO_DISPLAY) {
592                     loader.close(cnx->dso);
593                     cnx->dso = NULL;
594                 }
595             }
596         } else {
597             LOGD("3D hardware acceleration is disabled");
598         }
599     }
600 
601     if (!gEGLImpl[IMPL_SOFTWARE].dso && !gEGLImpl[IMPL_HARDWARE].dso) {
602         return EGL_FALSE;
603     }
604 
605     return EGL_TRUE;
606 }
607 
egl_init_drivers()608 EGLBoolean egl_init_drivers()
609 {
610     EGLBoolean res;
611     pthread_mutex_lock(&gInitDriverMutex);
612     res = egl_init_drivers_locked();
613     pthread_mutex_unlock(&gInitDriverMutex);
614     return res;
615 }
616 
617 // ----------------------------------------------------------------------------
618 }; // namespace android
619 // ----------------------------------------------------------------------------
620 
621 using namespace android;
622 
eglGetDisplay(NativeDisplayType display)623 EGLDisplay eglGetDisplay(NativeDisplayType display)
624 {
625     uint32_t index = uint32_t(display);
626     if (index >= NUM_DISPLAYS) {
627         return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
628     }
629 
630     if (egl_init_drivers() == EGL_FALSE) {
631         return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
632     }
633 
634     EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
635     return dpy;
636 }
637 
638 // ----------------------------------------------------------------------------
639 // Initialization
640 // ----------------------------------------------------------------------------
641 
eglInitialize(EGLDisplay dpy,EGLint * major,EGLint * minor)642 EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
643 {
644     egl_display_t * const dp = get_display(dpy);
645     if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
646 
647     if (android_atomic_inc(&dp->refs) > 0) {
648         if (major != NULL) *major = VERSION_MAJOR;
649         if (minor != NULL) *minor = VERSION_MINOR;
650         return EGL_TRUE;
651     }
652 
653     setGlThreadSpecific(&gHooksNoContext);
654 
655     // initialize each EGL and
656     // build our own extension string first, based on the extension we know
657     // and the extension supported by our client implementation
658     for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
659         egl_connection_t* const cnx = &gEGLImpl[i];
660         cnx->major = -1;
661         cnx->minor = -1;
662         if (!cnx->dso)
663             continue;
664 
665 #if defined(ADRENO130)
666 #warning "Adreno-130 eglInitialize() workaround"
667         /*
668          * The ADRENO 130 driver returns a different EGLDisplay each time
669          * eglGetDisplay() is called, but also makes the EGLDisplay invalid
670          * after eglTerminate() has been called, so that eglInitialize()
671          * cannot be called again. Therefore, we need to make sure to call
672          * eglGetDisplay() before calling eglInitialize();
673          */
674         if (i == IMPL_HARDWARE) {
675             dp->disp[i].dpy =
676                 cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
677         }
678 #endif
679 
680 
681         EGLDisplay idpy = dp->disp[i].dpy;
682         if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) {
683             //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
684             //        i, idpy, cnx->major, cnx->minor, cnx);
685 
686             // display is now initialized
687             dp->disp[i].state = egl_display_t::INITIALIZED;
688 
689             // get the query-strings for this display for each implementation
690             dp->disp[i].queryString.vendor =
691                 cnx->egl.eglQueryString(idpy, EGL_VENDOR);
692             dp->disp[i].queryString.version =
693                 cnx->egl.eglQueryString(idpy, EGL_VERSION);
694             dp->disp[i].queryString.extensions =
695                     cnx->egl.eglQueryString(idpy, EGL_EXTENSIONS);
696             dp->disp[i].queryString.clientApi =
697                 cnx->egl.eglQueryString(idpy, EGL_CLIENT_APIS);
698 
699         } else {
700             LOGW("%d: eglInitialize(%p) failed (%s)", i, idpy,
701                     egl_strerror(cnx->egl.eglGetError()));
702         }
703     }
704 
705     EGLBoolean res = EGL_FALSE;
706     for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
707         egl_connection_t* const cnx = &gEGLImpl[i];
708         if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
709             EGLint n;
710             if (cnx->egl.eglGetConfigs(dp->disp[i].dpy, 0, 0, &n)) {
711                 dp->disp[i].config = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
712                 if (dp->disp[i].config) {
713                     if (cnx->egl.eglGetConfigs(
714                             dp->disp[i].dpy, dp->disp[i].config, n,
715                             &dp->disp[i].numConfigs))
716                     {
717                         // sort the configurations so we can do binary searches
718                         qsort(  dp->disp[i].config,
719                                 dp->disp[i].numConfigs,
720                                 sizeof(EGLConfig), cmp_configs);
721 
722                         dp->numTotalConfigs += n;
723                         res = EGL_TRUE;
724                     }
725                 }
726             }
727         }
728     }
729 
730     if (res == EGL_TRUE) {
731         if (major != NULL) *major = VERSION_MAJOR;
732         if (minor != NULL) *minor = VERSION_MINOR;
733         return EGL_TRUE;
734     }
735     return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
736 }
737 
eglTerminate(EGLDisplay dpy)738 EGLBoolean eglTerminate(EGLDisplay dpy)
739 {
740     // NOTE: don't unload the drivers b/c some APIs can be called
741     // after eglTerminate() has been called. eglTerminate() only
742     // terminates an EGLDisplay, not a EGL itself.
743 
744     egl_display_t* const dp = get_display(dpy);
745     if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
746     if (android_atomic_dec(&dp->refs) != 1)
747         return EGL_TRUE;
748 
749     EGLBoolean res = EGL_FALSE;
750     for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
751         egl_connection_t* const cnx = &gEGLImpl[i];
752         if (cnx->dso && dp->disp[i].state == egl_display_t::INITIALIZED) {
753             if (cnx->egl.eglTerminate(dp->disp[i].dpy) == EGL_FALSE) {
754                 LOGW("%d: eglTerminate(%p) failed (%s)", i, dp->disp[i].dpy,
755                         egl_strerror(cnx->egl.eglGetError()));
756             }
757             // REVISIT: it's unclear what to do if eglTerminate() fails
758             free(dp->disp[i].config);
759 
760             dp->disp[i].numConfigs = 0;
761             dp->disp[i].config = 0;
762             dp->disp[i].state = egl_display_t::TERMINATED;
763 
764             res = EGL_TRUE;
765         }
766     }
767 
768     // TODO: all egl_object_t should be marked for termination
769 
770     dp->numTotalConfigs = 0;
771     clearTLS();
772     return res;
773 }
774 
775 // ----------------------------------------------------------------------------
776 // configuration
777 // ----------------------------------------------------------------------------
778 
eglGetConfigs(EGLDisplay dpy,EGLConfig * configs,EGLint config_size,EGLint * num_config)779 EGLBoolean eglGetConfigs(   EGLDisplay dpy,
780                             EGLConfig *configs,
781                             EGLint config_size, EGLint *num_config)
782 {
783     egl_display_t const * const dp = get_display(dpy);
784     if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
785 
786     GLint numConfigs = dp->numTotalConfigs;
787     if (!configs) {
788         *num_config = numConfigs;
789         return EGL_TRUE;
790     }
791     GLint n = 0;
792     for (int j=0 ; j<IMPL_NUM_IMPLEMENTATIONS ; j++) {
793         for (int i=0 ; i<dp->disp[j].numConfigs && config_size ; i++) {
794             *configs++ = MAKE_CONFIG(j, i);
795             config_size--;
796             n++;
797         }
798     }
799 
800     *num_config = n;
801     return EGL_TRUE;
802 }
803 
eglChooseConfig(EGLDisplay dpy,const EGLint * attrib_list,EGLConfig * configs,EGLint config_size,EGLint * num_config)804 EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
805                             EGLConfig *configs, EGLint config_size,
806                             EGLint *num_config)
807 {
808     egl_display_t const * const dp = get_display(dpy);
809     if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
810 
811     if (num_config==0) {
812         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
813     }
814 
815     EGLint n;
816     EGLBoolean res = EGL_FALSE;
817     *num_config = 0;
818 
819 
820     // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
821     // to do  this, we have to go through the attrib_list array once
822     // to figure out both its size and if it contains an EGL_CONFIG_ID
823     // key. If so, the full array is copied and patched.
824     // NOTE: we assume that there can be only one occurrence
825     // of EGL_CONFIG_ID.
826 
827     EGLint patch_index = -1;
828     GLint attr;
829     size_t size = 0;
830     while ((attr=attrib_list[size]) != EGL_NONE) {
831         if (attr == EGL_CONFIG_ID)
832             patch_index = size;
833         size += 2;
834     }
835     if (patch_index >= 0) {
836         size += 2; // we need copy the sentinel as well
837         EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
838         if (new_list == 0)
839             return setError(EGL_BAD_ALLOC, EGL_FALSE);
840         memcpy(new_list, attrib_list, size*sizeof(EGLint));
841 
842         // patch the requested EGL_CONFIG_ID
843         int i, index;
844         EGLint& configId(new_list[patch_index+1]);
845         uniqueIdToConfig(dp, configId, i, index);
846 
847         egl_connection_t* const cnx = &gEGLImpl[i];
848         if (cnx->dso) {
849             cnx->egl.eglGetConfigAttrib(
850                     dp->disp[i].dpy, dp->disp[i].config[index],
851                     EGL_CONFIG_ID, &configId);
852 
853             // and switch to the new list
854             attrib_list = const_cast<const EGLint *>(new_list);
855 
856             // At this point, the only configuration that can match is
857             // dp->configs[i][index], however, we don't know if it would be
858             // rejected because of the other attributes, so we do have to call
859             // cnx->egl.eglChooseConfig() -- but we don't have to loop
860             // through all the EGLimpl[].
861             // We also know we can only get a single config back, and we know
862             // which one.
863 
864             res = cnx->egl.eglChooseConfig(
865                     dp->disp[i].dpy, attrib_list, configs, config_size, &n);
866             if (res && n>0) {
867                 // n has to be 0 or 1, by construction, and we already know
868                 // which config it will return (since there can be only one).
869                 if (configs) {
870                     configs[0] = MAKE_CONFIG(i, index);
871                 }
872                 *num_config = 1;
873             }
874         }
875 
876         free(const_cast<EGLint *>(attrib_list));
877         return res;
878     }
879 
880     for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
881         egl_connection_t* const cnx = &gEGLImpl[i];
882         if (cnx->dso) {
883             if (cnx->egl.eglChooseConfig(
884                     dp->disp[i].dpy, attrib_list, configs, config_size, &n)) {
885                 if (configs) {
886                     // now we need to convert these client EGLConfig to our
887                     // internal EGLConfig format. This is done in O(n log n).
888                     for (int j=0 ; j<n ; j++) {
889                         int index = binarySearch<EGLConfig>(
890                                 dp->disp[i].config, 0,
891                                 dp->disp[i].numConfigs-1, configs[j]);
892                         if (index >= 0) {
893                             if (configs) {
894                                 configs[j] = MAKE_CONFIG(i, index);
895                             }
896                         } else {
897                             return setError(EGL_BAD_CONFIG, EGL_FALSE);
898                         }
899                     }
900                     configs += n;
901                     config_size -= n;
902                 }
903                 *num_config += n;
904                 res = EGL_TRUE;
905             }
906         }
907     }
908     return res;
909 }
910 
eglGetConfigAttrib(EGLDisplay dpy,EGLConfig config,EGLint attribute,EGLint * value)911 EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
912         EGLint attribute, EGLint *value)
913 {
914     egl_display_t const* dp = 0;
915     int i=0, index=0;
916     egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
917     if (!cnx) return EGL_FALSE;
918 
919     if (attribute == EGL_CONFIG_ID) {
920         // EGL_CONFIG_IDs must be unique, just use the order of the selected
921         // EGLConfig.
922         *value = configToUniqueId(dp, i, index);
923         return EGL_TRUE;
924     }
925     return cnx->egl.eglGetConfigAttrib(
926             dp->disp[i].dpy, dp->disp[i].config[index], attribute, value);
927 }
928 
929 // ----------------------------------------------------------------------------
930 // surfaces
931 // ----------------------------------------------------------------------------
932 
eglCreateWindowSurface(EGLDisplay dpy,EGLConfig config,NativeWindowType window,const EGLint * attrib_list)933 EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
934                                     NativeWindowType window,
935                                     const EGLint *attrib_list)
936 {
937     egl_display_t const* dp = 0;
938     int i=0, index=0;
939     egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
940     if (cnx) {
941         EGLSurface surface = cnx->egl.eglCreateWindowSurface(
942                 dp->disp[i].dpy, dp->disp[i].config[index], window, attrib_list);
943         if (surface != EGL_NO_SURFACE) {
944             egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
945             return s;
946         }
947     }
948     return EGL_NO_SURFACE;
949 }
950 
eglCreatePixmapSurface(EGLDisplay dpy,EGLConfig config,NativePixmapType pixmap,const EGLint * attrib_list)951 EGLSurface eglCreatePixmapSurface(  EGLDisplay dpy, EGLConfig config,
952                                     NativePixmapType pixmap,
953                                     const EGLint *attrib_list)
954 {
955     egl_display_t const* dp = 0;
956     int i=0, index=0;
957     egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
958     if (cnx) {
959         EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
960                 dp->disp[i].dpy, dp->disp[i].config[index], pixmap, attrib_list);
961         if (surface != EGL_NO_SURFACE) {
962             egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
963             return s;
964         }
965     }
966     return EGL_NO_SURFACE;
967 }
968 
eglCreatePbufferSurface(EGLDisplay dpy,EGLConfig config,const EGLint * attrib_list)969 EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
970                                     const EGLint *attrib_list)
971 {
972     egl_display_t const* dp = 0;
973     int i=0, index=0;
974     egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
975     if (cnx) {
976         EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
977                 dp->disp[i].dpy, dp->disp[i].config[index], attrib_list);
978         if (surface != EGL_NO_SURFACE) {
979             egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
980             return s;
981         }
982     }
983     return EGL_NO_SURFACE;
984 }
985 
eglDestroySurface(EGLDisplay dpy,EGLSurface surface)986 EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
987 {
988     SurfaceRef _s(surface);
989     if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
990 
991     if (!validate_display_surface(dpy, surface))
992         return EGL_FALSE;
993     egl_display_t const * const dp = get_display(dpy);
994 
995     egl_surface_t * const s = get_surface(surface);
996     EGLBoolean result = s->cnx->egl.eglDestroySurface(
997             dp->disp[s->impl].dpy, s->surface);
998     if (result == EGL_TRUE) {
999         _s.terminate();
1000     }
1001     return result;
1002 }
1003 
eglQuerySurface(EGLDisplay dpy,EGLSurface surface,EGLint attribute,EGLint * value)1004 EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
1005                             EGLint attribute, EGLint *value)
1006 {
1007     SurfaceRef _s(surface);
1008     if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1009 
1010     if (!validate_display_surface(dpy, surface))
1011         return EGL_FALSE;
1012     egl_display_t const * const dp = get_display(dpy);
1013     egl_surface_t const * const s = get_surface(surface);
1014 
1015     return s->cnx->egl.eglQuerySurface(
1016             dp->disp[s->impl].dpy, s->surface, attribute, value);
1017 }
1018 
1019 // ----------------------------------------------------------------------------
1020 // contextes
1021 // ----------------------------------------------------------------------------
1022 
eglCreateContext(EGLDisplay dpy,EGLConfig config,EGLContext share_list,const EGLint * attrib_list)1023 EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
1024                             EGLContext share_list, const EGLint *attrib_list)
1025 {
1026     egl_display_t const* dp = 0;
1027     int i=0, index=0;
1028     egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1029     if (cnx) {
1030         EGLContext context = cnx->egl.eglCreateContext(
1031                 dp->disp[i].dpy, dp->disp[i].config[index],
1032                 share_list, attrib_list);
1033         if (context != EGL_NO_CONTEXT) {
1034             // figure out if it's a GLESv1 or GLESv2
1035             int version = 0;
1036             if (attrib_list) {
1037                 while (*attrib_list != EGL_NONE) {
1038                     GLint attr = *attrib_list++;
1039                     GLint value = *attrib_list++;
1040                     if (attr == EGL_CONTEXT_CLIENT_VERSION) {
1041                         if (value == 1) {
1042                             version = GLESv1_INDEX;
1043                         } else if (value == 2) {
1044                             version = GLESv2_INDEX;
1045                         }
1046                     }
1047                 };
1048             }
1049             egl_context_t* c = new egl_context_t(dpy, context, i, cnx, version);
1050             return c;
1051         }
1052     }
1053     return EGL_NO_CONTEXT;
1054 }
1055 
eglDestroyContext(EGLDisplay dpy,EGLContext ctx)1056 EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
1057 {
1058     ContextRef _c(ctx);
1059     if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1060 
1061     if (!validate_display_context(dpy, ctx))
1062         return EGL_FALSE;
1063     egl_display_t const * const dp = get_display(dpy);
1064     egl_context_t * const c = get_context(ctx);
1065     EGLBoolean result = c->cnx->egl.eglDestroyContext(
1066             dp->disp[c->impl].dpy, c->context);
1067     if (result == EGL_TRUE) {
1068         _c.terminate();
1069     }
1070     return result;
1071 }
1072 
eglMakeCurrent(EGLDisplay dpy,EGLSurface draw,EGLSurface read,EGLContext ctx)1073 EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
1074                             EGLSurface read, EGLContext ctx)
1075 {
1076     // get a reference to the object passed in
1077     ContextRef _c(ctx);
1078     SurfaceRef _d(draw);
1079     SurfaceRef _r(read);
1080 
1081     // validate the display and the context (if not EGL_NO_CONTEXT)
1082     egl_display_t const * const dp = get_display(dpy);
1083     if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1084     if ((ctx != EGL_NO_CONTEXT) && (!validate_display_context(dpy, ctx))) {
1085         // EGL_NO_CONTEXT is valid
1086         return EGL_FALSE;
1087     }
1088 
1089     // these are the underlying implementation's object
1090     EGLContext impl_ctx  = EGL_NO_CONTEXT;
1091     EGLSurface impl_draw = EGL_NO_SURFACE;
1092     EGLSurface impl_read = EGL_NO_SURFACE;
1093 
1094     // these are our objects structs passed in
1095     egl_context_t       * c = NULL;
1096     egl_surface_t const * d = NULL;
1097     egl_surface_t const * r = NULL;
1098 
1099     // these are the current objects structs
1100     egl_context_t * cur_c = get_context(getContext());
1101     egl_surface_t * cur_r = NULL;
1102     egl_surface_t * cur_d = NULL;
1103 
1104     if (ctx != EGL_NO_CONTEXT) {
1105         c = get_context(ctx);
1106         cur_r = get_surface(c->read);
1107         cur_d = get_surface(c->draw);
1108         impl_ctx = c->context;
1109     } else {
1110         // no context given, use the implementation of the current context
1111         if (cur_c == NULL) {
1112             // no current context
1113             if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
1114                 // calling eglMakeCurrent( ..., EGL_NO_CONTEXT, !=0, !=0);
1115                 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1116             }
1117             // not an error, there is just not current context.
1118             return EGL_TRUE;
1119         }
1120     }
1121 
1122     // retrieve the underlying implementation's draw EGLSurface
1123     if (draw != EGL_NO_SURFACE) {
1124         d = get_surface(draw);
1125         // make sure the EGLContext and EGLSurface passed in are for
1126         // the same driver
1127         if (c && d->impl != c->impl)
1128             return setError(EGL_BAD_MATCH, EGL_FALSE);
1129         impl_draw = d->surface;
1130     }
1131 
1132     // retrieve the underlying implementation's read EGLSurface
1133     if (read != EGL_NO_SURFACE) {
1134         r = get_surface(read);
1135         // make sure the EGLContext and EGLSurface passed in are for
1136         // the same driver
1137         if (c && r->impl != c->impl)
1138             return setError(EGL_BAD_MATCH, EGL_FALSE);
1139         impl_read = r->surface;
1140     }
1141 
1142     EGLBoolean result;
1143 
1144     if (c) {
1145         result = c->cnx->egl.eglMakeCurrent(
1146                 dp->disp[c->impl].dpy, impl_draw, impl_read, impl_ctx);
1147     } else {
1148         result = cur_c->cnx->egl.eglMakeCurrent(
1149                 dp->disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx);
1150     }
1151 
1152     if (result == EGL_TRUE) {
1153         // by construction, these are either 0 or valid (possibly terminated)
1154         // it should be impossible for these to be invalid
1155         ContextRef _cur_c(cur_c);
1156         SurfaceRef _cur_r(cur_r);
1157         SurfaceRef _cur_d(cur_d);
1158 
1159         // cur_c has to be valid here (but could be terminated)
1160         if (ctx != EGL_NO_CONTEXT) {
1161             setGlThreadSpecific(c->cnx->hooks[c->version]);
1162             setContext(ctx);
1163             _c.acquire();
1164         } else {
1165             setGlThreadSpecific(&gHooksNoContext);
1166             setContext(EGL_NO_CONTEXT);
1167         }
1168         _cur_c.release();
1169 
1170         _r.acquire();
1171         _cur_r.release();
1172         if (c) c->read = read;
1173 
1174         _d.acquire();
1175         _cur_d.release();
1176         if (c) c->draw = draw;
1177     }
1178     return result;
1179 }
1180 
1181 
eglQueryContext(EGLDisplay dpy,EGLContext ctx,EGLint attribute,EGLint * value)1182 EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1183                             EGLint attribute, EGLint *value)
1184 {
1185     ContextRef _c(ctx);
1186     if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1187 
1188     if (!validate_display_context(dpy, ctx))
1189         return EGL_FALSE;
1190 
1191     egl_display_t const * const dp = get_display(dpy);
1192     egl_context_t * const c = get_context(ctx);
1193 
1194     return c->cnx->egl.eglQueryContext(
1195             dp->disp[c->impl].dpy, c->context, attribute, value);
1196 }
1197 
eglGetCurrentContext(void)1198 EGLContext eglGetCurrentContext(void)
1199 {
1200     // could be called before eglInitialize(), but we wouldn't have a context
1201     // then, and this function would correctly return EGL_NO_CONTEXT.
1202 
1203     EGLContext ctx = getContext();
1204     return ctx;
1205 }
1206 
eglGetCurrentSurface(EGLint readdraw)1207 EGLSurface eglGetCurrentSurface(EGLint readdraw)
1208 {
1209     // could be called before eglInitialize(), but we wouldn't have a context
1210     // then, and this function would correctly return EGL_NO_SURFACE.
1211 
1212     EGLContext ctx = getContext();
1213     if (ctx) {
1214         egl_context_t const * const c = get_context(ctx);
1215         if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1216         switch (readdraw) {
1217             case EGL_READ: return c->read;
1218             case EGL_DRAW: return c->draw;
1219             default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1220         }
1221     }
1222     return EGL_NO_SURFACE;
1223 }
1224 
eglGetCurrentDisplay(void)1225 EGLDisplay eglGetCurrentDisplay(void)
1226 {
1227     // could be called before eglInitialize(), but we wouldn't have a context
1228     // then, and this function would correctly return EGL_NO_DISPLAY.
1229 
1230     EGLContext ctx = getContext();
1231     if (ctx) {
1232         egl_context_t const * const c = get_context(ctx);
1233         if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1234         return c->dpy;
1235     }
1236     return EGL_NO_DISPLAY;
1237 }
1238 
eglWaitGL(void)1239 EGLBoolean eglWaitGL(void)
1240 {
1241     // could be called before eglInitialize(), but we wouldn't have a context
1242     // then, and this function would return GL_TRUE, which isn't wrong.
1243 
1244     EGLBoolean res = EGL_TRUE;
1245     EGLContext ctx = getContext();
1246     if (ctx) {
1247         egl_context_t const * const c = get_context(ctx);
1248         if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1249         if (uint32_t(c->impl)>=2)
1250             return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1251         egl_connection_t* const cnx = &gEGLImpl[c->impl];
1252         if (!cnx->dso)
1253             return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1254         res = cnx->egl.eglWaitGL();
1255     }
1256     return res;
1257 }
1258 
eglWaitNative(EGLint engine)1259 EGLBoolean eglWaitNative(EGLint engine)
1260 {
1261     // could be called before eglInitialize(), but we wouldn't have a context
1262     // then, and this function would return GL_TRUE, which isn't wrong.
1263 
1264     EGLBoolean res = EGL_TRUE;
1265     EGLContext ctx = getContext();
1266     if (ctx) {
1267         egl_context_t const * const c = get_context(ctx);
1268         if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1269         if (uint32_t(c->impl)>=2)
1270             return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1271         egl_connection_t* const cnx = &gEGLImpl[c->impl];
1272         if (!cnx->dso)
1273             return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1274         res = cnx->egl.eglWaitNative(engine);
1275     }
1276     return res;
1277 }
1278 
eglGetError(void)1279 EGLint eglGetError(void)
1280 {
1281     EGLint result = EGL_SUCCESS;
1282     for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1283         EGLint err = EGL_SUCCESS;
1284         egl_connection_t* const cnx = &gEGLImpl[i];
1285         if (cnx->dso)
1286             err = cnx->egl.eglGetError();
1287         if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
1288             result = err;
1289     }
1290     if (result == EGL_SUCCESS)
1291         result = getError();
1292     return result;
1293 }
1294 
eglGetProcAddress(const char * procname)1295 __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
1296 {
1297     // eglGetProcAddress() could be the very first function called
1298     // in which case we must make sure we've initialized ourselves, this
1299     // happens the first time egl_get_display() is called.
1300 
1301     if (egl_init_drivers() == EGL_FALSE) {
1302         setError(EGL_BAD_PARAMETER, NULL);
1303         return  NULL;
1304     }
1305 
1306     __eglMustCastToProperFunctionPointerType addr;
1307     addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
1308     if (addr) return addr;
1309 
1310     return NULL; // TODO: finish implementation below
1311 
1312     addr = findProcAddress(procname, gGLExtentionMap, NELEM(gGLExtentionMap));
1313     if (addr) return addr;
1314 
1315     addr = 0;
1316     int slot = -1;
1317     for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1318         egl_connection_t* const cnx = &gEGLImpl[i];
1319         if (cnx->dso) {
1320             if (cnx->egl.eglGetProcAddress) {
1321                 addr = cnx->egl.eglGetProcAddress(procname);
1322                 if (addr) {
1323                     if (slot == -1) {
1324                         slot = 0; // XXX: find free slot
1325                         if (slot == -1) {
1326                             addr = 0;
1327                             break;
1328                         }
1329                     }
1330                     //cnx->hooks->ext.extensions[slot] = addr;
1331                 }
1332             }
1333         }
1334     }
1335 
1336     if (slot >= 0) {
1337         addr = 0; // XXX: address of stub 'slot'
1338         gGLExtentionMap[slot].name = strdup(procname);
1339         gGLExtentionMap[slot].address = addr;
1340     }
1341 
1342     return addr;
1343 
1344 
1345     /*
1346      *  TODO: For OpenGL ES extensions, we must generate a stub
1347      *  that looks like
1348      *      mov     r12, #0xFFFF0FFF
1349      *      ldr     r12, [r12, #-15]
1350      *      ldr     r12, [r12, #TLS_SLOT_OPENGL_API*4]
1351      *      mov     r12, [r12, #api_offset]
1352      *      ldrne   pc, r12
1353      *      mov     pc, #unsupported_extension
1354      *
1355      *  and write the address of the extension in *all*
1356      *  gl_hooks_t::gl_ext_t at offset "api_offset" from gl_hooks_t
1357      *
1358      */
1359 }
1360 
eglSwapBuffers(EGLDisplay dpy,EGLSurface draw)1361 EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1362 {
1363     SurfaceRef _s(draw);
1364     if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1365 
1366     if (!validate_display_surface(dpy, draw))
1367         return EGL_FALSE;
1368     egl_display_t const * const dp = get_display(dpy);
1369     egl_surface_t const * const s = get_surface(draw);
1370     return s->cnx->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface);
1371 }
1372 
eglCopyBuffers(EGLDisplay dpy,EGLSurface surface,NativePixmapType target)1373 EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
1374                             NativePixmapType target)
1375 {
1376     SurfaceRef _s(surface);
1377     if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1378 
1379     if (!validate_display_surface(dpy, surface))
1380         return EGL_FALSE;
1381     egl_display_t const * const dp = get_display(dpy);
1382     egl_surface_t const * const s = get_surface(surface);
1383     return s->cnx->egl.eglCopyBuffers(
1384             dp->disp[s->impl].dpy, s->surface, target);
1385 }
1386 
eglQueryString(EGLDisplay dpy,EGLint name)1387 const char* eglQueryString(EGLDisplay dpy, EGLint name)
1388 {
1389     egl_display_t const * const dp = get_display(dpy);
1390     switch (name) {
1391         case EGL_VENDOR:
1392             return gVendorString;
1393         case EGL_VERSION:
1394             return gVersionString;
1395         case EGL_EXTENSIONS:
1396             return gExtensionString;
1397         case EGL_CLIENT_APIS:
1398             return gClientApiString;
1399     }
1400     return setError(EGL_BAD_PARAMETER, (const char *)0);
1401 }
1402 
1403 
1404 // ----------------------------------------------------------------------------
1405 // EGL 1.1
1406 // ----------------------------------------------------------------------------
1407 
eglSurfaceAttrib(EGLDisplay dpy,EGLSurface surface,EGLint attribute,EGLint value)1408 EGLBoolean eglSurfaceAttrib(
1409         EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1410 {
1411     SurfaceRef _s(surface);
1412     if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1413 
1414     if (!validate_display_surface(dpy, surface))
1415         return EGL_FALSE;
1416     egl_display_t const * const dp = get_display(dpy);
1417     egl_surface_t const * const s = get_surface(surface);
1418     if (s->cnx->egl.eglSurfaceAttrib) {
1419         return s->cnx->egl.eglSurfaceAttrib(
1420                 dp->disp[s->impl].dpy, s->surface, attribute, value);
1421     }
1422     return setError(EGL_BAD_SURFACE, EGL_FALSE);
1423 }
1424 
eglBindTexImage(EGLDisplay dpy,EGLSurface surface,EGLint buffer)1425 EGLBoolean eglBindTexImage(
1426         EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1427 {
1428     SurfaceRef _s(surface);
1429     if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1430 
1431     if (!validate_display_surface(dpy, surface))
1432         return EGL_FALSE;
1433     egl_display_t const * const dp = get_display(dpy);
1434     egl_surface_t const * const s = get_surface(surface);
1435     if (s->cnx->egl.eglBindTexImage) {
1436         return s->cnx->egl.eglBindTexImage(
1437                 dp->disp[s->impl].dpy, s->surface, buffer);
1438     }
1439     return setError(EGL_BAD_SURFACE, EGL_FALSE);
1440 }
1441 
eglReleaseTexImage(EGLDisplay dpy,EGLSurface surface,EGLint buffer)1442 EGLBoolean eglReleaseTexImage(
1443         EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1444 {
1445     SurfaceRef _s(surface);
1446     if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1447 
1448     if (!validate_display_surface(dpy, surface))
1449         return EGL_FALSE;
1450     egl_display_t const * const dp = get_display(dpy);
1451     egl_surface_t const * const s = get_surface(surface);
1452     if (s->cnx->egl.eglReleaseTexImage) {
1453         return s->cnx->egl.eglReleaseTexImage(
1454                 dp->disp[s->impl].dpy, s->surface, buffer);
1455     }
1456     return setError(EGL_BAD_SURFACE, EGL_FALSE);
1457 }
1458 
eglSwapInterval(EGLDisplay dpy,EGLint interval)1459 EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1460 {
1461     egl_display_t * const dp = get_display(dpy);
1462     if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1463 
1464     EGLBoolean res = EGL_TRUE;
1465     for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1466         egl_connection_t* const cnx = &gEGLImpl[i];
1467         if (cnx->dso) {
1468             if (cnx->egl.eglSwapInterval) {
1469                 if (cnx->egl.eglSwapInterval(
1470                         dp->disp[i].dpy, interval) == EGL_FALSE) {
1471                     res = EGL_FALSE;
1472                 }
1473             }
1474         }
1475     }
1476     return res;
1477 }
1478 
1479 
1480 // ----------------------------------------------------------------------------
1481 // EGL 1.2
1482 // ----------------------------------------------------------------------------
1483 
eglWaitClient(void)1484 EGLBoolean eglWaitClient(void)
1485 {
1486     // could be called before eglInitialize(), but we wouldn't have a context
1487     // then, and this function would return GL_TRUE, which isn't wrong.
1488     EGLBoolean res = EGL_TRUE;
1489     EGLContext ctx = getContext();
1490     if (ctx) {
1491         egl_context_t const * const c = get_context(ctx);
1492         if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1493         if (uint32_t(c->impl)>=2)
1494             return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1495         egl_connection_t* const cnx = &gEGLImpl[c->impl];
1496         if (!cnx->dso)
1497             return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1498         if (cnx->egl.eglWaitClient) {
1499             res = cnx->egl.eglWaitClient();
1500         } else {
1501             res = cnx->egl.eglWaitGL();
1502         }
1503     }
1504     return res;
1505 }
1506 
eglBindAPI(EGLenum api)1507 EGLBoolean eglBindAPI(EGLenum api)
1508 {
1509     if (egl_init_drivers() == EGL_FALSE) {
1510         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1511     }
1512 
1513     // bind this API on all EGLs
1514     EGLBoolean res = EGL_TRUE;
1515     for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1516         egl_connection_t* const cnx = &gEGLImpl[i];
1517         if (cnx->dso) {
1518             if (cnx->egl.eglBindAPI) {
1519                 if (cnx->egl.eglBindAPI(api) == EGL_FALSE) {
1520                     res = EGL_FALSE;
1521                 }
1522             }
1523         }
1524     }
1525     return res;
1526 }
1527 
eglQueryAPI(void)1528 EGLenum eglQueryAPI(void)
1529 {
1530     if (egl_init_drivers() == EGL_FALSE) {
1531         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1532     }
1533 
1534     for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1535         egl_connection_t* const cnx = &gEGLImpl[i];
1536         if (cnx->dso) {
1537             if (cnx->egl.eglQueryAPI) {
1538                 // the first one we find is okay, because they all
1539                 // should be the same
1540                 return cnx->egl.eglQueryAPI();
1541             }
1542         }
1543     }
1544     // or, it can only be OpenGL ES
1545     return EGL_OPENGL_ES_API;
1546 }
1547 
eglReleaseThread(void)1548 EGLBoolean eglReleaseThread(void)
1549 {
1550     for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1551         egl_connection_t* const cnx = &gEGLImpl[i];
1552         if (cnx->dso) {
1553             if (cnx->egl.eglReleaseThread) {
1554                 cnx->egl.eglReleaseThread();
1555             }
1556         }
1557     }
1558     clearTLS();
1559     return EGL_TRUE;
1560 }
1561 
eglCreatePbufferFromClientBuffer(EGLDisplay dpy,EGLenum buftype,EGLClientBuffer buffer,EGLConfig config,const EGLint * attrib_list)1562 EGLSurface eglCreatePbufferFromClientBuffer(
1563           EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1564           EGLConfig config, const EGLint *attrib_list)
1565 {
1566     egl_display_t const* dp = 0;
1567     int i=0, index=0;
1568     egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1569     if (!cnx) return EGL_FALSE;
1570     if (cnx->egl.eglCreatePbufferFromClientBuffer) {
1571         return cnx->egl.eglCreatePbufferFromClientBuffer(
1572                 dp->disp[i].dpy, buftype, buffer,
1573                 dp->disp[i].config[index], attrib_list);
1574     }
1575     return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1576 }
1577 
1578 // ----------------------------------------------------------------------------
1579 // EGL_EGLEXT_VERSION 3
1580 // ----------------------------------------------------------------------------
1581 
eglLockSurfaceKHR(EGLDisplay dpy,EGLSurface surface,const EGLint * attrib_list)1582 EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1583         const EGLint *attrib_list)
1584 {
1585     SurfaceRef _s(surface);
1586     if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1587 
1588     if (!validate_display_surface(dpy, surface))
1589         return EGL_FALSE;
1590 
1591     egl_display_t const * const dp = get_display(dpy);
1592     egl_surface_t const * const s = get_surface(surface);
1593 
1594     if (s->cnx->egl.eglLockSurfaceKHR) {
1595         return s->cnx->egl.eglLockSurfaceKHR(
1596                 dp->disp[s->impl].dpy, s->surface, attrib_list);
1597     }
1598     return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1599 }
1600 
eglUnlockSurfaceKHR(EGLDisplay dpy,EGLSurface surface)1601 EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
1602 {
1603     SurfaceRef _s(surface);
1604     if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1605 
1606     if (!validate_display_surface(dpy, surface))
1607         return EGL_FALSE;
1608 
1609     egl_display_t const * const dp = get_display(dpy);
1610     egl_surface_t const * const s = get_surface(surface);
1611 
1612     if (s->cnx->egl.eglUnlockSurfaceKHR) {
1613         return s->cnx->egl.eglUnlockSurfaceKHR(
1614                 dp->disp[s->impl].dpy, s->surface);
1615     }
1616     return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1617 }
1618 
eglCreateImageKHR(EGLDisplay dpy,EGLContext ctx,EGLenum target,EGLClientBuffer buffer,const EGLint * attrib_list)1619 EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1620         EGLClientBuffer buffer, const EGLint *attrib_list)
1621 {
1622     if (ctx != EGL_NO_CONTEXT) {
1623         ContextRef _c(ctx);
1624         if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
1625         if (!validate_display_context(dpy, ctx))
1626             return EGL_NO_IMAGE_KHR;
1627         egl_display_t const * const dp = get_display(dpy);
1628         egl_context_t * const c = get_context(ctx);
1629         // since we have an EGLContext, we know which implementation to use
1630         EGLImageKHR image = c->cnx->egl.eglCreateImageKHR(
1631                 dp->disp[c->impl].dpy, c->context, target, buffer, attrib_list);
1632         if (image == EGL_NO_IMAGE_KHR)
1633             return image;
1634 
1635         egl_image_t* result = new egl_image_t(dpy, ctx);
1636         result->images[c->impl] = image;
1637         return (EGLImageKHR)result;
1638     } else {
1639         // EGL_NO_CONTEXT is a valid parameter
1640         egl_display_t const * const dp = get_display(dpy);
1641         if (dp == 0) {
1642             return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
1643         }
1644 
1645         /* Since we don't have a way to know which implementation to call,
1646          * we're calling all of them. If at least one of the implementation
1647          * succeeded, this is a success.
1648          */
1649 
1650         EGLint currentError = eglGetError();
1651 
1652         EGLImageKHR implImages[IMPL_NUM_IMPLEMENTATIONS];
1653         bool success = false;
1654         for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1655             egl_connection_t* const cnx = &gEGLImpl[i];
1656             implImages[i] = EGL_NO_IMAGE_KHR;
1657             if (cnx->dso) {
1658                 if (cnx->egl.eglCreateImageKHR) {
1659                     implImages[i] = cnx->egl.eglCreateImageKHR(
1660                             dp->disp[i].dpy, ctx, target, buffer, attrib_list);
1661                     if (implImages[i] != EGL_NO_IMAGE_KHR) {
1662                         success = true;
1663                     }
1664                 }
1665             }
1666         }
1667 
1668         if (!success) {
1669             // failure, if there was an error when we entered this function,
1670             // the error flag must not be updated.
1671             // Otherwise, the error is whatever happened in the implementation
1672             // that faulted.
1673             if (currentError != EGL_SUCCESS) {
1674                 setError(currentError, EGL_NO_IMAGE_KHR);
1675             }
1676             return EGL_NO_IMAGE_KHR;
1677         } else {
1678             // In case of success, we need to clear all error flags
1679             // (especially those caused by the implementation that didn't
1680             // succeed). TODO: we could avoid this if we knew this was
1681             // a "full" success (all implementation succeeded).
1682             eglGetError();
1683         }
1684 
1685         egl_image_t* result = new egl_image_t(dpy, ctx);
1686         memcpy(result->images, implImages, sizeof(implImages));
1687         return (EGLImageKHR)result;
1688     }
1689 }
1690 
eglDestroyImageKHR(EGLDisplay dpy,EGLImageKHR img)1691 EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1692 {
1693     egl_display_t const * const dp = get_display(dpy);
1694      if (dp == 0) {
1695          return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1696      }
1697 
1698      ImageRef _i(img);
1699      if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1700 
1701      egl_image_t* image = get_image(img);
1702      bool success = false;
1703      for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1704          egl_connection_t* const cnx = &gEGLImpl[i];
1705          if (image->images[i] != EGL_NO_IMAGE_KHR) {
1706              if (cnx->dso) {
1707                  if (cnx->egl.eglCreateImageKHR) {
1708                      if (cnx->egl.eglDestroyImageKHR(
1709                              dp->disp[i].dpy, image->images[i])) {
1710                          success = true;
1711                      }
1712                  }
1713              }
1714          }
1715      }
1716      if (!success)
1717          return EGL_FALSE;
1718 
1719      _i.terminate();
1720 
1721      return EGL_TRUE;
1722 }
1723 
1724 
1725 // ----------------------------------------------------------------------------
1726 // ANDROID extensions
1727 // ----------------------------------------------------------------------------
1728 
eglSetSwapRectangleANDROID(EGLDisplay dpy,EGLSurface draw,EGLint left,EGLint top,EGLint width,EGLint height)1729 EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
1730         EGLint left, EGLint top, EGLint width, EGLint height)
1731 {
1732     SurfaceRef _s(draw);
1733     if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1734 
1735     if (!validate_display_surface(dpy, draw))
1736         return EGL_FALSE;
1737     egl_display_t const * const dp = get_display(dpy);
1738     egl_surface_t const * const s = get_surface(draw);
1739     if (s->cnx->egl.eglSetSwapRectangleANDROID) {
1740         return s->cnx->egl.eglSetSwapRectangleANDROID(
1741                 dp->disp[s->impl].dpy, s->surface, left, top, width, height);
1742     }
1743     return setError(EGL_BAD_DISPLAY, NULL);
1744 }
1745 
eglGetRenderBufferANDROID(EGLDisplay dpy,EGLSurface draw)1746 EGLClientBuffer eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw)
1747 {
1748     SurfaceRef _s(draw);
1749     if (!_s.get()) return setError(EGL_BAD_SURFACE, (EGLClientBuffer*)0);
1750 
1751     if (!validate_display_surface(dpy, draw))
1752         return 0;
1753     egl_display_t const * const dp = get_display(dpy);
1754     egl_surface_t const * const s = get_surface(draw);
1755     if (s->cnx->egl.eglGetRenderBufferANDROID) {
1756         return s->cnx->egl.eglGetRenderBufferANDROID(
1757                 dp->disp[s->impl].dpy, s->surface);
1758     }
1759     return setError(EGL_BAD_DISPLAY, (EGLClientBuffer*)0);
1760 }
1761