/** * \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."
*/
#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;
};
staticstruct api api = { #ifndef _WIN32
.mutex = PTHREAD_MUTEX_INITIALIZER, #else
0, #endif
};
#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)
{ constchar *es_prefix = "OpenGL ES"; constchar *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: returntrue; case EGL_OPENGL_ES_API: returnfalse; case EGL_NONE: default: break;
}
} #endif
if (api.begin_count) returntrue;
version = (constchar *)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) returntrue;
staticint
epoxy_internal_gl_version(GLenum version_string, int error_version, int factor)
{ constchar *version = (constchar *)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;
/** * @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(constchar *extension_list, constchar *ext)
{ constchar *ptr = extension_list; int len;
if (!ext) returnfalse;
len = strlen(ext);
if (extension_list == NULL || *extension_list == '\0') returnfalse;
/* Make sure that don't just find an extension with our name as a prefix. */ while (true) {
ptr = strstr(ptr, ext); if (!ptr) returnfalse;
staticbool
epoxy_internal_has_gl_extension(constchar *ext, bool invalid_op_mode)
{ if (epoxy_gl_version() < 30) { constchar *exts = (constchar *)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++) { constchar *gl_ext = (constchar *)glGetStringi(GL_EXTENSIONS, i); if (!gl_ext) returnfalse; if (strcmp(ext, gl_ext) == 0) returntrue;
}
returnfalse;
}
}
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;
}
/** * @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(constchar *ext)
{ return epoxy_internal_has_gl_extension(ext, false);
}
bool
epoxy_conservative_has_gl_extension(constchar *ext)
{ if (api.begin_count) returntrue;
/** * 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(constchar *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(constchar *name, int core_version)
{ #ifdef _WIN32 int core_symbol_support = 11; #elifdefined(__ANDROID__) /** * All symbols must be resolved through eglGetProcAddress * on Android
*/ int core_symbol_support = 0; #else int core_symbol_support = 12; #endif
/** * 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(constchar *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);
}
/** * 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
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.