eglApi.cpp revision 5477d0e4e858df1ea9cb1b6965a160fb5fe23b57
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 50using namespace android; 51 52// ---------------------------------------------------------------------------- 53 54namespace android { 55 56struct 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 */ 72extern 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 */ 103static 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 156static DefaultKeyedVector<String8, __eglMustCastToProperFunctionPointerType> sGLExtentionMap; 157static int sGLExtentionSlot = 0; 158static pthread_mutex_t sExtensionMapMutex = PTHREAD_MUTEX_INITIALIZER; 159 160static 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 172extern void setGLHooksThreadSpecific(gl_hooks_t const *value); 173extern EGLBoolean egl_init_drivers(); 174extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS]; 175extern int getEGLDebugLevel(); 176extern void setEGLDebugLevel(int level); 177extern gl_hooks_t gHooksTrace; 178 179} // namespace android; 180 181 182// ---------------------------------------------------------------------------- 183 184static inline void clearError() { egl_tls_t::clearError(); } 185static inline EGLContext getContext() { return egl_tls_t::getContext(); } 186 187// ---------------------------------------------------------------------------- 188 189EGLDisplay 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 210EGLBoolean 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 222EGLBoolean 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 242EGLBoolean 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 267EGLBoolean 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 344EGLBoolean 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 361EGLSurface 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 413EGLSurface 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 433EGLSurface 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 452EGLBoolean 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 471EGLBoolean 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 488void 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 513EGLContext 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 (dp) { 521 if (share_list != EGL_NO_CONTEXT) { 522 if (!ContextRef(dp.get(), share_list).get()) { 523 return setError(EGL_BAD_CONTEXT, EGL_NO_CONTEXT); 524 } 525 egl_context_t* const c = get_context(share_list); 526 share_list = c->context; 527 } 528 EGLContext context = cnx->egl.eglCreateContext( 529 dp->disp.dpy, config, share_list, attrib_list); 530 if (context != EGL_NO_CONTEXT) { 531 // figure out if it's a GLESv1 or GLESv2 532 int version = 0; 533 if (attrib_list) { 534 while (*attrib_list != EGL_NONE) { 535 GLint attr = *attrib_list++; 536 GLint value = *attrib_list++; 537 if (attr == EGL_CONTEXT_CLIENT_VERSION) { 538 if (value == 1) { 539 version = egl_connection_t::GLESv1_INDEX; 540 } else if (value == 2 || value == 3) { 541 version = egl_connection_t::GLESv2_INDEX; 542 } 543 } 544 }; 545 } 546 egl_context_t* c = new egl_context_t(dpy, context, config, cnx, 547 version); 548#if EGL_TRACE 549 if (getEGLDebugLevel() > 0) 550 GLTrace_eglCreateContext(version, c); 551#endif 552 return c; 553 } else { 554 EGLint error = eglGetError(); 555 ALOGE_IF(error == EGL_SUCCESS, 556 "eglCreateContext(%p, %p, %p, %p) returned EGL_NO_CONTEXT " 557 "but no EGL error!", 558 dpy, config, share_list, attrib_list); 559 } 560 } 561 return EGL_NO_CONTEXT; 562} 563 564EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) 565{ 566 clearError(); 567 568 const egl_display_ptr dp = validate_display(dpy); 569 if (!dp) 570 return EGL_FALSE; 571 572 ContextRef _c(dp.get(), ctx); 573 if (!_c.get()) 574 return setError(EGL_BAD_CONTEXT, EGL_FALSE); 575 576 egl_context_t * const c = get_context(ctx); 577 EGLBoolean result = c->cnx->egl.eglDestroyContext(dp->disp.dpy, c->context); 578 if (result == EGL_TRUE) { 579 _c.terminate(); 580 } 581 return result; 582} 583 584EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, 585 EGLSurface read, EGLContext ctx) 586{ 587 clearError(); 588 589 egl_display_ptr dp = validate_display(dpy); 590 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE); 591 592 // If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not 593 // EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is 594 // a valid but uninitialized display. 595 if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) || 596 (draw != EGL_NO_SURFACE) ) { 597 if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, EGL_FALSE); 598 } 599 600 // get a reference to the object passed in 601 ContextRef _c(dp.get(), ctx); 602 SurfaceRef _d(dp.get(), draw); 603 SurfaceRef _r(dp.get(), read); 604 605 // validate the context (if not EGL_NO_CONTEXT) 606 if ((ctx != EGL_NO_CONTEXT) && !_c.get()) { 607 // EGL_NO_CONTEXT is valid 608 return setError(EGL_BAD_CONTEXT, EGL_FALSE); 609 } 610 611 // these are the underlying implementation's object 612 EGLContext impl_ctx = EGL_NO_CONTEXT; 613 EGLSurface impl_draw = EGL_NO_SURFACE; 614 EGLSurface impl_read = EGL_NO_SURFACE; 615 616 // these are our objects structs passed in 617 egl_context_t * c = NULL; 618 egl_surface_t const * d = NULL; 619 egl_surface_t const * r = NULL; 620 621 // these are the current objects structs 622 egl_context_t * cur_c = get_context(getContext()); 623 624 if (ctx != EGL_NO_CONTEXT) { 625 c = get_context(ctx); 626 impl_ctx = c->context; 627 } else { 628 // no context given, use the implementation of the current context 629 if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) { 630 // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT); 631 return setError(EGL_BAD_MATCH, EGL_FALSE); 632 } 633 if (cur_c == NULL) { 634 // no current context 635 // not an error, there is just no current context. 636 return EGL_TRUE; 637 } 638 } 639 640 // retrieve the underlying implementation's draw EGLSurface 641 if (draw != EGL_NO_SURFACE) { 642 if (!_d.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); 643 d = get_surface(draw); 644 impl_draw = d->surface; 645 } 646 647 // retrieve the underlying implementation's read EGLSurface 648 if (read != EGL_NO_SURFACE) { 649 if (!_r.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); 650 r = get_surface(read); 651 impl_read = r->surface; 652 } 653 654 655 EGLBoolean result = dp->makeCurrent(c, cur_c, 656 draw, read, ctx, 657 impl_draw, impl_read, impl_ctx); 658 659 if (result == EGL_TRUE) { 660 if (c) { 661 setGLHooksThreadSpecific(c->cnx->hooks[c->version]); 662 egl_tls_t::setContext(ctx); 663#if EGL_TRACE 664 if (getEGLDebugLevel() > 0) 665 GLTrace_eglMakeCurrent(c->version, c->cnx->hooks[c->version], ctx); 666#endif 667 _c.acquire(); 668 _r.acquire(); 669 _d.acquire(); 670 } else { 671 setGLHooksThreadSpecific(&gHooksNoContext); 672 egl_tls_t::setContext(EGL_NO_CONTEXT); 673 } 674 } else { 675 // this will ALOGE the error 676 result = setError(c->cnx->egl.eglGetError(), EGL_FALSE); 677 } 678 return result; 679} 680 681 682EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx, 683 EGLint attribute, EGLint *value) 684{ 685 clearError(); 686 687 const egl_display_ptr dp = validate_display(dpy); 688 if (!dp) return EGL_FALSE; 689 690 ContextRef _c(dp.get(), ctx); 691 if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE); 692 693 egl_context_t * const c = get_context(ctx); 694 return c->cnx->egl.eglQueryContext( 695 dp->disp.dpy, c->context, attribute, value); 696 697} 698 699EGLContext eglGetCurrentContext(void) 700{ 701 // could be called before eglInitialize(), but we wouldn't have a context 702 // then, and this function would correctly return EGL_NO_CONTEXT. 703 704 clearError(); 705 706 EGLContext ctx = getContext(); 707 return ctx; 708} 709 710EGLSurface eglGetCurrentSurface(EGLint readdraw) 711{ 712 // could be called before eglInitialize(), but we wouldn't have a context 713 // then, and this function would correctly return EGL_NO_SURFACE. 714 715 clearError(); 716 717 EGLContext ctx = getContext(); 718 if (ctx) { 719 egl_context_t const * const c = get_context(ctx); 720 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE); 721 switch (readdraw) { 722 case EGL_READ: return c->read; 723 case EGL_DRAW: return c->draw; 724 default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE); 725 } 726 } 727 return EGL_NO_SURFACE; 728} 729 730EGLDisplay eglGetCurrentDisplay(void) 731{ 732 // could be called before eglInitialize(), but we wouldn't have a context 733 // then, and this function would correctly return EGL_NO_DISPLAY. 734 735 clearError(); 736 737 EGLContext ctx = getContext(); 738 if (ctx) { 739 egl_context_t const * const c = get_context(ctx); 740 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE); 741 return c->dpy; 742 } 743 return EGL_NO_DISPLAY; 744} 745 746EGLBoolean eglWaitGL(void) 747{ 748 clearError(); 749 750 egl_connection_t* const cnx = &gEGLImpl; 751 if (!cnx->dso) 752 return setError(EGL_BAD_CONTEXT, EGL_FALSE); 753 754 return cnx->egl.eglWaitGL(); 755} 756 757EGLBoolean eglWaitNative(EGLint engine) 758{ 759 clearError(); 760 761 egl_connection_t* const cnx = &gEGLImpl; 762 if (!cnx->dso) 763 return setError(EGL_BAD_CONTEXT, EGL_FALSE); 764 765 return cnx->egl.eglWaitNative(engine); 766} 767 768EGLint eglGetError(void) 769{ 770 EGLint err = EGL_SUCCESS; 771 egl_connection_t* const cnx = &gEGLImpl; 772 if (cnx->dso) { 773 err = cnx->egl.eglGetError(); 774 } 775 if (err == EGL_SUCCESS) { 776 err = egl_tls_t::getError(); 777 } 778 return err; 779} 780 781static __eglMustCastToProperFunctionPointerType findBuiltinGLWrapper( 782 const char* procname) { 783 const egl_connection_t* cnx = &gEGLImpl; 784 void* proc = NULL; 785 786 proc = dlsym(cnx->libGles2, procname); 787 if (proc) return (__eglMustCastToProperFunctionPointerType)proc; 788 789 proc = dlsym(cnx->libGles1, procname); 790 if (proc) return (__eglMustCastToProperFunctionPointerType)proc; 791 792 return NULL; 793} 794 795__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) 796{ 797 // eglGetProcAddress() could be the very first function called 798 // in which case we must make sure we've initialized ourselves, this 799 // happens the first time egl_get_display() is called. 800 801 clearError(); 802 803 if (egl_init_drivers() == EGL_FALSE) { 804 setError(EGL_BAD_PARAMETER, NULL); 805 return NULL; 806 } 807 808 if (FILTER_EXTENSIONS(procname)) { 809 return NULL; 810 } 811 812 __eglMustCastToProperFunctionPointerType addr; 813 addr = findProcAddress(procname, sExtensionMap, NELEM(sExtensionMap)); 814 if (addr) return addr; 815 816 addr = findBuiltinGLWrapper(procname); 817 if (addr) return addr; 818 819 // this protects accesses to sGLExtentionMap and sGLExtentionSlot 820 pthread_mutex_lock(&sExtensionMapMutex); 821 822 /* 823 * Since eglGetProcAddress() is not associated to anything, it needs 824 * to return a function pointer that "works" regardless of what 825 * the current context is. 826 * 827 * For this reason, we return a "forwarder", a small stub that takes 828 * care of calling the function associated with the context 829 * currently bound. 830 * 831 * We first look for extensions we've already resolved, if we're seeing 832 * this extension for the first time, we go through all our 833 * implementations and call eglGetProcAddress() and record the 834 * result in the appropriate implementation hooks and return the 835 * address of the forwarder corresponding to that hook set. 836 * 837 */ 838 839 const String8 name(procname); 840 addr = sGLExtentionMap.valueFor(name); 841 const int slot = sGLExtentionSlot; 842 843 ALOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS, 844 "no more slots for eglGetProcAddress(\"%s\")", 845 procname); 846 847#if EGL_TRACE 848 gl_hooks_t *debugHooks = GLTrace_getGLHooks(); 849#endif 850 851 if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) { 852 bool found = false; 853 854 egl_connection_t* const cnx = &gEGLImpl; 855 if (cnx->dso && cnx->egl.eglGetProcAddress) { 856 // Extensions are independent of the bound context 857 addr = 858 cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] = 859 cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] = 860#if EGL_TRACE 861 debugHooks->ext.extensions[slot] = 862 gHooksTrace.ext.extensions[slot] = 863#endif 864 cnx->egl.eglGetProcAddress(procname); 865 if (addr) found = true; 866 } 867 868 if (found) { 869#if USE_FAST_TLS_KEY 870 addr = gExtensionForwarders[slot]; 871#endif 872 sGLExtentionMap.add(name, addr); 873 sGLExtentionSlot++; 874 } 875 } 876 877 pthread_mutex_unlock(&sExtensionMapMutex); 878 return addr; 879} 880 881class FrameCompletionThread : public Thread { 882public: 883 884 static void queueSync(EGLSyncKHR sync) { 885 static sp<FrameCompletionThread> thread(new FrameCompletionThread); 886 static bool running = false; 887 if (!running) { 888 thread->run("GPUFrameCompletion"); 889 running = true; 890 } 891 { 892 Mutex::Autolock lock(thread->mMutex); 893 ScopedTrace st(ATRACE_TAG, String8::format("kicked off frame %d", 894 thread->mFramesQueued).string()); 895 thread->mQueue.push_back(sync); 896 thread->mCondition.signal(); 897 thread->mFramesQueued++; 898 ATRACE_INT("GPU Frames Outstanding", thread->mQueue.size()); 899 } 900 } 901 902private: 903 FrameCompletionThread() : mFramesQueued(0), mFramesCompleted(0) {} 904 905 virtual bool threadLoop() { 906 EGLSyncKHR sync; 907 uint32_t frameNum; 908 { 909 Mutex::Autolock lock(mMutex); 910 while (mQueue.isEmpty()) { 911 mCondition.wait(mMutex); 912 } 913 sync = mQueue[0]; 914 frameNum = mFramesCompleted; 915 } 916 EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); 917 { 918 ScopedTrace st(ATRACE_TAG, String8::format("waiting for frame %d", 919 frameNum).string()); 920 EGLint result = eglClientWaitSyncKHR(dpy, sync, 0, EGL_FOREVER_KHR); 921 if (result == EGL_FALSE) { 922 ALOGE("FrameCompletion: error waiting for fence: %#x", eglGetError()); 923 } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { 924 ALOGE("FrameCompletion: timeout waiting for fence"); 925 } 926 eglDestroySyncKHR(dpy, sync); 927 } 928 { 929 Mutex::Autolock lock(mMutex); 930 mQueue.removeAt(0); 931 mFramesCompleted++; 932 ATRACE_INT("GPU Frames Outstanding", mQueue.size()); 933 } 934 return true; 935 } 936 937 uint32_t mFramesQueued; 938 uint32_t mFramesCompleted; 939 Vector<EGLSyncKHR> mQueue; 940 Condition mCondition; 941 Mutex mMutex; 942}; 943 944EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw) 945{ 946 ATRACE_CALL(); 947 clearError(); 948 949 const egl_display_ptr dp = validate_display(dpy); 950 if (!dp) return EGL_FALSE; 951 952 SurfaceRef _s(dp.get(), draw); 953 if (!_s.get()) 954 return setError(EGL_BAD_SURFACE, EGL_FALSE); 955 956#if EGL_TRACE 957 gl_hooks_t const *trace_hooks = getGLTraceThreadSpecific(); 958 if (getEGLDebugLevel() > 0) { 959 if (trace_hooks == NULL) { 960 if (GLTrace_start() < 0) { 961 ALOGE("Disabling Tracer for OpenGL ES"); 962 setEGLDebugLevel(0); 963 } else { 964 // switch over to the trace version of hooks 965 EGLContext ctx = egl_tls_t::getContext(); 966 egl_context_t * const c = get_context(ctx); 967 if (c) { 968 setGLHooksThreadSpecific(c->cnx->hooks[c->version]); 969 GLTrace_eglMakeCurrent(c->version, c->cnx->hooks[c->version], ctx); 970 } 971 } 972 } 973 974 GLTrace_eglSwapBuffers(dpy, draw); 975 } else if (trace_hooks != NULL) { 976 // tracing is now disabled, so switch back to the non trace version 977 EGLContext ctx = egl_tls_t::getContext(); 978 egl_context_t * const c = get_context(ctx); 979 if (c) setGLHooksThreadSpecific(c->cnx->hooks[c->version]); 980 GLTrace_stop(); 981 } 982#endif 983 984 egl_surface_t const * const s = get_surface(draw); 985 986 if (CC_UNLIKELY(dp->traceGpuCompletion)) { 987 EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL); 988 if (sync != EGL_NO_SYNC_KHR) { 989 FrameCompletionThread::queueSync(sync); 990 } 991 } 992 993 if (CC_UNLIKELY(dp->finishOnSwap)) { 994 uint32_t pixel; 995 egl_context_t * const c = get_context( egl_tls_t::getContext() ); 996 if (c) { 997 // glReadPixels() ensures that the frame is complete 998 s->cnx->hooks[c->version]->gl.glReadPixels(0,0,1,1, 999 GL_RGBA,GL_UNSIGNED_BYTE,&pixel); 1000 } 1001 } 1002 1003 return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface); 1004} 1005 1006EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface, 1007 NativePixmapType target) 1008{ 1009 clearError(); 1010 1011 const egl_display_ptr dp = validate_display(dpy); 1012 if (!dp) return EGL_FALSE; 1013 1014 SurfaceRef _s(dp.get(), surface); 1015 if (!_s.get()) 1016 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1017 1018 egl_surface_t const * const s = get_surface(surface); 1019 return s->cnx->egl.eglCopyBuffers(dp->disp.dpy, s->surface, target); 1020} 1021 1022const char* eglQueryString(EGLDisplay dpy, EGLint name) 1023{ 1024 clearError(); 1025 1026 const egl_display_ptr dp = validate_display(dpy); 1027 if (!dp) return (const char *) NULL; 1028 1029 switch (name) { 1030 case EGL_VENDOR: 1031 return dp->getVendorString(); 1032 case EGL_VERSION: 1033 return dp->getVersionString(); 1034 case EGL_EXTENSIONS: 1035 return dp->getExtensionString(); 1036 case EGL_CLIENT_APIS: 1037 return dp->getClientApiString(); 1038 } 1039 return setError(EGL_BAD_PARAMETER, (const char *)0); 1040} 1041 1042EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name) 1043{ 1044 clearError(); 1045 1046 const egl_display_ptr dp = validate_display(dpy); 1047 if (!dp) return (const char *) NULL; 1048 1049 switch (name) { 1050 case EGL_VENDOR: 1051 return dp->disp.queryString.vendor; 1052 case EGL_VERSION: 1053 return dp->disp.queryString.version; 1054 case EGL_EXTENSIONS: 1055 return dp->disp.queryString.extensions; 1056 case EGL_CLIENT_APIS: 1057 return dp->disp.queryString.clientApi; 1058 } 1059 return setError(EGL_BAD_PARAMETER, (const char *)0); 1060} 1061 1062// ---------------------------------------------------------------------------- 1063// EGL 1.1 1064// ---------------------------------------------------------------------------- 1065 1066EGLBoolean eglSurfaceAttrib( 1067 EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) 1068{ 1069 clearError(); 1070 1071 const egl_display_ptr dp = validate_display(dpy); 1072 if (!dp) return EGL_FALSE; 1073 1074 SurfaceRef _s(dp.get(), surface); 1075 if (!_s.get()) 1076 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1077 1078 egl_surface_t const * const s = get_surface(surface); 1079 if (s->cnx->egl.eglSurfaceAttrib) { 1080 return s->cnx->egl.eglSurfaceAttrib( 1081 dp->disp.dpy, s->surface, attribute, value); 1082 } 1083 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1084} 1085 1086EGLBoolean eglBindTexImage( 1087 EGLDisplay dpy, EGLSurface surface, EGLint buffer) 1088{ 1089 clearError(); 1090 1091 const egl_display_ptr dp = validate_display(dpy); 1092 if (!dp) return EGL_FALSE; 1093 1094 SurfaceRef _s(dp.get(), surface); 1095 if (!_s.get()) 1096 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1097 1098 egl_surface_t const * const s = get_surface(surface); 1099 if (s->cnx->egl.eglBindTexImage) { 1100 return s->cnx->egl.eglBindTexImage( 1101 dp->disp.dpy, s->surface, buffer); 1102 } 1103 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1104} 1105 1106EGLBoolean eglReleaseTexImage( 1107 EGLDisplay dpy, EGLSurface surface, EGLint buffer) 1108{ 1109 clearError(); 1110 1111 const egl_display_ptr dp = validate_display(dpy); 1112 if (!dp) return EGL_FALSE; 1113 1114 SurfaceRef _s(dp.get(), surface); 1115 if (!_s.get()) 1116 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1117 1118 egl_surface_t const * const s = get_surface(surface); 1119 if (s->cnx->egl.eglReleaseTexImage) { 1120 return s->cnx->egl.eglReleaseTexImage( 1121 dp->disp.dpy, s->surface, buffer); 1122 } 1123 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1124} 1125 1126EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) 1127{ 1128 clearError(); 1129 1130 const egl_display_ptr dp = validate_display(dpy); 1131 if (!dp) return EGL_FALSE; 1132 1133 EGLBoolean res = EGL_TRUE; 1134 egl_connection_t* const cnx = &gEGLImpl; 1135 if (cnx->dso && cnx->egl.eglSwapInterval) { 1136 res = cnx->egl.eglSwapInterval(dp->disp.dpy, interval); 1137 } 1138 1139 return res; 1140} 1141 1142 1143// ---------------------------------------------------------------------------- 1144// EGL 1.2 1145// ---------------------------------------------------------------------------- 1146 1147EGLBoolean eglWaitClient(void) 1148{ 1149 clearError(); 1150 1151 egl_connection_t* const cnx = &gEGLImpl; 1152 if (!cnx->dso) 1153 return setError(EGL_BAD_CONTEXT, EGL_FALSE); 1154 1155 EGLBoolean res; 1156 if (cnx->egl.eglWaitClient) { 1157 res = cnx->egl.eglWaitClient(); 1158 } else { 1159 res = cnx->egl.eglWaitGL(); 1160 } 1161 return res; 1162} 1163 1164EGLBoolean eglBindAPI(EGLenum api) 1165{ 1166 clearError(); 1167 1168 if (egl_init_drivers() == EGL_FALSE) { 1169 return setError(EGL_BAD_PARAMETER, EGL_FALSE); 1170 } 1171 1172 // bind this API on all EGLs 1173 EGLBoolean res = EGL_TRUE; 1174 egl_connection_t* const cnx = &gEGLImpl; 1175 if (cnx->dso && cnx->egl.eglBindAPI) { 1176 res = cnx->egl.eglBindAPI(api); 1177 } 1178 return res; 1179} 1180 1181EGLenum eglQueryAPI(void) 1182{ 1183 clearError(); 1184 1185 if (egl_init_drivers() == EGL_FALSE) { 1186 return setError(EGL_BAD_PARAMETER, EGL_FALSE); 1187 } 1188 1189 egl_connection_t* const cnx = &gEGLImpl; 1190 if (cnx->dso && cnx->egl.eglQueryAPI) { 1191 return cnx->egl.eglQueryAPI(); 1192 } 1193 1194 // or, it can only be OpenGL ES 1195 return EGL_OPENGL_ES_API; 1196} 1197 1198EGLBoolean eglReleaseThread(void) 1199{ 1200 clearError(); 1201 1202 // If there is context bound to the thread, release it 1203 egl_display_t::loseCurrent(get_context(getContext())); 1204 1205 egl_connection_t* const cnx = &gEGLImpl; 1206 if (cnx->dso && cnx->egl.eglReleaseThread) { 1207 cnx->egl.eglReleaseThread(); 1208 } 1209 1210 egl_tls_t::clearTLS(); 1211#if EGL_TRACE 1212 if (getEGLDebugLevel() > 0) 1213 GLTrace_eglReleaseThread(); 1214#endif 1215 return EGL_TRUE; 1216} 1217 1218EGLSurface eglCreatePbufferFromClientBuffer( 1219 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, 1220 EGLConfig config, const EGLint *attrib_list) 1221{ 1222 clearError(); 1223 1224 egl_connection_t* cnx = NULL; 1225 const egl_display_ptr dp = validate_display_connection(dpy, cnx); 1226 if (!dp) return EGL_FALSE; 1227 if (cnx->egl.eglCreatePbufferFromClientBuffer) { 1228 return cnx->egl.eglCreatePbufferFromClientBuffer( 1229 dp->disp.dpy, buftype, buffer, config, attrib_list); 1230 } 1231 return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE); 1232} 1233 1234// ---------------------------------------------------------------------------- 1235// EGL_EGLEXT_VERSION 3 1236// ---------------------------------------------------------------------------- 1237 1238EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, 1239 const EGLint *attrib_list) 1240{ 1241 clearError(); 1242 1243 const egl_display_ptr dp = validate_display(dpy); 1244 if (!dp) return EGL_FALSE; 1245 1246 SurfaceRef _s(dp.get(), surface); 1247 if (!_s.get()) 1248 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1249 1250 egl_surface_t const * const s = get_surface(surface); 1251 if (s->cnx->egl.eglLockSurfaceKHR) { 1252 return s->cnx->egl.eglLockSurfaceKHR( 1253 dp->disp.dpy, s->surface, attrib_list); 1254 } 1255 return setError(EGL_BAD_DISPLAY, EGL_FALSE); 1256} 1257 1258EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) 1259{ 1260 clearError(); 1261 1262 const egl_display_ptr dp = validate_display(dpy); 1263 if (!dp) return EGL_FALSE; 1264 1265 SurfaceRef _s(dp.get(), surface); 1266 if (!_s.get()) 1267 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1268 1269 egl_surface_t const * const s = get_surface(surface); 1270 if (s->cnx->egl.eglUnlockSurfaceKHR) { 1271 return s->cnx->egl.eglUnlockSurfaceKHR(dp->disp.dpy, s->surface); 1272 } 1273 return setError(EGL_BAD_DISPLAY, EGL_FALSE); 1274} 1275 1276EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, 1277 EGLClientBuffer buffer, const EGLint *attrib_list) 1278{ 1279 clearError(); 1280 1281 const egl_display_ptr dp = validate_display(dpy); 1282 if (!dp) return EGL_NO_IMAGE_KHR; 1283 1284 ContextRef _c(dp.get(), ctx); 1285 egl_context_t * const c = _c.get(); 1286 1287 EGLImageKHR result = EGL_NO_IMAGE_KHR; 1288 egl_connection_t* const cnx = &gEGLImpl; 1289 if (cnx->dso && cnx->egl.eglCreateImageKHR) { 1290 result = cnx->egl.eglCreateImageKHR( 1291 dp->disp.dpy, 1292 c ? c->context : EGL_NO_CONTEXT, 1293 target, buffer, attrib_list); 1294 } 1295 return result; 1296} 1297 1298EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) 1299{ 1300 clearError(); 1301 1302 const egl_display_ptr dp = validate_display(dpy); 1303 if (!dp) return EGL_FALSE; 1304 1305 EGLBoolean result = EGL_FALSE; 1306 egl_connection_t* const cnx = &gEGLImpl; 1307 if (cnx->dso && cnx->egl.eglDestroyImageKHR) { 1308 result = cnx->egl.eglDestroyImageKHR(dp->disp.dpy, img); 1309 } 1310 return result; 1311} 1312 1313// ---------------------------------------------------------------------------- 1314// EGL_EGLEXT_VERSION 5 1315// ---------------------------------------------------------------------------- 1316 1317 1318EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) 1319{ 1320 clearError(); 1321 1322 const egl_display_ptr dp = validate_display(dpy); 1323 if (!dp) return EGL_NO_SYNC_KHR; 1324 1325 EGLSyncKHR result = EGL_NO_SYNC_KHR; 1326 egl_connection_t* const cnx = &gEGLImpl; 1327 if (cnx->dso && cnx->egl.eglCreateSyncKHR) { 1328 result = cnx->egl.eglCreateSyncKHR(dp->disp.dpy, type, attrib_list); 1329 } 1330 return result; 1331} 1332 1333EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) 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.eglDestroySyncKHR) { 1343 result = cnx->egl.eglDestroySyncKHR(dp->disp.dpy, sync); 1344 } 1345 return result; 1346} 1347 1348EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) { 1349 clearError(); 1350 1351 const egl_display_ptr dp = validate_display(dpy); 1352 if (!dp) return EGL_FALSE; 1353 1354 EGLBoolean result = EGL_FALSE; 1355 egl_connection_t* const cnx = &gEGLImpl; 1356 if (cnx->dso && cnx->egl.eglSignalSyncKHR) { 1357 result = cnx->egl.eglSignalSyncKHR( 1358 dp->disp.dpy, sync, mode); 1359 } 1360 return result; 1361} 1362 1363EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, 1364 EGLint flags, EGLTimeKHR timeout) 1365{ 1366 clearError(); 1367 1368 const egl_display_ptr dp = validate_display(dpy); 1369 if (!dp) return EGL_FALSE; 1370 1371 EGLBoolean result = EGL_FALSE; 1372 egl_connection_t* const cnx = &gEGLImpl; 1373 if (cnx->dso && cnx->egl.eglClientWaitSyncKHR) { 1374 result = cnx->egl.eglClientWaitSyncKHR( 1375 dp->disp.dpy, sync, flags, timeout); 1376 } 1377 return result; 1378} 1379 1380EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, 1381 EGLint attribute, EGLint *value) 1382{ 1383 clearError(); 1384 1385 const egl_display_ptr dp = validate_display(dpy); 1386 if (!dp) return EGL_FALSE; 1387 1388 EGLBoolean result = EGL_FALSE; 1389 egl_connection_t* const cnx = &gEGLImpl; 1390 if (cnx->dso && cnx->egl.eglGetSyncAttribKHR) { 1391 result = cnx->egl.eglGetSyncAttribKHR( 1392 dp->disp.dpy, sync, attribute, value); 1393 } 1394 return result; 1395} 1396 1397// ---------------------------------------------------------------------------- 1398// EGL_EGLEXT_VERSION 15 1399// ---------------------------------------------------------------------------- 1400 1401EGLint eglWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) { 1402 clearError(); 1403 const egl_display_ptr dp = validate_display(dpy); 1404 if (!dp) return EGL_FALSE; 1405 EGLint result = EGL_FALSE; 1406 egl_connection_t* const cnx = &gEGLImpl; 1407 if (cnx->dso && cnx->egl.eglWaitSyncKHR) { 1408 result = cnx->egl.eglWaitSyncKHR(dp->disp.dpy, sync, flags); 1409 } 1410 return result; 1411} 1412 1413// ---------------------------------------------------------------------------- 1414// ANDROID extensions 1415// ---------------------------------------------------------------------------- 1416 1417EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync) 1418{ 1419 clearError(); 1420 1421 const egl_display_ptr dp = validate_display(dpy); 1422 if (!dp) return EGL_NO_NATIVE_FENCE_FD_ANDROID; 1423 1424 EGLint result = EGL_NO_NATIVE_FENCE_FD_ANDROID; 1425 egl_connection_t* const cnx = &gEGLImpl; 1426 if (cnx->dso && cnx->egl.eglDupNativeFenceFDANDROID) { 1427 result = cnx->egl.eglDupNativeFenceFDANDROID(dp->disp.dpy, sync); 1428 } 1429 return result; 1430} 1431 1432EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, 1433 EGLnsecsANDROID time) 1434{ 1435 clearError(); 1436 1437 const egl_display_ptr dp = validate_display(dpy); 1438 if (!dp) { 1439 return EGL_FALSE; 1440 } 1441 1442 SurfaceRef _s(dp.get(), surface); 1443 if (!_s.get()) { 1444 setError(EGL_BAD_SURFACE, EGL_FALSE); 1445 return EGL_FALSE; 1446 } 1447 1448 egl_surface_t const * const s = get_surface(surface); 1449 native_window_set_buffers_timestamp(s->win.get(), time); 1450 1451 return EGL_TRUE; 1452} 1453 1454// ---------------------------------------------------------------------------- 1455// NVIDIA extensions 1456// ---------------------------------------------------------------------------- 1457EGLuint64NV eglGetSystemTimeFrequencyNV() 1458{ 1459 clearError(); 1460 1461 if (egl_init_drivers() == EGL_FALSE) { 1462 return setError(EGL_BAD_PARAMETER, EGL_FALSE); 1463 } 1464 1465 EGLuint64NV ret = 0; 1466 egl_connection_t* const cnx = &gEGLImpl; 1467 1468 if (cnx->dso && cnx->egl.eglGetSystemTimeFrequencyNV) { 1469 return cnx->egl.eglGetSystemTimeFrequencyNV(); 1470 } 1471 1472 return setErrorQuiet(EGL_BAD_DISPLAY, 0); 1473} 1474 1475EGLuint64NV eglGetSystemTimeNV() 1476{ 1477 clearError(); 1478 1479 if (egl_init_drivers() == EGL_FALSE) { 1480 return setError(EGL_BAD_PARAMETER, EGL_FALSE); 1481 } 1482 1483 EGLuint64NV ret = 0; 1484 egl_connection_t* const cnx = &gEGLImpl; 1485 1486 if (cnx->dso && cnx->egl.eglGetSystemTimeNV) { 1487 return cnx->egl.eglGetSystemTimeNV(); 1488 } 1489 1490 return setErrorQuiet(EGL_BAD_DISPLAY, 0); 1491} 1492