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