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