/* $Id$
This file is part of gldbg
-Copyright © 2009 Mikko Rasa, Mikkosoft Productions
+Copyright © 2009-2010 Mikko Rasa, Mikkosoft Productions
Distributed under the GPL
*/
#include <string.h>
#include <dlfcn.h>
#include <sys/uio.h>
-#include <X11/Xlib.h>
-#include <GL/gl.h>
-#include <GL/glx.h>
-#include "arraysize.h"
-#include "functions.h"
-static inline void *glsym(const char *sym)
+#define INTERNAL __attribute__((visibility("internal")))
+
+INTERNAL inline const char *get_lib_names(void)
+{
+ const char *env = getenv("GLWRAP_LIBS");
+ if(env)
+ return env;
+ return "libGL.so";
+}
+
+INTERNAL inline void *glsym(const char *name)
{
- static void *libgl = NULL;
- if(!libgl)
+ static void **gl_libs = NULL;
+ unsigned i;
+
+ if(!gl_libs)
{
- const char *libgl_name = getenv("GLWRAP_LIBGL");
- if(!libgl_name)
- libgl_name = "libGL.so";
- libgl = dlopen(libgl_name, RTLD_NOW);
- if(!libgl)
+ char *lib_names = strdup(get_lib_names());
+ unsigned n_libs = 1;
+ unsigned j;
+
+ for(i=0; lib_names[i]; ++i)
+ if(lib_names[i]==':')
+ ++n_libs;
+
+ gl_libs = (void **)malloc((n_libs+1)*sizeof(void *));
+ i = 0;
+ n_libs = 0;
+ for(j=0;; ++j)
{
- fprintf(stderr, "Could not open %s: %s\n", libgl_name, dlerror());
- abort();
+ if(lib_names[j]==':' || lib_names[j]==0)
+ {
+ int at_end = (lib_names[j]==0);
+ lib_names[j] = 0;
+
+ gl_libs[n_libs] = dlopen(lib_names+i, RTLD_NOW);
+ if(!gl_libs[n_libs])
+ {
+ fprintf(stderr, "Could not open %s: %s\n", lib_names+i, dlerror());
+ abort();
+ }
+
+ i = j+1;
+ ++n_libs;
+
+ if(at_end)
+ break;
+ }
}
+
+ gl_libs[n_libs] = 0;
+ free(lib_names);
}
- return dlsym(libgl, sym);
+ for(i=0; gl_libs[i]; ++i)
+ {
+ void *sym = dlsym(gl_libs[i], name);
+ if(sym)
+ return sym;
+ }
+
+ return NULL;
}
-static char *buffer = 0;
-static char *write_pos;
-static struct iovec *iovecs = 0;
-static struct iovec *cur_vec;
-static unsigned length;
+INTERNAL char *buffer = 0;
+INTERNAL char *write_pos;
+INTERNAL struct iovec *iovecs = 0;
+INTERNAL struct iovec *cur_vec;
+INTERNAL unsigned length;
-static inline void next_vec()
+INTERNAL inline void next_vec(void)
{
if(write_pos!=cur_vec->iov_base)
{
}
}
-static inline void write_bytes(const char *ptr, unsigned size)
+INTERNAL inline void write_bytes(const char *ptr, unsigned size)
{
unsigned i;
for(i=0; i<size; ++i)
*write_pos++ = *ptr++;
}
-static inline void write_char(char v)
+INTERNAL inline void write_char(char v)
{
*write_pos++ = v;
}
-static inline void write_short(short v)
+INTERNAL inline void write_short(short v)
{
write_bytes((char *)&v, sizeof(short));
}
-static inline void write_int(int v)
+INTERNAL inline void write_int(int v)
{
write_bytes((char *)&v, sizeof(int));
}
-static inline void write_long(long v)
+INTERNAL inline void write_long(long v)
{
write_bytes((char *)&v, sizeof(long));
}
-static inline void write_long_long(long long v)
+INTERNAL inline void write_long_long(long long v)
{
write_bytes((char *)&v, sizeof(long long));
}
-static inline void write_float(float v)
+INTERNAL inline void write_float(float v)
{
write_bytes((char *)&v, sizeof(float));
}
-static inline void write_double(double v)
+INTERNAL inline void write_double(double v)
{
write_bytes((char *)&v, sizeof(double));
}
-static inline void write_pointer(const void *p)
+INTERNAL inline void write_pointer(const void *p)
{
write_bytes((char *)&p, sizeof(void *));
}
-static inline void write_data(const void *data, unsigned size)
+INTERNAL inline void write_data(const void *data, unsigned size)
{
if(data)
{
write_int(0);
}
-static inline void write_string(const char *s)
+INTERNAL inline void write_string(const char *s)
{
write_data(s, strlen(s)+1);
}
-static inline void write_string_array(const char **sa, unsigned size)
+INTERNAL inline void write_string_array(const char **sa, unsigned size)
{
unsigned i;
size /= sizeof(const char *);
write_string(sa[i]);
}
-static inline void begin_packet(int func)
+INTERNAL inline void begin_packet(int func)
{
if(!buffer)
buffer = (char *)malloc(1024);
write_short(func);
}
-static inline void send_packet()
+INTERNAL inline void send_packet(void)
{
static int fd = -1;
if(fd<0)
write_int(length);
writev(fd, iovecs, cur_vec-iovecs);
}
-
-int in_begin_block = 0;
-GLenum cur_error = GL_NO_ERROR;
-
-static void check_error()
-{
- GLenum (*orig_glGetError)() = 0;
- GLenum code;
-
- if(in_begin_block)
- return;
-
- if(!orig_glGetError)
- orig_glGetError = glsym("glGetError");
-
- code = orig_glGetError();
- if(code!=GL_NO_ERROR)
- {
- begin_packet(FUNC_GLDERROR);
- write_int(code);
- send_packet();
-
- if(cur_error==GL_NO_ERROR)
- cur_error = code;
- }
-}
-
-void APIENTRY glBegin(GLenum mode)
-{
- static void (*orig)(GLenum);
- if(!orig)
- orig = glsym("glBegin");
- orig(mode);
-
- begin_packet(FUNC_GLBEGIN);
- write_int(mode);
- send_packet();
-
- in_begin_block = 1;
-}
-
-void APIENTRY glEnd()
-{
- static void (*orig)();
- if(!orig)
- orig = glsym("glEnd");
- orig();
-
- begin_packet(FUNC_GLEND);
- send_packet();
-
- in_begin_block = 0;
- check_error();
-}
-
-GLenum APIENTRY glGetError()
-{
- GLenum ret = GL_NO_ERROR;
-
- if(in_begin_block)
- {
- if(cur_error==GL_NO_ERROR)
- cur_error = GL_INVALID_OPERATION;
- }
- else
- {
- ret = cur_error;
- cur_error = GL_NO_ERROR;
- }
-
- begin_packet(FUNC_GLGETERROR);
- write_int(ret);
- send_packet();
-
- return ret;
-}
-
-void (*glXGetProcAddress(const GLubyte *procname))(void)
-{
- void *handle = 0;
- void (*ret)() = 0;
-
- if(glsym((const char *)procname))
- {
- handle = dlopen(NULL, RTLD_LAZY);
- ret = dlsym(handle, (const char *)procname);
- }
-
- begin_packet(FUNC_GLXGETPROCADDRESS);
- write_pointer(ret);
- write_string((const char *)procname);
- send_packet();
-
- return ret;
-}
-
-void (*glXGetProcAddressARB(const GLubyte *))(void) __attribute__((alias("glXGetProcAddress")));
-
-#include "glwrap.funcs"