eglApi.cpp revision bee205fd58a27c10a0895de5339e76025d429d2b
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#include <ctype.h> 18#include <stdlib.h> 19#include <string.h> 20 21#include <hardware/gralloc.h> 22#include <system/window.h> 23 24#include <EGL/egl.h> 25#include <EGL/eglext.h> 26#include <GLES/gl.h> 27#include <GLES/glext.h> 28 29#include <cutils/log.h> 30#include <cutils/atomic.h> 31#include <cutils/properties.h> 32#include <cutils/memory.h> 33 34#include <utils/KeyedVector.h> 35#include <utils/SortedVector.h> 36#include <utils/String8.h> 37 38#include "egl_impl.h" 39#include "egl_tls.h" 40#include "glesv2dbg.h" 41#include "hooks.h" 42 43#include "egl_display.h" 44#include "egl_impl.h" 45#include "egl_object.h" 46#include "egl_tls.h" 47 48using namespace android; 49 50// ---------------------------------------------------------------------------- 51 52static char const * const sVendorString = "Android"; 53static char const * const sVersionString = "1.4 Android META-EGL"; 54static char const * const sClientApiString = "OpenGL ES"; 55static char const * const sExtensionString = 56 "EGL_KHR_image " 57 "EGL_KHR_image_base " 58 "EGL_KHR_image_pixmap " 59 "EGL_KHR_gl_texture_2D_image " 60 "EGL_KHR_gl_texture_cubemap_image " 61 "EGL_KHR_gl_renderbuffer_image " 62 "EGL_KHR_fence_sync " 63 "EGL_ANDROID_image_native_buffer " 64 "EGL_ANDROID_swap_rectangle " 65 ; 66 67struct extention_map_t { 68 const char* name; 69 __eglMustCastToProperFunctionPointerType address; 70}; 71 72static const extention_map_t sExtentionMap[] = { 73 { "eglLockSurfaceKHR", 74 (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR }, 75 { "eglUnlockSurfaceKHR", 76 (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR }, 77 { "eglCreateImageKHR", 78 (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR }, 79 { "eglDestroyImageKHR", 80 (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR }, 81 { "eglSetSwapRectangleANDROID", 82 (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID }, 83}; 84 85// accesses protected by sExtensionMapMutex 86static DefaultKeyedVector<String8, __eglMustCastToProperFunctionPointerType> sGLExtentionMap; 87static int sGLExtentionSlot = 0; 88static pthread_mutex_t sExtensionMapMutex = PTHREAD_MUTEX_INITIALIZER; 89 90static void(*findProcAddress(const char* name, 91 const extention_map_t* map, size_t n))() { 92 for (uint32_t i=0 ; i<n ; i++) { 93 if (!strcmp(name, map[i].name)) { 94 return map[i].address; 95 } 96 } 97 return NULL; 98} 99 100// ---------------------------------------------------------------------------- 101 102template<typename T> 103static __attribute__((noinline)) 104int binarySearch(T const sortedArray[], int first, int last, T key) { 105 while (first <= last) { 106 int mid = (first + last) / 2; 107 if (sortedArray[mid] < key) { 108 first = mid + 1; 109 } else if (key < sortedArray[mid]) { 110 last = mid - 1; 111 } else { 112 return mid; 113 } 114 } 115 return -1; 116} 117 118// ---------------------------------------------------------------------------- 119 120namespace android { 121extern void setGLHooksThreadSpecific(gl_hooks_t const *value); 122extern EGLBoolean egl_init_drivers(); 123extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS]; 124extern int gEGLDebugLevel; 125extern gl_hooks_t gHooksTrace; 126extern gl_hooks_t gHooksDebug; 127} // namespace android; 128 129// ---------------------------------------------------------------------------- 130 131static inline void clearError() { egl_tls_t::clearError(); } 132static inline EGLContext getContext() { return egl_tls_t::getContext(); } 133 134// ---------------------------------------------------------------------------- 135 136EGLDisplay eglGetDisplay(EGLNativeDisplayType display) 137{ 138 clearError(); 139 140 uint32_t index = uint32_t(display); 141 if (index >= NUM_DISPLAYS) { 142 return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); 143 } 144 145 if (egl_init_drivers() == EGL_FALSE) { 146 return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); 147 } 148 149 EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display); 150 return dpy; 151} 152 153// ---------------------------------------------------------------------------- 154// Initialization 155// ---------------------------------------------------------------------------- 156 157EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) 158{ 159 clearError(); 160 161 egl_display_t * const dp = get_display(dpy); 162 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE); 163 164 EGLBoolean res = dp->initialize(major, minor); 165 166 return res; 167} 168 169EGLBoolean eglTerminate(EGLDisplay dpy) 170{ 171 // NOTE: don't unload the drivers b/c some APIs can be called 172 // after eglTerminate() has been called. eglTerminate() only 173 // terminates an EGLDisplay, not a EGL itself. 174 175 clearError(); 176 177 egl_display_t* const dp = get_display(dpy); 178 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE); 179 180 EGLBoolean res = dp->terminate(); 181 182 return res; 183} 184 185// ---------------------------------------------------------------------------- 186// configuration 187// ---------------------------------------------------------------------------- 188 189EGLBoolean eglGetConfigs( EGLDisplay dpy, 190 EGLConfig *configs, 191 EGLint config_size, EGLint *num_config) 192{ 193 clearError(); 194 195 egl_display_t const * const dp = validate_display(dpy); 196 if (!dp) return EGL_FALSE; 197 198 GLint numConfigs = dp->numTotalConfigs; 199 if (!configs) { 200 *num_config = numConfigs; 201 return EGL_TRUE; 202 } 203 204 GLint n = 0; 205 for (intptr_t i=0 ; i<dp->numTotalConfigs && config_size ; i++) { 206 *configs++ = EGLConfig(i); 207 config_size--; 208 n++; 209 } 210 211 *num_config = n; 212 return EGL_TRUE; 213} 214 215EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, 216 EGLConfig *configs, EGLint config_size, 217 EGLint *num_config) 218{ 219 clearError(); 220 221 egl_display_t const * const dp = validate_display(dpy); 222 if (!dp) return EGL_FALSE; 223 224 if (num_config==0) { 225 return setError(EGL_BAD_PARAMETER, EGL_FALSE); 226 } 227 228 EGLint n; 229 EGLBoolean res = EGL_FALSE; 230 *num_config = 0; 231 232 233 // It is unfortunate, but we need to remap the EGL_CONFIG_IDs, 234 // to do this, we have to go through the attrib_list array once 235 // to figure out both its size and if it contains an EGL_CONFIG_ID 236 // key. If so, the full array is copied and patched. 237 // NOTE: we assume that there can be only one occurrence 238 // of EGL_CONFIG_ID. 239 240 EGLint patch_index = -1; 241 GLint attr; 242 size_t size = 0; 243 if (attrib_list) { 244 while ((attr=attrib_list[size]) != EGL_NONE) { 245 if (attr == EGL_CONFIG_ID) 246 patch_index = size; 247 size += 2; 248 } 249 } 250 if (patch_index >= 0) { 251 size += 2; // we need copy the sentinel as well 252 EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint)); 253 if (new_list == 0) 254 return setError(EGL_BAD_ALLOC, EGL_FALSE); 255 memcpy(new_list, attrib_list, size*sizeof(EGLint)); 256 257 // patch the requested EGL_CONFIG_ID 258 bool found = false; 259 EGLConfig ourConfig(0); 260 EGLint& configId(new_list[patch_index+1]); 261 for (intptr_t i=0 ; i<dp->numTotalConfigs ; i++) { 262 if (dp->configs[i].configId == configId) { 263 ourConfig = EGLConfig(i); 264 configId = dp->configs[i].implConfigId; 265 found = true; 266 break; 267 } 268 } 269 270 egl_connection_t* const cnx = &gEGLImpl[dp->configs[intptr_t(ourConfig)].impl]; 271 if (found && cnx->dso) { 272 // and switch to the new list 273 attrib_list = const_cast<const EGLint *>(new_list); 274 275 // At this point, the only configuration that can match is 276 // dp->configs[i][index], however, we don't know if it would be 277 // rejected because of the other attributes, so we do have to call 278 // cnx->egl.eglChooseConfig() -- but we don't have to loop 279 // through all the EGLimpl[]. 280 // We also know we can only get a single config back, and we know 281 // which one. 282 283 res = cnx->egl.eglChooseConfig( 284 dp->disp[ dp->configs[intptr_t(ourConfig)].impl ].dpy, 285 attrib_list, configs, config_size, &n); 286 if (res && n>0) { 287 // n has to be 0 or 1, by construction, and we already know 288 // which config it will return (since there can be only one). 289 if (configs) { 290 configs[0] = ourConfig; 291 } 292 *num_config = 1; 293 } 294 } 295 296 free(const_cast<EGLint *>(attrib_list)); 297 return res; 298 } 299 300 301 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { 302 egl_connection_t* const cnx = &gEGLImpl[i]; 303 if (cnx->dso) { 304 if (cnx->egl.eglChooseConfig( 305 dp->disp[i].dpy, attrib_list, configs, config_size, &n)) { 306 if (configs) { 307 // now we need to convert these client EGLConfig to our 308 // internal EGLConfig format. 309 // This is done in O(n Log(n)) time. 310 for (int j=0 ; j<n ; j++) { 311 egl_config_t key(i, configs[j]); 312 intptr_t index = binarySearch<egl_config_t>( 313 dp->configs, 0, dp->numTotalConfigs, key); 314 if (index >= 0) { 315 configs[j] = EGLConfig(index); 316 } else { 317 return setError(EGL_BAD_CONFIG, EGL_FALSE); 318 } 319 } 320 configs += n; 321 config_size -= n; 322 } 323 *num_config += n; 324 res = EGL_TRUE; 325 } 326 } 327 } 328 return res; 329} 330 331EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, 332 EGLint attribute, EGLint *value) 333{ 334 clearError(); 335 336 egl_display_t const* dp = 0; 337 egl_connection_t* cnx = validate_display_config(dpy, config, dp); 338 if (!cnx) return EGL_FALSE; 339 340 if (attribute == EGL_CONFIG_ID) { 341 *value = dp->configs[intptr_t(config)].configId; 342 return EGL_TRUE; 343 } 344 return cnx->egl.eglGetConfigAttrib( 345 dp->disp[ dp->configs[intptr_t(config)].impl ].dpy, 346 dp->configs[intptr_t(config)].config, attribute, value); 347} 348 349// ---------------------------------------------------------------------------- 350// surfaces 351// ---------------------------------------------------------------------------- 352 353EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, 354 NativeWindowType window, 355 const EGLint *attrib_list) 356{ 357 clearError(); 358 359 egl_display_t const* dp = 0; 360 egl_connection_t* cnx = validate_display_config(dpy, config, dp); 361 if (cnx) { 362 EGLDisplay iDpy = dp->disp[ dp->configs[intptr_t(config)].impl ].dpy; 363 EGLConfig iConfig = dp->configs[intptr_t(config)].config; 364 EGLint format; 365 366 // set the native window's buffers format to match this config 367 if (cnx->egl.eglGetConfigAttrib(iDpy, 368 iConfig, EGL_NATIVE_VISUAL_ID, &format)) { 369 if (format != 0) { 370 int err = native_window_set_buffers_format(window, format); 371 if (err != 0) { 372 LOGE("error setting native window pixel format: %s (%d)", 373 strerror(-err), err); 374 return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); 375 } 376 } 377 } 378 379 EGLSurface surface = cnx->egl.eglCreateWindowSurface( 380 iDpy, iConfig, window, attrib_list); 381 if (surface != EGL_NO_SURFACE) { 382 egl_surface_t* s = new egl_surface_t(dpy, config, window, surface, 383 dp->configs[intptr_t(config)].impl, cnx); 384 return s; 385 } 386 } 387 return EGL_NO_SURFACE; 388} 389 390EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, 391 NativePixmapType pixmap, 392 const EGLint *attrib_list) 393{ 394 clearError(); 395 396 egl_display_t const* dp = 0; 397 egl_connection_t* cnx = validate_display_config(dpy, config, dp); 398 if (cnx) { 399 EGLSurface surface = cnx->egl.eglCreatePixmapSurface( 400 dp->disp[ dp->configs[intptr_t(config)].impl ].dpy, 401 dp->configs[intptr_t(config)].config, pixmap, attrib_list); 402 if (surface != EGL_NO_SURFACE) { 403 egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface, 404 dp->configs[intptr_t(config)].impl, cnx); 405 return s; 406 } 407 } 408 return EGL_NO_SURFACE; 409} 410 411EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, 412 const EGLint *attrib_list) 413{ 414 clearError(); 415 416 egl_display_t const* dp = 0; 417 egl_connection_t* cnx = validate_display_config(dpy, config, dp); 418 if (cnx) { 419 EGLSurface surface = cnx->egl.eglCreatePbufferSurface( 420 dp->disp[ dp->configs[intptr_t(config)].impl ].dpy, 421 dp->configs[intptr_t(config)].config, attrib_list); 422 if (surface != EGL_NO_SURFACE) { 423 egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface, 424 dp->configs[intptr_t(config)].impl, cnx); 425 return s; 426 } 427 } 428 return EGL_NO_SURFACE; 429} 430 431EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) 432{ 433 clearError(); 434 435 egl_display_t const * const dp = validate_display(dpy); 436 if (!dp) return EGL_FALSE; 437 438 SurfaceRef _s(surface); 439 if (!_s.get()) 440 return setError(EGL_BAD_SURFACE, EGL_FALSE); 441 442 egl_surface_t * const s = get_surface(surface); 443 EGLBoolean result = s->cnx->egl.eglDestroySurface( 444 dp->disp[s->impl].dpy, s->surface); 445 if (result == EGL_TRUE) { 446 if (s->win != NULL) { 447 native_window_set_buffers_geometry(s->win.get(), 0, 0, 0); 448 } 449 _s.terminate(); 450 } 451 return result; 452} 453 454EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface, 455 EGLint attribute, EGLint *value) 456{ 457 clearError(); 458 459 egl_display_t const * const dp = validate_display(dpy); 460 if (!dp) return EGL_FALSE; 461 462 SurfaceRef _s(surface); 463 if (!_s.get()) 464 return setError(EGL_BAD_SURFACE, EGL_FALSE); 465 466 egl_surface_t const * const s = get_surface(surface); 467 EGLBoolean result(EGL_TRUE); 468 if (attribute == EGL_CONFIG_ID) { 469 // We need to remap EGL_CONFIG_IDs 470 *value = dp->configs[intptr_t(s->config)].configId; 471 } else { 472 result = s->cnx->egl.eglQuerySurface( 473 dp->disp[s->impl].dpy, s->surface, attribute, value); 474 } 475 476 return result; 477} 478 479// ---------------------------------------------------------------------------- 480// Contexts 481// ---------------------------------------------------------------------------- 482 483EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, 484 EGLContext share_list, const EGLint *attrib_list) 485{ 486 clearError(); 487 488 egl_display_t const* dp = 0; 489 egl_connection_t* cnx = validate_display_config(dpy, config, dp); 490 if (cnx) { 491 if (share_list != EGL_NO_CONTEXT) { 492 egl_context_t* const c = get_context(share_list); 493 share_list = c->context; 494 } 495 EGLContext context = cnx->egl.eglCreateContext( 496 dp->disp[ dp->configs[intptr_t(config)].impl ].dpy, 497 dp->configs[intptr_t(config)].config, 498 share_list, attrib_list); 499 if (context != EGL_NO_CONTEXT) { 500 // figure out if it's a GLESv1 or GLESv2 501 int version = 0; 502 if (attrib_list) { 503 while (*attrib_list != EGL_NONE) { 504 GLint attr = *attrib_list++; 505 GLint value = *attrib_list++; 506 if (attr == EGL_CONTEXT_CLIENT_VERSION) { 507 if (value == 1) { 508 version = GLESv1_INDEX; 509 } else if (value == 2) { 510 version = GLESv2_INDEX; 511 } 512 } 513 }; 514 } 515 egl_context_t* c = new egl_context_t(dpy, context, config, 516 dp->configs[intptr_t(config)].impl, cnx, version); 517 return c; 518 } 519 } 520 return EGL_NO_CONTEXT; 521} 522 523EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) 524{ 525 clearError(); 526 527 egl_display_t const * const dp = validate_display(dpy); 528 if (!dp) 529 return EGL_FALSE; 530 531 ContextRef _c(ctx); 532 if (!_c.get()) 533 return setError(EGL_BAD_CONTEXT, EGL_FALSE); 534 535 egl_context_t * const c = get_context(ctx); 536 EGLBoolean result = c->cnx->egl.eglDestroyContext( 537 dp->disp[c->impl].dpy, c->context); 538 if (result == EGL_TRUE) { 539 _c.terminate(); 540 } 541 return result; 542} 543 544static void loseCurrent(egl_context_t * cur_c) 545{ 546 if (cur_c) { 547 egl_surface_t * cur_r = get_surface(cur_c->read); 548 egl_surface_t * cur_d = get_surface(cur_c->draw); 549 550 // by construction, these are either 0 or valid (possibly terminated) 551 // it should be impossible for these to be invalid 552 ContextRef _cur_c(cur_c); 553 SurfaceRef _cur_r(cur_r); 554 SurfaceRef _cur_d(cur_d); 555 556 cur_c->read = NULL; 557 cur_c->draw = NULL; 558 559 _cur_c.release(); 560 _cur_r.release(); 561 _cur_d.release(); 562 } 563} 564 565EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, 566 EGLSurface read, EGLContext ctx) 567{ 568 clearError(); 569 570 egl_display_t const * const dp = get_display(dpy); 571 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE); 572 573 // If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not 574 // EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is 575 // a valid but uninitialized display. 576 if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) || 577 (draw != EGL_NO_SURFACE) ) { 578 if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, EGL_FALSE); 579 } 580 581 // get a reference to the object passed in 582 ContextRef _c(ctx); 583 SurfaceRef _d(draw); 584 SurfaceRef _r(read); 585 586 // validate the context (if not EGL_NO_CONTEXT) 587 if ((ctx != EGL_NO_CONTEXT) && !_c.get()) { 588 // EGL_NO_CONTEXT is valid 589 return EGL_FALSE; 590 } 591 592 // these are the underlying implementation's object 593 EGLContext impl_ctx = EGL_NO_CONTEXT; 594 EGLSurface impl_draw = EGL_NO_SURFACE; 595 EGLSurface impl_read = EGL_NO_SURFACE; 596 597 // these are our objects structs passed in 598 egl_context_t * c = NULL; 599 egl_surface_t const * d = NULL; 600 egl_surface_t const * r = NULL; 601 602 // these are the current objects structs 603 egl_context_t * cur_c = get_context(getContext()); 604 605 if (ctx != EGL_NO_CONTEXT) { 606 c = get_context(ctx); 607 impl_ctx = c->context; 608 } else { 609 // no context given, use the implementation of the current context 610 if (cur_c == NULL) { 611 // no current context 612 if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) { 613 // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT); 614 return setError(EGL_BAD_MATCH, EGL_FALSE); 615 } 616 // not an error, there is just no current context. 617 return EGL_TRUE; 618 } 619 } 620 621 // retrieve the underlying implementation's draw EGLSurface 622 if (draw != EGL_NO_SURFACE) { 623 d = get_surface(draw); 624 // make sure the EGLContext and EGLSurface passed in are for 625 // the same driver 626 if (c && d->impl != c->impl) 627 return setError(EGL_BAD_MATCH, EGL_FALSE); 628 impl_draw = d->surface; 629 } 630 631 // retrieve the underlying implementation's read EGLSurface 632 if (read != EGL_NO_SURFACE) { 633 r = get_surface(read); 634 // make sure the EGLContext and EGLSurface passed in are for 635 // the same driver 636 if (c && r->impl != c->impl) 637 return setError(EGL_BAD_MATCH, EGL_FALSE); 638 impl_read = r->surface; 639 } 640 641 EGLBoolean result; 642 643 if (c) { 644 result = c->cnx->egl.eglMakeCurrent( 645 dp->disp[c->impl].dpy, impl_draw, impl_read, impl_ctx); 646 } else { 647 result = cur_c->cnx->egl.eglMakeCurrent( 648 dp->disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx); 649 } 650 651 if (result == EGL_TRUE) { 652 653 loseCurrent(cur_c); 654 655 if (ctx != EGL_NO_CONTEXT) { 656 setGLHooksThreadSpecific(c->cnx->hooks[c->version]); 657 egl_tls_t::setContext(ctx); 658 if (gEGLDebugLevel > 0) { 659 CreateDbgContext(c->version, c->cnx->hooks[c->version]); 660 } 661 _c.acquire(); 662 _r.acquire(); 663 _d.acquire(); 664 c->read = read; 665 c->draw = draw; 666 } else { 667 setGLHooksThreadSpecific(&gHooksNoContext); 668 egl_tls_t::setContext(EGL_NO_CONTEXT); 669 } 670 } 671 return result; 672} 673 674 675EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx, 676 EGLint attribute, EGLint *value) 677{ 678 clearError(); 679 680 egl_display_t const * const dp = validate_display(dpy); 681 if (!dp) return EGL_FALSE; 682 683 ContextRef _c(ctx); 684 if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE); 685 686 egl_context_t * const c = get_context(ctx); 687 688 EGLBoolean result(EGL_TRUE); 689 if (attribute == EGL_CONFIG_ID) { 690 *value = dp->configs[intptr_t(c->config)].configId; 691 } else { 692 // We need to remap EGL_CONFIG_IDs 693 result = c->cnx->egl.eglQueryContext( 694 dp->disp[c->impl].dpy, c->context, attribute, value); 695 } 696 697 return result; 698} 699 700EGLContext eglGetCurrentContext(void) 701{ 702 // could be called before eglInitialize(), but we wouldn't have a context 703 // then, and this function would correctly return EGL_NO_CONTEXT. 704 705 clearError(); 706 707 EGLContext ctx = getContext(); 708 return ctx; 709} 710 711EGLSurface eglGetCurrentSurface(EGLint readdraw) 712{ 713 // could be called before eglInitialize(), but we wouldn't have a context 714 // then, and this function would correctly return EGL_NO_SURFACE. 715 716 clearError(); 717 718 EGLContext ctx = getContext(); 719 if (ctx) { 720 egl_context_t const * const c = get_context(ctx); 721 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE); 722 switch (readdraw) { 723 case EGL_READ: return c->read; 724 case EGL_DRAW: return c->draw; 725 default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE); 726 } 727 } 728 return EGL_NO_SURFACE; 729} 730 731EGLDisplay eglGetCurrentDisplay(void) 732{ 733 // could be called before eglInitialize(), but we wouldn't have a context 734 // then, and this function would correctly return EGL_NO_DISPLAY. 735 736 clearError(); 737 738 EGLContext ctx = getContext(); 739 if (ctx) { 740 egl_context_t const * const c = get_context(ctx); 741 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE); 742 return c->dpy; 743 } 744 return EGL_NO_DISPLAY; 745} 746 747EGLBoolean eglWaitGL(void) 748{ 749 // could be called before eglInitialize(), but we wouldn't have a context 750 // then, and this function would return GL_TRUE, which isn't wrong. 751 752 clearError(); 753 754 EGLBoolean res = EGL_TRUE; 755 EGLContext ctx = getContext(); 756 if (ctx) { 757 egl_context_t const * const c = get_context(ctx); 758 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE); 759 if (uint32_t(c->impl)>=2) 760 return setError(EGL_BAD_CONTEXT, EGL_FALSE); 761 egl_connection_t* const cnx = &gEGLImpl[c->impl]; 762 if (!cnx->dso) 763 return setError(EGL_BAD_CONTEXT, EGL_FALSE); 764 res = cnx->egl.eglWaitGL(); 765 } 766 return res; 767} 768 769EGLBoolean eglWaitNative(EGLint engine) 770{ 771 // could be called before eglInitialize(), but we wouldn't have a context 772 // then, and this function would return GL_TRUE, which isn't wrong. 773 774 clearError(); 775 776 EGLBoolean res = EGL_TRUE; 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_FALSE); 781 if (uint32_t(c->impl)>=2) 782 return setError(EGL_BAD_CONTEXT, EGL_FALSE); 783 egl_connection_t* const cnx = &gEGLImpl[c->impl]; 784 if (!cnx->dso) 785 return setError(EGL_BAD_CONTEXT, EGL_FALSE); 786 res = cnx->egl.eglWaitNative(engine); 787 } 788 return res; 789} 790 791EGLint eglGetError(void) 792{ 793 EGLint result = EGL_SUCCESS; 794 EGLint err; 795 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { 796 err = EGL_SUCCESS; 797 egl_connection_t* const cnx = &gEGLImpl[i]; 798 if (cnx->dso) 799 err = cnx->egl.eglGetError(); 800 if (err!=EGL_SUCCESS && result==EGL_SUCCESS) 801 result = err; 802 } 803 err = egl_tls_t::getError(); 804 if (result == EGL_SUCCESS) 805 result = err; 806 return result; 807} 808 809// Note: Similar implementations of these functions also exist in 810// gl2.cpp and gl.cpp, and are used by applications that call the 811// exported entry points directly. 812typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image); 813typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image); 814 815static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_impl = NULL; 816static PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES_impl = NULL; 817 818static void glEGLImageTargetTexture2DOES_wrapper(GLenum target, GLeglImageOES image) 819{ 820 GLeglImageOES implImage = 821 (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image); 822 glEGLImageTargetTexture2DOES_impl(target, implImage); 823} 824 825static void glEGLImageTargetRenderbufferStorageOES_wrapper(GLenum target, GLeglImageOES image) 826{ 827 GLeglImageOES implImage = 828 (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image); 829 glEGLImageTargetRenderbufferStorageOES_impl(target, implImage); 830} 831 832__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) 833{ 834 // eglGetProcAddress() could be the very first function called 835 // in which case we must make sure we've initialized ourselves, this 836 // happens the first time egl_get_display() is called. 837 838 clearError(); 839 840 if (egl_init_drivers() == EGL_FALSE) { 841 setError(EGL_BAD_PARAMETER, NULL); 842 return NULL; 843 } 844 845 __eglMustCastToProperFunctionPointerType addr; 846 addr = findProcAddress(procname, sExtentionMap, NELEM(sExtentionMap)); 847 if (addr) return addr; 848 849 // this protects accesses to sGLExtentionMap and sGLExtentionSlot 850 pthread_mutex_lock(&sExtensionMapMutex); 851 852 /* 853 * Since eglGetProcAddress() is not associated to anything, it needs 854 * to return a function pointer that "works" regardless of what 855 * the current context is. 856 * 857 * For this reason, we return a "forwarder", a small stub that takes 858 * care of calling the function associated with the context 859 * currently bound. 860 * 861 * We first look for extensions we've already resolved, if we're seeing 862 * this extension for the first time, we go through all our 863 * implementations and call eglGetProcAddress() and record the 864 * result in the appropriate implementation hooks and return the 865 * address of the forwarder corresponding to that hook set. 866 * 867 */ 868 869 const String8 name(procname); 870 addr = sGLExtentionMap.valueFor(name); 871 const int slot = sGLExtentionSlot; 872 873 LOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS, 874 "no more slots for eglGetProcAddress(\"%s\")", 875 procname); 876 877 if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) { 878 bool found = false; 879 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { 880 egl_connection_t* const cnx = &gEGLImpl[i]; 881 if (cnx->dso && cnx->egl.eglGetProcAddress) { 882 found = true; 883 // Extensions are independent of the bound context 884 cnx->hooks[GLESv1_INDEX]->ext.extensions[slot] = 885 cnx->hooks[GLESv2_INDEX]->ext.extensions[slot] = 886#if EGL_TRACE 887 gHooksDebug.ext.extensions[slot] = gHooksTrace.ext.extensions[slot] = 888#endif 889 cnx->egl.eglGetProcAddress(procname); 890 } 891 } 892 if (found) { 893 addr = gExtensionForwarders[slot]; 894 895 if (!strcmp(procname, "glEGLImageTargetTexture2DOES")) { 896 glEGLImageTargetTexture2DOES_impl = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)addr; 897 addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetTexture2DOES_wrapper; 898 } 899 if (!strcmp(procname, "glEGLImageTargetRenderbufferStorageOES")) { 900 glEGLImageTargetRenderbufferStorageOES_impl = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)addr; 901 addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetRenderbufferStorageOES_wrapper; 902 } 903 904 sGLExtentionMap.add(name, addr); 905 sGLExtentionSlot++; 906 } 907 } 908 909 pthread_mutex_unlock(&sExtensionMapMutex); 910 return addr; 911} 912 913EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw) 914{ 915 EGLBoolean Debug_eglSwapBuffers(EGLDisplay dpy, EGLSurface draw); 916 if (gEGLDebugLevel > 0) 917 Debug_eglSwapBuffers(dpy, draw); 918 919 clearError(); 920 921 egl_display_t const * const dp = validate_display(dpy); 922 if (!dp) return EGL_FALSE; 923 924 SurfaceRef _s(draw); 925 if (!_s.get()) 926 return setError(EGL_BAD_SURFACE, EGL_FALSE); 927 928 egl_surface_t const * const s = get_surface(draw); 929 return s->cnx->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface); 930} 931 932EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface, 933 NativePixmapType target) 934{ 935 clearError(); 936 937 egl_display_t const * const dp = validate_display(dpy); 938 if (!dp) return EGL_FALSE; 939 940 SurfaceRef _s(surface); 941 if (!_s.get()) 942 return setError(EGL_BAD_SURFACE, EGL_FALSE); 943 944 egl_surface_t const * const s = get_surface(surface); 945 return s->cnx->egl.eglCopyBuffers( 946 dp->disp[s->impl].dpy, s->surface, target); 947} 948 949const char* eglQueryString(EGLDisplay dpy, EGLint name) 950{ 951 clearError(); 952 953 egl_display_t const * const dp = validate_display(dpy); 954 if (!dp) return (const char *) NULL; 955 956 switch (name) { 957 case EGL_VENDOR: 958 return sVendorString; 959 case EGL_VERSION: 960 return sVersionString; 961 case EGL_EXTENSIONS: 962 return sExtensionString; 963 case EGL_CLIENT_APIS: 964 return sClientApiString; 965 } 966 return setError(EGL_BAD_PARAMETER, (const char *)0); 967} 968 969 970// ---------------------------------------------------------------------------- 971// EGL 1.1 972// ---------------------------------------------------------------------------- 973 974EGLBoolean eglSurfaceAttrib( 975 EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) 976{ 977 clearError(); 978 979 egl_display_t const * const dp = validate_display(dpy); 980 if (!dp) return EGL_FALSE; 981 982 SurfaceRef _s(surface); 983 if (!_s.get()) 984 return setError(EGL_BAD_SURFACE, EGL_FALSE); 985 986 egl_surface_t const * const s = get_surface(surface); 987 if (s->cnx->egl.eglSurfaceAttrib) { 988 return s->cnx->egl.eglSurfaceAttrib( 989 dp->disp[s->impl].dpy, s->surface, attribute, value); 990 } 991 return setError(EGL_BAD_SURFACE, EGL_FALSE); 992} 993 994EGLBoolean eglBindTexImage( 995 EGLDisplay dpy, EGLSurface surface, EGLint buffer) 996{ 997 clearError(); 998 999 egl_display_t const * const dp = validate_display(dpy); 1000 if (!dp) return EGL_FALSE; 1001 1002 SurfaceRef _s(surface); 1003 if (!_s.get()) 1004 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1005 1006 egl_surface_t const * const s = get_surface(surface); 1007 if (s->cnx->egl.eglBindTexImage) { 1008 return s->cnx->egl.eglBindTexImage( 1009 dp->disp[s->impl].dpy, s->surface, buffer); 1010 } 1011 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1012} 1013 1014EGLBoolean eglReleaseTexImage( 1015 EGLDisplay dpy, EGLSurface surface, EGLint buffer) 1016{ 1017 clearError(); 1018 1019 egl_display_t const * const dp = validate_display(dpy); 1020 if (!dp) return EGL_FALSE; 1021 1022 SurfaceRef _s(surface); 1023 if (!_s.get()) 1024 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1025 1026 egl_surface_t const * const s = get_surface(surface); 1027 if (s->cnx->egl.eglReleaseTexImage) { 1028 return s->cnx->egl.eglReleaseTexImage( 1029 dp->disp[s->impl].dpy, s->surface, buffer); 1030 } 1031 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1032} 1033 1034EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) 1035{ 1036 clearError(); 1037 1038 egl_display_t const * const dp = validate_display(dpy); 1039 if (!dp) return EGL_FALSE; 1040 1041 EGLBoolean res = EGL_TRUE; 1042 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { 1043 egl_connection_t* const cnx = &gEGLImpl[i]; 1044 if (cnx->dso) { 1045 if (cnx->egl.eglSwapInterval) { 1046 if (cnx->egl.eglSwapInterval( 1047 dp->disp[i].dpy, interval) == EGL_FALSE) { 1048 res = EGL_FALSE; 1049 } 1050 } 1051 } 1052 } 1053 return res; 1054} 1055 1056 1057// ---------------------------------------------------------------------------- 1058// EGL 1.2 1059// ---------------------------------------------------------------------------- 1060 1061EGLBoolean eglWaitClient(void) 1062{ 1063 clearError(); 1064 1065 // could be called before eglInitialize(), but we wouldn't have a context 1066 // then, and this function would return GL_TRUE, which isn't wrong. 1067 EGLBoolean res = EGL_TRUE; 1068 EGLContext ctx = getContext(); 1069 if (ctx) { 1070 egl_context_t const * const c = get_context(ctx); 1071 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE); 1072 if (uint32_t(c->impl)>=2) 1073 return setError(EGL_BAD_CONTEXT, EGL_FALSE); 1074 egl_connection_t* const cnx = &gEGLImpl[c->impl]; 1075 if (!cnx->dso) 1076 return setError(EGL_BAD_CONTEXT, EGL_FALSE); 1077 if (cnx->egl.eglWaitClient) { 1078 res = cnx->egl.eglWaitClient(); 1079 } else { 1080 res = cnx->egl.eglWaitGL(); 1081 } 1082 } 1083 return res; 1084} 1085 1086EGLBoolean eglBindAPI(EGLenum api) 1087{ 1088 clearError(); 1089 1090 if (egl_init_drivers() == EGL_FALSE) { 1091 return setError(EGL_BAD_PARAMETER, EGL_FALSE); 1092 } 1093 1094 // bind this API on all EGLs 1095 EGLBoolean res = EGL_TRUE; 1096 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { 1097 egl_connection_t* const cnx = &gEGLImpl[i]; 1098 if (cnx->dso) { 1099 if (cnx->egl.eglBindAPI) { 1100 if (cnx->egl.eglBindAPI(api) == EGL_FALSE) { 1101 res = EGL_FALSE; 1102 } 1103 } 1104 } 1105 } 1106 return res; 1107} 1108 1109EGLenum eglQueryAPI(void) 1110{ 1111 clearError(); 1112 1113 if (egl_init_drivers() == EGL_FALSE) { 1114 return setError(EGL_BAD_PARAMETER, EGL_FALSE); 1115 } 1116 1117 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { 1118 egl_connection_t* const cnx = &gEGLImpl[i]; 1119 if (cnx->dso) { 1120 if (cnx->egl.eglQueryAPI) { 1121 // the first one we find is okay, because they all 1122 // should be the same 1123 return cnx->egl.eglQueryAPI(); 1124 } 1125 } 1126 } 1127 // or, it can only be OpenGL ES 1128 return EGL_OPENGL_ES_API; 1129} 1130 1131EGLBoolean eglReleaseThread(void) 1132{ 1133 clearError(); 1134 1135 // If there is context bound to the thread, release it 1136 loseCurrent(get_context(getContext())); 1137 1138 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { 1139 egl_connection_t* const cnx = &gEGLImpl[i]; 1140 if (cnx->dso) { 1141 if (cnx->egl.eglReleaseThread) { 1142 cnx->egl.eglReleaseThread(); 1143 } 1144 } 1145 } 1146 egl_tls_t::clearTLS(); 1147 dbgReleaseThread(); 1148 return EGL_TRUE; 1149} 1150 1151EGLSurface eglCreatePbufferFromClientBuffer( 1152 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, 1153 EGLConfig config, const EGLint *attrib_list) 1154{ 1155 clearError(); 1156 1157 egl_display_t const* dp = 0; 1158 egl_connection_t* cnx = validate_display_config(dpy, config, dp); 1159 if (!cnx) return EGL_FALSE; 1160 if (cnx->egl.eglCreatePbufferFromClientBuffer) { 1161 return cnx->egl.eglCreatePbufferFromClientBuffer( 1162 dp->disp[ dp->configs[intptr_t(config)].impl ].dpy, 1163 buftype, buffer, 1164 dp->configs[intptr_t(config)].config, attrib_list); 1165 } 1166 return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE); 1167} 1168 1169// ---------------------------------------------------------------------------- 1170// EGL_EGLEXT_VERSION 3 1171// ---------------------------------------------------------------------------- 1172 1173EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, 1174 const EGLint *attrib_list) 1175{ 1176 clearError(); 1177 1178 egl_display_t const * const dp = validate_display(dpy); 1179 if (!dp) return EGL_FALSE; 1180 1181 SurfaceRef _s(surface); 1182 if (!_s.get()) 1183 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1184 1185 egl_surface_t const * const s = get_surface(surface); 1186 if (s->cnx->egl.eglLockSurfaceKHR) { 1187 return s->cnx->egl.eglLockSurfaceKHR( 1188 dp->disp[s->impl].dpy, s->surface, attrib_list); 1189 } 1190 return setError(EGL_BAD_DISPLAY, EGL_FALSE); 1191} 1192 1193EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) 1194{ 1195 clearError(); 1196 1197 egl_display_t const * const dp = validate_display(dpy); 1198 if (!dp) return EGL_FALSE; 1199 1200 SurfaceRef _s(surface); 1201 if (!_s.get()) 1202 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1203 1204 egl_surface_t const * const s = get_surface(surface); 1205 if (s->cnx->egl.eglUnlockSurfaceKHR) { 1206 return s->cnx->egl.eglUnlockSurfaceKHR( 1207 dp->disp[s->impl].dpy, s->surface); 1208 } 1209 return setError(EGL_BAD_DISPLAY, EGL_FALSE); 1210} 1211 1212EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, 1213 EGLClientBuffer buffer, const EGLint *attrib_list) 1214{ 1215 clearError(); 1216 1217 egl_display_t const * const dp = validate_display(dpy); 1218 if (!dp) return EGL_NO_IMAGE_KHR; 1219 1220 if (ctx != EGL_NO_CONTEXT) { 1221 ContextRef _c(ctx); 1222 if (!_c.get()) 1223 return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR); 1224 egl_context_t * const c = get_context(ctx); 1225 // since we have an EGLContext, we know which implementation to use 1226 EGLImageKHR image = c->cnx->egl.eglCreateImageKHR( 1227 dp->disp[c->impl].dpy, c->context, target, buffer, attrib_list); 1228 if (image == EGL_NO_IMAGE_KHR) 1229 return image; 1230 1231 egl_image_t* result = new egl_image_t(dpy, ctx); 1232 result->images[c->impl] = image; 1233 return (EGLImageKHR)result; 1234 } else { 1235 // EGL_NO_CONTEXT is a valid parameter 1236 1237 /* Since we don't have a way to know which implementation to call, 1238 * we're calling all of them. If at least one of the implementation 1239 * succeeded, this is a success. 1240 */ 1241 1242 EGLint currentError = eglGetError(); 1243 1244 EGLImageKHR implImages[IMPL_NUM_IMPLEMENTATIONS]; 1245 bool success = false; 1246 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { 1247 egl_connection_t* const cnx = &gEGLImpl[i]; 1248 implImages[i] = EGL_NO_IMAGE_KHR; 1249 if (cnx->dso) { 1250 if (cnx->egl.eglCreateImageKHR) { 1251 implImages[i] = cnx->egl.eglCreateImageKHR( 1252 dp->disp[i].dpy, ctx, target, buffer, attrib_list); 1253 if (implImages[i] != EGL_NO_IMAGE_KHR) { 1254 success = true; 1255 } 1256 } 1257 } 1258 } 1259 1260 if (!success) { 1261 // failure, if there was an error when we entered this function, 1262 // the error flag must not be updated. 1263 // Otherwise, the error is whatever happened in the implementation 1264 // that faulted. 1265 if (currentError != EGL_SUCCESS) { 1266 setError(currentError, EGL_NO_IMAGE_KHR); 1267 } 1268 return EGL_NO_IMAGE_KHR; 1269 } else { 1270 // In case of success, we need to clear all error flags 1271 // (especially those caused by the implementation that didn't 1272 // succeed). TODO: we could avoid this if we knew this was 1273 // a "full" success (all implementation succeeded). 1274 eglGetError(); 1275 } 1276 1277 egl_image_t* result = new egl_image_t(dpy, ctx); 1278 memcpy(result->images, implImages, sizeof(implImages)); 1279 return (EGLImageKHR)result; 1280 } 1281} 1282 1283EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) 1284{ 1285 clearError(); 1286 1287 egl_display_t const * const dp = validate_display(dpy); 1288 if (!dp) return EGL_FALSE; 1289 1290 ImageRef _i(img); 1291 if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE); 1292 1293 egl_image_t* image = get_image(img); 1294 bool success = false; 1295 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { 1296 egl_connection_t* const cnx = &gEGLImpl[i]; 1297 if (image->images[i] != EGL_NO_IMAGE_KHR) { 1298 if (cnx->dso) { 1299 if (cnx->egl.eglDestroyImageKHR) { 1300 if (cnx->egl.eglDestroyImageKHR( 1301 dp->disp[i].dpy, image->images[i])) { 1302 success = true; 1303 } 1304 } 1305 } 1306 } 1307 } 1308 if (!success) 1309 return EGL_FALSE; 1310 1311 _i.terminate(); 1312 1313 return EGL_TRUE; 1314} 1315 1316// ---------------------------------------------------------------------------- 1317// EGL_EGLEXT_VERSION 5 1318// ---------------------------------------------------------------------------- 1319 1320 1321EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) 1322{ 1323 clearError(); 1324 1325 egl_display_t const * const dp = validate_display(dpy); 1326 if (!dp) return EGL_NO_SYNC_KHR; 1327 1328 EGLContext ctx = eglGetCurrentContext(); 1329 ContextRef _c(ctx); 1330 if (!_c.get()) 1331 return setError(EGL_BAD_CONTEXT, EGL_NO_SYNC_KHR); 1332 1333 egl_context_t * const c = get_context(ctx); 1334 EGLSyncKHR result = EGL_NO_SYNC_KHR; 1335 if (c->cnx->egl.eglCreateSyncKHR) { 1336 EGLSyncKHR sync = c->cnx->egl.eglCreateSyncKHR( 1337 dp->disp[c->impl].dpy, type, attrib_list); 1338 if (sync == EGL_NO_SYNC_KHR) 1339 return sync; 1340 result = (egl_sync_t*)new egl_sync_t(dpy, ctx, sync); 1341 } 1342 return (EGLSyncKHR)result; 1343} 1344 1345EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) 1346{ 1347 clearError(); 1348 1349 egl_display_t const * const dp = validate_display(dpy); 1350 if (!dp) return EGL_FALSE; 1351 1352 SyncRef _s(sync); 1353 if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE); 1354 egl_sync_t* syncObject = get_sync(sync); 1355 1356 EGLContext ctx = syncObject->context; 1357 ContextRef _c(ctx); 1358 if (!_c.get()) 1359 return setError(EGL_BAD_CONTEXT, EGL_FALSE); 1360 1361 EGLBoolean result = EGL_FALSE; 1362 egl_context_t * const c = get_context(ctx); 1363 if (c->cnx->egl.eglDestroySyncKHR) { 1364 result = c->cnx->egl.eglDestroySyncKHR( 1365 dp->disp[c->impl].dpy, syncObject->sync); 1366 if (result) 1367 _s.terminate(); 1368 } 1369 return result; 1370} 1371 1372EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) 1373{ 1374 clearError(); 1375 1376 egl_display_t const * const dp = validate_display(dpy); 1377 if (!dp) return EGL_FALSE; 1378 1379 SyncRef _s(sync); 1380 if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE); 1381 egl_sync_t* syncObject = get_sync(sync); 1382 1383 EGLContext ctx = syncObject->context; 1384 ContextRef _c(ctx); 1385 if (!_c.get()) 1386 return setError(EGL_BAD_CONTEXT, EGL_FALSE); 1387 1388 egl_context_t * const c = get_context(ctx); 1389 if (c->cnx->egl.eglClientWaitSyncKHR) { 1390 return c->cnx->egl.eglClientWaitSyncKHR( 1391 dp->disp[c->impl].dpy, syncObject->sync, flags, timeout); 1392 } 1393 1394 return EGL_FALSE; 1395} 1396 1397EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value) 1398{ 1399 clearError(); 1400 1401 egl_display_t const * const dp = validate_display(dpy); 1402 if (!dp) return EGL_FALSE; 1403 1404 SyncRef _s(sync); 1405 if (!_s.get()) 1406 return setError(EGL_BAD_PARAMETER, EGL_FALSE); 1407 1408 egl_sync_t* syncObject = get_sync(sync); 1409 EGLContext ctx = syncObject->context; 1410 ContextRef _c(ctx); 1411 if (!_c.get()) 1412 return setError(EGL_BAD_CONTEXT, EGL_FALSE); 1413 1414 egl_context_t * const c = get_context(ctx); 1415 if (c->cnx->egl.eglGetSyncAttribKHR) { 1416 return c->cnx->egl.eglGetSyncAttribKHR( 1417 dp->disp[c->impl].dpy, syncObject->sync, attribute, value); 1418 } 1419 1420 return EGL_FALSE; 1421} 1422 1423// ---------------------------------------------------------------------------- 1424// ANDROID extensions 1425// ---------------------------------------------------------------------------- 1426 1427EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw, 1428 EGLint left, EGLint top, EGLint width, EGLint height) 1429{ 1430 clearError(); 1431 1432 egl_display_t const * const dp = validate_display(dpy); 1433 if (!dp) return EGL_FALSE; 1434 1435 SurfaceRef _s(draw); 1436 if (!_s.get()) 1437 return setError(EGL_BAD_SURFACE, EGL_FALSE); 1438 1439 egl_surface_t const * const s = get_surface(draw); 1440 if (s->cnx->egl.eglSetSwapRectangleANDROID) { 1441 return s->cnx->egl.eglSetSwapRectangleANDROID( 1442 dp->disp[s->impl].dpy, s->surface, left, top, width, height); 1443 } 1444 return setError(EGL_BAD_DISPLAY, NULL); 1445} 1446