dispatch_common.c revision e52adb7b
1e52adb7bSmrg/* 2e52adb7bSmrg * Copyright © 2013-2014 Intel Corporation 3e52adb7bSmrg * 4e52adb7bSmrg * Permission is hereby granted, free of charge, to any person obtaining a 5e52adb7bSmrg * copy of this software and associated documentation files (the "Software"), 6e52adb7bSmrg * to deal in the Software without restriction, including without limitation 7e52adb7bSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8e52adb7bSmrg * and/or sell copies of the Software, and to permit persons to whom the 9e52adb7bSmrg * Software is furnished to do so, subject to the following conditions: 10e52adb7bSmrg * 11e52adb7bSmrg * The above copyright notice and this permission notice (including the next 12e52adb7bSmrg * paragraph) shall be included in all copies or substantial portions of the 13e52adb7bSmrg * Software. 14e52adb7bSmrg * 15e52adb7bSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16e52adb7bSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17e52adb7bSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18e52adb7bSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19e52adb7bSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20e52adb7bSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21e52adb7bSmrg * IN THE SOFTWARE. 22e52adb7bSmrg */ 23e52adb7bSmrg 24e52adb7bSmrg/** 25e52adb7bSmrg * @file dispatch_common.c 26e52adb7bSmrg * 27e52adb7bSmrg * Implements common code shared by the generated GL/EGL/GLX dispatch code. 28e52adb7bSmrg * 29e52adb7bSmrg * A collection of some important specs on getting GL function pointers. 30e52adb7bSmrg * 31e52adb7bSmrg * From the linux GL ABI (http://www.opengl.org/registry/ABI/): 32e52adb7bSmrg * 33e52adb7bSmrg * "3.4. The libraries must export all OpenGL 1.2, GLU 1.3, GLX 1.3, and 34e52adb7bSmrg * ARB_multitexture entry points statically. 35e52adb7bSmrg * 36e52adb7bSmrg * 3.5. Because non-ARB extensions vary so widely and are constantly 37e52adb7bSmrg * increasing in number, it's infeasible to require that they all be 38e52adb7bSmrg * supported, and extensions can always be added to hardware drivers 39e52adb7bSmrg * after the base link libraries are released. These drivers are 40e52adb7bSmrg * dynamically loaded by libGL, so extensions not in the base 41e52adb7bSmrg * library must also be obtained dynamically. 42e52adb7bSmrg * 43e52adb7bSmrg * 3.6. To perform the dynamic query, libGL also must export an entry 44e52adb7bSmrg * point called 45e52adb7bSmrg * 46e52adb7bSmrg * void (*glXGetProcAddressARB(const GLubyte *))(); 47e52adb7bSmrg * 48e52adb7bSmrg * The full specification of this function is available separately. It 49e52adb7bSmrg * takes the string name of a GL or GLX entry point and returns a pointer 50e52adb7bSmrg * to a function implementing that entry point. It is functionally 51e52adb7bSmrg * identical to the wglGetProcAddress query defined by the Windows OpenGL 52e52adb7bSmrg * library, except that the function pointers returned are context 53e52adb7bSmrg * independent, unlike the WGL query." 54e52adb7bSmrg * 55e52adb7bSmrg * From the EGL 1.4 spec: 56e52adb7bSmrg * 57e52adb7bSmrg * "Client API function pointers returned by eglGetProcAddress are 58e52adb7bSmrg * independent of the display and the currently bound client API context, 59e52adb7bSmrg * and may be used by any client API context which supports the extension. 60e52adb7bSmrg * 61e52adb7bSmrg * eglGetProcAddress may be queried for all of the following functions: 62e52adb7bSmrg * 63e52adb7bSmrg * • All EGL and client API extension functions supported by the 64e52adb7bSmrg * implementation (whether those extensions are supported by the current 65e52adb7bSmrg * client API context or not). This includes any mandatory OpenGL ES 66e52adb7bSmrg * extensions. 67e52adb7bSmrg * 68e52adb7bSmrg * eglGetProcAddress may not be queried for core (non-extension) functions 69e52adb7bSmrg * in EGL or client APIs 20 . 70e52adb7bSmrg * 71e52adb7bSmrg * For functions that are queryable with eglGetProcAddress, 72e52adb7bSmrg * implementations may choose to also export those functions statically 73e52adb7bSmrg * from the object libraries im- plementing those functions. However, 74e52adb7bSmrg * portable clients cannot rely on this behavior. 75e52adb7bSmrg * 76e52adb7bSmrg * From the GLX 1.4 spec: 77e52adb7bSmrg * 78e52adb7bSmrg * "glXGetProcAddress may be queried for all of the following functions: 79e52adb7bSmrg * 80e52adb7bSmrg * • All GL and GLX extension functions supported by the implementation 81e52adb7bSmrg * (whether those extensions are supported by the current context or 82e52adb7bSmrg * not). 83e52adb7bSmrg * 84e52adb7bSmrg * • All core (non-extension) functions in GL and GLX from version 1.0 up 85e52adb7bSmrg * to and including the versions of those specifications supported by 86e52adb7bSmrg * the implementation, as determined by glGetString(GL VERSION) and 87e52adb7bSmrg * glXQueryVersion queries." 88e52adb7bSmrg */ 89e52adb7bSmrg 90e52adb7bSmrg#include <assert.h> 91e52adb7bSmrg#include <stdlib.h> 92e52adb7bSmrg#ifdef _WIN32 93e52adb7bSmrg#include <windows.h> 94e52adb7bSmrg#else 95e52adb7bSmrg#include <dlfcn.h> 96e52adb7bSmrg#include <err.h> 97e52adb7bSmrg#include <pthread.h> 98e52adb7bSmrg#endif 99e52adb7bSmrg#include <string.h> 100e52adb7bSmrg#include <ctype.h> 101e52adb7bSmrg#include <stdio.h> 102e52adb7bSmrg 103e52adb7bSmrg#include "dispatch_common.h" 104e52adb7bSmrg 105e52adb7bSmrg#ifdef __APPLE__ 106e52adb7bSmrg#define GLX_LIB "/opt/X11/lib/libGL.1.dylib" 107e52adb7bSmrg#elif defined(ANDROID) 108e52adb7bSmrg#define GLX_LIB "libGLESv2.so" 109e52adb7bSmrg#else 110e52adb7bSmrg#define GLX_LIB "libGL.so.1" 111e52adb7bSmrg#endif 112e52adb7bSmrg 113e52adb7bSmrg#ifdef ANDROID 114e52adb7bSmrg#define EGL_LIB "libEGL.so" 115e52adb7bSmrg#define GLES1_LIB "libGLESv1_CM.so" 116e52adb7bSmrg#define GLES2_LIB "libGLESv2.so" 117e52adb7bSmrg#else 118e52adb7bSmrg#define EGL_LIB "libEGL.so.1" 119e52adb7bSmrg#define GLES1_LIB "libGLESv1_CM.so.1" 120e52adb7bSmrg#define GLES2_LIB "libGLESv2.so.2" 121e52adb7bSmrg#endif 122e52adb7bSmrg 123e52adb7bSmrg#ifdef __GNUC__ 124e52adb7bSmrg#define CONSTRUCT(_func) static void _func (void) __attribute__((constructor)); 125e52adb7bSmrg#define DESTRUCT(_func) static void _func (void) __attribute__((destructor)); 126e52adb7bSmrg#elif defined (_MSC_VER) && (_MSC_VER >= 1500) 127e52adb7bSmrg#define CONSTRUCT(_func) \ 128e52adb7bSmrg static void _func(void); \ 129e52adb7bSmrg static int _func ## _wrapper(void) { _func(); return 0; } \ 130e52adb7bSmrg __pragma(section(".CRT$XCU",read)) \ 131e52adb7bSmrg __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _wrapper; 132e52adb7bSmrg 133e52adb7bSmrg#define DESTRUCT(_func) \ 134e52adb7bSmrg static void _func(void); \ 135e52adb7bSmrg static int _func ## _constructor(void) { atexit (_func); return 0; } \ 136e52adb7bSmrg __pragma(section(".CRT$XCU",read)) \ 137e52adb7bSmrg __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _constructor; 138e52adb7bSmrg 139e52adb7bSmrg#else 140e52adb7bSmrg#error "You will need constructor support for your compiler" 141e52adb7bSmrg#endif 142e52adb7bSmrg 143e52adb7bSmrgstruct api { 144e52adb7bSmrg#ifndef _WIN32 145e52adb7bSmrg /** 146e52adb7bSmrg * Locking for making sure we don't double-dlopen(). 147e52adb7bSmrg */ 148e52adb7bSmrg pthread_mutex_t mutex; 149e52adb7bSmrg#endif 150e52adb7bSmrg 151e52adb7bSmrg /** dlopen() return value for libGL.so.1. */ 152e52adb7bSmrg void *glx_handle; 153e52adb7bSmrg 154e52adb7bSmrg /** 155e52adb7bSmrg * dlopen() return value for OS X's GL library. 156e52adb7bSmrg * 157e52adb7bSmrg * On linux, glx_handle is used instead. 158e52adb7bSmrg */ 159e52adb7bSmrg void *gl_handle; 160e52adb7bSmrg 161e52adb7bSmrg /** dlopen() return value for libEGL.so.1 */ 162e52adb7bSmrg void *egl_handle; 163e52adb7bSmrg 164e52adb7bSmrg /** dlopen() return value for libGLESv1_CM.so.1 */ 165e52adb7bSmrg void *gles1_handle; 166e52adb7bSmrg 167e52adb7bSmrg /** dlopen() return value for libGLESv2.so.2 */ 168e52adb7bSmrg void *gles2_handle; 169e52adb7bSmrg 170e52adb7bSmrg /** 171e52adb7bSmrg * This value gets incremented when any thread is in 172e52adb7bSmrg * glBegin()/glEnd() called through epoxy. 173e52adb7bSmrg * 174e52adb7bSmrg * We're not guaranteed to be called through our wrapper, so the 175e52adb7bSmrg * conservative paths also try to handle the failure cases they'll 176e52adb7bSmrg * see if begin_count didn't reflect reality. It's also a bit of 177e52adb7bSmrg * a bug that the conservative paths might return success because 178e52adb7bSmrg * some other thread was in epoxy glBegin/glEnd while our thread 179e52adb7bSmrg * is trying to resolve, but given that it's basically just for 180e52adb7bSmrg * informative error messages, we shouldn't need to care. 181e52adb7bSmrg */ 182e52adb7bSmrg long begin_count; 183e52adb7bSmrg}; 184e52adb7bSmrg 185e52adb7bSmrgstatic struct api api = { 186e52adb7bSmrg#ifndef _WIN32 187e52adb7bSmrg .mutex = PTHREAD_MUTEX_INITIALIZER, 188e52adb7bSmrg#else 189e52adb7bSmrg 0, 190e52adb7bSmrg#endif 191e52adb7bSmrg}; 192e52adb7bSmrg 193e52adb7bSmrgstatic bool library_initialized; 194e52adb7bSmrg 195e52adb7bSmrgstatic bool epoxy_current_context_is_glx(void); 196e52adb7bSmrg 197e52adb7bSmrg#if PLATFORM_HAS_EGL 198e52adb7bSmrgstatic EGLenum 199e52adb7bSmrgepoxy_egl_get_current_gl_context_api(void); 200e52adb7bSmrg#endif 201e52adb7bSmrg 202e52adb7bSmrgCONSTRUCT (library_init) 203e52adb7bSmrg 204e52adb7bSmrgstatic void 205e52adb7bSmrglibrary_init(void) 206e52adb7bSmrg{ 207e52adb7bSmrg library_initialized = true; 208e52adb7bSmrg} 209e52adb7bSmrg 210e52adb7bSmrgstatic bool 211e52adb7bSmrgget_dlopen_handle(void **handle, const char *lib_name, bool exit_on_fail) 212e52adb7bSmrg{ 213e52adb7bSmrg if (*handle) 214e52adb7bSmrg return true; 215e52adb7bSmrg 216e52adb7bSmrg if (!library_initialized) { 217e52adb7bSmrg fprintf(stderr, 218e52adb7bSmrg "Attempting to dlopen() while in the dynamic linker.\n"); 219e52adb7bSmrg abort(); 220e52adb7bSmrg } 221e52adb7bSmrg 222e52adb7bSmrg#ifdef _WIN32 223e52adb7bSmrg *handle = LoadLibraryA(lib_name); 224e52adb7bSmrg#else 225e52adb7bSmrg pthread_mutex_lock(&api.mutex); 226e52adb7bSmrg if (!*handle) { 227e52adb7bSmrg *handle = dlopen(lib_name, RTLD_LAZY | RTLD_LOCAL); 228e52adb7bSmrg if (!*handle) { 229e52adb7bSmrg if (exit_on_fail) { 230e52adb7bSmrg fprintf(stderr, "Couldn't open %s: %s\n", lib_name, dlerror()); 231e52adb7bSmrg exit(1); 232e52adb7bSmrg } else { 233e52adb7bSmrg (void)dlerror(); 234e52adb7bSmrg } 235e52adb7bSmrg } 236e52adb7bSmrg } 237e52adb7bSmrg pthread_mutex_unlock(&api.mutex); 238e52adb7bSmrg#endif 239e52adb7bSmrg 240e52adb7bSmrg return *handle != NULL; 241e52adb7bSmrg} 242e52adb7bSmrg 243e52adb7bSmrgstatic void * 244e52adb7bSmrgdo_dlsym(void **handle, const char *lib_name, const char *name, 245e52adb7bSmrg bool exit_on_fail) 246e52adb7bSmrg{ 247e52adb7bSmrg void *result; 248e52adb7bSmrg const char *error = ""; 249e52adb7bSmrg 250e52adb7bSmrg if (!get_dlopen_handle(handle, lib_name, exit_on_fail)) 251e52adb7bSmrg return NULL; 252e52adb7bSmrg 253e52adb7bSmrg#ifdef _WIN32 254e52adb7bSmrg result = GetProcAddress(*handle, name); 255e52adb7bSmrg#else 256e52adb7bSmrg result = dlsym(*handle, name); 257e52adb7bSmrg if (!result) 258e52adb7bSmrg error = dlerror(); 259e52adb7bSmrg#endif 260e52adb7bSmrg if (!result && exit_on_fail) { 261e52adb7bSmrg fprintf(stderr,"%s() not found in %s: %s\n", name, lib_name, error); 262e52adb7bSmrg exit(1); 263e52adb7bSmrg } 264e52adb7bSmrg 265e52adb7bSmrg return result; 266e52adb7bSmrg} 267e52adb7bSmrg 268e52adb7bSmrgPUBLIC bool 269e52adb7bSmrgepoxy_is_desktop_gl(void) 270e52adb7bSmrg{ 271e52adb7bSmrg const char *es_prefix = "OpenGL ES"; 272e52adb7bSmrg const char *version; 273e52adb7bSmrg 274e52adb7bSmrg#if PLATFORM_HAS_EGL 275e52adb7bSmrg /* PowerVR's OpenGL ES implementation (and perhaps other) don't 276e52adb7bSmrg * comply with the standard, which states that 277e52adb7bSmrg * "glGetString(GL_VERSION)" should return a string starting with 278e52adb7bSmrg * "OpenGL ES". Therefore, to distinguish desktop OpenGL from 279e52adb7bSmrg * OpenGL ES, we must also check the context type through EGL (we 280e52adb7bSmrg * can do that as PowerVR is only usable through EGL). 281e52adb7bSmrg */ 282e52adb7bSmrg if (!epoxy_current_context_is_glx()) { 283e52adb7bSmrg switch (epoxy_egl_get_current_gl_context_api()) { 284e52adb7bSmrg case EGL_OPENGL_API: return true; 285e52adb7bSmrg case EGL_OPENGL_ES_API: return false; 286e52adb7bSmrg case EGL_NONE: 287e52adb7bSmrg default: break; 288e52adb7bSmrg } 289e52adb7bSmrg } 290e52adb7bSmrg#endif 291e52adb7bSmrg 292e52adb7bSmrg if (api.begin_count) 293e52adb7bSmrg return true; 294e52adb7bSmrg 295e52adb7bSmrg version = (const char *)glGetString(GL_VERSION); 296e52adb7bSmrg 297e52adb7bSmrg /* If we didn't get a version back, there are only two things that 298e52adb7bSmrg * could have happened: either malloc failure (which basically 299e52adb7bSmrg * doesn't exist), or we were called within a glBegin()/glEnd(). 300e52adb7bSmrg * Assume the second, which only exists for desktop GL. 301e52adb7bSmrg */ 302e52adb7bSmrg if (!version) 303e52adb7bSmrg return true; 304e52adb7bSmrg 305e52adb7bSmrg return strncmp(es_prefix, version, strlen(es_prefix)); 306e52adb7bSmrg} 307e52adb7bSmrg 308e52adb7bSmrgstatic int 309e52adb7bSmrgepoxy_internal_gl_version(int error_version) 310e52adb7bSmrg{ 311e52adb7bSmrg const char *version = (const char *)glGetString(GL_VERSION); 312e52adb7bSmrg GLint major, minor; 313e52adb7bSmrg int scanf_count; 314e52adb7bSmrg 315e52adb7bSmrg if (!version) 316e52adb7bSmrg return error_version; 317e52adb7bSmrg 318e52adb7bSmrg /* skip to version number */ 319e52adb7bSmrg while (!isdigit(*version) && *version != '\0') 320e52adb7bSmrg version++; 321e52adb7bSmrg 322e52adb7bSmrg /* Interpret version number */ 323e52adb7bSmrg scanf_count = sscanf(version, "%i.%i", &major, &minor); 324e52adb7bSmrg if (scanf_count != 2) { 325e52adb7bSmrg fprintf(stderr, "Unable to interpret GL_VERSION string: %s\n", 326e52adb7bSmrg version); 327e52adb7bSmrg exit(1); 328e52adb7bSmrg } 329e52adb7bSmrg return 10 * major + minor; 330e52adb7bSmrg} 331e52adb7bSmrg 332e52adb7bSmrgPUBLIC int 333e52adb7bSmrgepoxy_gl_version(void) 334e52adb7bSmrg{ 335e52adb7bSmrg return epoxy_internal_gl_version(0); 336e52adb7bSmrg} 337e52adb7bSmrg 338e52adb7bSmrgint 339e52adb7bSmrgepoxy_conservative_gl_version(void) 340e52adb7bSmrg{ 341e52adb7bSmrg if (api.begin_count) 342e52adb7bSmrg return 100; 343e52adb7bSmrg 344e52adb7bSmrg return epoxy_internal_gl_version(100); 345e52adb7bSmrg} 346e52adb7bSmrg 347e52adb7bSmrgbool 348e52adb7bSmrgepoxy_extension_in_string(const char *extension_list, const char *ext) 349e52adb7bSmrg{ 350e52adb7bSmrg const char *ptr = extension_list; 351e52adb7bSmrg int len = strlen(ext); 352e52adb7bSmrg 353e52adb7bSmrg /* Make sure that don't just find an extension with our name as a prefix. */ 354e52adb7bSmrg while (true) { 355e52adb7bSmrg ptr = strstr(ptr, ext); 356e52adb7bSmrg if (!ptr) 357e52adb7bSmrg return false; 358e52adb7bSmrg 359e52adb7bSmrg if (ptr[len] == ' ' || ptr[len] == 0) 360e52adb7bSmrg return true; 361e52adb7bSmrg ptr += len; 362e52adb7bSmrg } 363e52adb7bSmrg} 364e52adb7bSmrg 365e52adb7bSmrgstatic bool 366e52adb7bSmrgepoxy_internal_has_gl_extension(const char *ext, bool invalid_op_mode) 367e52adb7bSmrg{ 368e52adb7bSmrg if (epoxy_gl_version() < 30) { 369e52adb7bSmrg const char *exts = (const char *)glGetString(GL_EXTENSIONS); 370e52adb7bSmrg if (!exts) 371e52adb7bSmrg return invalid_op_mode; 372e52adb7bSmrg return epoxy_extension_in_string(exts, ext); 373e52adb7bSmrg } else { 374e52adb7bSmrg int num_extensions; 375e52adb7bSmrg int i; 376e52adb7bSmrg 377e52adb7bSmrg glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions); 378e52adb7bSmrg if (num_extensions == 0) 379e52adb7bSmrg return invalid_op_mode; 380e52adb7bSmrg 381e52adb7bSmrg for (i = 0; i < num_extensions; i++) { 382e52adb7bSmrg const char *gl_ext = (const char *)glGetStringi(GL_EXTENSIONS, i); 383e52adb7bSmrg if (strcmp(ext, gl_ext) == 0) 384e52adb7bSmrg return true; 385e52adb7bSmrg } 386e52adb7bSmrg 387e52adb7bSmrg return false; 388e52adb7bSmrg } 389e52adb7bSmrg} 390e52adb7bSmrg 391e52adb7bSmrg/** 392e52adb7bSmrg * Tests whether the currently bound context is EGL or GLX, trying to 393e52adb7bSmrg * avoid loading libraries unless necessary. 394e52adb7bSmrg */ 395e52adb7bSmrgstatic bool 396e52adb7bSmrgepoxy_current_context_is_glx(void) 397e52adb7bSmrg{ 398e52adb7bSmrg#if !PLATFORM_HAS_GLX 399e52adb7bSmrg return false; 400e52adb7bSmrg#else 401e52adb7bSmrg /* If the application hasn't explicitly called some of our GLX 402e52adb7bSmrg * or EGL code but has presumably set up a context on its own, 403e52adb7bSmrg * then we need to figure out how to getprocaddress anyway. 404e52adb7bSmrg * 405e52adb7bSmrg * If there's a public GetProcAddress loaded in the 406e52adb7bSmrg * application's namespace, then use that. 407e52adb7bSmrg */ 408e52adb7bSmrg void *sym; 409e52adb7bSmrg 410e52adb7bSmrg sym = dlsym(NULL, "glXGetCurrentContext"); 411e52adb7bSmrg if (sym) { 412e52adb7bSmrg if (glXGetCurrentContext()) 413e52adb7bSmrg return true; 414e52adb7bSmrg } else { 415e52adb7bSmrg (void)dlerror(); 416e52adb7bSmrg } 417e52adb7bSmrg 418e52adb7bSmrg#if PLATFORM_HAS_EGL 419e52adb7bSmrg sym = dlsym(NULL, "eglGetCurrentContext"); 420e52adb7bSmrg if (sym) { 421e52adb7bSmrg if (epoxy_egl_get_current_gl_context_api() != EGL_NONE) 422e52adb7bSmrg return false; 423e52adb7bSmrg } else { 424e52adb7bSmrg (void)dlerror(); 425e52adb7bSmrg } 426e52adb7bSmrg#endif /* PLATFORM_HAS_EGL */ 427e52adb7bSmrg 428e52adb7bSmrg /* OK, couldn't find anything in the app's address space. 429e52adb7bSmrg * Presumably they dlopened with RTLD_LOCAL, which hides it 430e52adb7bSmrg * from us. Just go dlopen()ing likely libraries and try them. 431e52adb7bSmrg */ 432e52adb7bSmrg sym = do_dlsym(&api.glx_handle, GLX_LIB, "glXGetCurrentContext", false); 433e52adb7bSmrg if (sym && glXGetCurrentContext()) 434e52adb7bSmrg return true; 435e52adb7bSmrg 436e52adb7bSmrg#if PLATFORM_HAS_EGL 437e52adb7bSmrg sym = do_dlsym(&api.egl_handle, EGL_LIB, "eglGetCurrentContext", 438e52adb7bSmrg false); 439e52adb7bSmrg if (sym && epoxy_egl_get_current_gl_context_api() != EGL_NONE) 440e52adb7bSmrg return false; 441e52adb7bSmrg#endif /* PLATFORM_HAS_EGL */ 442e52adb7bSmrg 443e52adb7bSmrg return false; 444e52adb7bSmrg#endif /* PLATFORM_HAS_GLX */ 445e52adb7bSmrg} 446e52adb7bSmrg 447e52adb7bSmrg/** 448e52adb7bSmrg * Returns true if the given GL extension is supported in the current context. 449e52adb7bSmrg * 450e52adb7bSmrg * Note that this function can't be called from within glBegin()/glEnd(). 451e52adb7bSmrg * 452e52adb7bSmrg * \sa epoxy_has_egl_extension() 453e52adb7bSmrg * \sa epoxy_has_glx_extension() 454e52adb7bSmrg */ 455e52adb7bSmrgPUBLIC bool 456e52adb7bSmrgepoxy_has_gl_extension(const char *ext) 457e52adb7bSmrg{ 458e52adb7bSmrg return epoxy_internal_has_gl_extension(ext, false); 459e52adb7bSmrg} 460e52adb7bSmrg 461e52adb7bSmrgbool 462e52adb7bSmrgepoxy_conservative_has_gl_extension(const char *ext) 463e52adb7bSmrg{ 464e52adb7bSmrg if (api.begin_count) 465e52adb7bSmrg return true; 466e52adb7bSmrg 467e52adb7bSmrg return epoxy_internal_has_gl_extension(ext, true); 468e52adb7bSmrg} 469e52adb7bSmrg 470e52adb7bSmrgvoid * 471e52adb7bSmrgepoxy_egl_dlsym(const char *name) 472e52adb7bSmrg{ 473e52adb7bSmrg return do_dlsym(&api.egl_handle, EGL_LIB, name, true); 474e52adb7bSmrg} 475e52adb7bSmrg 476e52adb7bSmrgvoid * 477e52adb7bSmrgepoxy_glx_dlsym(const char *name) 478e52adb7bSmrg{ 479e52adb7bSmrg return do_dlsym(&api.glx_handle, GLX_LIB, name, true); 480e52adb7bSmrg} 481e52adb7bSmrg 482e52adb7bSmrgvoid * 483e52adb7bSmrgepoxy_gl_dlsym(const char *name) 484e52adb7bSmrg{ 485e52adb7bSmrg#ifdef _WIN32 486e52adb7bSmrg return do_dlsym(&api.gl_handle, "OPENGL32", name, true); 487e52adb7bSmrg#elif defined(__APPLE__) 488e52adb7bSmrg return do_dlsym(&api.gl_handle, 489e52adb7bSmrg "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL", 490e52adb7bSmrg name, true); 491e52adb7bSmrg#else 492e52adb7bSmrg /* There's no library for desktop GL support independent of GLX. */ 493e52adb7bSmrg return epoxy_glx_dlsym(name); 494e52adb7bSmrg#endif 495e52adb7bSmrg} 496e52adb7bSmrg 497e52adb7bSmrgvoid * 498e52adb7bSmrgepoxy_gles1_dlsym(const char *name) 499e52adb7bSmrg{ 500e52adb7bSmrg if (epoxy_current_context_is_glx()) { 501e52adb7bSmrg return epoxy_get_proc_address(name); 502e52adb7bSmrg } else { 503e52adb7bSmrg return do_dlsym(&api.gles1_handle, GLES1_LIB, name, true); 504e52adb7bSmrg } 505e52adb7bSmrg} 506e52adb7bSmrg 507e52adb7bSmrgvoid * 508e52adb7bSmrgepoxy_gles2_dlsym(const char *name) 509e52adb7bSmrg{ 510e52adb7bSmrg if (epoxy_current_context_is_glx()) { 511e52adb7bSmrg return epoxy_get_proc_address(name); 512e52adb7bSmrg } else { 513e52adb7bSmrg return do_dlsym(&api.gles2_handle, GLES2_LIB, name, true); 514e52adb7bSmrg } 515e52adb7bSmrg} 516e52adb7bSmrg 517e52adb7bSmrg/** 518e52adb7bSmrg * Does the appropriate dlsym() or eglGetProcAddress() for GLES3 519e52adb7bSmrg * functions. 520e52adb7bSmrg * 521e52adb7bSmrg * Mesa interpreted GLES as intending that the GLES3 functions were 522e52adb7bSmrg * available only through eglGetProcAddress() and not dlsym(), while 523e52adb7bSmrg * ARM's Mali drivers interpreted GLES as intending that GLES3 524e52adb7bSmrg * functions were available only through dlsym() and not 525e52adb7bSmrg * eglGetProcAddress(). Thanks, Khronos. 526e52adb7bSmrg */ 527e52adb7bSmrgvoid * 528e52adb7bSmrgepoxy_gles3_dlsym(const char *name) 529e52adb7bSmrg{ 530e52adb7bSmrg if (epoxy_current_context_is_glx()) { 531e52adb7bSmrg return epoxy_get_proc_address(name); 532e52adb7bSmrg } else { 533e52adb7bSmrg void *func = do_dlsym(&api.gles2_handle, GLES2_LIB, name, false); 534e52adb7bSmrg 535e52adb7bSmrg if (func) 536e52adb7bSmrg return func; 537e52adb7bSmrg 538e52adb7bSmrg return epoxy_get_proc_address(name); 539e52adb7bSmrg } 540e52adb7bSmrg} 541e52adb7bSmrg 542e52adb7bSmrg/** 543e52adb7bSmrg * Performs either the dlsym or glXGetProcAddress()-equivalent for 544e52adb7bSmrg * core functions in desktop GL. 545e52adb7bSmrg */ 546e52adb7bSmrgvoid * 547e52adb7bSmrgepoxy_get_core_proc_address(const char *name, int core_version) 548e52adb7bSmrg{ 549e52adb7bSmrg#ifdef _WIN32 550e52adb7bSmrg int core_symbol_support = 11; 551e52adb7bSmrg#elif defined(ANDROID) 552e52adb7bSmrg /** 553e52adb7bSmrg * All symbols must be resolved through eglGetProcAddress 554e52adb7bSmrg * on Android 555e52adb7bSmrg */ 556e52adb7bSmrg int core_symbol_support = 0; 557e52adb7bSmrg#else 558e52adb7bSmrg int core_symbol_support = 12; 559e52adb7bSmrg#endif 560e52adb7bSmrg 561e52adb7bSmrg if (core_version <= core_symbol_support) { 562e52adb7bSmrg return epoxy_gl_dlsym(name); 563e52adb7bSmrg } else { 564e52adb7bSmrg return epoxy_get_proc_address(name); 565e52adb7bSmrg } 566e52adb7bSmrg} 567e52adb7bSmrg 568e52adb7bSmrg#if PLATFORM_HAS_EGL 569e52adb7bSmrgstatic EGLenum 570e52adb7bSmrgepoxy_egl_get_current_gl_context_api(void) 571e52adb7bSmrg{ 572e52adb7bSmrg EGLenum save_api = eglQueryAPI(); 573e52adb7bSmrg EGLContext ctx; 574e52adb7bSmrg 575e52adb7bSmrg if (eglBindAPI(EGL_OPENGL_API)) { 576e52adb7bSmrg ctx = eglGetCurrentContext(); 577e52adb7bSmrg if (ctx) { 578e52adb7bSmrg eglBindAPI(save_api); 579e52adb7bSmrg return EGL_OPENGL_API; 580e52adb7bSmrg } 581e52adb7bSmrg } else { 582e52adb7bSmrg (void)eglGetError(); 583e52adb7bSmrg } 584e52adb7bSmrg 585e52adb7bSmrg if (eglBindAPI(EGL_OPENGL_ES_API)) { 586e52adb7bSmrg ctx = eglGetCurrentContext(); 587e52adb7bSmrg eglBindAPI(save_api); 588e52adb7bSmrg if (ctx) { 589e52adb7bSmrg eglBindAPI(save_api); 590e52adb7bSmrg return EGL_OPENGL_ES_API; 591e52adb7bSmrg } 592e52adb7bSmrg } else { 593e52adb7bSmrg (void)eglGetError(); 594e52adb7bSmrg } 595e52adb7bSmrg 596e52adb7bSmrg return EGL_NONE; 597e52adb7bSmrg} 598e52adb7bSmrg#endif /* PLATFORM_HAS_EGL */ 599e52adb7bSmrg 600e52adb7bSmrg/** 601e52adb7bSmrg * Performs the dlsym() for the core GL 1.0 functions that we use for 602e52adb7bSmrg * determining version and extension support for deciding on dlsym 603e52adb7bSmrg * versus glXGetProcAddress() for all other functions. 604e52adb7bSmrg * 605e52adb7bSmrg * This needs to succeed on implementations without GLX (since 606e52adb7bSmrg * glGetString() and glGetIntegerv() are both in GLES1/2 as well, and 607e52adb7bSmrg * at call time we don't know for sure what API they're trying to use 608e52adb7bSmrg * without inspecting contexts ourselves). 609e52adb7bSmrg */ 610e52adb7bSmrgvoid * 611e52adb7bSmrgepoxy_get_bootstrap_proc_address(const char *name) 612e52adb7bSmrg{ 613e52adb7bSmrg /* If we already have a library that links to libglapi loaded, 614e52adb7bSmrg * use that. 615e52adb7bSmrg */ 616e52adb7bSmrg#if PLATFORM_HAS_GLX 617e52adb7bSmrg if (api.glx_handle && glXGetCurrentContext()) 618e52adb7bSmrg return epoxy_gl_dlsym(name); 619e52adb7bSmrg#endif 620e52adb7bSmrg 621e52adb7bSmrg /* If epoxy hasn't loaded any API-specific library yet, try to 622e52adb7bSmrg * figure out what API the context is using and use that library, 623e52adb7bSmrg * since future calls will also use that API (this prevents a 624e52adb7bSmrg * non-X11 ES2 context from loading a bunch of X11 junk). 625e52adb7bSmrg */ 626e52adb7bSmrg#if PLATFORM_HAS_EGL 627e52adb7bSmrg get_dlopen_handle(&api.egl_handle, EGL_LIB, false); 628e52adb7bSmrg if (api.egl_handle) { 629e52adb7bSmrg switch (epoxy_egl_get_current_gl_context_api()) { 630e52adb7bSmrg case EGL_OPENGL_API: 631e52adb7bSmrg return epoxy_gl_dlsym(name); 632e52adb7bSmrg case EGL_OPENGL_ES_API: 633e52adb7bSmrg /* We can't resolve the GL version, because 634e52adb7bSmrg * epoxy_glGetString() is one of the two things calling 635e52adb7bSmrg * us. Try the GLES2 implementation first, and fall back 636e52adb7bSmrg * to GLES1 otherwise. 637e52adb7bSmrg */ 638e52adb7bSmrg get_dlopen_handle(&api.gles2_handle, GLES2_LIB, false); 639e52adb7bSmrg if (api.gles2_handle) 640e52adb7bSmrg return epoxy_gles2_dlsym(name); 641e52adb7bSmrg else 642e52adb7bSmrg return epoxy_gles1_dlsym(name); 643e52adb7bSmrg } 644e52adb7bSmrg } 645e52adb7bSmrg#endif /* PLATFORM_HAS_EGL */ 646e52adb7bSmrg 647e52adb7bSmrg /* Fall back to GLX */ 648e52adb7bSmrg return epoxy_gl_dlsym(name); 649e52adb7bSmrg} 650e52adb7bSmrg 651e52adb7bSmrgvoid * 652e52adb7bSmrgepoxy_get_proc_address(const char *name) 653e52adb7bSmrg{ 654e52adb7bSmrg#ifdef _WIN32 655e52adb7bSmrg return wglGetProcAddress(name); 656e52adb7bSmrg#elif defined(__APPLE__) 657e52adb7bSmrg return epoxy_gl_dlsym(name); 658e52adb7bSmrg#else 659e52adb7bSmrg if (epoxy_current_context_is_glx()) { 660e52adb7bSmrg return glXGetProcAddressARB((const GLubyte *)name); 661e52adb7bSmrg } else { 662e52adb7bSmrg#if PLATFORM_HAS_EGL 663e52adb7bSmrg GLenum egl_api = epoxy_egl_get_current_gl_context_api(); 664e52adb7bSmrg 665e52adb7bSmrg switch (egl_api) { 666e52adb7bSmrg case EGL_OPENGL_API: 667e52adb7bSmrg case EGL_OPENGL_ES_API: 668e52adb7bSmrg return eglGetProcAddress(name); 669e52adb7bSmrg case EGL_NONE: 670e52adb7bSmrg break; 671e52adb7bSmrg } 672e52adb7bSmrg#endif 673e52adb7bSmrg } 674e52adb7bSmrg errx(1, "Couldn't find current GLX or EGL context.\n"); 675e52adb7bSmrg#endif 676e52adb7bSmrg} 677e52adb7bSmrg 678e52adb7bSmrgWRAPPER_VISIBILITY (void) 679e52adb7bSmrgWRAPPER(epoxy_glBegin)(GLenum primtype) 680e52adb7bSmrg{ 681e52adb7bSmrg#ifdef _WIN32 682e52adb7bSmrg InterlockedIncrement(&api.begin_count); 683e52adb7bSmrg#else 684e52adb7bSmrg pthread_mutex_lock(&api.mutex); 685e52adb7bSmrg api.begin_count++; 686e52adb7bSmrg pthread_mutex_unlock(&api.mutex); 687e52adb7bSmrg#endif 688e52adb7bSmrg 689e52adb7bSmrg epoxy_glBegin_unwrapped(primtype); 690e52adb7bSmrg} 691e52adb7bSmrg 692e52adb7bSmrgWRAPPER_VISIBILITY (void) 693e52adb7bSmrgWRAPPER(epoxy_glEnd)(void) 694e52adb7bSmrg{ 695e52adb7bSmrg epoxy_glEnd_unwrapped(); 696e52adb7bSmrg 697e52adb7bSmrg#ifdef _WIN32 698e52adb7bSmrg InterlockedDecrement(&api.begin_count); 699e52adb7bSmrg#else 700e52adb7bSmrg pthread_mutex_lock(&api.mutex); 701e52adb7bSmrg api.begin_count--; 702e52adb7bSmrg pthread_mutex_unlock(&api.mutex); 703e52adb7bSmrg#endif 704e52adb7bSmrg} 705e52adb7bSmrg 706e52adb7bSmrgPUBLIC PFNGLBEGINPROC epoxy_glBegin = epoxy_glBegin_wrapped; 707e52adb7bSmrgPUBLIC PFNGLENDPROC epoxy_glEnd = epoxy_glEnd_wrapped; 708