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