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