sync code with last improvements from OpenBSD
This commit is contained in:
commit
88965415ff
26235 changed files with 29195616 additions and 0 deletions
940
dist/libepoxy/src/dispatch_common.c
vendored
Normal file
940
dist/libepoxy/src/dispatch_common.c
vendored
Normal 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
206
dist/libepoxy/src/dispatch_common.h
vendored
Normal 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
122
dist/libepoxy/src/dispatch_egl.c
vendored
Normal 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
172
dist/libepoxy/src/dispatch_glx.c
vendored
Normal 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
196
dist/libepoxy/src/dispatch_wgl.c
vendored
Normal 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
932
dist/libepoxy/src/gen_dispatch.py
vendored
Executable 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
115
dist/libepoxy/src/meson.build
vendored
Normal 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),
|
||||
)
|
Loading…
Add table
Add a link
Reference in a new issue