1 /* 2 * Copyright 2013-2014 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24 /** 25 * \mainpage Epoxy 26 * 27 * \section intro_sec Introduction 28 * 29 * Epoxy is a library for handling OpenGL function pointer management for 30 * you. 31 * 32 * It hides the complexity of `dlopen()`, `dlsym()`, `glXGetProcAddress()`, 33 * `eglGetProcAddress()`, etc. from the app developer, with very little 34 * knowledge needed on their part. They get to read GL specs and write 35 * code using undecorated function names like `glCompileShader()`. 36 * 37 * Don't forget to check for your extensions or versions being present 38 * before you use them, just like before! We'll tell you what you forgot 39 * to check for instead of just segfaulting, though. 40 * 41 * \section features_sec Features 42 * 43 * - Automatically initializes as new GL functions are used. 44 * - GL 4.6 core and compatibility context support. 45 * - GLES 1/2/3 context support. 46 * - Knows about function aliases so (e.g.) `glBufferData()` can be 47 * used with `GL_ARB_vertex_buffer_object` implementations, along 48 * with GL 1.5+ implementations. 49 * - EGL, GLX, and WGL support. 50 * - Can be mixed with non-epoxy GL usage. 51 * 52 * \section using_sec Using Epoxy 53 * 54 * Using Epoxy should be as easy as replacing: 55 * 56 * ```cpp 57 * #include <GL/gl.h> 58 * #include <GL/glx.h> 59 * #include <GL/glext.h> 60 * ``` 61 * 62 * with: 63 * 64 * ```cpp 65 * #include <epoxy/gl.h> 66 * #include <epoxy/glx.h> 67 * ``` 68 * 69 * \subsection using_include_sec Headers 70 * 71 * Epoxy comes with the following public headers: 72 * 73 * - `epoxy/gl.h` - For GL API 74 * - `epoxy/egl.h` - For EGL API 75 * - `epoxy/glx.h` - For GLX API 76 * - `epoxy/wgl.h` - For WGL API 77 * 78 * \section links_sec Additional links 79 * 80 * The latest version of the Epoxy code is available on [GitHub](https://github.com/anholt/libepoxy). 81 * 82 * For bug reports and enhancements, please use the [Issues](https://github.com/anholt/libepoxy/issues) 83 * link. 84 * 85 * The scope of this API reference does not include the documentation for 86 * OpenGL and OpenGL ES. For more information on those programming interfaces 87 * please visit: 88 * 89 * - [Khronos](https://www.khronos.org/) 90 * - [OpenGL page on Khronos.org](https://www.khronos.org/opengl/) 91 * - [OpenGL ES page on Khronos.org](https://www.khronos.org/opengles/) 92 * - [docs.GL](http://docs.gl/) 93 */ 94 95 /** 96 * @file dispatch_common.c 97 * 98 * @brief Implements common code shared by the generated GL/EGL/GLX dispatch code. 99 * 100 * A collection of some important specs on getting GL function pointers. 101 * 102 * From the linux GL ABI (http://www.opengl.org/registry/ABI/): 103 * 104 * "3.4. The libraries must export all OpenGL 1.2, GLU 1.3, GLX 1.3, and 105 * ARB_multitexture entry points statically. 106 * 107 * 3.5. Because non-ARB extensions vary so widely and are constantly 108 * increasing in number, it's infeasible to require that they all be 109 * supported, and extensions can always be added to hardware drivers 110 * after the base link libraries are released. These drivers are 111 * dynamically loaded by libGL, so extensions not in the base 112 * library must also be obtained dynamically. 113 * 114 * 3.6. To perform the dynamic query, libGL also must export an entry 115 * point called 116 * 117 * void (*glXGetProcAddressARB(const GLubyte *))(); 118 * 119 * The full specification of this function is available separately. It 120 * takes the string name of a GL or GLX entry point and returns a pointer 121 * to a function implementing that entry point. It is functionally 122 * identical to the wglGetProcAddress query defined by the Windows OpenGL 123 * library, except that the function pointers returned are context 124 * independent, unlike the WGL query." 125 * 126 * From the EGL 1.4 spec: 127 * 128 * "Client API function pointers returned by eglGetProcAddress are 129 * independent of the display and the currently bound client API context, 130 * and may be used by any client API context which supports the extension. 131 * 132 * eglGetProcAddress may be queried for all of the following functions: 133 * 134 * All EGL and client API extension functions supported by the 135 * implementation (whether those extensions are supported by the current 136 * client API context or not). This includes any mandatory OpenGL ES 137 * extensions. 138 * 139 * eglGetProcAddress may not be queried for core (non-extension) functions 140 * in EGL or client APIs 20 . 141 * 142 * For functions that are queryable with eglGetProcAddress, 143 * implementations may choose to also export those functions statically 144 * from the object libraries im- plementing those functions. However, 145 * portable clients cannot rely on this behavior. 146 * 147 * From the GLX 1.4 spec: 148 * 149 * "glXGetProcAddress may be queried for all of the following functions: 150 * 151 * All GL and GLX extension functions supported by the implementation 152 * (whether those extensions are supported by the current context or 153 * not). 154 * 155 * All core (non-extension) functions in GL and GLX from version 1.0 up 156 * to and including the versions of those specifications supported by 157 * the implementation, as determined by glGetString(GL VERSION) and 158 * glXQueryVersion queries." 159 */ 160 161 #include <assert.h> 162 #include <stdlib.h> 163 #ifdef _WIN32 164 #include <windows.h> 165 #else 166 #include <dlfcn.h> 167 #include <err.h> 168 #include <pthread.h> 169 #endif 170 #include <string.h> 171 #include <ctype.h> 172 #include <stdio.h> 173 174 #include "dispatch_common.h" 175 176 #if defined(__APPLE__) 177 #define GLX_LIB "/opt/X11/lib/libGL.1.dylib" 178 #define OPENGL_LIB "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL" 179 #define GLES1_LIB "libGLESv1_CM.so" 180 #define GLES2_LIB "libGLESv2.so" 181 #elif defined(__ANDROID__) 182 #define GLX_LIB "libGLESv2.so" 183 #elif __NetBSD__ 184 #define GLX_LIB "libGL.so" 185 #endif 186 187 #if defined(ANDROID) || defined(__NetBSD__) 188 #define EGL_LIB "libEGL.so" 189 #define GLES1_LIB "libGLESv1_CM.so" 190 #define GLES2_LIB "libGLESv2.so" 191 #elif defined(_WIN32) 192 #define EGL_LIB "libEGL.dll" 193 #define GLES1_LIB "libGLES_CM.dll" 194 #define GLES2_LIB "libGLESv2.dll" 195 #define OPENGL_LIB "OPENGL32" 196 #else 197 #define GLVND_GLX_LIB "libGLX.so.1" 198 #define GLX_LIB "libGL.so.1" 199 #define EGL_LIB "libEGL.so.1" 200 #define GLES1_LIB "libGLESv1_CM.so.1" 201 #define GLES2_LIB "libGLESv2.so.2" 202 #define OPENGL_LIB "libOpenGL.so.0" 203 #endif 204 205 #ifdef __GNUC__ 206 #define CONSTRUCT(_func) static void _func (void) __attribute__((constructor)); 207 #define DESTRUCT(_func) static void _func (void) __attribute__((destructor)); 208 #elif defined (_MSC_VER) && (_MSC_VER >= 1500) 209 #define CONSTRUCT(_func) \ 210 static void _func(void); \ 211 static int _func ## _wrapper(void) { _func(); return 0; } \ 212 __pragma(section(".CRT$XCU",read)) \ 213 __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _wrapper; 214 215 #define DESTRUCT(_func) \ 216 static void _func(void); \ 217 static int _func ## _constructor(void) { atexit (_func); return 0; } \ 218 __pragma(section(".CRT$XCU",read)) \ 219 __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _constructor; 220 221 #elif defined(__lint__) 222 #define CONSTRUCT(_func) 223 #define DESTRUCT(_func) 224 #else 225 #error "You will need constructor support for your compiler" 226 #endif 227 228 struct api { 229 #ifndef _WIN32 230 /* 231 * Locking for making sure we don't double-dlopen(). 232 */ 233 pthread_mutex_t mutex; 234 #endif 235 236 /* 237 * dlopen() return value for the GLX API. This is libGLX.so.1 if the 238 * runtime is glvnd-enabled, else libGL.so.1 239 */ 240 void *glx_handle; 241 242 /* 243 * dlopen() return value for the desktop GL library. 244 * 245 * On Windows this is OPENGL32. On OSX this is classic libGL. On Linux 246 * this is either libOpenGL (if the runtime is glvnd-enabled) or 247 * classic libGL.so.1 248 */ 249 void *gl_handle; 250 251 /* dlopen() return value for libEGL.so.1 */ 252 void *egl_handle; 253 254 /* dlopen() return value for libGLESv1_CM.so.1 */ 255 void *gles1_handle; 256 257 /* dlopen() return value for libGLESv2.so.2 */ 258 void *gles2_handle; 259 260 /* 261 * This value gets incremented when any thread is in 262 * glBegin()/glEnd() called through epoxy. 263 * 264 * We're not guaranteed to be called through our wrapper, so the 265 * conservative paths also try to handle the failure cases they'll 266 * see if begin_count didn't reflect reality. It's also a bit of 267 * a bug that the conservative paths might return success because 268 * some other thread was in epoxy glBegin/glEnd while our thread 269 * is trying to resolve, but given that it's basically just for 270 * informative error messages, we shouldn't need to care. 271 */ 272 long begin_count; 273 }; 274 275 static struct api api = { 276 #ifndef _WIN32 277 .mutex = PTHREAD_MUTEX_INITIALIZER, 278 #else 279 0, 280 #endif 281 }; 282 283 static bool library_initialized; 284 285 static bool epoxy_current_context_is_glx(void); 286 287 #if PLATFORM_HAS_EGL 288 static EGLenum 289 epoxy_egl_get_current_gl_context_api(void); 290 #endif 291 292 CONSTRUCT (library_init) 293 294 static void 295 library_init(void) 296 { 297 library_initialized = true; 298 } 299 300 static bool 301 get_dlopen_handle(void **handle, const char *lib_name, bool exit_on_fail, bool load) 302 { 303 if (*handle) 304 return true; 305 306 if (!library_initialized) { 307 fputs("Attempting to dlopen() while in the dynamic linker.\n", stderr); 308 abort(); 309 } 310 311 #ifdef _WIN32 312 *handle = LoadLibraryA(lib_name); 313 #else 314 pthread_mutex_lock(&api.mutex); 315 if (!*handle) { 316 int flags = RTLD_LAZY | RTLD_LOCAL; 317 if (!load) 318 flags |= RTLD_NOLOAD; 319 320 *handle = dlopen(lib_name, flags); 321 if (!*handle) { 322 if (exit_on_fail) { 323 fprintf(stderr, "Couldn't open %s: %s\n", lib_name, dlerror()); 324 abort(); 325 } else { 326 (void)dlerror(); 327 } 328 } 329 } 330 pthread_mutex_unlock(&api.mutex); 331 #endif 332 333 return *handle != NULL; 334 } 335 336 static void * 337 do_dlsym(void **handle, const char *name, bool exit_on_fail) 338 { 339 void *result; 340 const char *error = ""; 341 342 #ifdef _WIN32 343 result = GetProcAddress(*handle, name); 344 #else 345 result = dlsym(*handle, name); 346 if (!result) 347 error = dlerror(); 348 #endif 349 if (!result && exit_on_fail) { 350 fprintf(stderr, "%s() not found: %s\n", name, error); 351 abort(); 352 } 353 354 return result; 355 } 356 357 /** 358 * @brief Checks whether we're using OpenGL or OpenGL ES 359 * 360 * @return `true` if we're using OpenGL 361 */ 362 bool 363 epoxy_is_desktop_gl(void) 364 { 365 const char *es_prefix = "OpenGL ES"; 366 const char *version; 367 368 #if PLATFORM_HAS_EGL 369 /* PowerVR's OpenGL ES implementation (and perhaps other) don't 370 * comply with the standard, which states that 371 * "glGetString(GL_VERSION)" should return a string starting with 372 * "OpenGL ES". Therefore, to distinguish desktop OpenGL from 373 * OpenGL ES, we must also check the context type through EGL (we 374 * can do that as PowerVR is only usable through EGL). 375 */ 376 if (!epoxy_current_context_is_glx()) { 377 switch (epoxy_egl_get_current_gl_context_api()) { 378 case EGL_OPENGL_API: return true; 379 case EGL_OPENGL_ES_API: return false; 380 case EGL_NONE: 381 default: break; 382 } 383 } 384 #endif 385 386 if (api.begin_count) 387 return true; 388 389 version = (const char *)glGetString(GL_VERSION); 390 391 /* If we didn't get a version back, there are only two things that 392 * could have happened: either malloc failure (which basically 393 * doesn't exist), or we were called within a glBegin()/glEnd(). 394 * Assume the second, which only exists for desktop GL. 395 */ 396 if (!version) 397 return true; 398 399 return strncmp(es_prefix, version, strlen(es_prefix)); 400 } 401 402 static int 403 epoxy_internal_gl_version(GLenum version_string, int error_version) 404 { 405 const char *version = (const char *)glGetString(version_string); 406 GLint major, minor, factor; 407 int scanf_count; 408 409 if (!version) 410 return error_version; 411 412 /* skip to version number */ 413 while (!isdigit(*version) && *version != '\0') 414 version++; 415 416 /* Interpret version number */ 417 scanf_count = sscanf(version, "%i.%i", &major, &minor); 418 if (scanf_count != 2) { 419 fprintf(stderr, "Unable to interpret GL_VERSION string: %s\n", 420 version); 421 abort(); 422 } 423 424 if (minor >= 10) 425 factor = 100; 426 else 427 factor = 10; 428 429 return factor * major + minor; 430 } 431 432 /** 433 * @brief Returns the version of OpenGL we are using 434 * 435 * The version is encoded as: 436 * 437 * ``` 438 * 439 * version = major * 10 + minor 440 * 441 * ``` 442 * 443 * So it can be easily used for version comparisons. 444 * 445 * @return The encoded version of OpenGL we are using 446 */ 447 int 448 epoxy_gl_version(void) 449 { 450 return epoxy_internal_gl_version(GL_VERSION, 0); 451 } 452 453 int 454 epoxy_conservative_gl_version(void) 455 { 456 if (api.begin_count) 457 return 100; 458 459 return epoxy_internal_gl_version(GL_VERSION, 100); 460 } 461 462 /** 463 * @brief Returns the version of the GL Shading Language we are using 464 * 465 * The version is encoded as: 466 * 467 * ``` 468 * 469 * version = major * 100 + minor 470 * 471 * ``` 472 * 473 * So it can be easily used for version comparisons. 474 * 475 * @return The encoded version of the GL Shading Language we are using 476 */ 477 int 478 epoxy_glsl_version(void) 479 { 480 if (epoxy_gl_version() >= 20 || 481 epoxy_has_gl_extension ("GL_ARB_shading_language_100")) 482 return epoxy_internal_gl_version(GL_SHADING_LANGUAGE_VERSION, 0); 483 484 return 0; 485 } 486 487 /** 488 * @brief Checks for the presence of an extension in an OpenGL extension string 489 * 490 * @param extension_list The string containing the list of extensions to check 491 * @param ext The name of the GL extension 492 * @return `true` if the extension is available' 493 * 494 * @note If you are looking to check whether a normal GL, EGL or GLX extension 495 * is supported by the client, this probably isn't the function you want. 496 * 497 * Some parts of the spec for OpenGL and friends will return an OpenGL formatted 498 * extension string that is separate from the usual extension strings for the 499 * spec. This function provides easy parsing of those strings. 500 * 501 * @see epoxy_has_gl_extension() 502 * @see epoxy_has_egl_extension() 503 * @see epoxy_has_glx_extension() 504 */ 505 bool 506 epoxy_extension_in_string(const char *extension_list, const char *ext) 507 { 508 const char *ptr = extension_list; 509 int len; 510 511 if (!ext) 512 return false; 513 514 len = strlen(ext); 515 516 if (extension_list == NULL || *extension_list == '\0') 517 return false; 518 519 /* Make sure that don't just find an extension with our name as a prefix. */ 520 while (true) { 521 ptr = strstr(ptr, ext); 522 if (!ptr) 523 return false; 524 525 if (ptr[len] == ' ' || ptr[len] == 0) 526 return true; 527 ptr += len; 528 } 529 } 530 531 static bool 532 epoxy_internal_has_gl_extension(const char *ext, bool invalid_op_mode) 533 { 534 if (epoxy_gl_version() < 30) { 535 const char *exts = (const char *)glGetString(GL_EXTENSIONS); 536 if (!exts) 537 return invalid_op_mode; 538 return epoxy_extension_in_string(exts, ext); 539 } else { 540 int num_extensions; 541 int i; 542 543 glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions); 544 if (num_extensions == 0) 545 return invalid_op_mode; 546 547 for (i = 0; i < num_extensions; i++) { 548 const char *gl_ext = (const char *)glGetStringi(GL_EXTENSIONS, i); 549 if (!gl_ext) 550 return false; 551 if (strcmp(ext, gl_ext) == 0) 552 return true; 553 } 554 555 return false; 556 } 557 } 558 559 bool 560 epoxy_load_glx(bool exit_if_fails, bool load) 561 { 562 #if PLATFORM_HAS_GLX 563 # ifdef GLVND_GLX_LIB 564 /* prefer the glvnd library if it exists */ 565 if (!api.glx_handle) 566 get_dlopen_handle(&api.glx_handle, GLVND_GLX_LIB, false, load); 567 # endif 568 if (!api.glx_handle) 569 get_dlopen_handle(&api.glx_handle, GLX_LIB, exit_if_fails, load); 570 #endif 571 return api.glx_handle != NULL; 572 } 573 574 void * 575 epoxy_conservative_glx_dlsym(const char *name, bool exit_if_fails) 576 { 577 #if PLATFORM_HAS_GLX 578 if (epoxy_load_glx(exit_if_fails, exit_if_fails)) 579 return do_dlsym(&api.glx_handle, name, exit_if_fails); 580 #endif 581 return NULL; 582 } 583 584 /** 585 * Tests whether the currently bound context is EGL or GLX, trying to 586 * avoid loading libraries unless necessary. 587 */ 588 static bool 589 epoxy_current_context_is_glx(void) 590 { 591 #if !PLATFORM_HAS_GLX 592 return false; 593 #else 594 void *sym; 595 596 sym = epoxy_conservative_glx_dlsym("glXGetCurrentContext", false); 597 if (sym) { 598 if (glXGetCurrentContext()) 599 return true; 600 } else { 601 (void)dlerror(); 602 } 603 604 #if PLATFORM_HAS_EGL 605 sym = epoxy_conservative_egl_dlsym("eglGetCurrentContext", false); 606 if (sym) { 607 if (epoxy_egl_get_current_gl_context_api() != EGL_NONE) 608 return false; 609 } else { 610 (void)dlerror(); 611 } 612 #endif /* PLATFORM_HAS_EGL */ 613 614 return false; 615 #endif /* PLATFORM_HAS_GLX */ 616 } 617 618 /** 619 * @brief Returns true if the given GL extension is supported in the current context. 620 * 621 * @param ext The name of the GL extension 622 * @return `true` if the extension is available 623 * 624 * @note that this function can't be called from within `glBegin()` and `glEnd()`. 625 * 626 * @see epoxy_has_egl_extension() 627 * @see epoxy_has_glx_extension() 628 */ 629 bool 630 epoxy_has_gl_extension(const char *ext) 631 { 632 return epoxy_internal_has_gl_extension(ext, false); 633 } 634 635 bool 636 epoxy_conservative_has_gl_extension(const char *ext) 637 { 638 if (api.begin_count) 639 return true; 640 641 return epoxy_internal_has_gl_extension(ext, true); 642 } 643 644 bool 645 epoxy_load_egl(bool exit_if_fails, bool load) 646 { 647 #if PLATFORM_HAS_EGL 648 return get_dlopen_handle(&api.egl_handle, EGL_LIB, exit_if_fails, load); 649 #else 650 return false; 651 #endif 652 } 653 654 void * 655 epoxy_conservative_egl_dlsym(const char *name, bool exit_if_fails) 656 { 657 #if PLATFORM_HAS_EGL 658 if (epoxy_load_egl(exit_if_fails, exit_if_fails)) 659 return do_dlsym(&api.egl_handle, name, exit_if_fails); 660 #endif 661 return NULL; 662 } 663 664 void * 665 epoxy_egl_dlsym(const char *name) 666 { 667 return epoxy_conservative_egl_dlsym(name, true); 668 } 669 670 void * 671 epoxy_glx_dlsym(const char *name) 672 { 673 return epoxy_conservative_glx_dlsym(name, true); 674 } 675 676 static void 677 epoxy_load_gl(void) 678 { 679 if (api.gl_handle) 680 return; 681 682 #if defined(_WIN32) || defined(__APPLE__) 683 get_dlopen_handle(&api.gl_handle, OPENGL_LIB, true, true); 684 #else 685 686 #if defined(OPENGL_LIB) 687 if (!api.gl_handle) 688 get_dlopen_handle(&api.gl_handle, OPENGL_LIB, false, true); 689 #endif 690 691 get_dlopen_handle(&api.glx_handle, GLX_LIB, true, true); 692 api.gl_handle = api.glx_handle; 693 #endif 694 } 695 696 void * 697 epoxy_gl_dlsym(const char *name) 698 { 699 epoxy_load_gl(); 700 701 return do_dlsym(&api.gl_handle, name, true); 702 } 703 704 void * 705 epoxy_gles1_dlsym(const char *name) 706 { 707 if (epoxy_current_context_is_glx()) { 708 return epoxy_get_proc_address(name); 709 } else { 710 get_dlopen_handle(&api.gles1_handle, GLES1_LIB, true, true); 711 return do_dlsym(&api.gles1_handle, name, true); 712 } 713 } 714 715 void * 716 epoxy_gles2_dlsym(const char *name) 717 { 718 if (epoxy_current_context_is_glx()) { 719 return epoxy_get_proc_address(name); 720 } else { 721 get_dlopen_handle(&api.gles2_handle, GLES2_LIB, true, true); 722 return do_dlsym(&api.gles2_handle, name, true); 723 } 724 } 725 726 /** 727 * Does the appropriate dlsym() or eglGetProcAddress() for GLES3 728 * functions. 729 * 730 * Mesa interpreted GLES as intending that the GLES3 functions were 731 * available only through eglGetProcAddress() and not dlsym(), while 732 * ARM's Mali drivers interpreted GLES as intending that GLES3 733 * functions were available only through dlsym() and not 734 * eglGetProcAddress(). Thanks, Khronos. 735 */ 736 void * 737 epoxy_gles3_dlsym(const char *name) 738 { 739 if (epoxy_current_context_is_glx()) { 740 return epoxy_get_proc_address(name); 741 } else { 742 if (get_dlopen_handle(&api.gles2_handle, GLES2_LIB, false, true)) { 743 void *func = do_dlsym(&api.gles2_handle, name, false); 744 745 if (func) 746 return func; 747 } 748 749 return epoxy_get_proc_address(name); 750 } 751 } 752 753 /** 754 * Performs either the dlsym or glXGetProcAddress()-equivalent for 755 * core functions in desktop GL. 756 */ 757 void * 758 epoxy_get_core_proc_address(const char *name, int core_version) 759 { 760 #ifdef _WIN32 761 int core_symbol_support = 11; 762 #elif defined(__ANDROID__) 763 /** 764 * All symbols must be resolved through eglGetProcAddress 765 * on Android 766 */ 767 int core_symbol_support = 0; 768 #else 769 int core_symbol_support = 12; 770 #endif 771 772 if (core_version <= core_symbol_support) { 773 return epoxy_gl_dlsym(name); 774 } else { 775 return epoxy_get_proc_address(name); 776 } 777 } 778 779 #if PLATFORM_HAS_EGL 780 static EGLenum 781 epoxy_egl_get_current_gl_context_api(void) 782 { 783 EGLint curapi; 784 785 if (eglQueryContext(eglGetCurrentDisplay(), eglGetCurrentContext(), 786 EGL_CONTEXT_CLIENT_TYPE, &curapi) == EGL_FALSE) { 787 (void)eglGetError(); 788 return EGL_NONE; 789 } 790 791 return (EGLenum) curapi; 792 } 793 #endif /* PLATFORM_HAS_EGL */ 794 795 /** 796 * Performs the dlsym() for the core GL 1.0 functions that we use for 797 * determining version and extension support for deciding on dlsym 798 * versus glXGetProcAddress() for all other functions. 799 * 800 * This needs to succeed on implementations without GLX (since 801 * glGetString() and glGetIntegerv() are both in GLES1/2 as well, and 802 * at call time we don't know for sure what API they're trying to use 803 * without inspecting contexts ourselves). 804 */ 805 void * 806 epoxy_get_bootstrap_proc_address(const char *name) 807 { 808 /* If we already have a library that links to libglapi loaded, 809 * use that. 810 */ 811 #if PLATFORM_HAS_GLX 812 if (api.glx_handle && glXGetCurrentContext()) 813 return epoxy_gl_dlsym(name); 814 #endif 815 816 /* If epoxy hasn't loaded any API-specific library yet, try to 817 * figure out what API the context is using and use that library, 818 * since future calls will also use that API (this prevents a 819 * non-X11 ES2 context from loading a bunch of X11 junk). 820 */ 821 #if PLATFORM_HAS_EGL 822 get_dlopen_handle(&api.egl_handle, EGL_LIB, false, true); 823 if (api.egl_handle) { 824 int version = 0; 825 switch (epoxy_egl_get_current_gl_context_api()) { 826 case EGL_OPENGL_API: 827 return epoxy_gl_dlsym(name); 828 case EGL_OPENGL_ES_API: 829 if (eglQueryContext(eglGetCurrentDisplay(), 830 eglGetCurrentContext(), 831 EGL_CONTEXT_CLIENT_VERSION, 832 &version)) { 833 if (version >= 2) 834 return epoxy_gles2_dlsym(name); 835 else 836 return epoxy_gles1_dlsym(name); 837 } 838 } 839 } 840 #endif /* PLATFORM_HAS_EGL */ 841 842 /* Fall back to GLX */ 843 return epoxy_gl_dlsym(name); 844 } 845 846 void * 847 epoxy_get_proc_address(const char *name) 848 { 849 #if PLATFORM_HAS_EGL 850 GLenum egl_api = EGL_NONE; 851 852 if (!epoxy_current_context_is_glx()) 853 egl_api = epoxy_egl_get_current_gl_context_api(); 854 855 switch (egl_api) { 856 case EGL_OPENGL_API: 857 case EGL_OPENGL_ES_API: 858 return eglGetProcAddress(name); 859 case EGL_NONE: 860 break; 861 } 862 #endif 863 864 #if defined(_WIN32) 865 return wglGetProcAddress(name); 866 #elif defined(__APPLE__) 867 return epoxy_gl_dlsym(name); 868 #elif PLATFORM_HAS_GLX 869 if (epoxy_current_context_is_glx()) 870 return glXGetProcAddressARB((const GLubyte *)name); 871 assert(0 && "Couldn't find current GLX or EGL context.\n"); 872 #endif 873 874 return NULL; 875 } 876 877 WRAPPER_VISIBILITY (void) 878 WRAPPER(epoxy_glBegin)(GLenum primtype) 879 { 880 #ifdef _WIN32 881 InterlockedIncrement(&api.begin_count); 882 #else 883 pthread_mutex_lock(&api.mutex); 884 api.begin_count++; 885 pthread_mutex_unlock(&api.mutex); 886 #endif 887 888 epoxy_glBegin_unwrapped(primtype); 889 } 890 891 WRAPPER_VISIBILITY (void) 892 WRAPPER(epoxy_glEnd)(void) 893 { 894 epoxy_glEnd_unwrapped(); 895 896 #ifdef _WIN32 897 InterlockedDecrement(&api.begin_count); 898 #else 899 pthread_mutex_lock(&api.mutex); 900 api.begin_count--; 901 pthread_mutex_unlock(&api.mutex); 902 #endif 903 } 904 905 PFNGLBEGINPROC epoxy_glBegin = epoxy_glBegin_wrapped; 906 PFNGLENDPROC epoxy_glEnd = epoxy_glEnd_wrapped; 907 908 epoxy_resolver_failure_handler_t epoxy_resolver_failure_handler; 909 910 /** 911 * Sets the function that will be called every time Epoxy fails to 912 * resolve a symbol. 913 * 914 * @param handler The new handler function 915 * @return The previous handler function 916 */ 917 epoxy_resolver_failure_handler_t 918 epoxy_set_resolver_failure_handler(epoxy_resolver_failure_handler_t handler) 919 { 920 #ifdef _WIN32 921 return InterlockedExchangePointer((void**)&epoxy_resolver_failure_handler, 922 handler); 923 #else 924 epoxy_resolver_failure_handler_t old; 925 pthread_mutex_lock(&api.mutex); 926 old = epoxy_resolver_failure_handler; 927 epoxy_resolver_failure_handler = handler; 928 pthread_mutex_unlock(&api.mutex); 929 return old; 930 #endif 931 } 932