sync code with last improvements from OpenBSD

This commit is contained in:
purplerain 2023-08-28 05:57:34 +00:00
commit 88965415ff
Signed by: purplerain
GPG key ID: F42C07F07E2E35B7
26235 changed files with 29195616 additions and 0 deletions

940
dist/libepoxy/src/dispatch_common.c vendored Normal file
View file

@ -0,0 +1,940 @@
/*
* Copyright © 2013-2014 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
/**
* \mainpage Epoxy
*
* \section intro_sec Introduction
*
* Epoxy is a library for handling OpenGL function pointer management for
* you.
*
* It hides the complexity of `dlopen()`, `dlsym()`, `glXGetProcAddress()`,
* `eglGetProcAddress()`, etc. from the app developer, with very little
* knowledge needed on their part. They get to read GL specs and write
* code using undecorated function names like `glCompileShader()`.
*
* Don't forget to check for your extensions or versions being present
* before you use them, just like before! We'll tell you what you forgot
* to check for instead of just segfaulting, though.
*
* \section features_sec Features
*
* - Automatically initializes as new GL functions are used.
* - GL 4.6 core and compatibility context support.
* - GLES 1/2/3 context support.
* - Knows about function aliases so (e.g.) `glBufferData()` can be
* used with `GL_ARB_vertex_buffer_object` implementations, along
* with GL 1.5+ implementations.
* - EGL, GLX, and WGL support.
* - Can be mixed with non-epoxy GL usage.
*
* \section using_sec Using Epoxy
*
* Using Epoxy should be as easy as replacing:
*
* ```cpp
* #include <GL/gl.h>
* #include <GL/glx.h>
* #include <GL/glext.h>
* ```
*
* with:
*
* ```cpp
* #include <epoxy/gl.h>
* #include <epoxy/glx.h>
* ```
*
* \subsection using_include_sec Headers
*
* Epoxy comes with the following public headers:
*
* - `epoxy/gl.h` - For GL API
* - `epoxy/egl.h` - For EGL API
* - `epoxy/glx.h` - For GLX API
* - `epoxy/wgl.h` - For WGL API
*
* \section links_sec Additional links
*
* The latest version of the Epoxy code is available on [GitHub](https://github.com/anholt/libepoxy).
*
* For bug reports and enhancements, please use the [Issues](https://github.com/anholt/libepoxy/issues)
* link.
*
* The scope of this API reference does not include the documentation for
* OpenGL and OpenGL ES. For more information on those programming interfaces
* please visit:
*
* - [Khronos](https://www.khronos.org/)
* - [OpenGL page on Khronos.org](https://www.khronos.org/opengl/)
* - [OpenGL ES page on Khronos.org](https://www.khronos.org/opengles/)
* - [docs.GL](http://docs.gl/)
*/
/**
* @file dispatch_common.c
*
* @brief Implements common code shared by the generated GL/EGL/GLX dispatch code.
*
* A collection of some important specs on getting GL function pointers.
*
* From the linux GL ABI (http://www.opengl.org/registry/ABI/):
*
* "3.4. The libraries must export all OpenGL 1.2, GLU 1.3, GLX 1.3, and
* ARB_multitexture entry points statically.
*
* 3.5. Because non-ARB extensions vary so widely and are constantly
* increasing in number, it's infeasible to require that they all be
* supported, and extensions can always be added to hardware drivers
* after the base link libraries are released. These drivers are
* dynamically loaded by libGL, so extensions not in the base
* library must also be obtained dynamically.
*
* 3.6. To perform the dynamic query, libGL also must export an entry
* point called
*
* void (*glXGetProcAddressARB(const GLubyte *))();
*
* The full specification of this function is available separately. It
* takes the string name of a GL or GLX entry point and returns a pointer
* to a function implementing that entry point. It is functionally
* identical to the wglGetProcAddress query defined by the Windows OpenGL
* library, except that the function pointers returned are context
* independent, unlike the WGL query."
*
* From the EGL 1.4 spec:
*
* "Client API function pointers returned by eglGetProcAddress are
* independent of the display and the currently bound client API context,
* and may be used by any client API context which supports the extension.
*
* eglGetProcAddress may be queried for all of the following functions:
*
* All EGL and client API extension functions supported by the
* implementation (whether those extensions are supported by the current
* client API context or not). This includes any mandatory OpenGL ES
* extensions.
*
* eglGetProcAddress may not be queried for core (non-extension) functions
* in EGL or client APIs 20 .
*
* For functions that are queryable with eglGetProcAddress,
* implementations may choose to also export those functions statically
* from the object libraries im- plementing those functions. However,
* portable clients cannot rely on this behavior.
*
* From the GLX 1.4 spec:
*
* "glXGetProcAddress may be queried for all of the following functions:
*
* All GL and GLX extension functions supported by the implementation
* (whether those extensions are supported by the current context or
* not).
*
* All core (non-extension) functions in GL and GLX from version 1.0 up
* to and including the versions of those specifications supported by
* the implementation, as determined by glGetString(GL VERSION) and
* glXQueryVersion queries."
*/
#include <assert.h>
#include <stdlib.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#include <err.h>
#include <pthread.h>
#endif
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include "dispatch_common.h"
#if defined(__APPLE__)
#define GLX_LIB "/opt/X11/lib/libGL.1.dylib"
#define OPENGL_LIB "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL"
#define GLES1_LIB "libGLESv1_CM.so"
#define GLES2_LIB "libGLESv2.so"
#elif defined(__ANDROID__)
#define GLX_LIB "libGLESv2.so"
#define EGL_LIB "libEGL.so"
#define GLES1_LIB "libGLESv1_CM.so"
#define GLES2_LIB "libGLESv2.so"
#elif defined(__OpenBSD__)
#define GLX_LIB "libGL.so"
#define EGL_LIB "libEGL.so"
#define GLES1_LIB "libGLESv1_CM.so"
#define GLES2_LIB "libGLESv2.so"
#elif defined(_WIN32)
#define EGL_LIB "libEGL.dll"
#define GLES1_LIB "libGLES_CM.dll"
#define GLES2_LIB "libGLESv2.dll"
#define OPENGL_LIB "OPENGL32"
#else
#define GLVND_GLX_LIB "libGLX.so.1"
#define GLX_LIB "libGL.so.1"
#define EGL_LIB "libEGL.so.1"
#define GLES1_LIB "libGLESv1_CM.so.1"
#define GLES2_LIB "libGLESv2.so.2"
#define OPENGL_LIB "libOpenGL.so.0"
#endif
#ifdef __GNUC__
#define CONSTRUCT(_func) static void _func (void) __attribute__((constructor));
#define DESTRUCT(_func) static void _func (void) __attribute__((destructor));
#elif defined (_MSC_VER) && (_MSC_VER >= 1500)
#define CONSTRUCT(_func) \
static void _func(void); \
static int _func ## _wrapper(void) { _func(); return 0; } \
__pragma(section(".CRT$XCU",read)) \
__declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _wrapper;
#define DESTRUCT(_func) \
static void _func(void); \
static int _func ## _constructor(void) { atexit (_func); return 0; } \
__pragma(section(".CRT$XCU",read)) \
__declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _constructor;
#else
#error "You will need constructor support for your compiler"
#endif
struct api {
#ifndef _WIN32
/*
* Locking for making sure we don't double-dlopen().
*/
pthread_mutex_t mutex;
#endif
/*
* dlopen() return value for the GLX API. This is libGLX.so.1 if the
* runtime is glvnd-enabled, else libGL.so.1
*/
void *glx_handle;
/*
* dlopen() return value for the desktop GL library.
*
* On Windows this is OPENGL32. On OSX this is classic libGL. On Linux
* this is either libOpenGL (if the runtime is glvnd-enabled) or
* classic libGL.so.1
*/
void *gl_handle;
/* dlopen() return value for libEGL.so.1 */
void *egl_handle;
/* dlopen() return value for libGLESv1_CM.so.1 */
void *gles1_handle;
/* dlopen() return value for libGLESv2.so.2 */
void *gles2_handle;
/*
* This value gets incremented when any thread is in
* glBegin()/glEnd() called through epoxy.
*
* We're not guaranteed to be called through our wrapper, so the
* conservative paths also try to handle the failure cases they'll
* see if begin_count didn't reflect reality. It's also a bit of
* a bug that the conservative paths might return success because
* some other thread was in epoxy glBegin/glEnd while our thread
* is trying to resolve, but given that it's basically just for
* informative error messages, we shouldn't need to care.
*/
long begin_count;
};
static struct api api = {
#ifndef _WIN32
.mutex = PTHREAD_MUTEX_INITIALIZER,
#else
0,
#endif
};
static bool library_initialized;
static bool epoxy_current_context_is_glx(void);
#if PLATFORM_HAS_EGL
static EGLenum
epoxy_egl_get_current_gl_context_api(void);
#endif
CONSTRUCT (library_init)
static void
library_init(void)
{
library_initialized = true;
}
static bool
get_dlopen_handle(void **handle, const char *lib_name, bool exit_on_fail, bool load)
{
if (*handle)
return true;
if (!library_initialized) {
fputs("Attempting to dlopen() while in the dynamic linker.\n", stderr);
abort();
}
#ifdef _WIN32
*handle = LoadLibraryA(lib_name);
#else
pthread_mutex_lock(&api.mutex);
if (!*handle) {
int flags = RTLD_LAZY | RTLD_LOCAL;
#ifndef __OpenBSD__
if (!load)
flags |= RTLD_NOLOAD;
#endif
*handle = dlopen(lib_name, flags);
if (!*handle) {
if (exit_on_fail) {
fprintf(stderr, "Couldn't open %s: %s\n", lib_name, dlerror());
abort();
} else {
(void)dlerror();
}
}
}
pthread_mutex_unlock(&api.mutex);
#endif
return *handle != NULL;
}
static void *
do_dlsym(void **handle, const char *name, bool exit_on_fail)
{
void *result;
const char *error = "";
#ifdef _WIN32
result = GetProcAddress(*handle, name);
#else
result = dlsym(*handle, name);
if (!result)
error = dlerror();
#endif
if (!result && exit_on_fail) {
fprintf(stderr, "%s() not found: %s\n", name, error);
abort();
}
return result;
}
/**
* @brief Checks whether we're using OpenGL or OpenGL ES
*
* @return `true` if we're using OpenGL
*/
bool
epoxy_is_desktop_gl(void)
{
const char *es_prefix = "OpenGL ES";
const char *version;
#if PLATFORM_HAS_EGL
/* PowerVR's OpenGL ES implementation (and perhaps other) don't
* comply with the standard, which states that
* "glGetString(GL_VERSION)" should return a string starting with
* "OpenGL ES". Therefore, to distinguish desktop OpenGL from
* OpenGL ES, we must also check the context type through EGL (we
* can do that as PowerVR is only usable through EGL).
*/
if (!epoxy_current_context_is_glx()) {
switch (epoxy_egl_get_current_gl_context_api()) {
case EGL_OPENGL_API: return true;
case EGL_OPENGL_ES_API: return false;
case EGL_NONE:
default: break;
}
}
#endif
if (api.begin_count)
return true;
version = (const char *)glGetString(GL_VERSION);
/* If we didn't get a version back, there are only two things that
* could have happened: either malloc failure (which basically
* doesn't exist), or we were called within a glBegin()/glEnd().
* Assume the second, which only exists for desktop GL.
*/
if (!version)
return true;
return strncmp(es_prefix, version, strlen(es_prefix));
}
static int
epoxy_internal_gl_version(GLenum version_string, int error_version, int factor)
{
const char *version = (const char *)glGetString(version_string);
GLint major, minor;
int scanf_count;
if (!version)
return error_version;
/* skip to version number */
while (!isdigit(*version) && *version != '\0')
version++;
/* Interpret version number */
scanf_count = sscanf(version, "%i.%i", &major, &minor);
if (scanf_count != 2) {
fprintf(stderr, "Unable to interpret GL_VERSION string: %s\n",
version);
abort();
}
return factor * major + minor;
}
/**
* @brief Returns the version of OpenGL we are using
*
* The version is encoded as:
*
* ```
*
* version = major * 10 + minor
*
* ```
*
* So it can be easily used for version comparisons.
*
* @return The encoded version of OpenGL we are using
*/
int
epoxy_gl_version(void)
{
return epoxy_internal_gl_version(GL_VERSION, 0, 10);
}
int
epoxy_conservative_gl_version(void)
{
if (api.begin_count)
return 100;
return epoxy_internal_gl_version(GL_VERSION, 100, 10);
}
/**
* @brief Returns the version of the GL Shading Language we are using
*
* The version is encoded as:
*
* ```
*
* version = major * 100 + minor
*
* ```
*
* So it can be easily used for version comparisons.
*
* @return The encoded version of the GL Shading Language we are using
*/
int
epoxy_glsl_version(void)
{
if (epoxy_gl_version() >= 20 ||
epoxy_has_gl_extension ("GL_ARB_shading_language_100"))
return epoxy_internal_gl_version(GL_SHADING_LANGUAGE_VERSION, 0, 100);
return 0;
}
/**
* @brief Checks for the presence of an extension in an OpenGL extension string
*
* @param extension_list The string containing the list of extensions to check
* @param ext The name of the GL extension
* @return `true` if the extension is available'
*
* @note If you are looking to check whether a normal GL, EGL or GLX extension
* is supported by the client, this probably isn't the function you want.
*
* Some parts of the spec for OpenGL and friends will return an OpenGL formatted
* extension string that is separate from the usual extension strings for the
* spec. This function provides easy parsing of those strings.
*
* @see epoxy_has_gl_extension()
* @see epoxy_has_egl_extension()
* @see epoxy_has_glx_extension()
*/
bool
epoxy_extension_in_string(const char *extension_list, const char *ext)
{
const char *ptr = extension_list;
int len;
if (!ext)
return false;
len = strlen(ext);
if (extension_list == NULL || *extension_list == '\0')
return false;
/* Make sure that don't just find an extension with our name as a prefix. */
while (true) {
ptr = strstr(ptr, ext);
if (!ptr)
return false;
if (ptr[len] == ' ' || ptr[len] == 0)
return true;
ptr += len;
}
}
static bool
epoxy_internal_has_gl_extension(const char *ext, bool invalid_op_mode)
{
if (epoxy_gl_version() < 30) {
const char *exts = (const char *)glGetString(GL_EXTENSIONS);
if (!exts)
return invalid_op_mode;
return epoxy_extension_in_string(exts, ext);
} else {
int num_extensions;
int i;
glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
if (num_extensions == 0)
return invalid_op_mode;
for (i = 0; i < num_extensions; i++) {
const char *gl_ext = (const char *)glGetStringi(GL_EXTENSIONS, i);
if (!gl_ext)
return false;
if (strcmp(ext, gl_ext) == 0)
return true;
}
return false;
}
}
bool
epoxy_load_glx(bool exit_if_fails, bool load)
{
#if PLATFORM_HAS_GLX
# ifdef GLVND_GLX_LIB
/* prefer the glvnd library if it exists */
if (!api.glx_handle)
get_dlopen_handle(&api.glx_handle, GLVND_GLX_LIB, false, load);
# endif
if (!api.glx_handle)
get_dlopen_handle(&api.glx_handle, GLX_LIB, exit_if_fails, load);
#endif
return api.glx_handle != NULL;
}
void *
epoxy_conservative_glx_dlsym(const char *name, bool exit_if_fails)
{
#if PLATFORM_HAS_GLX
if (epoxy_load_glx(exit_if_fails, exit_if_fails))
return do_dlsym(&api.glx_handle, name, exit_if_fails);
#endif
return NULL;
}
/**
* Tests whether the currently bound context is EGL or GLX, trying to
* avoid loading libraries unless necessary.
*/
static bool
epoxy_current_context_is_glx(void)
{
#if !PLATFORM_HAS_GLX
return false;
#else
void *sym;
sym = epoxy_conservative_glx_dlsym("glXGetCurrentContext", false);
if (sym) {
if (glXGetCurrentContext())
return true;
} else {
(void)dlerror();
}
#if PLATFORM_HAS_EGL
sym = epoxy_conservative_egl_dlsym("eglGetCurrentContext", false);
if (sym) {
if (epoxy_egl_get_current_gl_context_api() != EGL_NONE)
return false;
} else {
(void)dlerror();
}
#endif /* PLATFORM_HAS_EGL */
return false;
#endif /* PLATFORM_HAS_GLX */
}
/**
* @brief Returns true if the given GL extension is supported in the current context.
*
* @param ext The name of the GL extension
* @return `true` if the extension is available
*
* @note that this function can't be called from within `glBegin()` and `glEnd()`.
*
* @see epoxy_has_egl_extension()
* @see epoxy_has_glx_extension()
*/
bool
epoxy_has_gl_extension(const char *ext)
{
return epoxy_internal_has_gl_extension(ext, false);
}
bool
epoxy_conservative_has_gl_extension(const char *ext)
{
if (api.begin_count)
return true;
return epoxy_internal_has_gl_extension(ext, true);
}
bool
epoxy_load_egl(bool exit_if_fails, bool load)
{
#if PLATFORM_HAS_EGL
return get_dlopen_handle(&api.egl_handle, EGL_LIB, exit_if_fails, load);
#else
return false;
#endif
}
void *
epoxy_conservative_egl_dlsym(const char *name, bool exit_if_fails)
{
#if PLATFORM_HAS_EGL
if (epoxy_load_egl(exit_if_fails, exit_if_fails))
return do_dlsym(&api.egl_handle, name, exit_if_fails);
#endif
return NULL;
}
void *
epoxy_egl_dlsym(const char *name)
{
return epoxy_conservative_egl_dlsym(name, true);
}
void *
epoxy_glx_dlsym(const char *name)
{
return epoxy_conservative_glx_dlsym(name, true);
}
static void
epoxy_load_gl(void)
{
if (api.gl_handle)
return;
#if defined(_WIN32) || defined(__APPLE__)
get_dlopen_handle(&api.gl_handle, OPENGL_LIB, true, true);
#else
// Prefer GLX_LIB over OPENGL_LIB to maintain existing behavior.
// Using the inverse ordering OPENGL_LIB -> GLX_LIB, causes issues such as:
// https://github.com/anholt/libepoxy/issues/240 (apitrace missing calls)
// https://github.com/anholt/libepoxy/issues/252 (Xorg boot crash)
get_dlopen_handle(&api.glx_handle, GLX_LIB, false, true);
api.gl_handle = api.glx_handle;
#if defined(OPENGL_LIB)
if (!api.gl_handle)
get_dlopen_handle(&api.gl_handle, OPENGL_LIB, false, true);
if (!api.gl_handle) {
fprintf(stderr, "Couldn't open %s or %s\n", GLX_LIB, OPENGL_LIB);
abort();
}
#else
if (!api.gl_handle) {
fprintf(stderr, "Couldn't open %s\n", GLX_LIB);
abort();
}
#endif
#endif
}
void *
epoxy_gl_dlsym(const char *name)
{
epoxy_load_gl();
return do_dlsym(&api.gl_handle, name, true);
}
void *
epoxy_gles1_dlsym(const char *name)
{
if (epoxy_current_context_is_glx()) {
return epoxy_get_proc_address(name);
} else {
get_dlopen_handle(&api.gles1_handle, GLES1_LIB, true, true);
return do_dlsym(&api.gles1_handle, name, true);
}
}
void *
epoxy_gles2_dlsym(const char *name)
{
if (epoxy_current_context_is_glx()) {
return epoxy_get_proc_address(name);
} else {
get_dlopen_handle(&api.gles2_handle, GLES2_LIB, true, true);
return do_dlsym(&api.gles2_handle, name, true);
}
}
/**
* Does the appropriate dlsym() or eglGetProcAddress() for GLES3
* functions.
*
* Mesa interpreted GLES as intending that the GLES3 functions were
* available only through eglGetProcAddress() and not dlsym(), while
* ARM's Mali drivers interpreted GLES as intending that GLES3
* functions were available only through dlsym() and not
* eglGetProcAddress(). Thanks, Khronos.
*/
void *
epoxy_gles3_dlsym(const char *name)
{
if (epoxy_current_context_is_glx()) {
return epoxy_get_proc_address(name);
} else {
if (get_dlopen_handle(&api.gles2_handle, GLES2_LIB, false, true)) {
void *func = do_dlsym(&api.gles2_handle, name, false);
if (func)
return func;
}
return epoxy_get_proc_address(name);
}
}
/**
* Performs either the dlsym or glXGetProcAddress()-equivalent for
* core functions in desktop GL.
*/
void *
epoxy_get_core_proc_address(const char *name, int core_version)
{
#ifdef _WIN32
int core_symbol_support = 11;
#elif defined(__ANDROID__)
/**
* All symbols must be resolved through eglGetProcAddress
* on Android
*/
int core_symbol_support = 0;
#else
int core_symbol_support = 12;
#endif
if (core_version <= core_symbol_support) {
return epoxy_gl_dlsym(name);
} else {
return epoxy_get_proc_address(name);
}
}
#if PLATFORM_HAS_EGL
static EGLenum
epoxy_egl_get_current_gl_context_api(void)
{
EGLint curapi;
if (eglQueryContext(eglGetCurrentDisplay(), eglGetCurrentContext(),
EGL_CONTEXT_CLIENT_TYPE, &curapi) == EGL_FALSE) {
(void)eglGetError();
return EGL_NONE;
}
return (EGLenum) curapi;
}
#endif /* PLATFORM_HAS_EGL */
/**
* Performs the dlsym() for the core GL 1.0 functions that we use for
* determining version and extension support for deciding on dlsym
* versus glXGetProcAddress() for all other functions.
*
* This needs to succeed on implementations without GLX (since
* glGetString() and glGetIntegerv() are both in GLES1/2 as well, and
* at call time we don't know for sure what API they're trying to use
* without inspecting contexts ourselves).
*/
void *
epoxy_get_bootstrap_proc_address(const char *name)
{
/* If we already have a library that links to libglapi loaded,
* use that.
*/
#if PLATFORM_HAS_GLX
if (api.glx_handle && glXGetCurrentContext())
return epoxy_gl_dlsym(name);
#endif
/* If epoxy hasn't loaded any API-specific library yet, try to
* figure out what API the context is using and use that library,
* since future calls will also use that API (this prevents a
* non-X11 ES2 context from loading a bunch of X11 junk).
*/
#if PLATFORM_HAS_EGL
get_dlopen_handle(&api.egl_handle, EGL_LIB, false, true);
if (api.egl_handle) {
int version = 0;
switch (epoxy_egl_get_current_gl_context_api()) {
case EGL_OPENGL_API:
return epoxy_gl_dlsym(name);
case EGL_OPENGL_ES_API:
if (eglQueryContext(eglGetCurrentDisplay(),
eglGetCurrentContext(),
EGL_CONTEXT_CLIENT_VERSION,
&version)) {
if (version >= 2)
return epoxy_gles2_dlsym(name);
else
return epoxy_gles1_dlsym(name);
}
}
}
#endif /* PLATFORM_HAS_EGL */
/* Fall back to GLX */
return epoxy_gl_dlsym(name);
}
void *
epoxy_get_proc_address(const char *name)
{
#if PLATFORM_HAS_EGL
GLenum egl_api = EGL_NONE;
if (!epoxy_current_context_is_glx())
egl_api = epoxy_egl_get_current_gl_context_api();
switch (egl_api) {
case EGL_OPENGL_API:
case EGL_OPENGL_ES_API:
return eglGetProcAddress(name);
case EGL_NONE:
break;
}
#endif
#if defined(_WIN32)
return wglGetProcAddress(name);
#elif defined(__APPLE__)
return epoxy_gl_dlsym(name);
#elif PLATFORM_HAS_GLX
if (epoxy_current_context_is_glx())
return glXGetProcAddressARB((const GLubyte *)name);
assert(0 && "Couldn't find current GLX or EGL context.\n");
#endif
return NULL;
}
WRAPPER_VISIBILITY (void)
WRAPPER(epoxy_glBegin)(GLenum primtype)
{
#ifdef _WIN32
InterlockedIncrement(&api.begin_count);
#else
pthread_mutex_lock(&api.mutex);
api.begin_count++;
pthread_mutex_unlock(&api.mutex);
#endif
epoxy_glBegin_unwrapped(primtype);
}
WRAPPER_VISIBILITY (void)
WRAPPER(epoxy_glEnd)(void)
{
epoxy_glEnd_unwrapped();
#ifdef _WIN32
InterlockedDecrement(&api.begin_count);
#else
pthread_mutex_lock(&api.mutex);
api.begin_count--;
pthread_mutex_unlock(&api.mutex);
#endif
}
PFNGLBEGINPROC epoxy_glBegin = epoxy_glBegin_wrapped;
PFNGLENDPROC epoxy_glEnd = epoxy_glEnd_wrapped;
epoxy_resolver_failure_handler_t epoxy_resolver_failure_handler;
/**
* Sets the function that will be called every time Epoxy fails to
* resolve a symbol.
*
* @param handler The new handler function
* @return The previous handler function
*/
epoxy_resolver_failure_handler_t
epoxy_set_resolver_failure_handler(epoxy_resolver_failure_handler_t handler)
{
#ifdef _WIN32
return InterlockedExchangePointer((void**)&epoxy_resolver_failure_handler,
handler);
#else
epoxy_resolver_failure_handler_t old;
pthread_mutex_lock(&api.mutex);
old = epoxy_resolver_failure_handler;
epoxy_resolver_failure_handler = handler;
pthread_mutex_unlock(&api.mutex);
return old;
#endif
}

