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