fixed bug added support for Programiv
[libgliar] / src / gliar.c
1 /*
2 libgliar - a library that can fake the OpenGL context info returned by
3 the glGet OpenGL calls
4
5 Copyright (C) 2013 Canonical Ltd
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.    See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program.        If not, see <http://www.gnu.org/licenses/>.
19
20 Author: Eleni Maria Stea <elene.mst@gmail.com>
21 */
22
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <ctype.h>
27 #include <unistd.h>
28 #include <dlfcn.h>
29 #include <pwd.h>
30 #include <GL/gl.h>
31 #include "cfg.h"
32
33 #ifndef GL_NUM_SHADING_LANGUAGE_VERSIONS
34 #define GL_NUM_SHADING_LANGUAGE_VERSIONS        0x82E9
35 #endif
36
37 static int init_valid_extensions(void);
38
39 static int done_init;
40
41 static const GLubyte* (*gl_get_string)(GLenum);
42 static const GLubyte* (*gl_get_stringi)(GLenum, GLuint);
43 static void (*gl_get_integerv)(GLenum, GLint*);
44 static void (*gl_get_programiv)(GLuint, GLenum, GLint*);
45 static void *(*glx_get_proc_address)(const unsigned char*);
46
47 /*static const void* (*gl_get_booleanv)(GLenum, GLboolean*);
48 static const void* (*gl_get_doublev)(GLenum, GLdouble*);
49 static const void* (*gl_get_floatv)(GLenum, GLfloat*);
50 static const void* (*gl_get_integer64v)(GLenum, GLint64*);
51 static const void* (*gl_get_booleani_v)(GLenum, GLuint, GLboolean*);
52 static const void* (*gl_get_doublei_v)(GLenum, GLuint, GLdouble*);
53 static const void* (*gl_get_floati_v)(GLenum, GLuint, GLfloat*);
54 static const void* (*gl_get_integeri_v)(GLenum, GLuint, GLint*);
55 static const void* (*gl_get_integer64i_v)(GLenum, GLuint, GLint64*);*/
56
57 static struct cfgopt *cfglist;
58
59 static int init(void)
60 {
61         if(done_init) {
62                 return 0;
63         }
64
65         gl_get_string = dlsym(RTLD_NEXT, "glGetString");
66         gl_get_stringi = dlsym(RTLD_NEXT, "glGetStringi");
67         gl_get_integerv = dlsym(RTLD_NEXT, "glGetIntegerv");
68         gl_get_programiv = dlsym(RTLD_NEXT, "glGetProgramivARB");
69         glx_get_proc_address = dlsym(RTLD_NEXT, "glXGetProcAddress");
70
71         if(init_valid_extensions() == -1) {
72                 fprintf(stderr, "GLIAR: failed to initialize the valid extension list, might end up with unavailable extensions!\n");
73         }
74
75         if(!(cfglist = gliar_load_cfg("gliar.conf"))) {
76                 struct passwd *pw;
77                 char *homedir, *path;
78
79                 if((pw = getpwuid(getuid()))) {
80                         homedir = pw->pw_dir;
81                 } else {
82                         homedir = getenv("HOME");
83                 }
84
85                 if(homedir) {
86                         path = alloca(strlen(homedir) + strlen(".gliar.conf") + 2);
87                         sprintf(path, "%s/.gliar.conf", homedir);
88
89                         cfglist = gliar_load_cfg(path);
90                 }
91         }
92
93         done_init = 1;
94         return 0;
95 }
96
97 static int init_valid_extensions(void)
98 {
99         int i, num_ext, prev_space = 0;
100         const char *gl_ext_str;
101         char *ext_str, *tok, *ptr, **ext_table;
102
103         /* initialize the list of valid extensions */
104         if(!(gl_ext_str = (const char*)gl_get_string(GL_EXTENSIONS))) {
105                 return -1;
106         }
107
108         if(!(ext_str = malloc(strlen(gl_ext_str) + 1))) {
109                 return -1;
110         }
111         strcpy(ext_str, gl_ext_str);
112
113         /* count the extensions */
114         num_ext = 0;
115         ptr = ext_str;
116         while(*ptr) {
117                 if(isspace(*ptr) && prev_space == 0) {
118                         prev_space = 1;
119                         num_ext++;
120                 } else {
121                         prev_space = 0;
122                 }
123                 ptr++;
124         }
125
126         /* allocate extension table */
127         if(!(ext_table = malloc(num_ext * sizeof *ext_table))) {
128                 free(ext_str);
129                 return -1;
130         }
131
132         /* setup the ext_table slots to point to the start of each substring (extension) */
133         for(i=0; i<num_ext; i++) {
134                 if(!(tok = strtok(i == 0 ? ext_str : 0, " \t\v\n\r"))) {
135                         fprintf(stderr, "DEBUG: strtok returned 0 at token %d\n", i);
136                         num_ext = i;
137                 }
138                 ext_table[i] = tok;
139         }
140
141         gliar_value_set("extensions", ext_table, num_ext);
142
143         free(ext_table);
144         free(ext_str);
145         return 0;
146 }
147
148 const GLubyte *glGetString(GLenum name)
149 {
150         const char *key;
151         const struct cfgopt *option;
152
153         init();
154
155         if(!gl_get_string) {
156                 fprintf(stderr, "Unable to fake the %s function. It is not supported by your OpenGL implementation.\n", __func__);
157                 return 0;
158         }
159
160         switch(name) {
161         case GL_VENDOR:
162                 key = "vendor";
163                 break;
164
165         case GL_VERSION:
166                 key = "version";
167                 break;
168
169         case GL_EXTENSIONS:
170                 key = "extensions";
171                 break;
172
173         case GL_RENDERER:
174                 key = "renderer";
175                 break;
176
177         case GL_SHADING_LANGUAGE_VERSION:
178                 key = "sl version";
179                 break;
180
181         default:
182                 key = 0;
183         }
184
185         if(key && (option = gliar_find_opt(cfglist, key))) {
186                 return (const GLubyte*)option->conc_vals;
187         }
188
189         return gl_get_string(name);
190 }
191
192 const GLubyte *glGetStringi(GLenum name, GLuint index)
193 {
194         char *key;
195         const struct cfgopt *option;
196
197         init();
198
199         if(!gl_get_stringi) {
200                 fprintf(stderr, "Unable to fake the %s function. It is not supported by your OpenGL implementation.\n", __func__);
201                 return 0;
202         }
203
204         switch(name) {
205         case GL_EXTENSIONS:
206                 key = "extensions";
207                 break;
208
209         case GL_SHADING_LANGUAGE_VERSION:
210                 key = "sl version";
211                 break;
212
213         default:
214                 key = 0;
215         }
216
217         if(key && (option = gliar_find_opt(cfglist, key))) {
218                 return (const GLubyte*)option->str_val[index];
219         }
220
221         return gl_get_stringi(name, index);
222 }
223
224 void glGetIntegerv(GLenum name, GLint *val)
225 {
226         char *key;
227         const struct cfgopt *option;
228
229         init();
230
231         if(!gl_get_integerv) {
232                 fprintf(stderr, "Unable to fake the %s function. It is not supported by your OpenGL implementation.\n", __func__);
233                 return;
234         }
235
236         switch(name) {
237         case GL_NUM_EXTENSIONS:
238                 if(1) {
239                         key = "extensions";
240                 } else {
241         case GL_NUM_SHADING_LANGUAGE_VERSIONS:
242                         key = "sl version";
243                 }
244                 if(key && (option = gliar_find_opt(cfglist, key))) {
245                         *val = option->str_count;
246                         return;
247                 }
248                 break;
249
250         case GL_MAJOR_VERSION:
251                 key = "major version";
252                 break;
253
254         case GL_MINOR_VERSION:
255                 key = "minor version";
256                 break;
257
258         case GL_MAX_TEXTURE_UNITS:
259                 key = "max texture units";
260                 break;
261
262         case GL_MAX_TEXTURE_IMAGE_UNITS:
263                 key = "max texture image units";
264                 break;
265
266         case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
267                 key = "max combined texture image units";
268                 break;
269
270         case GL_MAX_TEXTURE_SIZE:
271                 key = "max texture size";
272                 break;
273
274         case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
275                 key = "max cube map texture size";
276                 break;
277
278         case GL_MAX_TEXTURE_COORDS:
279                 key = "max texture coordinates";
280                 break;
281
282         case GL_MAX_VERTEX_ATTRIBS:
283                 key = "max vertex attributes";
284                 break;
285
286         case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
287                 key = "max vertex texture image units";
288                 break;
289
290         case GL_MAX_VERTEX_UNIFORM_VECTORS:
291                 key = "max vertex uniform vectors";
292                 break;
293
294         case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
295                 key = "max fragment uniform vectors";
296                 break;
297
298         case GL_MAX_VARYING_VECTORS:
299                 key = "max varying vectors";
300                 break;
301
302         case GL_MAX_COLOR_ATTACHMENTS_EXT:
303                 key = "max color attachments";
304                 break;
305
306         case GL_MAX_RENDERBUFFER_SIZE_EXT:
307                 key = "max renderbuffer size ext";
308                 break;
309
310         default:
311                 key = 0;
312         }
313
314         if(key && (option = gliar_find_opt(cfglist, key)) && option->type == GLIAR_NUMBER) {
315                 *val = option->num_val;
316                 return;
317         }
318
319         gl_get_integerv(name, val);
320 }
321
322 void glGetProgramivARB(GLuint program, GLenum pname, GLint *params)
323 {
324         char *key;
325         const struct cfgopt *option;
326
327         init();
328
329         if(!gl_get_programiv) {
330                 fprintf(stderr, "GLIAR: Unable to fake the %s function. It is not supported by your OpenGL implementation.\n", __func__);
331                 return;
332         }
333
334         switch(pname) {
335         case GL_MAX_PROGRAM_INSTRUCTIONS_ARB:
336                 key = "max program instructions arb";
337                 break;
338
339         case GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB:
340                 key = "max program native instructions arb";
341                 break;
342
343         case GL_MAX_PROGRAM_TEMPORARIES_ARB:
344                 key = "max program temporaries arb";
345                 break;
346
347         case GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB:
348                 key = "max program native temporaries arb";
349                 break;
350
351         case GL_MAX_PROGRAM_PARAMETERS_ARB:
352                 key = "max program parameters arb";
353                 break;
354
355         case GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB:
356                 key = "max program native parameters arb";
357                 break;
358
359         case GL_MAX_PROGRAM_ATTRIBS_ARB:
360                 key = "max program attribs arb";
361                 break;
362
363         case GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB:
364                 key = "max program native attribs arb";
365                 break;
366
367         case GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB:
368                 key = "max program address registers arb";
369                 break;
370
371         case GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB:
372                 key = "max program native address registers arb";
373                 break;
374
375         case GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB:
376                 key = "max program local parameters arb";
377                 break;
378
379         case GL_MAX_PROGRAM_ENV_PARAMETERS_ARB:
380                 key = "max program env parameters arb";
381                 break;
382
383         case GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB:
384                 key = "max program alu instructions arb";
385                 break;
386
387         case GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB:
388                 key = "max program native alu instructions arb";
389                 break;
390
391         case GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB:
392                 key = "max program tex instructions arb";
393                 break;
394
395         case GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB:
396                 key = "max program native tex instructions arb";
397                 break;
398
399         default:
400                 key = 0;
401         }
402
403         if(key) {
404                 char buf[256];
405                 if(program == GL_VERTEX_PROGRAM_ARB) {
406                         sprintf(buf, "v %s", key);
407                 }
408                 else if(program == GL_FRAGMENT_PROGRAM_ARB) {
409                         sprintf(buf, "f %s", key);
410                 }
411                 key = buf;
412
413                 if((option = gliar_find_opt(cfglist, key)) && option->type == GLIAR_NUMBER) {
414                         *params = option->num_val;
415                         return;
416                 }
417         }
418
419         gl_get_programiv(program, pname, params);
420
421 }
422
423 void *glXGetProcAddress(const unsigned char *procname)
424 {
425         init();
426
427         if(!strcmp((char*)procname, "glGetProgramivARB") || !strcmp((char*)procname, "glGetProgramiv")) {
428                 return glGetProgramivARB;
429         }
430
431         return glx_get_proc_address(procname);
432 }
433
434 void *glXGetProcAddressARB(const unsigned char *procname)
435 {
436         return glXGetProcAddress(procname);
437 }