]> git.tdb.fi Git - gldbg.git/blob - source/glwrap.c
Don't call glGetError between glBegin and glEnd
[gldbg.git] / source / glwrap.c
1 /* $Id$
2
3 This file is part of gldbg
4 Copyright © 2009  Mikko Rasa, Mikkosoft Productions
5 Distributed under the GPL
6 */
7
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <dlfcn.h>
12 #include <sys/uio.h>
13 #include <X11/Xlib.h>
14 #include <GL/gl.h>
15 #include <GL/glx.h>
16 #include "arraysize.h"
17 #include "functions.h"
18
19 static inline void *glsym(const char *sym)
20 {
21         static void *libgl = NULL;
22         if(!libgl)
23         {
24                 const char *libgl_name = getenv("GLWRAP_LIBGL");
25                 if(!libgl_name)
26                         libgl_name = "libGL.so";
27                 libgl = dlopen(libgl_name, RTLD_NOW);
28                 if(!libgl)
29                 {
30                         fprintf(stderr, "Could not open %s: %s\n", libgl_name, dlerror());
31                         abort();
32                 }
33         }
34
35         return dlsym(libgl, sym);
36 }
37
38 static char *buffer = 0;
39 static char *write_pos;
40 static struct iovec *iovecs = 0;
41 static struct iovec *cur_vec;
42 static unsigned length;
43
44 static inline void next_vec()
45 {
46         if(write_pos!=cur_vec->iov_base)
47         {
48                 cur_vec->iov_len = write_pos-(char *)cur_vec->iov_base;
49                 length += cur_vec->iov_len;
50                 ++cur_vec;
51                 cur_vec->iov_base = write_pos;
52         }
53 }
54
55 static inline void write_bytes(const char *ptr, unsigned size)
56 {
57         unsigned i;
58         for(i=0; i<size; ++i)
59                 *write_pos++ = *ptr++;
60 }
61
62 static inline void write_char(char v)
63 {
64         *write_pos++ = v;
65 }
66
67 static inline void write_short(short v)
68 {
69         write_bytes((char *)&v, sizeof(short));
70 }
71
72 static inline void write_int(int v)
73 {
74         write_bytes((char *)&v, sizeof(int));
75 }
76
77 static inline void write_long(long v)
78 {
79         write_bytes((char *)&v, sizeof(long));
80 }
81
82 static inline void write_long_long(long long v)
83 {
84         write_bytes((char *)&v, sizeof(long long));
85 }
86
87 static inline void write_float(float v)
88 {
89         write_bytes((char *)&v, sizeof(float));
90 }
91
92 static inline void write_double(double v)
93 {
94         write_bytes((char *)&v, sizeof(double));
95 }
96
97 static inline void write_pointer(const void *p)
98 {
99         write_bytes((char *)&p, sizeof(void *));
100 }
101
102 static inline void write_data(const void *data, unsigned size)
103 {
104         if(data)
105         {
106                 write_int(size);
107                 next_vec();
108                 cur_vec->iov_base = (void *)data;
109                 cur_vec->iov_len = size;
110                 length += size;
111                 ++cur_vec;
112                 cur_vec->iov_base = write_pos;
113         }
114         else
115                 write_int(0);
116 }
117
118 static inline void write_string(const char *s)
119 {
120         write_data(s, strlen(s)+1);
121 }
122
123 static inline void write_string_array(const char **sa, unsigned size)
124 {
125         unsigned i;
126         size /= sizeof(const char *);
127         write_int(size);
128         for(i=0; i<size; ++i)
129                 write_string(sa[i]);
130 }
131
132 static inline void begin_packet(int func)
133 {
134         if(!buffer)
135                 buffer = (char *)malloc(1024);
136         if(!iovecs)
137                 iovecs = (struct iovec *)malloc(16*sizeof(struct iovec));
138         write_pos = buffer;
139         cur_vec = iovecs;
140         cur_vec->iov_base = write_pos;
141         length = 0;
142         write_int(0);
143         write_short(func);
144 }
145
146 static inline void send_packet()
147 {
148         static int fd = -1;
149         if(fd<0)
150         {
151                 const char *var = getenv("GLWRAP_FD");
152                 if(var)
153                         fd = strtol(var, NULL, 0);
154                 else
155                         fd = 2;
156         }
157         next_vec();
158         write_pos = buffer;
159         write_int(length);
160         writev(fd, iovecs, cur_vec-iovecs);
161 }
162
163 int in_begin_block = 0;
164 GLenum cur_error = GL_NO_ERROR;
165
166 static void check_error()
167 {
168         GLenum (*orig_glGetError)() = 0;
169         GLenum code;
170
171         if(in_begin_block)
172                 return;
173
174         if(!orig_glGetError)
175                 orig_glGetError = glsym("glGetError");
176
177         code = orig_glGetError();
178         if(code!=GL_NO_ERROR)
179         {
180                 begin_packet(FUNC_GLDERROR);
181                 write_int(code);
182                 send_packet();
183
184                 if(cur_error==GL_NO_ERROR)
185                         cur_error = code;
186         }
187 }
188
189 void APIENTRY glBegin(GLenum mode)
190 {
191         static void (*orig)(GLenum);
192         if(!orig)
193                 orig = glsym("glBegin");
194         orig(mode);
195
196         begin_packet(FUNC_GLBEGIN);
197         write_int(mode);
198         send_packet();
199
200         in_begin_block = 1;
201 }
202
203 void APIENTRY glEnd()
204 {
205         static void (*orig)();
206         if(!orig)
207                 orig = glsym("glEnd");
208         orig();
209
210         begin_packet(FUNC_GLEND);
211         send_packet();
212
213         in_begin_block = 0;
214         check_error();
215 }
216
217 GLenum APIENTRY glGetError()
218 {
219         GLenum ret = GL_NO_ERROR;
220
221         if(in_begin_block)
222         {
223                 if(cur_error==GL_NO_ERROR)
224                         cur_error = GL_INVALID_OPERATION;
225         }
226         else
227         {
228                 ret = cur_error;
229                 cur_error = GL_NO_ERROR;
230         }
231
232         begin_packet(FUNC_GLGETERROR);
233         write_int(ret);
234         send_packet();
235
236         return ret;
237 }
238
239 void (*glXGetProcAddress(const GLubyte *procname))(void)
240 {
241         void *handle = 0;
242         void (*ret)() = 0;
243
244         if(glsym((const char *)procname))
245         {
246                 handle = dlopen(NULL, RTLD_LAZY);
247                 ret = dlsym(handle, (const char *)procname);
248         }
249
250         begin_packet(FUNC_GLXGETPROCADDRESS);
251         write_pointer(ret);
252         write_string((const char *)procname);
253         send_packet();
254
255         return ret;
256 }
257
258 void (*glXGetProcAddressARB(const GLubyte *))(void) __attribute__((alias("glXGetProcAddress")));
259
260 #include "glwrap.funcs"