• 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