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