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