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