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