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