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