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