You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
libepoxy/src/dispatch_common.c

280 lines
8.3 KiB

/*
* 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.
*/
/**
* @file dispatch_common.c
*
* 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>
#include <dlfcn.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include "epoxy/gl.h"
#include "epoxy/glx.h"
#include "dispatch_common.h"
/* XXX: Make this thread local */
struct api local_api;
struct api *api = &local_api;
PUBLIC bool
epoxy_is_desktop_gl(void)
{
const char *es_prefix = "OpenGL ES ";
const char *version = (const char *)glGetString(GL_VERSION);
return strncmp(es_prefix, version, strlen(es_prefix));
}
PUBLIC int
epoxy_gl_version(void)
{
const char *version = (const char *)glGetString(GL_VERSION);
GLint major, minor;
int scanf_count;
/* 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);
exit(1);
}
return 10 * major + minor;
}
PUBLIC bool
epoxy_is_glx(void)
{
return true; /* XXX */
}
/**
* 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);
}
PUBLIC 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);
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);
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;
}
static bool
epoxy_extension_in_string(const char *extension_list, const char *ext)
{
const char *ptr = extension_list;
int len = strlen(ext);
/* Make sure that don't just find an extension with our name as a prefix. */
do {
ptr = strstr(ptr, ext);
} while (ptr && (ptr[len] != ' ' && ptr[len] != 0));
return ptr != NULL;
}
PUBLIC bool
epoxy_has_gl_extension(const char *ext)
{
return epoxy_extension_in_string((const char *)glGetString(GL_EXTENSIONS),
ext);
}
#if 0
PUBLIC bool
epoxy_has_egl_extension(const char *ext)
{
return epoxy_extension_in_string(eglQueryString(EGL_EXTENSIONS), ext);
}
#endif
PUBLIC bool
epoxy_has_glx_extension(const char *ext)
{
Display *dpy = glXGetCurrentDisplay();
int screen = 0;
if (!dpy) {
fprintf(stderr, "waffle needs a display!"); /* XXX */
return false;
}
/* 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);
}
void *
epoxy_dlsym(const char *name)
{
assert(api->gl_handle);
return dlsym(api->gl_handle, name);
}
void *
epoxy_get_proc_address(const char *name)
{
return glXGetProcAddress((const GLubyte *)name);
}
void
epoxy_glx_autoinit(void)
{
if (api->gl_handle)
return;
api->gl_handle = dlopen("libGL.so.1", RTLD_LAZY | RTLD_LOCAL);
if (!api->gl_handle) {
fprintf(stderr, "Couldn't open libGL.so.1: %s", dlerror());
exit(1);
}
api->winsys_handle = api->gl_handle;
}
void
epoxy_platform_autoinit(void)
{
epoxy_glx_autoinit();
}
void
epoxy_print_failure_reasons(const char *name,
const char **provider_names,
const int *providers)
{
int i;
printf("No provider of %s found. Requires one of:\n", name);
for (i = 0; providers[i] != 0; i++)
puts(provider_names[providers[i]]);
}