blob: b3e4f5f42885be22d6fecaf52298f1062d090924 [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
Emmanuele Bassi8c3d3712018-05-29 22:23:23 +0100176#if defined(__APPLE__)
Eric Anholt8d8334c2013-12-12 10:55:32 -0800177#define GLX_LIB "/opt/X11/lib/libGL.1.dylib"
Adam Jackson53ae0bb2018-05-01 11:16:46 -0400178#define OPENGL_LIB "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL"
Emmanuele Bassi8c3d3712018-05-29 22:23:23 +0100179#define GLES1_LIB "libGLESv1_CM.so"
180#define GLES2_LIB "libGLESv2.so"
Robert Bragg4e5e17e2018-01-18 21:21:15 +0000181#elif defined(__ANDROID__)
Ryan Houdekc7916122014-05-04 19:05:34 -0500182#define GLX_LIB "libGLESv2.so"
Ryan Houdekc7916122014-05-04 19:05:34 -0500183#define EGL_LIB "libEGL.so"
184#define GLES1_LIB "libGLESv1_CM.so"
185#define GLES2_LIB "libGLESv2.so"
Emmanuele Bassi8c3d3712018-05-29 22:23:23 +0100186#elif defined(_WIN32)
Yaron Cohen-Tal9e46b8e2016-12-13 12:26:41 +0000187#define EGL_LIB "libEGL.dll"
188#define GLES1_LIB "libGLES_CM.dll"
189#define GLES2_LIB "libGLESv2.dll"
Adam Jackson53ae0bb2018-05-01 11:16:46 -0400190#define OPENGL_LIB "OPENGL32"
Ryan Houdekc7916122014-05-04 19:05:34 -0500191#else
Emmanuele Bassi8c3d3712018-05-29 22:23:23 +0100192#define GLVND_GLX_LIB "libGLX.so.1"
193#define GLX_LIB "libGL.so.1"
Ryan Houdekc7916122014-05-04 19:05:34 -0500194#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
Adam Jackson90db0062018-05-01 11:34:23 -0400293get_dlopen_handle(void **handle, const char *lib_name, bool exit_on_fail, bool load)
Eric Anholt0270c802013-12-02 16:25:02 -0800294{
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) {
Adam Jacksona33623d2018-04-09 16:10:52 -0400308 int flags = RTLD_LAZY | RTLD_LOCAL;
Adam Jackson90db0062018-05-01 11:34:23 -0400309 if (!load)
Adam Jacksona33623d2018-04-09 16:10:52 -0400310 flags |= RTLD_NOLOAD;
311
312 *handle = dlopen(lib_name, flags);
Eric Anholtd48978c2014-03-27 18:54:12 -0700313 if (!*handle) {
314 if (exit_on_fail) {
315 fprintf(stderr, "Couldn't open %s: %s\n", lib_name, dlerror());
Emmanuele Bassi791b28c2018-05-14 12:49:21 +0100316 abort();
Eric Anholtd48978c2014-03-27 18:54:12 -0700317 } else {
318 (void)dlerror();
319 }
Eric Anholt0270c802013-12-02 16:25:02 -0800320 }
321 }
322 pthread_mutex_unlock(&api.mutex);
Eric Anholt5112b472013-12-17 10:38:29 -0800323#endif
Eric Anholt72187a22014-03-27 18:53:10 -0700324
325 return *handle != NULL;
Eric Anholt0270c802013-12-02 16:25:02 -0800326}
327
328static void *
Adam Jackson53ae0bb2018-05-01 11:16:46 -0400329do_dlsym(void **handle, const char *name, bool exit_on_fail)
Eric Anholt0270c802013-12-02 16:25:02 -0800330{
331 void *result;
Eric Anholtd48978c2014-03-27 18:54:12 -0700332 const char *error = "";
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) {
Adam Jackson53ae0bb2018-05-01 11:16:46 -0400342 fprintf(stderr, "%s() not found: %s\n", name, error);
Emmanuele Bassi791b28c2018-05-14 12:49:21 +0100343 abort();
Eric Anholt5112b472013-12-17 10:38:29 -0800344 }
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);
Emmanuele Bassi791b28c2018-05-14 12:49:21 +0100413 abort();
Eric Anholt66d7b9f2013-11-11 09:27:07 -0800414 }
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 Jackson90db0062018-05-01 11:34:23 -0400551bool
552epoxy_load_glx(bool exit_if_fails, bool load)
Adam Jacksonf81274b2017-07-12 14:03:35 -0400553{
Zhao Zhili119f06f2018-07-16 12:51:48 +0800554#if PLATFORM_HAS_GLX
Emmanuele Bassi8c3d3712018-05-29 22:23:23 +0100555# ifdef GLVND_GLX_LIB
Adam Jacksonf81274b2017-07-12 14:03:35 -0400556 /* prefer the glvnd library if it exists */
557 if (!api.glx_handle)
Adam Jackson90db0062018-05-01 11:34:23 -0400558 get_dlopen_handle(&api.glx_handle, GLVND_GLX_LIB, false, load);
Emmanuele Bassi8c3d3712018-05-29 22:23:23 +0100559# endif
Adam Jackson53ae0bb2018-05-01 11:16:46 -0400560 if (!api.glx_handle)
Adam Jackson90db0062018-05-01 11:34:23 -0400561 get_dlopen_handle(&api.glx_handle, GLX_LIB, exit_if_fails, load);
Emmanuele Bassi8c3d3712018-05-29 22:23:23 +0100562#endif
Adam Jackson53ae0bb2018-05-01 11:16:46 -0400563 return api.glx_handle != NULL;
564}
565
566void *
567epoxy_conservative_glx_dlsym(const char *name, bool exit_if_fails)
568{
Zhao Zhili119f06f2018-07-16 12:51:48 +0800569#if PLATFORM_HAS_GLX
Adam Jackson90db0062018-05-01 11:34:23 -0400570 if (epoxy_load_glx(exit_if_fails, exit_if_fails))
Adam Jackson53ae0bb2018-05-01 11:16:46 -0400571 return do_dlsym(&api.glx_handle, name, exit_if_fails);
Emmanuele Bassi8c3d3712018-05-29 22:23:23 +0100572#endif
Adam Jackson53ae0bb2018-05-01 11:16:46 -0400573 return NULL;
Adam Jacksonf81274b2017-07-12 14:03:35 -0400574}
575
Eric Anholt09839962013-12-05 13:59:34 -0800576/**
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000577 * Tests whether the currently bound context is EGL or GLX, trying to
578 * avoid loading libraries unless necessary.
Eric Anholtb251e3a2014-03-27 19:04:27 -0700579 */
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000580static bool
581epoxy_current_context_is_glx(void)
Eric Anholtb251e3a2014-03-27 19:04:27 -0700582{
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000583#if !PLATFORM_HAS_GLX
584 return false;
585#else
Adam Jackson7c4817f2017-07-12 13:26:05 -0400586 void *sym;
587
Adam Jacksona33623d2018-04-09 16:10:52 -0400588 sym = epoxy_conservative_glx_dlsym("glXGetCurrentContext", false);
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000589 if (sym) {
590 if (glXGetCurrentContext())
591 return true;
592 } else {
593 (void)dlerror();
594 }
595
596#if PLATFORM_HAS_EGL
Adam Jacksona33623d2018-04-09 16:10:52 -0400597 sym = epoxy_conservative_egl_dlsym("eglGetCurrentContext", false);
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000598 if (sym) {
599 if (epoxy_egl_get_current_gl_context_api() != EGL_NONE)
600 return false;
601 } else {
602 (void)dlerror();
603 }
604#endif /* PLATFORM_HAS_EGL */
605
Eric Anholtb251e3a2014-03-27 19:04:27 -0700606 return false;
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000607#endif /* PLATFORM_HAS_GLX */
Eric Anholtb251e3a2014-03-27 19:04:27 -0700608}
609
610/**
Emmanuele Bassi6af57b02017-01-27 18:12:05 +0000611 * @brief Returns true if the given GL extension is supported in the current context.
Eric Anholt09839962013-12-05 13:59:34 -0800612 *
Emmanuele Bassi6af57b02017-01-27 18:12:05 +0000613 * @param ext The name of the GL extension
614 * @return `true` if the extension is available
Eric Anholt09839962013-12-05 13:59:34 -0800615 *
Emmanuele Bassi6af57b02017-01-27 18:12:05 +0000616 * @note that this function can't be called from within `glBegin()` and `glEnd()`.
617 *
618 * @see epoxy_has_egl_extension()
619 * @see epoxy_has_glx_extension()
Eric Anholt09839962013-12-05 13:59:34 -0800620 */
Emmanuele Bassi7a068032017-01-24 17:43:59 +0000621bool
Eric Anholt09839962013-12-05 13:59:34 -0800622epoxy_has_gl_extension(const char *ext)
623{
624 return epoxy_internal_has_gl_extension(ext, false);
625}
626
627bool
628epoxy_conservative_has_gl_extension(const char *ext)
629{
630 if (api.begin_count)
631 return true;
632
633 return epoxy_internal_has_gl_extension(ext, true);
634}
635
Adam Jackson90db0062018-05-01 11:34:23 -0400636bool
637epoxy_load_egl(bool exit_if_fails, bool load)
Adam Jackson53ae0bb2018-05-01 11:16:46 -0400638{
Emmanuele Bassi8c3d3712018-05-29 22:23:23 +0100639#if PLATFORM_HAS_EGL
Adam Jackson90db0062018-05-01 11:34:23 -0400640 return get_dlopen_handle(&api.egl_handle, EGL_LIB, exit_if_fails, load);
Emmanuele Bassi8c3d3712018-05-29 22:23:23 +0100641#else
642 return false;
643#endif
Adam Jackson53ae0bb2018-05-01 11:16:46 -0400644}
645
Eric Anholta909eb42013-09-19 09:50:49 -0700646void *
Emmanuele Bassi30b8a4c2017-02-03 16:13:45 +0000647epoxy_conservative_egl_dlsym(const char *name, bool exit_if_fails)
648{
Emmanuele Bassi8c3d3712018-05-29 22:23:23 +0100649#if PLATFORM_HAS_EGL
Adam Jackson90db0062018-05-01 11:34:23 -0400650 if (epoxy_load_egl(exit_if_fails, exit_if_fails))
Adam Jackson53ae0bb2018-05-01 11:16:46 -0400651 return do_dlsym(&api.egl_handle, name, exit_if_fails);
Emmanuele Bassi8c3d3712018-05-29 22:23:23 +0100652#endif
Adam Jackson53ae0bb2018-05-01 11:16:46 -0400653 return NULL;
Emmanuele Bassi30b8a4c2017-02-03 16:13:45 +0000654}
655
656void *
Eric Anholt0270c802013-12-02 16:25:02 -0800657epoxy_egl_dlsym(const char *name)
Eric Anholta909eb42013-09-19 09:50:49 -0700658{
Emmanuele Bassi30b8a4c2017-02-03 16:13:45 +0000659 return epoxy_conservative_egl_dlsym(name, true);
660}
661
662void *
Eric Anholt0270c802013-12-02 16:25:02 -0800663epoxy_glx_dlsym(const char *name)
664{
Emmanuele Bassi30b8a4c2017-02-03 16:13:45 +0000665 return epoxy_conservative_glx_dlsym(name, true);
Eric Anholt0270c802013-12-02 16:25:02 -0800666}
667
Adam Jackson53ae0bb2018-05-01 11:16:46 -0400668static void
669epoxy_load_gl(void)
670{
671 if (api.gl_handle)
672 return;
673
674#if defined(_WIN32) || defined(__APPLE__)
Adam Jackson90db0062018-05-01 11:34:23 -0400675 get_dlopen_handle(&api.gl_handle, OPENGL_LIB, true, true);
Adam Jackson53ae0bb2018-05-01 11:16:46 -0400676#else
677
678#if defined(OPENGL_LIB)
679 if (!api.gl_handle)
Adam Jackson90db0062018-05-01 11:34:23 -0400680 get_dlopen_handle(&api.gl_handle, OPENGL_LIB, false, true);
Adam Jackson53ae0bb2018-05-01 11:16:46 -0400681#endif
682
Adam Jackson90db0062018-05-01 11:34:23 -0400683 get_dlopen_handle(&api.glx_handle, GLX_LIB, true, true);
Adam Jackson53ae0bb2018-05-01 11:16:46 -0400684 api.gl_handle = api.glx_handle;
685#endif
686}
687
Eric Anholt0270c802013-12-02 16:25:02 -0800688void *
689epoxy_gl_dlsym(const char *name)
690{
Adam Jackson53ae0bb2018-05-01 11:16:46 -0400691 epoxy_load_gl();
Adam Jackson759de642017-06-16 14:37:06 -0400692
Adam Jackson53ae0bb2018-05-01 11:16:46 -0400693 return do_dlsym(&api.gl_handle, name, true);
Eric Anholt0270c802013-12-02 16:25:02 -0800694}
695
696void *
697epoxy_gles1_dlsym(const char *name)
698{
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000699 if (epoxy_current_context_is_glx()) {
Eric Anholtdb5b9392014-03-27 19:06:21 -0700700 return epoxy_get_proc_address(name);
701 } else {
Adam Jackson90db0062018-05-01 11:34:23 -0400702 get_dlopen_handle(&api.gles1_handle, GLES1_LIB, true, true);
Adam Jackson53ae0bb2018-05-01 11:16:46 -0400703 return do_dlsym(&api.gles1_handle, name, true);
Eric Anholtdb5b9392014-03-27 19:06:21 -0700704 }
Eric Anholt0270c802013-12-02 16:25:02 -0800705}
706
707void *
708epoxy_gles2_dlsym(const char *name)
709{
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000710 if (epoxy_current_context_is_glx()) {
Eric Anholtdb5b9392014-03-27 19:06:21 -0700711 return epoxy_get_proc_address(name);
712 } else {
Adam Jackson90db0062018-05-01 11:34:23 -0400713 get_dlopen_handle(&api.gles2_handle, GLES2_LIB, true, true);
Adam Jackson53ae0bb2018-05-01 11:16:46 -0400714 return do_dlsym(&api.gles2_handle, name, true);
Eric Anholtdb5b9392014-03-27 19:06:21 -0700715 }
Eric Anholta909eb42013-09-19 09:50:49 -0700716}
717
Eric Anholt10644062014-01-31 14:49:00 -0800718/**
Eric Anholt14f24482014-03-17 11:17:19 -0700719 * Does the appropriate dlsym() or eglGetProcAddress() for GLES3
720 * functions.
721 *
722 * Mesa interpreted GLES as intending that the GLES3 functions were
723 * available only through eglGetProcAddress() and not dlsym(), while
724 * ARM's Mali drivers interpreted GLES as intending that GLES3
725 * functions were available only through dlsym() and not
726 * eglGetProcAddress(). Thanks, Khronos.
727 */
728void *
729epoxy_gles3_dlsym(const char *name)
730{
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000731 if (epoxy_current_context_is_glx()) {
Eric Anholtdb5b9392014-03-27 19:06:21 -0700732 return epoxy_get_proc_address(name);
733 } else {
Adam Jackson90db0062018-05-01 11:34:23 -0400734 if (get_dlopen_handle(&api.gles2_handle, GLES2_LIB, false, true)) {
Adam Jackson2edc4972018-07-05 15:26:04 -0400735 void *func = do_dlsym(&api.gles2_handle, name, false);
Eric Anholt14f24482014-03-17 11:17:19 -0700736
Adam Jackson53ae0bb2018-05-01 11:16:46 -0400737 if (func)
738 return func;
739 }
Eric Anholt14f24482014-03-17 11:17:19 -0700740
Eric Anholtdb5b9392014-03-27 19:06:21 -0700741 return epoxy_get_proc_address(name);
742 }
Eric Anholt14f24482014-03-17 11:17:19 -0700743}
744
745/**
Eric Anholt10644062014-01-31 14:49:00 -0800746 * Performs either the dlsym or glXGetProcAddress()-equivalent for
747 * core functions in desktop GL.
748 */
Eric Anholta909eb42013-09-19 09:50:49 -0700749void *
Eric Anholtb128dd92013-12-09 22:14:09 -0800750epoxy_get_core_proc_address(const char *name, int core_version)
751{
Eric Anholt1d746bf2013-12-09 14:52:19 -0800752#ifdef _WIN32
Eric Anholt227d1312015-07-15 13:52:56 -0700753 int core_symbol_support = 11;
Robert Bragg4e5e17e2018-01-18 21:21:15 +0000754#elif defined(__ANDROID__)
Ryan Houdekc7916122014-05-04 19:05:34 -0500755 /**
756 * All symbols must be resolved through eglGetProcAddress
757 * on Android
758 */
759 int core_symbol_support = 0;
Eric Anholt1d746bf2013-12-09 14:52:19 -0800760#else
761 int core_symbol_support = 12;
762#endif
763
764 if (core_version <= core_symbol_support) {
Eric Anholtb128dd92013-12-09 22:14:09 -0800765 return epoxy_gl_dlsym(name);
766 } else {
767 return epoxy_get_proc_address(name);
768 }
769}
770
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000771#if PLATFORM_HAS_EGL
Eric Anholtb670c842014-03-19 18:24:29 -0700772static EGLenum
773epoxy_egl_get_current_gl_context_api(void)
774{
Adam Jackson91916262016-10-18 11:08:12 -0400775 EGLint curapi;
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000776
Adam Jackson91916262016-10-18 11:08:12 -0400777 if (eglQueryContext(eglGetCurrentDisplay(), eglGetCurrentContext(),
778 EGL_CONTEXT_CLIENT_TYPE, &curapi) == EGL_FALSE) {
779 (void)eglGetError();
780 return EGL_NONE;
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000781 }
782
Adam Jackson91916262016-10-18 11:08:12 -0400783 return (EGLenum) curapi;
Eric Anholtb670c842014-03-19 18:24:29 -0700784}
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000785#endif /* PLATFORM_HAS_EGL */
Eric Anholtb670c842014-03-19 18:24:29 -0700786
Eric Anholt10644062014-01-31 14:49:00 -0800787/**
788 * Performs the dlsym() for the core GL 1.0 functions that we use for
789 * determining version and extension support for deciding on dlsym
790 * versus glXGetProcAddress() for all other functions.
791 *
792 * This needs to succeed on implementations without GLX (since
793 * glGetString() and glGetIntegerv() are both in GLES1/2 as well, and
794 * at call time we don't know for sure what API they're trying to use
795 * without inspecting contexts ourselves).
796 */
797void *
798epoxy_get_bootstrap_proc_address(const char *name)
799{
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000800 /* If we already have a library that links to libglapi loaded,
801 * use that.
802 */
803#if PLATFORM_HAS_GLX
804 if (api.glx_handle && glXGetCurrentContext())
805 return epoxy_gl_dlsym(name);
806#endif
807
Eric Anholt10644062014-01-31 14:49:00 -0800808 /* If epoxy hasn't loaded any API-specific library yet, try to
809 * figure out what API the context is using and use that library,
810 * since future calls will also use that API (this prevents a
811 * non-X11 ES2 context from loading a bunch of X11 junk).
812 */
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000813#if PLATFORM_HAS_EGL
Adam Jackson90db0062018-05-01 11:34:23 -0400814 get_dlopen_handle(&api.egl_handle, EGL_LIB, false, true);
Eric Anholt10644062014-01-31 14:49:00 -0800815 if (api.egl_handle) {
Adam Jacksonb5a4b162018-04-30 15:26:17 -0400816 int version = 0;
Eric Anholtb670c842014-03-19 18:24:29 -0700817 switch (epoxy_egl_get_current_gl_context_api()) {
818 case EGL_OPENGL_API:
819 return epoxy_gl_dlsym(name);
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000820 case EGL_OPENGL_ES_API:
Adam Jacksonb5a4b162018-04-30 15:26:17 -0400821 if (eglQueryContext(eglGetCurrentDisplay(),
822 eglGetCurrentContext(),
823 EGL_CONTEXT_CLIENT_VERSION,
824 &version)) {
825 if (version >= 2)
826 return epoxy_gles2_dlsym(name);
827 else
828 return epoxy_gles1_dlsym(name);
829 }
Eric Anholt10644062014-01-31 14:49:00 -0800830 }
Eric Anholt10644062014-01-31 14:49:00 -0800831 }
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000832#endif /* PLATFORM_HAS_EGL */
Eric Anholt10644062014-01-31 14:49:00 -0800833
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000834 /* Fall back to GLX */
Eric Anholt10644062014-01-31 14:49:00 -0800835 return epoxy_gl_dlsym(name);
836}
837
Eric Anholtb128dd92013-12-09 22:14:09 -0800838void *
Eric Anholta909eb42013-09-19 09:50:49 -0700839epoxy_get_proc_address(const char *name)
840{
Emmanuele Bassibac94002017-01-18 15:36:54 +0000841#if PLATFORM_HAS_EGL
842 GLenum egl_api = EGL_NONE;
843
844 if (!epoxy_current_context_is_glx())
845 egl_api = epoxy_egl_get_current_gl_context_api();
846
847 switch (egl_api) {
848 case EGL_OPENGL_API:
849 case EGL_OPENGL_ES_API:
850 return eglGetProcAddress(name);
851 case EGL_NONE:
852 break;
853 }
854#endif
855
856#if defined(_WIN32)
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000857 return wglGetProcAddress(name);
858#elif defined(__APPLE__)
Eric Anholt26880542013-12-15 20:21:02 -0800859 return epoxy_gl_dlsym(name);
Emmanuele Bassibac94002017-01-18 15:36:54 +0000860#elif PLATFORM_HAS_GLX
861 if (epoxy_current_context_is_glx())
Emmanuele Bassi8dead452016-12-07 14:45:14 +0000862 return glXGetProcAddressARB((const GLubyte *)name);
Adam Jacksonf7486f72018-04-12 11:04:10 -0400863 assert(0 && "Couldn't find current GLX or EGL context.\n");
Emmanuele Bassi5df022e2017-01-19 17:58:59 +0000864#endif
Emmanuele Bassibac94002017-01-18 15:36:54 +0000865
866 return NULL;
Eric Anholta909eb42013-09-19 09:50:49 -0700867}
868
Chun-wei Fan7d5e8e92015-06-05 17:38:26 -0700869WRAPPER_VISIBILITY (void)
Eric Anholt3d2a2b32013-12-13 14:41:12 -0800870WRAPPER(epoxy_glBegin)(GLenum primtype)
Eric Anholt09839962013-12-05 13:59:34 -0800871{
Eric Anholt25913682013-12-06 13:40:30 -0800872#ifdef _WIN32
Eric Anholt4eaf4bf2013-12-10 14:09:37 -0800873 InterlockedIncrement(&api.begin_count);
Eric Anholt25913682013-12-06 13:40:30 -0800874#else
Eric Anholt09839962013-12-05 13:59:34 -0800875 pthread_mutex_lock(&api.mutex);
876 api.begin_count++;
877 pthread_mutex_unlock(&api.mutex);
Eric Anholt25913682013-12-06 13:40:30 -0800878#endif
Eric Anholt09839962013-12-05 13:59:34 -0800879
880 epoxy_glBegin_unwrapped(primtype);
881}
882
Chun-wei Fan7d5e8e92015-06-05 17:38:26 -0700883WRAPPER_VISIBILITY (void)
Eric Anholt3d2a2b32013-12-13 14:41:12 -0800884WRAPPER(epoxy_glEnd)(void)
Eric Anholt09839962013-12-05 13:59:34 -0800885{
886 epoxy_glEnd_unwrapped();
887
Eric Anholt25913682013-12-06 13:40:30 -0800888#ifdef _WIN32
Eric Anholt4eaf4bf2013-12-10 14:09:37 -0800889 InterlockedDecrement(&api.begin_count);
Eric Anholt25913682013-12-06 13:40:30 -0800890#else
Eric Anholt09839962013-12-05 13:59:34 -0800891 pthread_mutex_lock(&api.mutex);
892 api.begin_count--;
893 pthread_mutex_unlock(&api.mutex);
Eric Anholt25913682013-12-06 13:40:30 -0800894#endif
Eric Anholt09839962013-12-05 13:59:34 -0800895}
Eric Anholt3d2a2b32013-12-13 14:41:12 -0800896
Emmanuele Bassi7a068032017-01-24 17:43:59 +0000897PFNGLBEGINPROC epoxy_glBegin = epoxy_glBegin_wrapped;
898PFNGLENDPROC epoxy_glEnd = epoxy_glEnd_wrapped;
Adam Jackson7ff061a2017-07-05 16:54:15 -0400899
900epoxy_resolver_failure_handler_t epoxy_resolver_failure_handler;
901
Emmanuele Bassi158ce2b2018-02-23 16:56:52 +0000902/**
903 * Sets the function that will be called every time Epoxy fails to
904 * resolve a symbol.
905 *
906 * @param handler The new handler function
907 * @return The previous handler function
908 */
Adam Jackson7ff061a2017-07-05 16:54:15 -0400909epoxy_resolver_failure_handler_t
910epoxy_set_resolver_failure_handler(epoxy_resolver_failure_handler_t handler)
911{
912#ifdef _WIN32
danem60271ab2017-10-13 16:20:11 -0700913 return InterlockedExchangePointer((void**)&epoxy_resolver_failure_handler,
Adam Jackson7ff061a2017-07-05 16:54:15 -0400914 handler);
915#else
916 epoxy_resolver_failure_handler_t old;
917 pthread_mutex_lock(&api.mutex);
918 old = epoxy_resolver_failure_handler;
919 epoxy_resolver_failure_handler = handler;
920 pthread_mutex_unlock(&api.mutex);
921 return old;
922#endif
923}