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