206
dist/libepoxy/src/dispatch_common.h vendored Normal file
View file

@ -0,0 +1,206 @@
/*
* Copyright © 2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "config.h"
#ifdef _WIN32
#define PLATFORM_HAS_EGL ENABLE_EGL
#define PLATFORM_HAS_GLX ENABLE_GLX
#define PLATFORM_HAS_WGL 1
#elif defined(__APPLE__)
#define PLATFORM_HAS_EGL 0
#define PLATFORM_HAS_GLX ENABLE_GLX
#define PLATFORM_HAS_WGL 0
#elif defined(ANDROID)
#define PLATFORM_HAS_EGL ENABLE_EGL
#define PLATFORM_HAS_GLX 0
#define PLATFORM_HAS_WGL 0
#else
#define PLATFORM_HAS_EGL ENABLE_EGL
#define PLATFORM_HAS_GLX ENABLE_GLX
#define PLATFORM_HAS_WGL 0
#endif
#include "epoxy/gl.h"
#if PLATFORM_HAS_GLX
#include "epoxy/glx.h"
#endif
#if PLATFORM_HAS_EGL
# if !ENABLE_X11
/* Disable including X11 headers if the X11 support was disabled at
* configuration time
*/
# define EGL_NO_X11 1
/* Older versions of Mesa use this symbol to achieve the same result
* as EGL_NO_X11
*/
# define MESA_EGL_NO_X11_HEADERS 1
# endif
#include "epoxy/egl.h"
#endif
#if PLATFORM_HAS_WGL
#include "epoxy/wgl.h"
#endif
#if defined(__GNUC__)
#define PACKED __attribute__((__packed__))
#define ENDPACKED
#elif defined (_MSC_VER)
#define PACKED __pragma(pack(push,1))
#define ENDPACKED __pragma(pack(pop))
#else
#define PACKED
#define ENDPACKED
#endif
/* On win32, we're going to need to keep a per-thread dispatch table,
* since the function pointers depend on the device and pixel format
* of the current context.
*/
#if defined(_WIN32)
#define USING_DISPATCH_TABLE 1
#else
#define USING_DISPATCH_TABLE 0
#endif
#define UNWRAPPED_PROTO(x) (GLAPIENTRY *x)
#define WRAPPER_VISIBILITY(type) static type GLAPIENTRY
#define WRAPPER(x) x ## _wrapped
#define GEN_GLOBAL_REWRITE_PTR(name, args, passthrough) \
static void EPOXY_CALLSPEC \
name##_global_rewrite_ptr args \
{ \
if (name == (void *)name##_global_rewrite_ptr) \
name = (void *)name##_resolver(); \
name passthrough; \
}
#define GEN_GLOBAL_REWRITE_PTR_RET(ret, name, args, passthrough) \
static ret EPOXY_CALLSPEC \
name##_global_rewrite_ptr args \
{ \
if (name == (void *)name##_global_rewrite_ptr) \
name = (void *)name##_resolver(); \
return name passthrough; \
}
#if USING_DISPATCH_TABLE
#define GEN_DISPATCH_TABLE_REWRITE_PTR(name, args, passthrough) \
static void EPOXY_CALLSPEC \
name##_dispatch_table_rewrite_ptr args \
{ \
struct dispatch_table *dispatch_table = get_dispatch_table(); \
\
dispatch_table->name = (void *)name##_resolver(); \
dispatch_table->name passthrough; \
}
#define GEN_DISPATCH_TABLE_REWRITE_PTR_RET(ret, name, args, passthrough) \
static ret EPOXY_CALLSPEC \
name##_dispatch_table_rewrite_ptr args \
{ \
struct dispatch_table *dispatch_table = get_dispatch_table(); \
\
dispatch_table->name = (void *)name##_resolver(); \
return dispatch_table->name passthrough; \
}
#define GEN_DISPATCH_TABLE_THUNK(name, args, passthrough) \
static void EPOXY_CALLSPEC \
name##_dispatch_table_thunk args \
{ \
get_dispatch_table()->name passthrough; \
}
#define GEN_DISPATCH_TABLE_THUNK_RET(ret, name, args, passthrough) \
static ret EPOXY_CALLSPEC \
name##_dispatch_table_thunk args \
{ \
return get_dispatch_table()->name passthrough; \
}
#else
#define GEN_DISPATCH_TABLE_REWRITE_PTR(name, args, passthrough)
#define GEN_DISPATCH_TABLE_REWRITE_PTR_RET(ret, name, args, passthrough)
#define GEN_DISPATCH_TABLE_THUNK(name, args, passthrough)
#define GEN_DISPATCH_TABLE_THUNK_RET(ret, name, args, passthrough)
#endif
#define GEN_THUNKS(name, args, passthrough) \
GEN_GLOBAL_REWRITE_PTR(name, args, passthrough) \
GEN_DISPATCH_TABLE_REWRITE_PTR(name, args, passthrough) \
GEN_DISPATCH_TABLE_THUNK(name, args, passthrough)
#define GEN_THUNKS_RET(ret, name, args, passthrough) \
GEN_GLOBAL_REWRITE_PTR_RET(ret, name, args, passthrough) \
GEN_DISPATCH_TABLE_REWRITE_PTR_RET(ret, name, args, passthrough) \
GEN_DISPATCH_TABLE_THUNK_RET(ret, name, args, passthrough)
void *epoxy_egl_dlsym(const char *name);
void *epoxy_glx_dlsym(const char *name);
void *epoxy_gl_dlsym(const char *name);
void *epoxy_gles1_dlsym(const char *name);
void *epoxy_gles2_dlsym(const char *name);
void *epoxy_gles3_dlsym(const char *name);
void *epoxy_get_proc_address(const char *name);
void *epoxy_get_core_proc_address(const char *name, int core_version);
void *epoxy_get_bootstrap_proc_address(const char *name);
int epoxy_conservative_gl_version(void);
bool epoxy_conservative_has_gl_extension(const char *name);
int epoxy_conservative_glx_version(void);
bool epoxy_conservative_has_glx_extension(const char *name);
int epoxy_conservative_egl_version(void);
bool epoxy_conservative_has_egl_extension(const char *name);
bool epoxy_conservative_has_wgl_extension(const char *name);
void *epoxy_conservative_egl_dlsym(const char *name, bool exit_if_fails);
void *epoxy_conservative_glx_dlsym(const char *name, bool exit_if_fails);
bool epoxy_load_glx(bool exit_if_fails, bool load);
bool epoxy_load_egl(bool exit_if_fails, bool load);
#define glBegin_unwrapped epoxy_glBegin_unwrapped
#define glEnd_unwrapped epoxy_glEnd_unwrapped
extern void UNWRAPPED_PROTO(glBegin_unwrapped)(GLenum primtype);
extern void UNWRAPPED_PROTO(glEnd_unwrapped)(void);
extern epoxy_resolver_failure_handler_t epoxy_resolver_failure_handler;
#if USING_DISPATCH_TABLE
void gl_init_dispatch_table(void);
void gl_switch_to_dispatch_table(void);
void wgl_init_dispatch_table(void);
void wgl_switch_to_dispatch_table(void);
extern uint32_t gl_tls_index, gl_tls_size;
extern uint32_t wgl_tls_index, wgl_tls_size;
#define wglMakeCurrent_unwrapped epoxy_wglMakeCurrent_unwrapped
#define wglMakeContextCurrentARB_unwrapped epoxy_wglMakeContextCurrentARB_unwrapped
#define wglMakeContextCurrentEXT_unwrapped epoxy_wglMakeContextCurrentEXT_unwrapped
#define wglMakeAssociatedContextCurrentAMD_unwrapped epoxy_wglMakeAssociatedContextCurrentAMD_unwrapped
extern BOOL UNWRAPPED_PROTO(wglMakeCurrent_unwrapped)(HDC hdc, HGLRC hglrc);
extern BOOL UNWRAPPED_PROTO(wglMakeContextCurrentARB_unwrapped)(HDC hDrawDC, HDC hReadDC, HGLRC hglrc);
extern BOOL UNWRAPPED_PROTO(wglMakeContextCurrentEXT_unwrapped)(HDC hDrawDC, HDC hReadDC, HGLRC hglrc);
extern BOOL UNWRAPPED_PROTO(wglMakeAssociatedContextCurrentAMD_unwrapped)(HGLRC hglrc);
#endif /* _WIN32_ */

122
dist/libepoxy/src/dispatch_egl.c vendored Normal file
View file

@ -0,0 +1,122 @@
/*
* Copyright © 2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include "dispatch_common.h"
int
epoxy_conservative_egl_version(void)
{
EGLDisplay dpy = eglGetCurrentDisplay();
if (!dpy)
return 14;
return epoxy_egl_version(dpy);
}
/**
* @brief Returns the version of OpenGL we are using
*
* The version is encoded as:
*
* ```
*
* version = major * 10 + minor
*
* ```
*
* So it can be easily used for version comparisons.
*
* @param The EGL display
*
* @return The encoded version of EGL we are using
*
* @see epoxy_gl_version()
*/
int
epoxy_egl_version(EGLDisplay dpy)
{
int major, minor;
const char *version_string;
int ret;
version_string = eglQueryString(dpy, EGL_VERSION);
if (!version_string)
return 0;
ret = sscanf(version_string, "%d.%d", &major, &minor);
assert(ret == 2);
return major * 10 + minor;
}
bool
epoxy_conservative_has_egl_extension(const char *ext)
{
return epoxy_has_egl_extension(eglGetCurrentDisplay(), ext);
}
/**
* @brief Returns true if the given EGL extension is supported in the current context.
*
* @param dpy The EGL display
* @param extension The name of the EGL extension
*
* @return `true` if the extension is available
*
* @see epoxy_has_gl_extension()
* @see epoxy_has_glx_extension()
*/
bool
epoxy_has_egl_extension(EGLDisplay dpy, const char *ext)
{
return epoxy_extension_in_string(eglQueryString(dpy, EGL_EXTENSIONS), ext) || epoxy_extension_in_string(eglQueryString(NULL, EGL_EXTENSIONS), ext);
}
/**
* @brief Checks whether EGL is available.
*
* @return `true` if EGL is available
*
* @newin{1,4}
*/
bool
epoxy_has_egl(void)
{
#if !PLATFORM_HAS_EGL
return false;
#else
if (epoxy_load_egl(false, true)) {
EGLDisplay* (* pf_eglGetCurrentDisplay) (void);
pf_eglGetCurrentDisplay = epoxy_conservative_egl_dlsym("eglGetCurrentDisplay", false);
if (pf_eglGetCurrentDisplay)
return true;
}
return false;
#endif /* PLATFORM_HAS_EGL */
}

172
dist/libepoxy/src/dispatch_glx.c vendored Normal file
View file

@ -0,0 +1,172 @@
/*
* Copyright © 2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include "dispatch_common.h"
/**
* If we can determine the GLX version from the current context, then
* return that, otherwise return a version that will just send us on
* to dlsym() or get_proc_address().
*/
int
epoxy_conservative_glx_version(void)
{
Display *dpy = glXGetCurrentDisplay();
GLXContext ctx = glXGetCurrentContext();
int screen;
if (!dpy || !ctx)
return 14;
glXQueryContext(dpy, ctx, GLX_SCREEN, &screen);
return epoxy_glx_version(dpy, screen);
}
/**
* @brief Returns the version of GLX we are using
*
* The version is encoded as:
*
* ```
*
* version = major * 10 + minor
*
* ```
*
* So it can be easily used for version comparisons.
*
* @param dpy The X11 display
* @param screen The X11 screen
*
* @return The encoded version of GLX we are using
*
* @see epoxy_gl_version()
*/
int
epoxy_glx_version(Display *dpy, int screen)
{
int server_major, server_minor;
int client_major, client_minor;
int server, client;
const char *version_string;
int ret;
version_string = glXQueryServerString(dpy, screen, GLX_VERSION);
if (!version_string)
return 0;
ret = sscanf(version_string, "%d.%d", &server_major, &server_minor);
assert(ret == 2);
server = server_major * 10 + server_minor;
version_string = glXGetClientString(dpy, GLX_VERSION);
if (!version_string)
return 0;
ret = sscanf(version_string, "%d.%d", &client_major, &client_minor);
assert(ret == 2);
client = client_major * 10 + client_minor;
if (client < server)
return client;
else
return server;
}
/**
* If we can determine the GLX extension support from the current
* context, then return that, otherwise give the answer that will just
* send us on to get_proc_address().
*/
bool
epoxy_conservative_has_glx_extension(const char *ext)
{
Display *dpy = glXGetCurrentDisplay();
GLXContext ctx = glXGetCurrentContext();
int screen;
if (!dpy || !ctx)
return true;
glXQueryContext(dpy, ctx, GLX_SCREEN, &screen);
return epoxy_has_glx_extension(dpy, screen, ext);
}
/**
* @brief Returns true if the given GLX extension is supported in the current context.
*
* @param dpy The X11 display
* @param screen The X11 screen
* @param extension The name of the GLX extension
*
* @return `true` if the extension is available
*
* @see epoxy_has_gl_extension()
* @see epoxy_has_egl_extension()
*/
bool
epoxy_has_glx_extension(Display *dpy, int screen, const char *ext)
{
/* No, you can't just use glXGetClientString or
* glXGetServerString() here. Those each tell you about one half
* of what's needed for an extension to be supported, and
* glXQueryExtensionsString() is what gives you the intersection
* of the two.
*/
return epoxy_extension_in_string(glXQueryExtensionsString(dpy, screen), ext);
}
/**
* @brief Checks whether GLX is available.
*
* @param dpy The X11 display
*
* @return `true` if GLX is available
*
* @newin{1,4}
*/
bool
epoxy_has_glx(Display *dpy)
{
#if !PLATFORM_HAS_GLX
return false;
#else
if (epoxy_load_glx(false, true)) {
Bool (* pf_glXQueryExtension) (Display *, int *, int *);
int error_base, event_base;
pf_glXQueryExtension = epoxy_conservative_glx_dlsym("glXQueryExtension", false);
if (pf_glXQueryExtension && pf_glXQueryExtension(dpy, &error_base, &event_base))
return true;
}
return false;
#endif /* !PLATFORM_HAS_GLX */
}

196
dist/libepoxy/src/dispatch_wgl.c vendored Normal file
View file

@ -0,0 +1,196 @@
/*
* Copyright © 2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include "dispatch_common.h"
static bool first_context_current = false;
static bool already_switched_to_dispatch_table = false;
/**
* If we can determine the WGL extension support from the current
* context, then return that, otherwise give the answer that will just
* send us on to get_proc_address().
*/
bool
epoxy_conservative_has_wgl_extension(const char *ext)
{
HDC hdc = wglGetCurrentDC();
if (!hdc)
return true;
return epoxy_has_wgl_extension(hdc, ext);
}
bool
epoxy_has_wgl_extension(HDC hdc, const char *ext)
{
PFNWGLGETEXTENSIONSSTRINGARBPROC getext;
getext = (void *)wglGetProcAddress("wglGetExtensionsStringARB");
if (!getext) {
fputs("Implementation unexpectedly missing "
"WGL_ARB_extensions_string. Probably a libepoxy bug.\n",
stderr);
return false;
}
return epoxy_extension_in_string(getext(hdc), ext);
}
/**
* Does the work necessary to update the win32 per-thread dispatch
* tables when wglMakeCurrent() is called.
*
* Right now, we use global function pointers until the second
* MakeCurrent occurs, at which point we switch to dispatch tables.
* This could be improved in the future to track a resolved dispatch
* table per context and reuse it when the context is made current
* again.
*/
void
epoxy_handle_external_wglMakeCurrent(void)
{
if (!first_context_current) {
first_context_current = true;
} else {
if (!already_switched_to_dispatch_table) {
already_switched_to_dispatch_table = true;
gl_switch_to_dispatch_table();
wgl_switch_to_dispatch_table();
}
gl_init_dispatch_table();
wgl_init_dispatch_table();
}
}
/**
* This global symbol is apparently looked up by Windows when loading
* a DLL, but it doesn't declare the prototype.
*/
BOOL WINAPI
DllMain(HINSTANCE dll, DWORD reason, LPVOID reserved);
BOOL WINAPI
DllMain(HINSTANCE dll, DWORD reason, LPVOID reserved)
{
void *data;
switch (reason) {
case DLL_PROCESS_ATTACH:
gl_tls_index = TlsAlloc();
if (gl_tls_index == TLS_OUT_OF_INDEXES)
return FALSE;
wgl_tls_index = TlsAlloc();
if (wgl_tls_index == TLS_OUT_OF_INDEXES)
return FALSE;
first_context_current = false;
/* FALLTHROUGH */
case DLL_THREAD_ATTACH:
data = LocalAlloc(LPTR, gl_tls_size);
TlsSetValue(gl_tls_index, data);
data = LocalAlloc(LPTR, wgl_tls_size);
TlsSetValue(wgl_tls_index, data);
break;
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
data = TlsGetValue(gl_tls_index);
LocalFree(data);
data = TlsGetValue(wgl_tls_index);
LocalFree(data);
if (reason == DLL_PROCESS_DETACH) {
TlsFree(gl_tls_index);
TlsFree(wgl_tls_index);
}
break;
}
return TRUE;
}
WRAPPER_VISIBILITY (BOOL)
WRAPPER(epoxy_wglMakeCurrent)(HDC hdc, HGLRC hglrc)
{
BOOL ret = epoxy_wglMakeCurrent_unwrapped(hdc, hglrc);
epoxy_handle_external_wglMakeCurrent();
return ret;
}
WRAPPER_VISIBILITY (BOOL)
WRAPPER(epoxy_wglMakeContextCurrentARB)(HDC hDrawDC,
HDC hReadDC,
HGLRC hglrc)
{
BOOL ret = epoxy_wglMakeContextCurrentARB_unwrapped(hDrawDC, hReadDC,
hglrc);
epoxy_handle_external_wglMakeCurrent();
return ret;
}
WRAPPER_VISIBILITY (BOOL)
WRAPPER(epoxy_wglMakeContextCurrentEXT)(HDC hDrawDC,
HDC hReadDC,
HGLRC hglrc)
{
BOOL ret = epoxy_wglMakeContextCurrentEXT_unwrapped(hDrawDC, hReadDC,
hglrc);
epoxy_handle_external_wglMakeCurrent();
return ret;
}
WRAPPER_VISIBILITY (BOOL)
WRAPPER(epoxy_wglMakeAssociatedContextCurrentAMD)(HGLRC hglrc)
{
BOOL ret = epoxy_wglMakeAssociatedContextCurrentAMD_unwrapped(hglrc);
epoxy_handle_external_wglMakeCurrent();
return ret;
}
PFNWGLMAKECURRENTPROC epoxy_wglMakeCurrent = epoxy_wglMakeCurrent_wrapped;
PFNWGLMAKECONTEXTCURRENTEXTPROC epoxy_wglMakeContextCurrentEXT = epoxy_wglMakeContextCurrentEXT_wrapped;
PFNWGLMAKECONTEXTCURRENTARBPROC epoxy_wglMakeContextCurrentARB = epoxy_wglMakeContextCurrentARB_wrapped;
PFNWGLMAKEASSOCIATEDCONTEXTCURRENTAMDPROC epoxy_wglMakeAssociatedContextCurrentEXT = epoxy_wglMakeAssociatedContextCurrentAMD_wrapped;

932
dist/libepoxy/src/gen_dispatch.py vendored Executable file
View file

@ -0,0 +1,932 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright © 2013 Intel Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
import sys
import argparse
import xml.etree.ElementTree as ET
import re
import os
class GLProvider(object):
def __init__(self, condition, condition_name, loader, name):
# C code for determining if this function is available.
# (e.g. epoxy_is_desktop_gl() && epoxy_gl_version() >= 20
self.condition = condition
# A string (possibly with spaces) describing the condition.
self.condition_name = condition_name
# The loader for getting the symbol -- either dlsym or
# getprocaddress. This is a python format string to generate
# C code, given self.name.
self.loader = loader
# The name of the function to be loaded (possibly an
# ARB/EXT/whatever-decorated variant).
self.name = name
# This is the C enum name we'll use for referring to this provider.
self.enum = condition_name
self.enum = self.enum.replace(' ', '_')
self.enum = self.enum.replace('\\"', '')
self.enum = self.enum.replace('.', '_')
self.enum = "PROVIDER_" + self.enum
class GLFunction(object):
def __init__(self, ret_type, name):
self.name = name
self.ptr_type = 'PFN' + name.upper() + 'PROC'
self.ret_type = ret_type
self.providers = {}
self.args = []
# These are functions with hand-written wrapper code in
# dispatch_common.c. Their dispatch entries are replaced with
# non-public symbols with a "_unwrapped" suffix.
wrapped_functions = {
'glBegin',
'glEnd',
'wglMakeCurrent',
'wglMakeContextCurrentEXT',
'wglMakeContextCurrentARB',
'wglMakeAssociatedContextCurrentAMD',
}
if name in wrapped_functions:
self.wrapped_name = name + '_unwrapped'
self.public = ''
else:
self.wrapped_name = name
self.public = 'EPOXY_PUBLIC '
# This is the string of C code for passing through the
# arguments to the function.
self.args_list = ''
# This is the string of C code for declaring the arguments
# list.
self.args_decl = 'void'
# This is the string name of the function that this is an
# alias of, or self.name. This initially comes from the
# registry, and may get updated if it turns out our alias is
# itself an alias (for example glFramebufferTextureEXT ->
# glFramebufferTextureARB -> glFramebufferTexture)
self.alias_name = name
# After alias resolution, this is the function that this is an
# alias of.
self.alias_func = None
# For the root of an alias tree, this lists the functions that
# are marked as aliases of it, so that it can write a resolver
# for all of them.
self.alias_exts = []
def add_arg(self, arg_type, arg_name):
# Reword glDepthRange() arguments to avoid clashing with the
# "near" and "far" keywords on win32.
if arg_name == "near":
arg_name = "hither"
elif arg_name == "far":
arg_name = "yon"
# Mac screwed up GLhandleARB and made it a void * instead of
# uint32_t, despite it being specced as only necessarily 32
# bits wide, causing portability problems all over. There are
# prototype conflicts between things like
# glAttachShader(GLuint program, GLuint shader) and
# glAttachObjectARB(GLhandleARB container, GLhandleARB obj),
# even though they are marked as aliases in the XML (and being
# aliases in Mesa).
#
# We retain those aliases. In the x86_64 ABI, the first 6
# args are stored in 64-bit registers, so the calls end up
# being the same despite the different types. We just need to
# add a cast to uintptr_t to shut up the compiler.
if arg_type == 'GLhandleARB':
assert len(self.args) < 6
arg_list_name = '(uintptr_t)' + arg_name
else:
arg_list_name = arg_name
self.args.append((arg_type, arg_name))
if self.args_decl == 'void':
self.args_list = arg_list_name
self.args_decl = arg_type + ' ' + arg_name
else:
self.args_list += ', ' + arg_list_name
self.args_decl += ', ' + arg_type + ' ' + arg_name
def add_provider(self, condition, loader, condition_name):
self.providers[condition_name] = GLProvider(condition, condition_name,
loader, self.name)
def add_alias(self, ext):
assert self.alias_func is None
self.alias_exts.append(ext)
ext.alias_func = self
class Generator(object):
def __init__(self, target):
self.target = target
self.enums = {}
self.functions = {}
self.sorted_functions = []
self.enum_string_offset = {}
self.max_enum_name_len = 1
self.entrypoint_string_offset = {}
self.copyright_comment = None
self.typedefs = ''
self.out_file = None
# GL versions named in the registry, which we should generate
# #defines for.
self.supported_versions = set()
# Extensions named in the registry, which we should generate
# #defines for.
self.supported_extensions = set()
# Dictionary mapping human-readable names of providers to a C
# enum token that will be used to reference those names, to
# reduce generated binary size.
self.provider_enum = {}
# Dictionary mapping human-readable names of providers to C
# code to detect if it's present.
self.provider_condition = {}
# Dictionary mapping human-readable names of providers to
# format strings for fetching the function pointer when
# provided the name of the symbol to be requested.
self.provider_loader = {}
def all_text_until_element_name(self, element, element_name):
text = ''
if element.text is not None:
text += element.text
for child in element:
if child.tag == element_name:
break
if child.text:
text += child.text
if child.tail:
text += child.tail
return text
def out(self, text):
self.out_file.write(text)
def outln(self, text):
self.out_file.write(text + '\n')
def parse_typedefs(self, reg):
for t in reg.findall('types/type'):
if 'name' in t.attrib and t.attrib['name'] not in {'GLhandleARB'}:
continue
# The gles1/gles2-specific types are redundant
# declarations, and the different types used for them (int
# vs int32_t) caused problems on win32 builds.
api = t.get('api')
if api:
continue
if t.text is not None:
self.typedefs += t.text
for child in t:
if child.tag == 'apientry':
self.typedefs += 'APIENTRY'
if child.text:
self.typedefs += child.text
if child.tail:
self.typedefs += child.tail
self.typedefs += '\n'
def parse_enums(self, reg):
for enum in reg.findall('enums/enum'):
name = enum.get('name')
# wgl.xml's 0xwhatever definitions end up colliding with
# wingdi.h's decimal definitions of these.
if name in ['WGL_SWAP_OVERLAY', 'WGL_SWAP_UNDERLAY', 'WGL_SWAP_MAIN_PLANE']:
continue
self.max_enum_name_len = max(self.max_enum_name_len, len(name))
self.enums[name] = enum.get('value')
def get_function_return_type(self, proto):
# Everything up to the start of the name element is the return type.
return self.all_text_until_element_name(proto, 'name').strip()
def parse_function_definitions(self, reg):
for command in reg.findall('commands/command'):
proto = command.find('proto')
name = proto.find('name').text
ret_type = self.get_function_return_type(proto)
func = GLFunction(ret_type, name)
for arg in command.findall('param'):
func.add_arg(self.all_text_until_element_name(arg, 'name').strip(),
arg.find('name').text)
alias = command.find('alias')
if alias is not None:
# Note that some alias references appear before the
# target command is defined (glAttachObjectARB() ->
# glAttachShader(), for example).
func.alias_name = alias.get('name')
self.functions[name] = func
def drop_weird_glx_functions(self):
# Drop a few ancient SGIX GLX extensions that use types not defined
# anywhere in Xlib. In glxext.h, they're protected by #ifdefs for the
# headers that defined them.
weird_functions = [name for name, func in self.functions.items()
if 'VLServer' in func.args_decl
or 'DMparams' in func.args_decl]
for name in weird_functions:
del self.functions[name]
def resolve_aliases(self):
for func in self.functions.values():
# Find the root of the alias tree, and add ourselves to it.
if func.alias_name != func.name:
alias_func = func
while alias_func.alias_name != alias_func.name:
alias_func = self.functions[alias_func.alias_name]
func.alias_name = alias_func.name
func.alias_func = alias_func
alias_func.alias_exts.append(func)
def prepare_provider_enum(self):
self.provider_enum = {}
# We assume that for any given provider, all functions using
# it will have the same loader. This lets us generate a
# general C function for detecting conditions and calling the
# dlsym/getprocaddress, and have our many resolver stubs just
# call it with a table of values.
for func in self.functions.values():
for provider in func.providers.values():
if provider.condition_name in self.provider_enum:
assert self.provider_condition[provider.condition_name] == provider.condition
assert self.provider_loader[provider.condition_name] == provider.loader
continue
self.provider_enum[provider.condition_name] = provider.enum
self.provider_condition[provider.condition_name] = provider.condition
self.provider_loader[provider.condition_name] = provider.loader
def sort_functions(self):
self.sorted_functions = sorted(self.functions.values(), key=lambda func: func.name)
def process_require_statements(self, feature, condition, loader, human_name):
for command in feature.findall('require/command'):
name = command.get('name')
# wgl.xml describes 6 functions in WGL 1.0 that are in
# gdi32.dll instead of opengl32.dll, and we would need to
# change up our symbol loading to support that. Just
# don't wrap those functions.
if self.target == 'wgl' and 'wgl' not in name:
del self.functions[name]
continue
func = self.functions[name]
func.add_provider(condition, loader, human_name)
def parse_function_providers(self, reg):
for feature in reg.findall('feature'):
api = feature.get('api') # string gl, gles1, gles2, glx
m = re.match(r'([0-9])\.([0-9])', feature.get('number'))
version = int(m.group(1)) * 10 + int(m.group(2))
self.supported_versions.add(feature.get('name'))
if api == 'gl':
human_name = 'Desktop OpenGL {0}'.format(feature.get('number'))
condition = 'epoxy_is_desktop_gl()'
loader = 'epoxy_get_core_proc_address({0}, {1})'.format('{0}', version)
if version >= 11:
condition += ' && epoxy_conservative_gl_version() >= {0}'.format(version)
elif api == 'gles2':
human_name = 'OpenGL ES {0}'.format(feature.get('number'))
condition = '!epoxy_is_desktop_gl() && epoxy_gl_version() >= {0}'.format(version)
if version <= 20:
loader = 'epoxy_gles2_dlsym({0})'
else:
loader = 'epoxy_gles3_dlsym({0})'
elif api == 'gles1':
human_name = 'OpenGL ES 1.0'
condition = '!epoxy_is_desktop_gl() && epoxy_gl_version() >= 10 && epoxy_gl_version() < 20'
loader = 'epoxy_gles1_dlsym({0})'
elif api == 'glx':
human_name = 'GLX {0}'.format(version)
# We could just always use GPA for loading everything
# but glXGetProcAddress(), but dlsym() is a more
# efficient lookup.
if version > 13:
condition = 'epoxy_conservative_glx_version() >= {0}'.format(version)
loader = 'glXGetProcAddress((const GLubyte *){0})'
else:
condition = 'true'
loader = 'epoxy_glx_dlsym({0})'
elif api == 'egl':
human_name = 'EGL {0}'.format(version)
if version > 10:
condition = 'epoxy_conservative_egl_version() >= {0}'.format(version)
else:
condition = 'true'
# All EGL core entrypoints must be dlsym()ed out --
# eglGetProcAdddress() will return NULL.
loader = 'epoxy_egl_dlsym({0})'
elif api == 'wgl':
human_name = 'WGL {0}'.format(version)
condition = 'true'
loader = 'epoxy_gl_dlsym({0})'
elif api == 'glsc2':
continue
else:
sys.exit('unknown API: "{0}"'.format(api))
self.process_require_statements(feature, condition, loader, human_name)
for extension in reg.findall('extensions/extension'):
extname = extension.get('name')
cond_extname = "enum_string[enum_string_offsets[i]]"
self.supported_extensions.add(extname)
# 'supported' is a set of strings like gl, gles1, gles2,
# or glx, which are separated by '|'
apis = extension.get('supported').split('|')
if 'glx' in apis:
condition = 'epoxy_conservative_has_glx_extension(provider_name)'
loader = 'glXGetProcAddress((const GLubyte *){0})'
self.process_require_statements(extension, condition, loader, extname)
if 'egl' in apis:
condition = 'epoxy_conservative_has_egl_extension(provider_name)'
loader = 'eglGetProcAddress({0})'
self.process_require_statements(extension, condition, loader, extname)
if 'wgl' in apis:
condition = 'epoxy_conservative_has_wgl_extension(provider_name)'
loader = 'wglGetProcAddress({0})'
self.process_require_statements(extension, condition, loader, extname)
if {'gl', 'gles1', 'gles2'}.intersection(apis):
condition = 'epoxy_conservative_has_gl_extension(provider_name)'
loader = 'epoxy_get_proc_address({0})'
self.process_require_statements(extension, condition, loader, extname)
def fixup_bootstrap_function(self, name, loader):
# We handle glGetString(), glGetIntegerv(), and
# glXGetProcAddressARB() specially, because we need to use
# them in the process of deciding on loaders for resolving,
# and the naive code generation would result in their
# resolvers calling their own resolvers.
if name not in self.functions:
return
func = self.functions[name]
func.providers = {}
func.add_provider('true', loader, 'always present')
def parse(self, xml_file):
reg = ET.parse(xml_file)
comment = reg.find('comment')
if comment is not None:
self.copyright_comment = comment.text
else:
self.copyright_comment = ''
self.parse_typedefs(reg)
self.parse_enums(reg)
self.parse_function_definitions(reg)
self.parse_function_providers(reg)
def write_copyright_comment_body(self):
for line in self.copyright_comment.splitlines():
if '-----' in line:
break
self.outln(' * ' + line)
def write_enums(self):
for name in sorted(self.supported_versions):
self.outln('#define {0} 1'.format(name))
self.outln('')
for name in sorted(self.supported_extensions):
self.outln('#define {0} 1'.format(name))
self.outln('')
# We want to sort by enum number (which puts a bunch of things
# in a logical order), then by name after that, so we do those
# sorts in reverse. This is still way uglier than doing some
# sort based on what version/extensions things are introduced
# in, but we haven't paid any attention to those attributes
# for enums yet.
sorted_by_name = sorted(self.enums.keys())
sorted_by_number = sorted(sorted_by_name, key=lambda name: self.enums[name])
for name in sorted_by_number:
self.outln('#define ' + name.ljust(self.max_enum_name_len + 3) + self.enums[name] + '')
def write_function_ptr_typedefs(self):
for func in self.sorted_functions:
self.outln('typedef {0} (GLAPIENTRY *{1})({2});'.format(func.ret_type,
func.ptr_type,
func.args_decl))
def write_header_header(self, out_file):
self.close()
self.out_file = open(out_file, 'w')
self.outln('/* GL dispatch header.')
self.outln(' * This is code-generated from the GL API XML files from Khronos.')
self.write_copyright_comment_body()
self.outln(' */')
self.outln('')
self.outln('#pragma once')
self.outln('#include <inttypes.h>')
self.outln('#include <stddef.h>')
self.outln('')
def write_header(self, out_file):
self.write_header_header(out_file)
self.outln('#include "epoxy/common.h"')
if self.target != "gl":
self.outln('#include "epoxy/gl.h"')
if self.target == "egl":
self.outln('#include "EGL/eglplatform.h"')
# Account for older eglplatform.h, which doesn't define
# the EGL_CAST macro.
self.outln('#ifndef EGL_CAST')
self.outln('#if defined(__cplusplus)')
self.outln('#define EGL_CAST(type, value) (static_cast<type>(value))')
self.outln('#else')
self.outln('#define EGL_CAST(type, value) ((type) (value))')
self.outln('#endif')
self.outln('#endif')
else:
# Add some ridiculous inttypes.h redefinitions that are
# from khrplatform.h and not included in the XML. We
# don't directly include khrplatform.h because it's not
# present on many systems, and coming up with #ifdefs to
# decide when it's not present would be hard.
self.outln('#define __khrplatform_h_ 1')
self.outln('typedef int8_t khronos_int8_t;')
self.outln('typedef int16_t khronos_int16_t;')
self.outln('typedef int32_t khronos_int32_t;')
self.outln('typedef int64_t khronos_int64_t;')
self.outln('typedef uint8_t khronos_uint8_t;')
self.outln('typedef uint16_t khronos_uint16_t;')
self.outln('typedef uint32_t khronos_uint32_t;')
self.outln('typedef uint64_t khronos_uint64_t;')
self.outln('typedef float khronos_float_t;')
self.outln('#ifdef _WIN64')
self.outln('typedef signed long long int khronos_intptr_t;')
self.outln('typedef unsigned long long int khronos_uintptr_t;')
self.outln('typedef signed long long int khronos_ssize_t;')
self.outln('typedef unsigned long long int khronos_usize_t;')
self.outln('#else')
self.outln('typedef signed long int khronos_intptr_t;')
self.outln('typedef unsigned long int khronos_uintptr_t;')
self.outln('typedef signed long int khronos_ssize_t;')
self.outln('typedef unsigned long int khronos_usize_t;')
self.outln('#endif')
self.outln('typedef uint64_t khronos_utime_nanoseconds_t;')
self.outln('typedef int64_t khronos_stime_nanoseconds_t;')
self.outln('#define KHRONOS_MAX_ENUM 0x7FFFFFFF')
self.outln('typedef enum {')
self.outln(' KHRONOS_FALSE = 0,')
self.outln(' KHRONOS_TRUE = 1,')
self.outln(' KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM')
self.outln('} khronos_boolean_enum_t;')
if self.target == "glx":
self.outln('#include <X11/Xlib.h>')
self.outln('#include <X11/Xutil.h>')
self.out(self.typedefs)
self.outln('')
self.write_enums()
self.outln('')
self.write_function_ptr_typedefs()
for func in self.sorted_functions:
self.outln('EPOXY_PUBLIC {0} (EPOXY_CALLSPEC *epoxy_{1})({2});'.format(func.ret_type,
func.name,
func.args_decl))
self.outln('')
for func in self.sorted_functions:
self.outln('#define {0} epoxy_{0}'.format(func.name))
def write_function_ptr_resolver(self, func):
self.outln('static {0}'.format(func.ptr_type))
self.outln('epoxy_{0}_resolver(void)'.format(func.wrapped_name))
self.outln('{')
providers = []
# Make a local list of all the providers for this alias group
alias_root = func
if func.alias_func:
alias_root = func.alias_func
for provider in alias_root.providers.values():
providers.append(provider)
for alias_func in alias_root.alias_exts:
for provider in alias_func.providers.values():
providers.append(provider)
# Add some partial aliases of a few functions. These are ones
# that aren't quite aliases, because of some trivial behavior
# difference (like whether to produce an error for a
# non-Genned name), but where we'd like to fall back to the
# similar function if the proper one isn't present.
half_aliases = {
'glBindVertexArray' : 'glBindVertexArrayAPPLE',
'glBindVertexArrayAPPLE' : 'glBindVertexArray',
'glBindFramebuffer' : 'glBindFramebufferEXT',
'glBindFramebufferEXT' : 'glBindFramebuffer',
'glBindRenderbuffer' : 'glBindRenderbufferEXT',
'glBindRenderbufferEXT' : 'glBindRenderbuffer',
}
if func.name in half_aliases:
alias_func = self.functions[half_aliases[func.name]]
for provider in alias_func.providers.values():
providers.append(provider)
def provider_sort(provider):
return (provider.name != func.name, provider.name, provider.enum)
providers.sort(key=provider_sort)
if len(providers) != 1:
self.outln(' static const enum {0}_provider providers[] = {{'.format(self.target))
for provider in providers:
self.outln(' {0},'.format(provider.enum))
self.outln(' {0}_provider_terminator'.format(self.target))
self.outln(' };')
self.outln(' static const uint32_t entrypoints[] = {')
if len(providers) > 1:
for provider in providers:
self.outln(' {0} /* "{1}" */,'.format(self.entrypoint_string_offset[provider.name], provider.name))
else:
self.outln(' 0 /* None */,')
self.outln(' };')
self.outln(' return {0}_provider_resolver(entrypoint_strings + {1} /* "{2}" */,'.format(self.target,
self.entrypoint_string_offset[func.name],
func.name))
self.outln(' providers, entrypoints);')
else:
assert providers[0].name == func.name
self.outln(' return {0}_single_resolver({1}, {2} /* {3} */);'.format(self.target,
providers[0].enum,
self.entrypoint_string_offset[func.name],
func.name))
self.outln('}')
self.outln('')
def write_thunks(self, func):
# Writes out the function that's initially plugged into the
# global function pointer, which resolves, updates the global
# function pointer, and calls down to it.
#
# It also writes out the actual initialized global function
# pointer.
if func.ret_type == 'void':
self.outln('GEN_THUNKS({0}, ({1}), ({2}))'.format(func.wrapped_name,
func.args_decl,
func.args_list))
else:
self.outln('GEN_THUNKS_RET({0}, {1}, ({2}), ({3}))'.format(func.ret_type,
func.wrapped_name,
func.args_decl,
func.args_list))
def write_function_pointer(self, func):
self.outln('{0} epoxy_{1} = epoxy_{1}_global_rewrite_ptr;'.format(func.ptr_type, func.wrapped_name))
self.outln('')
def write_provider_enums(self):
# Writes the enum declaration for the list of providers
# supported by gl_provider_resolver()
self.outln('')
self.outln('enum {0}_provider {{'.format(self.target))
sorted_providers = sorted(self.provider_enum.keys())
# We always put a 0 enum first so that we can have a
# terminator in our arrays
self.outln(' {0}_provider_terminator = 0,'.format(self.target))
for human_name in sorted_providers:
enum = self.provider_enum[human_name]
self.outln(' {0},'.format(enum))
self.outln('} PACKED;')
self.outln('ENDPACKED')
self.outln('')
def write_provider_enum_strings(self):
# Writes the mapping from enums to the strings describing them
# for epoxy_print_failure_reasons().
sorted_providers = sorted(self.provider_enum.keys())
offset = 0
self.outln('static const char *enum_string =')
for human_name in sorted_providers:
self.outln(' "{0}\\0"'.format(human_name))
self.enum_string_offset[human_name] = offset
offset += len(human_name.replace('\\', '')) + 1
self.outln(' ;')
self.outln('')
# We're using uint16_t for the offsets.
assert offset < 65536
self.outln('static const uint16_t enum_string_offsets[] = {')
self.outln(' -1, /* {0}_provider_terminator, unused */'.format(self.target))
for human_name in sorted_providers:
enum = self.provider_enum[human_name]
self.outln(' {1}, /* {0} */'.format(human_name, self.enum_string_offset[human_name]))
self.outln('};')
self.outln('')
def write_entrypoint_strings(self):
self.outln('static const char entrypoint_strings[] = {')
offset = 0
for func in self.sorted_functions:
if func.name not in self.entrypoint_string_offset:
self.entrypoint_string_offset[func.name] = offset
offset += len(func.name) + 1
for c in func.name:
self.outln(" '{0}',".format(c))
self.outln(' 0, // {0}'.format(func.name))
self.outln(' 0 };')
# We're using uint16_t for the offsets.
#assert(offset < 65536)
self.outln('')
def write_provider_resolver(self):
self.outln('static void *{0}_provider_resolver(const char *name,'.format(self.target))
self.outln(' const enum {0}_provider *providers,'.format(self.target))
self.outln(' const uint32_t *entrypoints)')
self.outln('{')
self.outln(' int i;')
self.outln(' for (i = 0; providers[i] != {0}_provider_terminator; i++) {{'.format(self.target))
self.outln(' const char *provider_name = enum_string + enum_string_offsets[providers[i]];')
self.outln(' switch (providers[i]) {')
self.outln('')
for human_name in sorted(self.provider_enum.keys()):
enum = self.provider_enum[human_name]
self.outln(' case {0}:'.format(enum))
self.outln(' if ({0})'.format(self.provider_condition[human_name]))
self.outln(' return {0};'.format(self.provider_loader[human_name]).format("entrypoint_strings + entrypoints[i]"))
self.outln(' break;')
self.outln(' case {0}_provider_terminator:'.format(self.target))
self.outln(' abort(); /* Not reached */')
self.outln(' }')
self.outln(' }')
self.outln('')
self.outln(' if (epoxy_resolver_failure_handler)')
self.outln(' return epoxy_resolver_failure_handler(name);')
self.outln('')
# If the function isn't provided by any known extension, print
# something useful for the poor application developer before
# aborting. (In non-epoxy GL usage, the app developer would
# call into some blank stub function and segfault).
self.outln(' fprintf(stderr, "No provider of %s found. Requires one of:\\n", name);')
self.outln(' for (i = 0; providers[i] != {0}_provider_terminator; i++) {{'.format(self.target))
self.outln(' fprintf(stderr, " %s\\n", enum_string + enum_string_offsets[providers[i]]);')
self.outln(' }')
self.outln(' if (providers[0] == {0}_provider_terminator) {{'.format(self.target))
self.outln(' fprintf(stderr, " No known providers. This is likely a bug "')
self.outln(' "in libepoxy code generation\\n");')
self.outln(' }')
self.outln(' abort();')
self.outln('}')
self.outln('')
single_resolver_proto = '{0}_single_resolver(enum {0}_provider provider, uint32_t entrypoint_offset)'.format(self.target)
self.outln('EPOXY_NOINLINE static void *')
self.outln('{0};'.format(single_resolver_proto))
self.outln('')
self.outln('static void *')
self.outln('{0}'.format(single_resolver_proto))
self.outln('{')
self.outln(' enum {0}_provider providers[] = {{'.format(self.target))
self.outln(' provider,')
self.outln(' {0}_provider_terminator'.format(self.target))
self.outln(' };')
self.outln(' return {0}_provider_resolver(entrypoint_strings + entrypoint_offset,'.format(self.target))
self.outln(' providers, &entrypoint_offset);')
self.outln('}')
self.outln('')
def write_source(self, f):
self.close()
self.out_file = open(f, 'w')
self.outln('/* GL dispatch code.')
self.outln(' * This is code-generated from the GL API XML files from Khronos.')
self.write_copyright_comment_body()
self.outln(' */')
self.outln('')
self.outln('#include "config.h"')
self.outln('')
self.outln('#include <stdlib.h>')
self.outln('#include <string.h>')
self.outln('#include <stdio.h>')
self.outln('')
self.outln('#include "dispatch_common.h"')
self.outln('#include "epoxy/{0}.h"'.format(self.target))
self.outln('')
self.outln('#ifdef __GNUC__')
self.outln('#define EPOXY_NOINLINE __attribute__((noinline))')
self.outln('#elif defined (_MSC_VER)')
self.outln('#define EPOXY_NOINLINE __declspec(noinline)')
self.outln('#endif')
self.outln('struct dispatch_table {')
for func in self.sorted_functions:
self.outln(' {0} epoxy_{1};'.format(func.ptr_type, func.wrapped_name))
self.outln('};')
self.outln('')
# Early declaration, so we can declare the real thing at the
# bottom. (I want the function_ptr_resolver as the first
# per-GL-call code, since it's the most interesting to see
# when you search for the implementation of a call)
self.outln('#if USING_DISPATCH_TABLE')
self.outln('static inline struct dispatch_table *')
self.outln('get_dispatch_table(void);')
self.outln('')
self.outln('#endif')
self.write_provider_enums()
self.write_provider_enum_strings()
self.write_entrypoint_strings()
self.write_provider_resolver()
for func in self.sorted_functions:
self.write_function_ptr_resolver(func)
for func in self.sorted_functions:
self.write_thunks(func)
self.outln('')
self.outln('#if USING_DISPATCH_TABLE')
self.outln('static struct dispatch_table resolver_table = {')
for func in self.sorted_functions:
self.outln(' epoxy_{0}_dispatch_table_rewrite_ptr, /* {0} */'.format(func.wrapped_name))
self.outln('};')
self.outln('')
self.outln('uint32_t {0}_tls_index;'.format(self.target))
self.outln('uint32_t {0}_tls_size = sizeof(struct dispatch_table);'.format(self.target))
self.outln('')
self.outln('static inline struct dispatch_table *')
self.outln('get_dispatch_table(void)')
self.outln('{')
self.outln(' return TlsGetValue({0}_tls_index);'.format(self.target))
self.outln('}')
self.outln('')
self.outln('void')
self.outln('{0}_init_dispatch_table(void)'.format(self.target))
self.outln('{')
self.outln(' struct dispatch_table *dispatch_table = get_dispatch_table();')
self.outln(' memcpy(dispatch_table, &resolver_table, sizeof(resolver_table));')
self.outln('}')
self.outln('')
self.outln('void')
self.outln('{0}_switch_to_dispatch_table(void)'.format(self.target))
self.outln('{')
for func in self.sorted_functions:
self.outln(' epoxy_{0} = epoxy_{0}_dispatch_table_thunk;'.format(func.wrapped_name))
self.outln('}')
self.outln('')
self.outln('#endif /* !USING_DISPATCH_TABLE */')
for func in self.sorted_functions:
self.write_function_pointer(func)
def close(self):
if self.out_file:
self.out_file.close()
self.out_file = None
argparser = argparse.ArgumentParser(description='Generate GL dispatch wrappers.')
argparser.add_argument('files', metavar='file.xml', nargs='+', help='GL API XML files to be parsed')
argparser.add_argument('--outputdir', metavar='dir', required=False, help='Destination directory for files (default to current dir)')
argparser.add_argument('--includedir', metavar='dir', required=False, help='Destination directory for headers')
argparser.add_argument('--srcdir', metavar='dir', required=False, help='Destination directory for source')
argparser.add_argument('--source', dest='source', action='store_true', required=False, help='Generate the source file')
argparser.add_argument('--no-source', dest='source', action='store_false', required=False, help='Do not generate the source file')
argparser.add_argument('--header', dest='header', action='store_true', required=False, help='Generate the header file')
argparser.add_argument('--no-header', dest='header', action='store_false', required=False, help='Do not generate the header file')
args = argparser.parse_args()
if args.outputdir:
outputdir = args.outputdir
else:
outputdir = os.getcwd()
if args.includedir:
includedir = args.includedir
else:
includedir = outputdir
if args.srcdir:
srcdir = args.srcdir
else:
srcdir = outputdir
build_source = args.source
build_header = args.header
if not build_source and not build_header:
build_source = True
build_header = True
for f in args.files:
name = os.path.basename(f).split('.xml')[0]
generator = Generator(name)
generator.parse(f)
generator.drop_weird_glx_functions()
# This is an ANSI vs Unicode function, handled specially by
# include/epoxy/wgl.h
if 'wglUseFontBitmaps' in generator.functions:
del generator.functions['wglUseFontBitmaps']
generator.sort_functions()
generator.resolve_aliases()
generator.fixup_bootstrap_function('glGetString',
'epoxy_get_bootstrap_proc_address({0})')
generator.fixup_bootstrap_function('glGetIntegerv',
'epoxy_get_bootstrap_proc_address({0})')
# While this is technically exposed as a GLX extension, it's
# required to be present as a public symbol by the Linux OpenGL
# ABI.
generator.fixup_bootstrap_function('glXGetProcAddress',
'epoxy_glx_dlsym({0})')
generator.prepare_provider_enum()
if build_header:
generator.write_header(os.path.join(includedir, name + '_generated.h'))
if build_source:
generator.write_source(os.path.join(srcdir, name + '_generated_dispatch.c'))
generator.close()

115
dist/libepoxy/src/meson.build vendored Normal file
View file

@ -0,0 +1,115 @@
# Configuration file
configure_file(output: 'config.h', configuration: conf)
# List of generated sources:
# - name of the generated file
# - registry source file
# - additional sources
generated_sources = [
[ 'gl_generated_dispatch.c', gl_registry, [ 'dispatch_common.c', 'dispatch_common.h' ] ]
]
if build_egl
generated_sources += [ [ 'egl_generated_dispatch.c', egl_registry, 'dispatch_egl.c' ] ]
endif
if build_glx
generated_sources += [ [ 'glx_generated_dispatch.c', glx_registry, 'dispatch_glx.c' ] ]
endif
if build_wgl
generated_sources += [ [ 'wgl_generated_dispatch.c', wgl_registry, 'dispatch_wgl.c' ] ]
endif
gen_sources = [ ]
sources = [ ]
foreach g: generated_sources
gen_source = g[0]
registry = g[1]
source = g[2]
generated = custom_target(gen_source,
input: registry,
output: [ gen_source ],
command: [
gen_dispatch_py,
'--source',
'--no-header',
'--outputdir=@OUTDIR@',
'@INPUT@',
])
gen_sources += [ generated ]
sources += [ source ]
endforeach
epoxy_sources = sources + gen_sources
common_ldflags = []
if host_system == 'linux' and cc.get_id() == 'gcc'
common_ldflags += cc.get_supported_link_arguments([ '-Wl,-Bsymbolic-functions', '-Wl,-z,relro' ])
endif
# Maintain compatibility with autotools; see: https://github.com/anholt/libepoxy/issues/108
darwin_versions = [1, '1.0']
epoxy_deps = [ dl_dep, ]
if host_system == 'windows'
epoxy_deps += [ opengl32_dep, gdi32_dep ]
endif
libepoxy = library(
'epoxy',
sources: epoxy_sources + epoxy_headers,
version: '0.0.0',
darwin_versions: darwin_versions,
install: true,
dependencies: epoxy_deps,
include_directories: libepoxy_inc,
c_args: common_cflags + visibility_cflags,
link_args: common_ldflags,
)
epoxy_has_glx = build_glx ? '1' : '0'
epoxy_has_egl = build_egl ? '1' : '0'
epoxy_has_wgl = build_wgl ? '1' : '0'
libepoxy_dep = declare_dependency(
link_with: libepoxy,
include_directories: libepoxy_inc,
dependencies: epoxy_deps,
sources: epoxy_headers,
variables: {
'epoxy_has_glx': epoxy_has_glx,
'epoxy_has_egl': epoxy_has_egl,
'epoxy_has_wgl': epoxy_has_wgl,
},
)
# We don't want to add these dependencies to the library, as they are
# not needed when building Epoxy; we do want to add them to the generated
# pkg-config file, for consumers of Epoxy
gl_reqs = []
if gl_dep.found() and gl_dep.type_name() == 'pkgconfig'
gl_reqs += 'gl'
endif
if build_egl and egl_dep.found() and egl_dep.type_name() == 'pkgconfig'
gl_reqs += 'egl'
endif
pkg = import('pkgconfig')
pkg.generate(
libraries: libepoxy,
name: 'epoxy',
description: 'GL dispatch library',
version: meson.project_version(),
variables: [
'epoxy_has_glx=@0@'.format(epoxy_has_glx),
'epoxy_has_egl=@0@'.format(epoxy_has_egl),
'epoxy_has_wgl=@0@'.format(epoxy_has_wgl),
],
filebase: 'epoxy',
requires_private: ' '.join(gl_reqs),
)