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