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 #define ATRACE_TAG ATRACE_TAG_GRAPHICS 18 19 #include <dlfcn.h> 20 #include <ctype.h> 21 #include <stdlib.h> 22 #include <string.h> 23 24 #include <hardware/gralloc.h> 25 #include <system/window.h> 26 27 #include <EGL/egl.h> 28 #include <EGL/eglext.h> 29 30 #include <cutils/log.h> 31 #include <cutils/atomic.h> 32 #include <cutils/compiler.h> 33 #include <cutils/properties.h> 34 #include <cutils/memory.h> 35 36 #include <utils/KeyedVector.h> 37 #include <utils/SortedVector.h> 38 #include <utils/String8.h> 39 #include <utils/Trace.h> 40 41 #include "../egl_impl.h" 42 #include "../glestrace.h" 43 #include "../hooks.h" 44 45 #include "egl_display.h" 46 #include "egl_object.h" 47 #include "egl_tls.h" 48 #include "egldefs.h" 49 50 using namespace android; 51 52 // ---------------------------------------------------------------------------- 53 54 namespace android { 55 56 struct extention_map_t { 57 const char* name; 58 __eglMustCastToProperFunctionPointerType address; 59 }; 60 61 /* 62 * This is the list of EGL extensions exposed to applications, 63 * some of them are mandatory because used by the ANDROID system. 64 * 65 * Mandatory extensions are required per the CDD and not explicitly 66 * checked during EGL initialization. the system *assumes* these extensions 67 * are present. the system may not function properly if some mandatory 68 * extensions are missing. 69 * 70 * NOTE: gExtensionString MUST have a single space as the last character. 71 */ 72 extern char const * const gExtensionString = 73 "EGL_KHR_image " // mandatory 74 "EGL_KHR_image_base " // mandatory 75 "EGL_KHR_image_pixmap " 76 "EGL_KHR_lock_surface " 77 "EGL_KHR_gl_texture_2D_image " 78 "EGL_KHR_gl_texture_cubemap_image " 79 "EGL_KHR_gl_renderbuffer_image " 80 "EGL_KHR_reusable_sync " 81 "EGL_KHR_fence_sync " 82 "EGL_KHR_create_context " 83 "EGL_EXT_create_context_robustness " 84 "EGL_NV_system_time " 85 "EGL_ANDROID_image_native_buffer " // mandatory 86 "EGL_KHR_wait_sync " // strongly recommended 87 "EGL_ANDROID_presentation_time " 88 ; 89 90 // extensions not exposed to applications but used by the ANDROID system 91 // "EGL_ANDROID_blob_cache " // strongly recommended 92 // "EGL_IMG_hibernate_process " // optional 93 // "EGL_ANDROID_native_fence_sync " // strongly recommended 94 // "EGL_ANDROID_framebuffer_target " // mandatory for HWC 1.1 95 // "EGL_ANDROID_recordable " // mandatory 96 97 98 /* 99 * EGL Extensions entry-points exposed to 3rd party applications 100 * (keep in sync with gExtensionString above) 101 * 102 */ 103 static const extention_map_t sExtensionMap[] = { 104 // EGL_KHR_lock_surface 105 { "eglLockSurfaceKHR", 106 (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR }, 107 { "eglUnlockSurfaceKHR", 108 (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR }, 109 110 // EGL_KHR_image, EGL_KHR_image_base 111 { "eglCreateImageKHR", 112 (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR }, 113 { "eglDestroyImageKHR", 114 (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR }, 115 116 // EGL_KHR_reusable_sync, EGL_KHR_fence_sync 117 { "eglCreateSyncKHR", 118 (__eglMustCastToProperFunctionPointerType)&eglCreateSyncKHR }, 119 { "eglDestroySyncKHR", 120 (__eglMustCastToProperFunctionPointerType)&eglDestroySyncKHR }, 121 { "eglClientWaitSyncKHR", 122 (__eglMustCastToProperFunctionPointerType)&eglClientWaitSyncKHR }, 123 { "eglSignalSyncKHR", 124 (__eglMustCastToProperFunctionPointerType)&eglSignalSyncKHR }, 125 { "eglGetSyncAttribKHR", 126 (__eglMustCastToProperFunctionPointerType)&eglGetSyncAttribKHR }, 127 128 // EGL_NV_system_time 129 { "eglGetSystemTimeFrequencyNV", 130 (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeFrequencyNV }, 131 { "eglGetSystemTimeNV", 132 (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeNV }, 133 134 // EGL_KHR_wait_sync 135 { "eglWaitSyncKHR", 136 (__eglMustCastToProperFunctionPointerType)&eglWaitSyncKHR }, 137 138 // EGL_ANDROID_presentation_time 139 { "eglPresentationTimeANDROID", 140 (__eglMustCastToProperFunctionPointerType)&eglPresentationTimeANDROID }, 141 }; 142 143 /* 144 * These extensions entry-points should not be exposed to applications. 145 * They're used internally by the Android EGL layer. 146 */ 147 #define FILTER_EXTENSIONS(procname) \ 148 (!strcmp((procname), "eglSetBlobCacheFuncsANDROID") || \ 149 !strcmp((procname), "eglHibernateProcessIMG") || \ 150 !strcmp((procname), "eglAwakenProcessIMG") || \ 151 !strcmp((procname), "eglDupNativeFenceFDANDROID")) 152 153 154 155 // accesses protected by sExtensionMapMutex 156 static DefaultKeyedVector<String8, __eglMustCastToProperFunctionPointerType> sGLExtentionMap; 157 static int sGLExtentionSlot = 0; 158 static pthread_mutex_t sExtensionMapMutex = PTHREAD_MUTEX_INITIALIZER; 159 160 static void(*findProcAddress(const char* name, 161 const extention_map_t* map, size_t n))() { 162 for (uint32_t i=0 ; i<n ; i++) { 163 if (!strcmp(name, map[i].name)) { 164 return map[i].address; 165 } 166 } 167 return NULL; 168 } 169 170 // ---------------------------------------------------------------------------- 171 172 extern void setGLHooksThreadSpecific(gl_hooks_t const *value); 173 extern EGLBoolean egl_init_drivers(); 174 extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS]; 175 extern int getEGLDebugLevel(); 176 extern void setEGLDebugLevel(int level); 177 extern gl_hooks_t gHooksTrace; 178 179 } // namespace android; 180 181 182 // ---------------------------------------------------------------------------- 183 184 static inline void clearError() { egl_tls_t::clearError(); } 185 static inline EGLContext getContext() { return egl_tls_t::getContext(); } 186 187 // ---------------------------------------------------------------------------- 188 189 EGLDisplay eglGetDisplay(EGLNativeDisplayType display) 190 { 191 clearError(); 192 193 uint32_t index = uint32_t(display); 194 if (index >= NUM_DISPLAYS) { 195 return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); 196 } 197 198 if (egl_init_drivers() == EGL_FALSE) { 199 return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); 200 } 201 202 EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display); 203 return dpy; 204 } 205 206 // ---------------------------------------------------------------------------- 207 // Initialization 208 // ---------------------------------------------------------------------------- 209 210 EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) 211 { 212 clearError(); 213 214 egl_display_ptr dp = get_display(dpy); 215 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE); 216 217 EGLBoolean res = dp->initialize(major, minor); 218 219 return res; 220 } 221 222 EGLBoolean eglTerminate(EGLDisplay dpy) 223 { 224 // NOTE: don't unload the drivers b/c some APIs can be called 225 // after eglTerminate() has been called. eglTerminate() only 226 // terminates an EGLDisplay, not a EGL itself. 227 228 clearError(); 229 230 egl_display_ptr dp = get_display(dpy); 231 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE); 232 233 EGLBoolean res = dp->terminate(); 234 235 return res; 236 } 237 238 // ---------------------------------------------------------------------------- 239 // configuration 240 // ---------------------------------------------------------------------------- 241 242 EGLBoolean eglGetConfigs( EGLDisplay dpy, 243 EGLConfig *configs, 244 EGLint config_size, EGLint *num_config) 245 { 246 clearError(); 247 248 const egl_display_ptr dp = validate_display(dpy); 249 if (!dp) return EGL_FALSE; 250 251 if (num_config==0) { 252 return setError(EGL_BAD_PARAMETER, EGL_FALSE); 253 } 254 255 EGLBoolean res = EGL_FALSE; 256 *num_config = 0; 257 258 egl_connection_t* const cnx = &gEGLImpl; 259 if (cnx->dso) { 260 res = cnx->egl.eglGetConfigs( 261 dp->disp.dpy, configs, config_size, num_config); 262 } 263 264 return res; 265 } 266 267 EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, 268 EGLConfig *configs, EGLint config_size, 269 EGLint *num_config) 270 { 271 clearError(); 272 273 const egl_display_ptr dp = validate_display(dpy); 274 if (!dp) return EGL_FALSE; 275 276 if (num_config==0) { 277 return setError(EGL_BAD_PARAMETER, EGL_FALSE); 278 } 279 280 EGLBoolean res = EGL_FALSE; 281 *num_config = 0; 282 283 egl_connection_t* const cnx = &gEGLImpl; 284 if (cnx->dso) { 285 if (attrib_list) { 286 char value[PROPERTY_VALUE_MAX]; 287 property_get("debug.egl.force_msaa", value, "false"); 288 289 if (!strcmp(value, "true")) { 290 size_t attribCount = 0; 291 EGLint attrib = attrib_list[0]; 292 293 // Only enable MSAA if the context is OpenGL ES 2.0 and 294 // if no caveat is requested 295 const EGLint *attribRendererable = NULL; 296 const EGLint *attribCaveat = NULL; 297 298 // Count the number of attributes and look for 299 // EGL_RENDERABLE_TYPE and EGL_CONFIG_CAVEAT 300 while (attrib != EGL_NONE) { 301 attrib = attrib_list[attribCount]; 302 switch (attrib) { 303 case EGL_RENDERABLE_TYPE: 304 attribRendererable = &attrib_list[attribCount]; 305 break; 306 case EGL_CONFIG_CAVEAT: 307 attribCaveat = &attrib_list[attribCount]; 308 break; 309 } 310 attribCount++; 311 } 312 313 if (attribRendererable && attribRendererable[1] == EGL_OPENGL_ES2_BIT && 314 (!attribCaveat || attribCaveat[1] != EGL_NONE)) { 315 316 // Insert 2 extra attributes to force-enable MSAA 4x 317 EGLint aaAttribs[attribCount + 4]; 318 aaAttribs[0] = EGL_SAMPLE_BUFFERS; 319 aaAttribs[1] = 1; 320 aaAttribs[2] = EGL_SAMPLES; 321 aaAttribs[3] = 4; 322 323 memcpy(&aaAttribs[4], attrib_list, attribCount * sizeof(EGLint)); 324 325 EGLint numConfigAA; 326 EGLBoolean resAA = cnx->egl.eglChooseConfig( 327 dp->disp.dpy, aaAttribs, configs, config_size, &numConfigAA); 328 329 if (resAA == EGL_TRUE && numConfigAA > 0) { 330 ALOGD("Enabling MSAA 4x"); 331 *num_config = numConfigAA; 332 return resAA; 333 } 334 } 335 } 336 } 337 338 res = cnx->egl.eglChooseConfig( 339 dp->disp.dpy, attrib_list, configs, config_size, num_config); 340 } 341 return res; 342 } 343 344 EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, 345 EGLint attribute, EGLint *value) 346 { 347 clearError(); 348 349 egl_connection_t* cnx = NULL; 350 const egl_display_ptr dp = validate_display_connection(dpy, cnx); 351 if (!dp) return EGL_FALSE; 352 353 return cnx->egl.eglGetConfigAttrib( 354 dp->disp.dpy, config, attribute, value); 355 } 356 357 // ---------------------------------------------------------------------------- 358 // surfaces 359 // ---------------------------------------------------------------------------- 360 361 EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, 362 NativeWindowType window, 363 const EGLint *attrib_list) 364 { 365 clearError(); 366 367 egl_connection_t* cnx = NULL; 368 egl_display_ptr dp = validate_display_connection(dpy, cnx); 369 if (dp) { 370 EGLDisplay iDpy = dp->disp.dpy; 371 EGLint format; 372 373 if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) != OK) { 374 ALOGE("EGLNativeWindowType %p already connected to another API", 375 window); 376 return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); 377 } 378 379 // set the native window's buffers format to match this config 380 if (cnx->egl.eglGetConfigAttrib(iDpy, 381 config, EGL_NATIVE_VISUAL_ID, &format)) { 382 if (format != 0) { 383 int err = native_window_set_buffers_format(window, format); 384 if (err != 0) { 385 ALOGE("error setting native window pixel format: %s (%d)", 386 strerror(-err), err); 387 native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); 388 return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); 389 } 390 } 391 } 392 393 // the EGL spec requires that a new EGLSurface default to swap interval 394 // 1, so explicitly set that on the window here. 395 ANativeWindow* anw = reinterpret_cast<ANativeWindow*>(window); 396 anw->setSwapInterval(anw, 1); 397 398 EGLSurface surface = cnx->egl.eglCreateWindowSurface( 399 iDpy, config, window, attrib_list); 400 if (surface != EGL_NO_SURFACE) { 401 egl_surface_t* s = new egl_surface_t(dp.get(), config, window, 402 surface, cnx); 403 return s; 404 } 405 406 // EGLSurface creation failed 407 native_window_set_buffers_format(window, 0); 408 native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); 409 } 410 return EGL_NO_SURFACE; 411 } 412 413 EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, 414 NativePixmapType pixmap, 415 const EGLint *attrib_list) 416 { 417 clearError(); 418 419 egl_connection_t* cnx = NULL; 420 egl_display_ptr dp = validate_display_connection(dpy, cnx); 421 if (dp) { 422 EGLSurface surface = cnx->egl.eglCreatePixmapSurface( 423 dp->disp.dpy, config, pixmap, attrib_list); 424 if (surface != EGL_NO_SURFACE) { 425 egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, 426 surface, cnx); 427 return s; 428 } 429 } 430 return EGL_NO_SURFACE; 431 } 432 433 EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, 434 const EGLint *attrib_list) 435 { 436 clearError(); 437 438 egl_connection_t* cnx = NULL; 439 egl_display_ptr dp = validate_display_connection(dpy, cnx); 440 if (dp) { 441 EGLSurface surface = cnx->egl.eglCreatePbufferSurface( 442 dp->disp.dpy, config, attrib_list); 443 if (surface != EGL_NO_SURFACE) { 444 egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, 445 surface, cnx); 446 return s; 447 } 448 } 449 return EGL_NO_SURFACE; 450 } 451 452 EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) 453 { 454 clearError(); 455 456 const egl_display_ptr dp = validate_display(dpy); 457 if (!dp) return EGL_FALSE; 458 459 SurfaceRef _s(dp.get(), surface); 460 if (!_s.get()) 461 return setError(EGL_BAD_SURFACE, EGL_FALSE); 462 463 egl_surface_t * const s = get_surface(surface); 464 EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface); 465 if (result == EGL_TRUE) { 466 _s.terminate(); 467 } 468 return result; 469 } 470 471 EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface, 472 EGLint attribute, EGLint *value) 473 { 474 clearError(); 475 476 const egl_display_ptr dp = validate_display(dpy); 477 if (!dp) return EGL_FALSE; 478 479 SurfaceRef _s(dp.get(), surface); 480 if (!_s.get()) 481 return setError(EGL_BAD_SURFACE, EGL_FALSE); 482 483 egl_surface_t const * const s = get_surface(surface); 484 return s->cnx->egl.eglQuerySurface( 485 dp->disp.dpy, s->surface, attribute, value); 486 } 487 488 void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) { 489 ATRACE_CALL(); 490 clearError(); 491 492 const egl_display_ptr dp = validate_display(dpy); 493 if (!dp) { 494 return; 495 } 496 497 SurfaceRef _s(dp.get(), surface); 498 if (!_s.get()) { 499 setError(EGL_BAD_SURFACE, EGL_FALSE); 500 return; 501 } 502 503 int64_t timestamp = systemTime(SYSTEM_TIME_MONOTONIC); 504 505 egl_surface_t const * const s = get_surface(surface); 506 native_window_set_buffers_timestamp(s->win.get(), timestamp); 507 } 508 509 // ---------------------------------------------------------------------------- 510 // Contexts 511 // ---------------------------------------------------------------------------- 512 513 EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, 514 EGLContext share_list, const EGLint *attrib_list) 515 { 516 clearError(); 517 518 egl_connection_t* cnx = NULL; 519 const egl_display_ptr dp = validate_display_connection(dpy, cnx); 520 if (dpy) { 521 if (share_list != EGL_NO_CONTEXT) { 522 egl_context_t* const c = get_context(share_list); 523 share_list = c->context; 524 } 525 EGLContext context = cnx->egl.eglCreateContext( 526 dp->disp.dpy, config, share_list, attrib_list); 527 if (context != EGL_NO_CONTEXT) { 528 // figure out if it's a GLESv1 or GLESv2 529 int version = 0; 530 if (attrib_list) { 531 while (*attrib_list != EGL_NONE) { 532 GLint attr = *attrib_list++; 533 GLint value = *attrib_list++; 534 if (attr == EGL_CONTEXT_CLIENT_VERSION) { 535 if (value == 1) { 536 version = egl_connection_t::GLESv1_INDEX; 537 } else if (value == 2 || value == 3) { 538 version = egl_connection_t::GLESv2_INDEX; 539 } 540 } 541 }; 542 } 543 egl_context_t* c = new egl_context_t(dpy, context, config, cnx, 544 version); 545 #if EGL_TRACE 546 if (getEGLDebugLevel() > 0) 547 GLTrace_eglCreateContext(version, c); 548 #endif 549 return c; 550 } else { 551 EGLint error = eglGetError(); 552 ALOGE_IF(error == EGL_SUCCESS, 553 "eglCreateContext(%p, %p, %p, %p) returned EGL_NO_CONTEXT " 554 "but no EGL error!", 555 dpy, config, share_list, attrib_list); 556 } 557 } 558 return EGL_NO_CONTEXT; 559 } 560 561 EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) 562 { 563 clearError(); 564 565 const egl_display_ptr dp = validate_display(dpy); 566 if (!dp) 567 return EGL_FALSE; 568 569 ContextRef _c(dp.get(), ctx); 570 if (!_c.get()) 571 return setError(EGL_BAD_CONTEXT, EGL_FALSE); 572 573 egl_context_t * const c = get_context(ctx); 574 EGLBoolean result = c->cnx->egl.eglDestroyContext(dp->disp.dpy, c->context); 575 if (result == EGL_TRUE) { 576 _c.terminate(); 577 } 578 return result; 579 } 580 581 EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, 582 EGLSurface read, EGLContext ctx) 583 { 584 clearError(); 585 586 egl_display_ptr dp = validate_display(dpy); 587 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE); 588 589 // If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not 590 // EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is 591 // a valid but uninitialized display. 592 if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) || 593 (draw != EGL_NO_SURFACE) ) { 594 if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, EGL_FALSE); 595 } 596 597 // get a reference to the object passed in 598 ContextRef _c(dp.get(), ctx); 599 SurfaceRef _d(dp.get(), draw); 600 SurfaceRef _r(dp.get(), read); 601 602 // validate the context (if not EGL_NO_CONTEXT) 603 if ((ctx != EGL_NO_CONTEXT) && !_c.get()) { 604 // EGL_NO_CONTEXT is valid 605 return EGL_FALSE; 606 } 607 608 // these are the underlying implementation's object 609 EGLContext impl_ctx = EGL_NO_CONTEXT; 610 EGLSurface impl_draw = EGL_NO_SURFACE; 611 EGLSurface impl_read = EGL_NO_SURFACE; 612 613 // these are our objects structs passed in 614 egl_context_t * c = NULL; 615 egl_surface_t const * d = NULL; 616 egl_surface_t const * r = NULL; 617 618 // these are the current objects structs 619 egl_context_t * cur_c = get_context(getContext()); 620 621 if (ctx != EGL_NO_CONTEXT) { 622 c = get_context(ctx); 623 impl_ctx = c->context; 624 } else { 625 // no context given, use the implementation of the current context 626 if (cur_c == NULL) { 627 // no current context 628 if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) { 629 // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT); 630 return setError(EGL_BAD_MATCH, EGL_FALSE); 631 } 632 // not an error, there is just no current context. 633 return EGL_TRUE; 634 } 635 } 636 637 // retrieve the underlying implementation's draw EGLSurface 638 if (draw != EGL_NO_SURFACE) { 639 d = get_surface(draw); 640 impl_draw = d->surface; 641 } 642 643 // retrieve the underlying implementation's read EGLSurface 644 if (read != EGL_NO_SURFACE) { 645 r = get_surface(read); 646 impl_read = r->surface; 647 } 648 649 650 EGLBoolean result = dp->makeCurrent(c, cur_c, 651 draw, read, ctx, 652 impl_draw, impl_read, impl_ctx); 653 654 if (result == EGL_TRUE) { 655 if (c) { 656 setGLHooksThreadSpecific(c->cnx->hooks[c->version]); 657 egl_tls_t::setContext(ctx); 658 #if EGL_TRACE 659 if (getEGLDebugLevel() > 0) 660 GLTrace_eglMakeCurrent(c->version, c->cnx->hooks[c->version], ctx); 661 #endif 662 _c.acquire(); 663 _r.acquire(); 664 _d.acquire(); 665 } else { 666 setGLHooksThreadSpecific(&gHooksNoContext); 667 egl_tls_t::setContext(EGL_NO_CONTEXT); 668 } 669 } else { 670 // this will ALOGE the error 671 result = setError(c->cnx->egl.eglGetError(), EGL_FALSE); 672 } 673 return result; 674 } 675 676 677 EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx, 678 EGLint attribute, EGLint *value) 679 { 680 clearError(); 681 682 const egl_display_ptr dp = validate_display(dpy); 683 if (!dp) return EGL_FALSE; 684 685 ContextRef _c(dp.get(), ctx); 686 if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE); 687 688 egl_context_t * const c = get_context(ctx); 689 return c->cnx->egl.eglQueryContext( 690 dp->disp.dpy, c->context, attribute, value); 691 692 } 693 694 EGLContext eglGetCurrentContext(void) 695 { 696 // could be called before eglInitialize(), but we wouldn't have a context 697 // then, and this function would correctly return EGL_NO_CONTEXT. 698 699 clearError(); 700 701 EGLContext ctx = getContext(); 702 return ctx; 703 } 704 705 EGLSurface eglGetCurrentSurface(EGLint readdraw) 706 { 707 // could be called before eglInitialize(), but we wouldn't have a context 708 // then, and this function would correctly return EGL_NO_SURFACE. 709 710 clearError(); 711 712 EGLContext ctx = getContext(); 713 if (ctx) { 714 egl_context_t const * const c = get_context(ctx); 715 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE); 716 switch (readdraw) { 717 case EGL_READ: return c->read; 718 case EGL_DRAW: return c->draw; 719 default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE); 720 } 721 } 722 return EGL_NO_SURFACE; 723 } 724 725 EGLDisplay eglGetCurrentDisplay(void) 726 { 727 // could be called before eglInitialize(), but we wouldn't have a context 728 // then, and this function would correctly return EGL_NO_DISPLAY. 729 730 clearError(); 731 732 EGLContext ctx = getContext(); 733 if (ctx) { 734 egl_context_t const * const c = get_context(ctx); 735 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE); 736 return c->dpy; 737 } 738 return EGL_NO_DISPLAY; 739 } 740 741 EGLBoolean eglWaitGL(void) 742 { 743 clearError(); 744 745 egl_connection_t* const cnx = &gEGLImpl; 746 if (!cnx->dso) 747 return setError(EGL_BAD_CONTEXT, EGL_FALSE); 748 749 return cnx->egl.eglWaitGL(); 750 } 751 752 EGLBoolean eglWaitNative(EGLint engine) 753 { 754 clearError(); 755 756 egl_connection_t* const cnx = &gEGLImpl; 757 if (!cnx->dso) 758 return setError(EGL_BAD_CONTEXT, EGL_FALSE); 759 760 return cnx->egl.eglWaitNative(engine); 761 } 762 763 EGLint eglGetError(void) 764 { 765 EGLint err = EGL_SUCCESS; 766 egl_connection_t* const cnx = &gEGLImpl; 767 if (cnx->dso) { 768 err = cnx->egl.eglGetError(); 769 } 770 if (err == EGL_SUCCESS) { 771 err = egl_tls_t::getError(); 772 } 773 return err; 774 } 775 776 static __eglMustCastToProperFunctionPointerType findBuiltinGLWrapper( 777 const char* procname) { 778 const egl_connection_t* cnx = &gEGLImpl; 779 void* proc = NULL; 780 781 proc = dlsym(cnx->libGles2, procname); 782 if (proc) return (__eglMustCastToProperFunctionPointerType)proc; 783 784 proc = dlsym(cnx->libGles1, procname); 785 if (proc) return (__eglMustCastToProperFunctionPointerType)proc; 786 787 return NULL; 788 } 789 790 __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) 791 { 792 // eglGetProcAddress() could be the very first function called 793 // in which case we must make sure we've initialized ourselves, this 794 // happens the first time egl_get_display() is called. 795 796 clearError(); 797 798 if (egl_init_drivers() == EGL_FALSE) { 799 setError(EGL_BAD_PARAMETER, NULL); 800 return NULL; 801 } 802 803 if (FILTER_EXTENSIONS(procname)) { 804 return NULL; 805 } 806 807 __eglMustCastToProperFunctionPointerType addr; 808 addr = findProcAddress(procname, sExtensionMap, NELEM(sExtensionMap)); 809 if (addr) return addr; 810 811 addr = findBuiltinGLWrapper(procname); 812 if (addr) return addr; 813 814 // this protects accesses to sGLExtentionMap and sGLExtentionSlot 815 pthread_mutex_lock(&sExtensionMapMutex); 816 817 /* 818 * Since eglGetProcAddress() is not associated to anything, it needs 819 * to return a function pointer that "works" regardless of what 820 * the current context is. 821 * 822 * For this reason, we return a "forwarder", a small stub that takes 823 * care of calling the function associated with the context 824 * currently bound. 825 * 826 * We first look for extensions we've already resolved, if we're seeing 827 * this extension for the first time, we go through all our 828 * implementations and call eglGetProcAddress() and record the 829 * result in the appropriate implementation hooks and return the 830 * address of the forwarder corresponding to that hook set. 831 * 832 */ 833 834 const String8 name(procname); 835 addr = sGLExtentionMap.valueFor(name); 836 const int slot = sGLExtentionSlot; 837 838 ALOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS, 839 "no more slots for eglGetProcAddress(\"%s\")", 840 procname); 841 842 #if EGL_TRACE 843 gl_hooks_t *debugHooks = GLTrace_getGLHooks(); 844 #endif 845 846 if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) { 847 bool found = false; 848 849 egl_connection_t* const cnx = &gEGLImpl; 850 if (cnx->dso && cnx->egl.eglGetProcAddress) { 851 // Extensions are independent of the bound context 852 addr = 853 cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] = 854 cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] = 855 #if EGL_TRACE 856 debugHooks->ext.extensions[slot] = 857 gHooksTrace.ext.extensions[slot] = 858 #endif 859 cnx->egl.eglGetProcAddress(procname); 860 if (addr) found = true; 861 } 862 863 if (found) { 864 #if USE_FAST_TLS_KEY 865 addr = gExtensionForwarders[slot]; 866 #endif 867 sGLExtentionMap.add(name, addr); 868 sGLExtentionSlot++; 869 } 870 } 871 872 pthread_mutex_unlock(&sExtensionMapMutex); 873 return addr; 874 } 875 876 class FrameCompletionThread : public Thread { 877 public: 878 879 static void queueSync(EGLSyncKHR sync) { 880 static sp<FrameCompletionThread> thread(new FrameCompletionThread); 881 static bool running = false; 882 if (!running) { 883 thread->run("GPUFrameCompletion"); 884 running = true; 885 } 886 { 887 Mutex::Autolock lock(thread->mMutex); 888 ScopedTrace st(ATRACE_TAG, String8::format("kicked off frame %d", 889 thread->mFramesQueued).string()); 890 thread->mQueue.push_back(sync); 891 thread->mCondition.signal(); 892 thread->mFramesQueued++; 893 ATRACE_INT("GPU Frames Outstanding", thread->mQueue.size()); 894 } 895 } 896 897 private: 898 FrameCompletionThread() : mFramesQueued(0), mFramesCompleted(0) {} 899 900 virtual bool threadLoop() { 901 EGLSyncKHR sync; 902 uint32_t frameNum; 903 { 904 Mutex::Autolock lock(mMutex); 905 while (mQueue.isEmpty()) { 906 mCondition.wait(mMutex); 907 } 908 sync = mQueue[0]; 909 frameNum = mFramesCompleted; 910 } 911 EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); 912 { 913 ScopedTrace st(ATRACE_TAG, String8::format("waiting for frame %d", 914 frameNum).string()); 915 EGLint result = eglClientWaitSyncKHR(dpy, sync, 0, EGL_FOREVER_KHR); 916 if (result == EGL_FALSE) { 917 ALOGE("FrameCompletion: error waiting for fence: %#x", eglGetError()); 918 } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { 919 ALOGE("FrameCompletion: timeout waiting for fence"); 920 } 921 eglDestroySyncKHR(dpy, sync); 922 } 923 { 924 Mutex::Autolock lock(mMutex); 925 mQueue.removeAt(0); 926 mFramesCompleted++; 927 ATRACE_INT("GPU Frames Outstanding", mQueue.size()); 928 } 929 return true; 930 } 931 932 uint32_t mFramesQueued; 933 uint32_t mFramesCompleted; 934 Vector<EGLSyncKHR> mQueue; 935 Condition mCondition; 936 Mutex mMutex; 937 }; 938 939 EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw) 940 { 941 ATRACE_CALL(); 942 clearError(); 943 944 const egl_display_ptr dp = validate_display(dpy); 945 if (!dp) return EGL_FALSE; 946 947 SurfaceRef _s(dp.get(), draw); 948 if (!_s.get()) 949 return setError(EGL_BAD_SURFACE, EGL_FALSE); 950 951 #if EGL_TRACE 952 gl_hooks_t const *trace_hooks = getGLTraceThreadSpecific(); 953 if (getEGLDebugLevel() > 0) { 954 if (trace_hooks == NULL) { 955 if (GLTrace_start() < 0) { 956 ALOGE("Disabling Tracer for OpenGL ES"); 957 setEGLDebugLevel(0); 958 } else { 959 // switch over to the trace version of hooks 960 EGLContext ctx = egl_tls_t::getContext(); 961 egl_context_t * const c = get_context(ctx); 962 if (c) { 963 setGLHooksThreadSpecific(c->cnx->hooks[c->version]); 964 GLTrace_eglMakeCurrent(c->version, c->cnx->hooks[c->version], ctx); 965 } 966 } 967 } 968 969 GLTrace_eglSwapBuffers(dpy, draw); 970 } else if (trace_hooks != NULL) { 971 // tracing is now disabled, so switch back to the non trace version 972 EGLContext ctx = egl_tls_t::getContext(); 973 egl_context_t * const c = get_context(ctx); 974 if (c) setGLHooksThreadSpecific(c->cnx->hooks[c->version]); 975 GLTrace_stop(); 976 } 977 #endif 978 979 egl_surface_t const * const s = get_surface(draw); 980 981 if (CC_UNLIKELY(dp->traceGpuCompletion)) { 982 EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL); 983 if (sync != EGL_NO_SYNC_KHR) { 984 FrameCompletionThread::queueSync(sync); 985 } 986 } 987 988 if (CC_UNLIKELY(dp->finishOnSwap)) { 989 uint32_t pixel; 990 egl_context_t * const c = get_context( egl_tls_t::getContext() ); 991 if (c) { 992 // glReadPixels() ensures that the frame is complete 993 s->cnx->hooks[c->version]->gl.glReadPixels(0,0,1,1, 994 GL_RGBA,GL_UNSIGNED_BYTE,&pixel); 995 } 996 } 997 998 return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface); 999 } 1000 1001 EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface, 1002 NativePixmapType target) 1003 { 1004 clearError(); 1005 1006 const egl_display_ptr dp = validate_display(dpy); 1007 if (!dp) return EGL_FALSE; 1008 1009 SurfaceRef _s(dp.get(), surface); 1010 if (!_s.get()) 1011 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1012 1013 egl_surface_t const * const s = get_surface(surface); 1014 return s->cnx->egl.eglCopyBuffers(dp->disp.dpy, s->surface, target); 1015 } 1016 1017 const char* eglQueryString(EGLDisplay dpy, EGLint name) 1018 { 1019 clearError(); 1020 1021 const egl_display_ptr dp = validate_display(dpy); 1022 if (!dp) return (const char *) NULL; 1023 1024 switch (name) { 1025 case EGL_VENDOR: 1026 return dp->getVendorString(); 1027 case EGL_VERSION: 1028 return dp->getVersionString(); 1029 case EGL_EXTENSIONS: 1030 return dp->getExtensionString(); 1031 case EGL_CLIENT_APIS: 1032 return dp->getClientApiString(); 1033 } 1034 return setError(EGL_BAD_PARAMETER, (const char *)0); 1035 } 1036 1037 EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name) 1038 { 1039 clearError(); 1040 1041 const egl_display_ptr dp = validate_display(dpy); 1042 if (!dp) return (const char *) NULL; 1043 1044 switch (name) { 1045 case EGL_VENDOR: 1046 return dp->disp.queryString.vendor; 1047 case EGL_VERSION: 1048 return dp->disp.queryString.version; 1049 case EGL_EXTENSIONS: 1050 return dp->disp.queryString.extensions; 1051 case EGL_CLIENT_APIS: 1052 return dp->disp.queryString.clientApi; 1053 } 1054 return setError(EGL_BAD_PARAMETER, (const char *)0); 1055 } 1056 1057 // ---------------------------------------------------------------------------- 1058 // EGL 1.1 1059 // ---------------------------------------------------------------------------- 1060 1061 EGLBoolean eglSurfaceAttrib( 1062 EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) 1063 { 1064 clearError(); 1065 1066 const egl_display_ptr dp = validate_display(dpy); 1067 if (!dp) return EGL_FALSE; 1068 1069 SurfaceRef _s(dp.get(), surface); 1070 if (!_s.get()) 1071 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1072 1073 egl_surface_t const * const s = get_surface(surface); 1074 if (s->cnx->egl.eglSurfaceAttrib) { 1075 return s->cnx->egl.eglSurfaceAttrib( 1076 dp->disp.dpy, s->surface, attribute, value); 1077 } 1078 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1079 } 1080 1081 EGLBoolean eglBindTexImage( 1082 EGLDisplay dpy, EGLSurface surface, EGLint buffer) 1083 { 1084 clearError(); 1085 1086 const egl_display_ptr dp = validate_display(dpy); 1087 if (!dp) return EGL_FALSE; 1088 1089 SurfaceRef _s(dp.get(), surface); 1090 if (!_s.get()) 1091 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1092 1093 egl_surface_t const * const s = get_surface(surface); 1094 if (s->cnx->egl.eglBindTexImage) { 1095 return s->cnx->egl.eglBindTexImage( 1096 dp->disp.dpy, s->surface, buffer); 1097 } 1098 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1099 } 1100 1101 EGLBoolean eglReleaseTexImage( 1102 EGLDisplay dpy, EGLSurface surface, EGLint buffer) 1103 { 1104 clearError(); 1105 1106 const egl_display_ptr dp = validate_display(dpy); 1107 if (!dp) return EGL_FALSE; 1108 1109 SurfaceRef _s(dp.get(), surface); 1110 if (!_s.get()) 1111 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1112 1113 egl_surface_t const * const s = get_surface(surface); 1114 if (s->cnx->egl.eglReleaseTexImage) { 1115 return s->cnx->egl.eglReleaseTexImage( 1116 dp->disp.dpy, s->surface, buffer); 1117 } 1118 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1119 } 1120 1121 EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) 1122 { 1123 clearError(); 1124 1125 const egl_display_ptr dp = validate_display(dpy); 1126 if (!dp) return EGL_FALSE; 1127 1128 EGLBoolean res = EGL_TRUE; 1129 egl_connection_t* const cnx = &gEGLImpl; 1130 if (cnx->dso && cnx->egl.eglSwapInterval) { 1131 res = cnx->egl.eglSwapInterval(dp->disp.dpy, interval); 1132 } 1133 1134 return res; 1135 } 1136 1137 1138 // ---------------------------------------------------------------------------- 1139 // EGL 1.2 1140 // ---------------------------------------------------------------------------- 1141 1142 EGLBoolean eglWaitClient(void) 1143 { 1144 clearError(); 1145 1146 egl_connection_t* const cnx = &gEGLImpl; 1147 if (!cnx->dso) 1148 return setError(EGL_BAD_CONTEXT, EGL_FALSE); 1149 1150 EGLBoolean res; 1151 if (cnx->egl.eglWaitClient) { 1152 res = cnx->egl.eglWaitClient(); 1153 } else { 1154 res = cnx->egl.eglWaitGL(); 1155 } 1156 return res; 1157 } 1158 1159 EGLBoolean eglBindAPI(EGLenum api) 1160 { 1161 clearError(); 1162 1163 if (egl_init_drivers() == EGL_FALSE) { 1164 return setError(EGL_BAD_PARAMETER, EGL_FALSE); 1165 } 1166 1167 // bind this API on all EGLs 1168 EGLBoolean res = EGL_TRUE; 1169 egl_connection_t* const cnx = &gEGLImpl; 1170 if (cnx->dso && cnx->egl.eglBindAPI) { 1171 res = cnx->egl.eglBindAPI(api); 1172 } 1173 return res; 1174 } 1175 1176 EGLenum eglQueryAPI(void) 1177 { 1178 clearError(); 1179 1180 if (egl_init_drivers() == EGL_FALSE) { 1181 return setError(EGL_BAD_PARAMETER, EGL_FALSE); 1182 } 1183 1184 egl_connection_t* const cnx = &gEGLImpl; 1185 if (cnx->dso && cnx->egl.eglQueryAPI) { 1186 return cnx->egl.eglQueryAPI(); 1187 } 1188 1189 // or, it can only be OpenGL ES 1190 return EGL_OPENGL_ES_API; 1191 } 1192 1193 EGLBoolean eglReleaseThread(void) 1194 { 1195 clearError(); 1196 1197 // If there is context bound to the thread, release it 1198 egl_display_t::loseCurrent(get_context(getContext())); 1199 1200 egl_connection_t* const cnx = &gEGLImpl; 1201 if (cnx->dso && cnx->egl.eglReleaseThread) { 1202 cnx->egl.eglReleaseThread(); 1203 } 1204 1205 egl_tls_t::clearTLS(); 1206 #if EGL_TRACE 1207 if (getEGLDebugLevel() > 0) 1208 GLTrace_eglReleaseThread(); 1209 #endif 1210 return EGL_TRUE; 1211 } 1212 1213 EGLSurface eglCreatePbufferFromClientBuffer( 1214 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, 1215 EGLConfig config, const EGLint *attrib_list) 1216 { 1217 clearError(); 1218 1219 egl_connection_t* cnx = NULL; 1220 const egl_display_ptr dp = validate_display_connection(dpy, cnx); 1221 if (!dp) return EGL_FALSE; 1222 if (cnx->egl.eglCreatePbufferFromClientBuffer) { 1223 return cnx->egl.eglCreatePbufferFromClientBuffer( 1224 dp->disp.dpy, buftype, buffer, config, attrib_list); 1225 } 1226 return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE); 1227 } 1228 1229 // ---------------------------------------------------------------------------- 1230 // EGL_EGLEXT_VERSION 3 1231 // ---------------------------------------------------------------------------- 1232 1233 EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, 1234 const EGLint *attrib_list) 1235 { 1236 clearError(); 1237 1238 const egl_display_ptr dp = validate_display(dpy); 1239 if (!dp) return EGL_FALSE; 1240 1241 SurfaceRef _s(dp.get(), surface); 1242 if (!_s.get()) 1243 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1244 1245 egl_surface_t const * const s = get_surface(surface); 1246 if (s->cnx->egl.eglLockSurfaceKHR) { 1247 return s->cnx->egl.eglLockSurfaceKHR( 1248 dp->disp.dpy, s->surface, attrib_list); 1249 } 1250 return setError(EGL_BAD_DISPLAY, EGL_FALSE); 1251 } 1252 1253 EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) 1254 { 1255 clearError(); 1256 1257 const egl_display_ptr dp = validate_display(dpy); 1258 if (!dp) return EGL_FALSE; 1259 1260 SurfaceRef _s(dp.get(), surface); 1261 if (!_s.get()) 1262 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1263 1264 egl_surface_t const * const s = get_surface(surface); 1265 if (s->cnx->egl.eglUnlockSurfaceKHR) { 1266 return s->cnx->egl.eglUnlockSurfaceKHR(dp->disp.dpy, s->surface); 1267 } 1268 return setError(EGL_BAD_DISPLAY, EGL_FALSE); 1269 } 1270 1271 EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, 1272 EGLClientBuffer buffer, const EGLint *attrib_list) 1273 { 1274 clearError(); 1275 1276 const egl_display_ptr dp = validate_display(dpy); 1277 if (!dp) return EGL_NO_IMAGE_KHR; 1278 1279 ContextRef _c(dp.get(), ctx); 1280 egl_context_t * const c = _c.get(); 1281 1282 EGLImageKHR result = EGL_NO_IMAGE_KHR; 1283 egl_connection_t* const cnx = &gEGLImpl; 1284 if (cnx->dso && cnx->egl.eglCreateImageKHR) { 1285 result = cnx->egl.eglCreateImageKHR( 1286 dp->disp.dpy, 1287 c ? c->context : EGL_NO_CONTEXT, 1288 target, buffer, attrib_list); 1289 } 1290 return result; 1291 } 1292 1293 EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) 1294 { 1295 clearError(); 1296 1297 const egl_display_ptr dp = validate_display(dpy); 1298 if (!dp) return EGL_FALSE; 1299 1300 EGLBoolean result = EGL_FALSE; 1301 egl_connection_t* const cnx = &gEGLImpl; 1302 if (cnx->dso && cnx->egl.eglDestroyImageKHR) { 1303 result = cnx->egl.eglDestroyImageKHR(dp->disp.dpy, img); 1304 } 1305 return result; 1306 } 1307 1308 // ---------------------------------------------------------------------------- 1309 // EGL_EGLEXT_VERSION 5 1310 // ---------------------------------------------------------------------------- 1311 1312 1313 EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) 1314 { 1315 clearError(); 1316 1317 const egl_display_ptr dp = validate_display(dpy); 1318 if (!dp) return EGL_NO_SYNC_KHR; 1319 1320 EGLSyncKHR result = EGL_NO_SYNC_KHR; 1321 egl_connection_t* const cnx = &gEGLImpl; 1322 if (cnx->dso && cnx->egl.eglCreateSyncKHR) { 1323 result = cnx->egl.eglCreateSyncKHR(dp->disp.dpy, type, attrib_list); 1324 } 1325 return result; 1326 } 1327 1328 EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) 1329 { 1330 clearError(); 1331 1332 const egl_display_ptr dp = validate_display(dpy); 1333 if (!dp) return EGL_FALSE; 1334 1335 EGLBoolean result = EGL_FALSE; 1336 egl_connection_t* const cnx = &gEGLImpl; 1337 if (cnx->dso && cnx->egl.eglDestroySyncKHR) { 1338 result = cnx->egl.eglDestroySyncKHR(dp->disp.dpy, sync); 1339 } 1340 return result; 1341 } 1342 1343 EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) { 1344 clearError(); 1345 1346 const egl_display_ptr dp = validate_display(dpy); 1347 if (!dp) return EGL_FALSE; 1348 1349 EGLBoolean result = EGL_FALSE; 1350 egl_connection_t* const cnx = &gEGLImpl; 1351 if (cnx->dso && cnx->egl.eglSignalSyncKHR) { 1352 result = cnx->egl.eglSignalSyncKHR( 1353 dp->disp.dpy, sync, mode); 1354 } 1355 return result; 1356 } 1357 1358 EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, 1359 EGLint flags, EGLTimeKHR timeout) 1360 { 1361 clearError(); 1362 1363 const egl_display_ptr dp = validate_display(dpy); 1364 if (!dp) return EGL_FALSE; 1365 1366 EGLBoolean result = EGL_FALSE; 1367 egl_connection_t* const cnx = &gEGLImpl; 1368 if (cnx->dso && cnx->egl.eglClientWaitSyncKHR) { 1369 result = cnx->egl.eglClientWaitSyncKHR( 1370 dp->disp.dpy, sync, flags, timeout); 1371 } 1372 return result; 1373 } 1374 1375 EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, 1376 EGLint attribute, EGLint *value) 1377 { 1378 clearError(); 1379 1380 const egl_display_ptr dp = validate_display(dpy); 1381 if (!dp) return EGL_FALSE; 1382 1383 EGLBoolean result = EGL_FALSE; 1384 egl_connection_t* const cnx = &gEGLImpl; 1385 if (cnx->dso && cnx->egl.eglGetSyncAttribKHR) { 1386 result = cnx->egl.eglGetSyncAttribKHR( 1387 dp->disp.dpy, sync, attribute, value); 1388 } 1389 return result; 1390 } 1391 1392 // ---------------------------------------------------------------------------- 1393 // EGL_EGLEXT_VERSION 15 1394 // ---------------------------------------------------------------------------- 1395 1396 EGLint eglWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) { 1397 clearError(); 1398 const egl_display_ptr dp = validate_display(dpy); 1399 if (!dp) return EGL_FALSE; 1400 EGLint result = EGL_FALSE; 1401 egl_connection_t* const cnx = &gEGLImpl; 1402 if (cnx->dso && cnx->egl.eglWaitSyncKHR) { 1403 result = cnx->egl.eglWaitSyncKHR(dp->disp.dpy, sync, flags); 1404 } 1405 return result; 1406 } 1407 1408 // ---------------------------------------------------------------------------- 1409 // ANDROID extensions 1410 // ---------------------------------------------------------------------------- 1411 1412 EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync) 1413 { 1414 clearError(); 1415 1416 const egl_display_ptr dp = validate_display(dpy); 1417 if (!dp) return EGL_NO_NATIVE_FENCE_FD_ANDROID; 1418 1419 EGLint result = EGL_NO_NATIVE_FENCE_FD_ANDROID; 1420 egl_connection_t* const cnx = &gEGLImpl; 1421 if (cnx->dso && cnx->egl.eglDupNativeFenceFDANDROID) { 1422 result = cnx->egl.eglDupNativeFenceFDANDROID(dp->disp.dpy, sync); 1423 } 1424 return result; 1425 } 1426 1427 EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, 1428 EGLnsecsANDROID time) 1429 { 1430 clearError(); 1431 1432 const egl_display_ptr dp = validate_display(dpy); 1433 if (!dp) { 1434 return EGL_FALSE; 1435 } 1436 1437 SurfaceRef _s(dp.get(), surface); 1438 if (!_s.get()) { 1439 setError(EGL_BAD_SURFACE, EGL_FALSE); 1440 return EGL_FALSE; 1441 } 1442 1443 egl_surface_t const * const s = get_surface(surface); 1444 native_window_set_buffers_timestamp(s->win.get(), time); 1445 1446 return EGL_TRUE; 1447 } 1448 1449 // ---------------------------------------------------------------------------- 1450 // NVIDIA extensions 1451 // ---------------------------------------------------------------------------- 1452 EGLuint64NV eglGetSystemTimeFrequencyNV() 1453 { 1454 clearError(); 1455 1456 if (egl_init_drivers() == EGL_FALSE) { 1457 return setError(EGL_BAD_PARAMETER, EGL_FALSE); 1458 } 1459 1460 EGLuint64NV ret = 0; 1461 egl_connection_t* const cnx = &gEGLImpl; 1462 1463 if (cnx->dso && cnx->egl.eglGetSystemTimeFrequencyNV) { 1464 return cnx->egl.eglGetSystemTimeFrequencyNV(); 1465 } 1466 1467 return setErrorQuiet(EGL_BAD_DISPLAY, 0); 1468 } 1469 1470 EGLuint64NV eglGetSystemTimeNV() 1471 { 1472 clearError(); 1473 1474 if (egl_init_drivers() == EGL_FALSE) { 1475 return setError(EGL_BAD_PARAMETER, EGL_FALSE); 1476 } 1477 1478 EGLuint64NV ret = 0; 1479 egl_connection_t* const cnx = &gEGLImpl; 1480 1481 if (cnx->dso && cnx->egl.eglGetSystemTimeNV) { 1482 return cnx->egl.eglGetSystemTimeNV(); 1483 } 1484 1485 return setErrorQuiet(EGL_BAD_DISPLAY, 0); 1486 } 1487