blob: bc2fb949d9fdb1b67ac41ac23ee08df490fc294d [file] [log] [blame]
Eric Anholta909eb42013-09-19 09:50:49 -07001/*
Eric Anholt10644062014-01-31 14:49:00 -08002 * Copyright © 2013-2014 Intel Corporation
Eric Anholta909eb42013-09-19 09:50:49 -07003 *
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/**
Emmanuele Bassi6af57b02017-01-27 18:12:05 +000025 * \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.
Emmanuele Bassic794dce2018-02-23 15:48:44 +000044 * - GL 4.6 core and compatibility context support.
Emmanuele Bassi6af57b02017-01-27 18:12:05 +000045 * - 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/**
Eric Anholta909eb42013-09-19 09:50:49 -070096 * @file dispatch_common.c
97 *
Emmanuele Bassi6af57b02017-01-27 18:12:05 +000098 * @brief Implements common code shared by the generated GL/EGL/GLX dispatch code.
Eric Anholta909eb42013-09-19 09:50:49 -070099 *
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>
Eric Anholt25913682013-12-06 13:40:30 -0800163#ifdef _WIN32
164#include <windows.h>
165#else
Eric Anholta909eb42013-09-19 09:50:49 -0700166#include <dlfcn.h>
Eric Anholt25913682013-12-06 13:40:30 -0800167#include <err.h>
168#include <pthread.h>
169#endif
Eric Anholta909eb42013-09-19 09:50:49 -0700170#include <string.h>
Eric Anholt66d7b9f2013-11-11 09:27:07 -0800171#include <ctype.h>
Eric Anholta909eb42013-09-19 09:50:49 -0700172#include <stdio.h>
Eric Anholt906d5b62013-12-06 12:21:54 -0800173
Eric Anholta909eb42013-09-19 09:50:49 -0700174#include "dispatch_common.h"
175
Eric Anholt8d8334c2013-12-12 10:55:32 -0800176#ifdef __APPLE__
177#define GLX_LIB "/opt/X11/lib/libGL.1.dylib"
Robert Bragg4e5e17e2018-01-18 21:21:15 +0000178#elif defined(__ANDROID__)
Ryan Houdekc7916122014-05-04 19:05:34 -0500179#define GLX_LIB "libGLESv2.so"
Eric Anholt8d8334c2013-12-12 10:55:32 -0800180#else
Adam Jackson759de642017-06-16 14:37:06 -0400181#define GLVND_GLX_LIB "libGLX.so.1"
Eric Anholt8d8334c2013-12-12 10:55:32 -0800182#define GLX_LIB "libGL.so.1"
183#endif
184
Robert Bragg4e5e17e2018-01-18 21:21:15 +0000185#ifdef __ANDROID__
Ryan Houdekc7916122014-05-04 19:05:34 -0500186#define EGL_LIB "libEGL.so"
187#define GLES1_LIB "libGLESv1_CM.so"
188#define GLES2_LIB "libGLESv2.so"
Yaron Cohen-Tal9e46b8e2016-12-13 12:26:41 +0000189#elif defined _WIN32
190#define EGL_LIB "libEGL.dll"
191#define GLES1_LIB "libGLES_CM.dll"
192#define GLES2_LIB "libGLESv2.dll"
Ryan Houdekc7916122014-05-04 19:05:34 -0500193#else
194#define EGL_LIB "libEGL.so.1"
195#define GLES1_LIB "libGLESv1_CM.so.1"
196#define GLES2_LIB "libGLESv2.so.2"
Adam Jacksone5372a22017-09-07 17:02:22 -0400197#define OPENGL_LIB "libOpenGL.so.0"
Ryan Houdekc7916122014-05-04 19:05:34 -0500198#endif
199
Chun-wei Fan95ecc2d2015-06-05 14:03:51 +0800200#ifdef __GNUC__
201#define CONSTRUCT(_func) static void _func (void) __attribute__((constructor));
202#define DESTRUCT(_func) static void _func (void) __attribute__((destructor));
203#elif defined (_MSC_VER) && (_MSC_VER >= 1500)
204#define CONSTRUCT(_func) \
205 static void _func(void); \
206 static int _func ## _wrapper(void) { _func(); return 0; } \
207 __pragma(section(".CRT$XCU",read)) \
208 __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _wrapper;
209
210#define DESTRUCT(_func) \
211 static void _func(void); \
212 static int _func ## _constructor(void) { atexit (_func); return 0; } \
213 __pragma(section(".CRT$XCU",read)) \
214 __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _constructor;
215
216#else
217#error "You will need constructor support for your compiler"
218#endif
219
Eric Anholt0270c802013-12-02 16:25:02 -0800220struct api {
Eric Anholt25913682013-12-06 13:40:30 -0800221#ifndef _WIN32
Emmanuele Bassi6af57b02017-01-27 18:12:05 +0000222 /*
Eric Anholt0270c802013-12-02 16:25:02 -0800223 * Locking for making sure we don't double-dlopen().
224 */
225 pthread_mutex_t mutex;
Eric Anholt25913682013-12-06 13:40:30 -0800226#endif
Eric Anholta909eb42013-09-19 09:50:49 -0700227
Adam Jackson759de642017-06-16 14:37:06 -0400228 /*
229 * dlopen() return value for the GLX API. This is libGLX.so.1 if the
230 * runtime is glvnd-enabled, else libGL.so.1
231 */
Eric Anholt0270c802013-12-02 16:25:02 -0800232 void *glx_handle;
233
Emmanuele Bassi6af57b02017-01-27 18:12:05 +0000234 /*
Adam Jackson759de642017-06-16 14:37:06 -0400235 * dlopen() return value for the desktop GL library.
Eric Anholtd82c5c32013-12-11 16:49:08 -0800236 *
Adam Jackson759de642017-06-16 14:37:06 -0400237 * On Windows this is OPENGL32. On OSX this is classic libGL. On Linux
238 * this is either libOpenGL (if the runtime is glvnd-enabled) or
239 * classic libGL.so.1
Eric Anholtd82c5c32013-12-11 16:49:08 -0800240 */
241 void *gl_handle;
242
Emmanuele Bassi6af57b02017-01-27 18:12:05 +0000243 /* dlopen() return value for libEGL.so.1 */
Eric Anholt0270c802013-12-02 16:25:02 -0800244 void *egl_handle;
245
Emmanuele Bassi6af57b02017-01-27 18:12:05 +0000246 /* dlopen() return value for libGLESv1_CM.so.1 */
Eric Anholt0270c802013-12-02 16:25:02 -0800247 void *gles1_handle;
248
Emmanuele Bassi6af57b02017-01-27 18:12:05 +0000249 /* dlopen() return value for libGLESv2.so.2 */
Eric Anholt0270c802013-12-02 16:25:02 -0800250 void *gles2_handle;
Eric Anholt09839962013-12-05 13:59:34 -0800251
Emmanuele Bassi6af57b02017-01-27 18:12:05 +0000252 /*
Eric Anholt09839962013-12-05 13:59:34 -0800253 * This value gets incremented when any thread is in
254 * glBegin()/glEnd() called through epoxy.
255 *
256 * We're not guaranteed to be called through our wrapper, so the
257 * conservative paths also try to handle the failure cases they'll
258 * see if begin_count didn't reflect reality. It's also a bit of
259 * a bug that the conservative paths might return success because
260 * some other thread was in epoxy glBegin/glEnd while our thread
261 * is trying to resolve, but given that it's basically just for
262 * informative error messages, we shouldn't need to care.
263 */
Eric Anholt4eaf4bf2013-12-10 14:09:37 -0800264 long begin_count;
Eric Anholt0270c802013-12-02 16:25:02 -0800265};
266
267static struct api api = {
Eric Anholt25913682013-12-06 13:40:30 -0800268#ifndef _WIN32
Eric Anholt0270c802013-12-02 16:25:02 -0800269 .mutex = PTHREAD_MUTEX_INITIALIZER,
Chun-wei Fane2424972015-06-05 17:37:01 -0700270#else
271 0,
Eric Anholt25913682013-12-06 13:40:30 -0800272#endif
Eric Anholt0270c802013-12-02 16:25:02 -0800273};
274
Eric Anholt10c611a2013-12-13 12:22:36 -0800275static bool library_initialized;
276
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000277static bool epoxy_current_context_is_glx(void);
278
279#if PLATFORM_HAS_EGL
Eric Anholtb251e3a2014-03-27 19:04:27 -0700280static EGLenum
281epoxy_egl_get_current_gl_context_api(void);
282#endif
283
Chun-wei Fan95ecc2d2015-06-05 14:03:51 +0800284CONSTRUCT (library_init)
Eric Anholt10c611a2013-12-13 12:22:36 -0800285
286static void
287library_init(void)
288{
289 library_initialized = true;
290}
291
Eric Anholt72187a22014-03-27 18:53:10 -0700292static bool
Eric Anholt0270c802013-12-02 16:25:02 -0800293get_dlopen_handle(void **handle, const char *lib_name, bool exit_on_fail)
294{
295 if (*handle)
Eric Anholt72187a22014-03-27 18:53:10 -0700296 return true;
Eric Anholt0270c802013-12-02 16:25:02 -0800297
Eric Anholt10c611a2013-12-13 12:22:36 -0800298 if (!library_initialized) {
Ikey Dohertyc8d7ae62017-10-19 16:02:57 +0100299 fputs("Attempting to dlopen() while in the dynamic linker.\n", stderr);
Eric Anholt10c611a2013-12-13 12:22:36 -0800300 abort();
301 }
302
Eric Anholt5112b472013-12-17 10:38:29 -0800303#ifdef _WIN32
304 *handle = LoadLibraryA(lib_name);
305#else
Eric Anholt0270c802013-12-02 16:25:02 -0800306 pthread_mutex_lock(&api.mutex);
307 if (!*handle) {
308 *handle = dlopen(lib_name, RTLD_LAZY | RTLD_LOCAL);
Eric Anholtd48978c2014-03-27 18:54:12 -0700309 if (!*handle) {
310 if (exit_on_fail) {
311 fprintf(stderr, "Couldn't open %s: %s\n", lib_name, dlerror());
312 exit(1);
313 } else {
314 (void)dlerror();
315 }
Eric Anholt0270c802013-12-02 16:25:02 -0800316 }
317 }
318 pthread_mutex_unlock(&api.mutex);
Eric Anholt5112b472013-12-17 10:38:29 -0800319#endif
Eric Anholt72187a22014-03-27 18:53:10 -0700320
321 return *handle != NULL;
Eric Anholt0270c802013-12-02 16:25:02 -0800322}
323
324static void *
325do_dlsym(void **handle, const char *lib_name, const char *name,
326 bool exit_on_fail)
327{
328 void *result;
Eric Anholtd48978c2014-03-27 18:54:12 -0700329 const char *error = "";
Eric Anholt0270c802013-12-02 16:25:02 -0800330
Eric Anholt72187a22014-03-27 18:53:10 -0700331 if (!get_dlopen_handle(handle, lib_name, exit_on_fail))
332 return NULL;
Eric Anholt0270c802013-12-02 16:25:02 -0800333
Eric Anholt5112b472013-12-17 10:38:29 -0800334#ifdef _WIN32
335 result = GetProcAddress(*handle, name);
336#else
Eric Anholt0270c802013-12-02 16:25:02 -0800337 result = dlsym(*handle, name);
Eric Anholtd48978c2014-03-27 18:54:12 -0700338 if (!result)
339 error = dlerror();
Eric Anholt5112b472013-12-17 10:38:29 -0800340#endif
Eric Anholt14f24482014-03-17 11:17:19 -0700341 if (!result && exit_on_fail) {
Eric Anholtd48978c2014-03-27 18:54:12 -0700342 fprintf(stderr,"%s() not found in %s: %s\n", name, lib_name, error);
Eric Anholt5112b472013-12-17 10:38:29 -0800343 exit(1);
344 }
Eric Anholt0270c802013-12-02 16:25:02 -0800345
346 return result;
347}
Eric Anholta909eb42013-09-19 09:50:49 -0700348
Emmanuele Bassi6af57b02017-01-27 18:12:05 +0000349/**
350 * @brief Checks whether we're using OpenGL or OpenGL ES
351 *
352 * @return `true` if we're using OpenGL
353 */
Emmanuele Bassi7a068032017-01-24 17:43:59 +0000354bool
Eric Anholta909eb42013-09-19 09:50:49 -0700355epoxy_is_desktop_gl(void)
356{
Eric Anholtaa778ef2014-01-22 00:57:35 -0800357 const char *es_prefix = "OpenGL ES";
Eric Anholt09839962013-12-05 13:59:34 -0800358 const char *version;
359
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000360#if PLATFORM_HAS_EGL
Yaron Cohen-Tala7c270f2015-07-09 13:44:52 +0300361 /* PowerVR's OpenGL ES implementation (and perhaps other) don't
362 * comply with the standard, which states that
363 * "glGetString(GL_VERSION)" should return a string starting with
364 * "OpenGL ES". Therefore, to distinguish desktop OpenGL from
365 * OpenGL ES, we must also check the context type through EGL (we
366 * can do that as PowerVR is only usable through EGL).
367 */
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000368 if (!epoxy_current_context_is_glx()) {
Yaron Cohen-Tala7c270f2015-07-09 13:44:52 +0300369 switch (epoxy_egl_get_current_gl_context_api()) {
370 case EGL_OPENGL_API: return true;
371 case EGL_OPENGL_ES_API: return false;
372 case EGL_NONE:
373 default: break;
374 }
375 }
376#endif
377
Eric Anholt09839962013-12-05 13:59:34 -0800378 if (api.begin_count)
379 return true;
380
381 version = (const char *)glGetString(GL_VERSION);
382
383 /* If we didn't get a version back, there are only two things that
384 * could have happened: either malloc failure (which basically
385 * doesn't exist), or we were called within a glBegin()/glEnd().
386 * Assume the second, which only exists for desktop GL.
387 */
388 if (!version)
389 return true;
Eric Anholta909eb42013-09-19 09:50:49 -0700390
Eric Anholt69241482013-11-11 09:19:36 -0800391 return strncmp(es_prefix, version, strlen(es_prefix));
Eric Anholta909eb42013-09-19 09:50:49 -0700392}
393
Eric Anholt09839962013-12-05 13:59:34 -0800394static int
Emmanuele Bassi60bb7672018-02-24 13:39:16 +0000395epoxy_internal_gl_version(GLenum version_string, int error_version)
Eric Anholta909eb42013-09-19 09:50:49 -0700396{
Emmanuele Bassid8726f22018-02-23 16:46:55 +0000397 const char *version = (const char *)glGetString(version_string);
Emmanuele Bassie1ffd322018-02-24 14:03:06 +0000398 GLint major, minor, factor;
Eric Anholt66d7b9f2013-11-11 09:27:07 -0800399 int scanf_count;
Eric Anholta909eb42013-09-19 09:50:49 -0700400
Eric Anholt09839962013-12-05 13:59:34 -0800401 if (!version)
402 return error_version;
403
Eric Anholt66d7b9f2013-11-11 09:27:07 -0800404 /* skip to version number */
405 while (!isdigit(*version) && *version != '\0')
406 version++;
Eric Anholta909eb42013-09-19 09:50:49 -0700407
Eric Anholt66d7b9f2013-11-11 09:27:07 -0800408 /* Interpret version number */
409 scanf_count = sscanf(version, "%i.%i", &major, &minor);
410 if (scanf_count != 2) {
411 fprintf(stderr, "Unable to interpret GL_VERSION string: %s\n",
412 version);
413 exit(1);
414 }
Emmanuele Bassie1ffd322018-02-24 14:03:06 +0000415
416 if (minor >= 10)
417 factor = 100;
418 else
419 factor = 10;
420
421 return factor * major + minor;
Eric Anholta909eb42013-09-19 09:50:49 -0700422}
423
Emmanuele Bassi6af57b02017-01-27 18:12:05 +0000424/**
425 * @brief Returns the version of OpenGL we are using
426 *
427 * The version is encoded as:
428 *
429 * ```
430 *
431 * version = major * 10 + minor
432 *
433 * ```
434 *
435 * So it can be easily used for version comparisons.
436 *
437 * @return The encoded version of OpenGL we are using
438 */
Emmanuele Bassi7a068032017-01-24 17:43:59 +0000439int
Eric Anholt09839962013-12-05 13:59:34 -0800440epoxy_gl_version(void)
441{
Emmanuele Bassid8726f22018-02-23 16:46:55 +0000442 return epoxy_internal_gl_version(GL_VERSION, 0);
Eric Anholt09839962013-12-05 13:59:34 -0800443}
444
Chun-wei Fand9df59d2015-06-17 09:38:53 +0800445int
Eric Anholt09839962013-12-05 13:59:34 -0800446epoxy_conservative_gl_version(void)
447{
448 if (api.begin_count)
449 return 100;
450
Emmanuele Bassid8726f22018-02-23 16:46:55 +0000451 return epoxy_internal_gl_version(GL_VERSION, 100);
452}
453
454/**
455 * @brief Returns the version of the GL Shading Language we are using
456 *
457 * The version is encoded as:
458 *
459 * ```
460 *
Emmanuele Bassie1ffd322018-02-24 14:03:06 +0000461 * version = major * 100 + minor
Emmanuele Bassid8726f22018-02-23 16:46:55 +0000462 *
463 * ```
464 *
465 * So it can be easily used for version comparisons.
466 *
467 * @return The encoded version of the GL Shading Language we are using
468 */
469int
470epoxy_glsl_version(void)
471{
472 if (epoxy_gl_version() >= 20 ||
473 epoxy_has_gl_extension ("GL_ARB_shading_language_100"))
474 return epoxy_internal_gl_version(GL_SHADING_LANGUAGE_VERSION, 0);
475
476 return 0;
Eric Anholt09839962013-12-05 13:59:34 -0800477}
478
Lyude Paul4bde48e2017-08-24 14:50:19 -0400479/**
480 * @brief Checks for the presence of an extension in an OpenGL extension string
481 *
482 * @param extension_list The string containing the list of extensions to check
483 * @param ext The name of the GL extension
484 * @return `true` if the extension is available'
485 *
486 * @note If you are looking to check whether a normal GL, EGL or GLX extension
487 * is supported by the client, this probably isn't the function you want.
488 *
489 * Some parts of the spec for OpenGL and friends will return an OpenGL formatted
luz.pazd60b9232018-03-05 06:08:53 -0500490 * extension string that is separate from the usual extension strings for the
Lyude Paul4bde48e2017-08-24 14:50:19 -0400491 * spec. This function provides easy parsing of those strings.
492 *
493 * @see epoxy_has_gl_extension()
494 * @see epoxy_has_egl_extension()
495 * @see epoxy_has_glx_extension()
496 */
Eric Anholt60ea7c32013-12-06 12:53:00 -0800497bool
Eric Anholta909eb42013-09-19 09:50:49 -0700498epoxy_extension_in_string(const char *extension_list, const char *ext)
499{
500 const char *ptr = extension_list;
Gianfranco Costamagna106eae72017-04-24 16:10:28 +0200501 int len;
502
503 if (!ext)
504 return false;
505
506 len = strlen(ext);
Eric Anholta909eb42013-09-19 09:50:49 -0700507
Emmanuele Bassiad1f9202016-12-07 15:12:15 +0000508 if (extension_list == NULL || *extension_list == '\0')
509 return false;
510
Eric Anholta909eb42013-09-19 09:50:49 -0700511 /* Make sure that don't just find an extension with our name as a prefix. */
Eric Anholt03e95372013-12-12 13:44:06 -0800512 while (true) {
Eric Anholta909eb42013-09-19 09:50:49 -0700513 ptr = strstr(ptr, ext);
Eric Anholt03e95372013-12-12 13:44:06 -0800514 if (!ptr)
515 return false;
Eric Anholta909eb42013-09-19 09:50:49 -0700516
Eric Anholt03e95372013-12-12 13:44:06 -0800517 if (ptr[len] == ' ' || ptr[len] == 0)
518 return true;
519 ptr += len;
520 }
Eric Anholta909eb42013-09-19 09:50:49 -0700521}
522
Eric Anholt09839962013-12-05 13:59:34 -0800523static bool
524epoxy_internal_has_gl_extension(const char *ext, bool invalid_op_mode)
Eric Anholta909eb42013-09-19 09:50:49 -0700525{
Eric Anholt8bb5a252013-12-05 13:02:51 -0800526 if (epoxy_gl_version() < 30) {
Eric Anholt09839962013-12-05 13:59:34 -0800527 const char *exts = (const char *)glGetString(GL_EXTENSIONS);
528 if (!exts)
529 return invalid_op_mode;
530 return epoxy_extension_in_string(exts, ext);
Eric Anholt8bb5a252013-12-05 13:02:51 -0800531 } else {
532 int num_extensions;
Eric Anholt28c9c472014-06-10 14:16:06 -0700533 int i;
Eric Anholt8bb5a252013-12-05 13:02:51 -0800534
535 glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
Eric Anholt09839962013-12-05 13:59:34 -0800536 if (num_extensions == 0)
537 return invalid_op_mode;
538
Eric Anholt28c9c472014-06-10 14:16:06 -0700539 for (i = 0; i < num_extensions; i++) {
Eric Anholt1cb041f2013-12-05 13:07:09 -0800540 const char *gl_ext = (const char *)glGetStringi(GL_EXTENSIONS, i);
Gianfranco Costamagna106eae72017-04-24 16:10:28 +0200541 if (!gl_ext)
542 return false;
Eric Anholt8bb5a252013-12-05 13:02:51 -0800543 if (strcmp(ext, gl_ext) == 0)
544 return true;
545 }
546
547 return false;
548 }
Eric Anholta909eb42013-09-19 09:50:49 -0700549}
550
Adam Jacksonf81274b2017-07-12 14:03:35 -0400551void *
552epoxy_conservative_glx_dlsym(const char *name, bool exit_if_fails)
553{
554#ifdef GLVND_GLX_LIB
555 /* prefer the glvnd library if it exists */
556 if (!api.glx_handle)
557 get_dlopen_handle(&api.glx_handle, GLVND_GLX_LIB, false);
558#endif
559
560 return do_dlsym(&api.glx_handle, GLX_LIB, name, exit_if_fails);
561}
562
Eric Anholt09839962013-12-05 13:59:34 -0800563/**
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000564 * Tests whether the currently bound context is EGL or GLX, trying to
565 * avoid loading libraries unless necessary.
Eric Anholtb251e3a2014-03-27 19:04:27 -0700566 */
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000567static bool
568epoxy_current_context_is_glx(void)
Eric Anholtb251e3a2014-03-27 19:04:27 -0700569{
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000570#if !PLATFORM_HAS_GLX
571 return false;
572#else
Adam Jackson7c4817f2017-07-12 13:26:05 -0400573 void *sym;
574
575 /* If we've been called already, don't load more */
576 if (!api.egl_handle != !api.glx_handle) {
577 if (api.glx_handle)
578 return true;
579 else if (api.egl_handle)
580 return false;
581 }
582
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000583 /* If the application hasn't explicitly called some of our GLX
584 * or EGL code but has presumably set up a context on its own,
585 * then we need to figure out how to getprocaddress anyway.
586 *
587 * If there's a public GetProcAddress loaded in the
588 * application's namespace, then use that.
589 */
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000590
591 sym = dlsym(NULL, "glXGetCurrentContext");
592 if (sym) {
593 if (glXGetCurrentContext())
594 return true;
595 } else {
596 (void)dlerror();
597 }
598
599#if PLATFORM_HAS_EGL
600 sym = dlsym(NULL, "eglGetCurrentContext");
601 if (sym) {
602 if (epoxy_egl_get_current_gl_context_api() != EGL_NONE)
603 return false;
604 } else {
605 (void)dlerror();
606 }
607#endif /* PLATFORM_HAS_EGL */
608
609 /* OK, couldn't find anything in the app's address space.
610 * Presumably they dlopened with RTLD_LOCAL, which hides it
611 * from us. Just go dlopen()ing likely libraries and try them.
612 */
Adam Jacksonf81274b2017-07-12 14:03:35 -0400613 sym = epoxy_conservative_glx_dlsym("glXGetCurrentContext", false);
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000614 if (sym && glXGetCurrentContext())
Eric Anholtb251e3a2014-03-27 19:04:27 -0700615 return true;
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000616
617#if PLATFORM_HAS_EGL
618 sym = do_dlsym(&api.egl_handle, EGL_LIB, "eglGetCurrentContext",
619 false);
620 if (sym && epoxy_egl_get_current_gl_context_api() != EGL_NONE)
621 return false;
622#endif /* PLATFORM_HAS_EGL */
Eric Anholtb251e3a2014-03-27 19:04:27 -0700623
624 return false;
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000625#endif /* PLATFORM_HAS_GLX */
Eric Anholtb251e3a2014-03-27 19:04:27 -0700626}
627
628/**
Emmanuele Bassi6af57b02017-01-27 18:12:05 +0000629 * @brief Returns true if the given GL extension is supported in the current context.
Eric Anholt09839962013-12-05 13:59:34 -0800630 *
Emmanuele Bassi6af57b02017-01-27 18:12:05 +0000631 * @param ext The name of the GL extension
632 * @return `true` if the extension is available
Eric Anholt09839962013-12-05 13:59:34 -0800633 *
Emmanuele Bassi6af57b02017-01-27 18:12:05 +0000634 * @note that this function can't be called from within `glBegin()` and `glEnd()`.
635 *
636 * @see epoxy_has_egl_extension()
637 * @see epoxy_has_glx_extension()
Eric Anholt09839962013-12-05 13:59:34 -0800638 */
Emmanuele Bassi7a068032017-01-24 17:43:59 +0000639bool
Eric Anholt09839962013-12-05 13:59:34 -0800640epoxy_has_gl_extension(const char *ext)
641{
642 return epoxy_internal_has_gl_extension(ext, false);
643}
644
645bool
646epoxy_conservative_has_gl_extension(const char *ext)
647{
648 if (api.begin_count)
649 return true;
650
651 return epoxy_internal_has_gl_extension(ext, true);
652}
653
Eric Anholta909eb42013-09-19 09:50:49 -0700654void *
Emmanuele Bassi30b8a4c2017-02-03 16:13:45 +0000655epoxy_conservative_egl_dlsym(const char *name, bool exit_if_fails)
656{
657 return do_dlsym(&api.egl_handle, EGL_LIB, name, exit_if_fails);
658}
659
660void *
Eric Anholt0270c802013-12-02 16:25:02 -0800661epoxy_egl_dlsym(const char *name)
Eric Anholta909eb42013-09-19 09:50:49 -0700662{
Emmanuele Bassi30b8a4c2017-02-03 16:13:45 +0000663 return epoxy_conservative_egl_dlsym(name, true);
664}
665
666void *
Eric Anholt0270c802013-12-02 16:25:02 -0800667epoxy_glx_dlsym(const char *name)
668{
Emmanuele Bassi30b8a4c2017-02-03 16:13:45 +0000669 return epoxy_conservative_glx_dlsym(name, true);
Eric Anholt0270c802013-12-02 16:25:02 -0800670}
671
672void *
673epoxy_gl_dlsym(const char *name)
674{
Eric Anholt1d746bf2013-12-09 14:52:19 -0800675#ifdef _WIN32
Eric Anholt5112b472013-12-17 10:38:29 -0800676 return do_dlsym(&api.gl_handle, "OPENGL32", name, true);
Eric Anholtd82c5c32013-12-11 16:49:08 -0800677#elif defined(__APPLE__)
678 return do_dlsym(&api.gl_handle,
679 "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL",
680 name, true);
Eric Anholt1d746bf2013-12-09 14:52:19 -0800681#else
Adam Jackson759de642017-06-16 14:37:06 -0400682 void *sym;
683
Emmanuele Bassif6d2b1f2018-02-23 19:59:48 +0000684# if defined(OPENGL_LIB)
Adam Jackson759de642017-06-16 14:37:06 -0400685 if (!api.gl_handle)
686 get_dlopen_handle(&api.gl_handle, OPENGL_LIB, false);
Emmanuele Bassif6d2b1f2018-02-23 19:59:48 +0000687# endif
Adam Jackson759de642017-06-16 14:37:06 -0400688
689 if (api.gl_handle)
690 return do_dlsym(&api.gl_handle, NULL, name, true);
691
692 sym = do_dlsym(&api.glx_handle, GLX_LIB, name, true);
693 api.gl_handle = api.glx_handle; /* skip the dlopen next time */
694
695 return sym;
Eric Anholt1d746bf2013-12-09 14:52:19 -0800696#endif
Eric Anholt0270c802013-12-02 16:25:02 -0800697}
698
699void *
700epoxy_gles1_dlsym(const char *name)
701{
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000702 if (epoxy_current_context_is_glx()) {
Eric Anholtdb5b9392014-03-27 19:06:21 -0700703 return epoxy_get_proc_address(name);
704 } else {
Ryan Houdekc7916122014-05-04 19:05:34 -0500705 return do_dlsym(&api.gles1_handle, GLES1_LIB, name, true);
Eric Anholtdb5b9392014-03-27 19:06:21 -0700706 }
Eric Anholt0270c802013-12-02 16:25:02 -0800707}
708
709void *
710epoxy_gles2_dlsym(const char *name)
711{
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000712 if (epoxy_current_context_is_glx()) {
Eric Anholtdb5b9392014-03-27 19:06:21 -0700713 return epoxy_get_proc_address(name);
714 } else {
Ryan Houdekc7916122014-05-04 19:05:34 -0500715 return do_dlsym(&api.gles2_handle, GLES2_LIB, name, true);
Eric Anholtdb5b9392014-03-27 19:06:21 -0700716 }
Eric Anholta909eb42013-09-19 09:50:49 -0700717}
718
Eric Anholt10644062014-01-31 14:49:00 -0800719/**
Eric Anholt14f24482014-03-17 11:17:19 -0700720 * Does the appropriate dlsym() or eglGetProcAddress() for GLES3
721 * functions.
722 *
723 * Mesa interpreted GLES as intending that the GLES3 functions were
724 * available only through eglGetProcAddress() and not dlsym(), while
725 * ARM's Mali drivers interpreted GLES as intending that GLES3
726 * functions were available only through dlsym() and not
727 * eglGetProcAddress(). Thanks, Khronos.
728 */
729void *
730epoxy_gles3_dlsym(const char *name)
731{
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000732 if (epoxy_current_context_is_glx()) {
Eric Anholtdb5b9392014-03-27 19:06:21 -0700733 return epoxy_get_proc_address(name);
734 } else {
Ryan Houdekc7916122014-05-04 19:05:34 -0500735 void *func = do_dlsym(&api.gles2_handle, GLES2_LIB, name, false);
Eric Anholt14f24482014-03-17 11:17:19 -0700736
Eric Anholtdb5b9392014-03-27 19:06:21 -0700737 if (func)
738 return func;
Eric Anholt14f24482014-03-17 11:17:19 -0700739
Eric Anholtdb5b9392014-03-27 19:06:21 -0700740 return epoxy_get_proc_address(name);
741 }
Eric Anholt14f24482014-03-17 11:17:19 -0700742}
743
744/**
Eric Anholt10644062014-01-31 14:49:00 -0800745 * Performs either the dlsym or glXGetProcAddress()-equivalent for
746 * core functions in desktop GL.
747 */
Eric Anholta909eb42013-09-19 09:50:49 -0700748void *
Eric Anholtb128dd92013-12-09 22:14:09 -0800749epoxy_get_core_proc_address(const char *name, int core_version)
750{
Eric Anholt1d746bf2013-12-09 14:52:19 -0800751#ifdef _WIN32
Eric Anholt227d1312015-07-15 13:52:56 -0700752 int core_symbol_support = 11;
Robert Bragg4e5e17e2018-01-18 21:21:15 +0000753#elif defined(__ANDROID__)
Ryan Houdekc7916122014-05-04 19:05:34 -0500754 /**
755 * All symbols must be resolved through eglGetProcAddress
756 * on Android
757 */
758 int core_symbol_support = 0;
Eric Anholt1d746bf2013-12-09 14:52:19 -0800759#else
760 int core_symbol_support = 12;
761#endif
762
763 if (core_version <= core_symbol_support) {
Eric Anholtb128dd92013-12-09 22:14:09 -0800764 return epoxy_gl_dlsym(name);
765 } else {
766 return epoxy_get_proc_address(name);
767 }
768}
769
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000770#if PLATFORM_HAS_EGL
Eric Anholtb670c842014-03-19 18:24:29 -0700771static EGLenum
772epoxy_egl_get_current_gl_context_api(void)
773{
Adam Jackson91916262016-10-18 11:08:12 -0400774 EGLint curapi;
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000775
Adam Jackson91916262016-10-18 11:08:12 -0400776 if (eglQueryContext(eglGetCurrentDisplay(), eglGetCurrentContext(),
777 EGL_CONTEXT_CLIENT_TYPE, &curapi) == EGL_FALSE) {
778 (void)eglGetError();
779 return EGL_NONE;
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000780 }
781
Adam Jackson91916262016-10-18 11:08:12 -0400782 return (EGLenum) curapi;
Eric Anholtb670c842014-03-19 18:24:29 -0700783}
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000784#endif /* PLATFORM_HAS_EGL */
Eric Anholtb670c842014-03-19 18:24:29 -0700785
Eric Anholt10644062014-01-31 14:49:00 -0800786/**
787 * Performs the dlsym() for the core GL 1.0 functions that we use for
788 * determining version and extension support for deciding on dlsym
789 * versus glXGetProcAddress() for all other functions.
790 *
791 * This needs to succeed on implementations without GLX (since
792 * glGetString() and glGetIntegerv() are both in GLES1/2 as well, and
793 * at call time we don't know for sure what API they're trying to use
794 * without inspecting contexts ourselves).
795 */
796void *
797epoxy_get_bootstrap_proc_address(const char *name)
798{
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000799 /* If we already have a library that links to libglapi loaded,
800 * use that.
801 */
802#if PLATFORM_HAS_GLX
803 if (api.glx_handle && glXGetCurrentContext())
804 return epoxy_gl_dlsym(name);
805#endif
806
Eric Anholt10644062014-01-31 14:49:00 -0800807 /* If epoxy hasn't loaded any API-specific library yet, try to
808 * figure out what API the context is using and use that library,
809 * since future calls will also use that API (this prevents a
810 * non-X11 ES2 context from loading a bunch of X11 junk).
811 */
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000812#if PLATFORM_HAS_EGL
Ryan Houdekc7916122014-05-04 19:05:34 -0500813 get_dlopen_handle(&api.egl_handle, EGL_LIB, false);
Eric Anholt10644062014-01-31 14:49:00 -0800814 if (api.egl_handle) {
Eric Anholtb670c842014-03-19 18:24:29 -0700815 switch (epoxy_egl_get_current_gl_context_api()) {
816 case EGL_OPENGL_API:
817 return epoxy_gl_dlsym(name);
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000818 case EGL_OPENGL_ES_API:
819 /* We can't resolve the GL version, because
820 * epoxy_glGetString() is one of the two things calling
821 * us. Try the GLES2 implementation first, and fall back
822 * to GLES1 otherwise.
823 */
824 get_dlopen_handle(&api.gles2_handle, GLES2_LIB, false);
825 if (api.gles2_handle)
826 return epoxy_gles2_dlsym(name);
Eric Anholtb670c842014-03-19 18:24:29 -0700827 else
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000828 return epoxy_gles1_dlsym(name);
Eric Anholt10644062014-01-31 14:49:00 -0800829 }
Eric Anholt10644062014-01-31 14:49:00 -0800830 }
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000831#endif /* PLATFORM_HAS_EGL */
Eric Anholt10644062014-01-31 14:49:00 -0800832
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000833 /* Fall back to GLX */
Eric Anholt10644062014-01-31 14:49:00 -0800834 return epoxy_gl_dlsym(name);
835}
836
Eric Anholtb128dd92013-12-09 22:14:09 -0800837void *
Eric Anholta909eb42013-09-19 09:50:49 -0700838epoxy_get_proc_address(const char *name)
839{
Emmanuele Bassibac94002017-01-18 15:36:54 +0000840#if PLATFORM_HAS_EGL
841 GLenum egl_api = EGL_NONE;
842
843 if (!epoxy_current_context_is_glx())
844 egl_api = epoxy_egl_get_current_gl_context_api();
845
846 switch (egl_api) {
847 case EGL_OPENGL_API:
848 case EGL_OPENGL_ES_API:
849 return eglGetProcAddress(name);
850 case EGL_NONE:
851 break;
852 }
853#endif
854
855#if defined(_WIN32)
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000856 return wglGetProcAddress(name);
857#elif defined(__APPLE__)
Eric Anholt26880542013-12-15 20:21:02 -0800858 return epoxy_gl_dlsym(name);
Emmanuele Bassibac94002017-01-18 15:36:54 +0000859#elif PLATFORM_HAS_GLX
860 if (epoxy_current_context_is_glx())
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000861 return glXGetProcAddressARB((const GLubyte *)name);
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000862 errx(1, "Couldn't find current GLX or EGL context.\n");
Emmanuele Bassi5df022e2017-01-19 17:58:59 +0000863#endif
Emmanuele Bassibac94002017-01-18 15:36:54 +0000864
865 return NULL;
Eric Anholta909eb42013-09-19 09:50:49 -0700866}
867
Chun-wei Fan7d5e8e92015-06-05 17:38:26 -0700868WRAPPER_VISIBILITY (void)
Eric Anholt3d2a2b32013-12-13 14:41:12 -0800869WRAPPER(epoxy_glBegin)(GLenum primtype)
Eric Anholt09839962013-12-05 13:59:34 -0800870{
Eric Anholt25913682013-12-06 13:40:30 -0800871#ifdef _WIN32
Eric Anholt4eaf4bf2013-12-10 14:09:37 -0800872 InterlockedIncrement(&api.begin_count);
Eric Anholt25913682013-12-06 13:40:30 -0800873#else
Eric Anholt09839962013-12-05 13:59:34 -0800874 pthread_mutex_lock(&api.mutex);
875 api.begin_count++;
876 pthread_mutex_unlock(&api.mutex);
Eric Anholt25913682013-12-06 13:40:30 -0800877#endif
Eric Anholt09839962013-12-05 13:59:34 -0800878
879 epoxy_glBegin_unwrapped(primtype);
880}
881
Chun-wei Fan7d5e8e92015-06-05 17:38:26 -0700882WRAPPER_VISIBILITY (void)
Eric Anholt3d2a2b32013-12-13 14:41:12 -0800883WRAPPER(epoxy_glEnd)(void)
Eric Anholt09839962013-12-05 13:59:34 -0800884{
885 epoxy_glEnd_unwrapped();
886
Eric Anholt25913682013-12-06 13:40:30 -0800887#ifdef _WIN32
Eric Anholt4eaf4bf2013-12-10 14:09:37 -0800888 InterlockedDecrement(&api.begin_count);
Eric Anholt25913682013-12-06 13:40:30 -0800889#else
Eric Anholt09839962013-12-05 13:59:34 -0800890 pthread_mutex_lock(&api.mutex);
891 api.begin_count--;
892 pthread_mutex_unlock(&api.mutex);
Eric Anholt25913682013-12-06 13:40:30 -0800893#endif
Eric Anholt09839962013-12-05 13:59:34 -0800894}
Eric Anholt3d2a2b32013-12-13 14:41:12 -0800895
Emmanuele Bassi7a068032017-01-24 17:43:59 +0000896PFNGLBEGINPROC epoxy_glBegin = epoxy_glBegin_wrapped;
897PFNGLENDPROC epoxy_glEnd = epoxy_glEnd_wrapped;
Adam Jackson7ff061a2017-07-05 16:54:15 -0400898
899epoxy_resolver_failure_handler_t epoxy_resolver_failure_handler;
900
Emmanuele Bassi158ce2b2018-02-23 16:56:52 +0000901/**
902 * Sets the function that will be called every time Epoxy fails to
903 * resolve a symbol.
904 *
905 * @param handler The new handler function
906 * @return The previous handler function
907 */
Adam Jackson7ff061a2017-07-05 16:54:15 -0400908epoxy_resolver_failure_handler_t
909epoxy_set_resolver_failure_handler(epoxy_resolver_failure_handler_t handler)
910{
911#ifdef _WIN32
danem60271ab2017-10-13 16:20:11 -0700912 return InterlockedExchangePointer((void**)&epoxy_resolver_failure_handler,
Adam Jackson7ff061a2017-07-05 16:54:15 -0400913 handler);
914#else
915 epoxy_resolver_failure_handler_t old;
916 pthread_mutex_lock(&api.mutex);
917 old = epoxy_resolver_failure_handler;
918 epoxy_resolver_failure_handler = handler;
919 pthread_mutex_unlock(&api.mutex);
920 return old;
921#endif
922}