e83d5cd3ae0391a2213dc8b7686372f145bbe286
[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
46 /*static const void* (*gl_get_booleanv)(GLenum, GLboolean*);
47 static const void* (*gl_get_doublev)(GLenum, GLdouble*);
48 static const void* (*gl_get_floatv)(GLenum, GLfloat*);
49 static const void* (*gl_get_integer64v)(GLenum, GLint64*);
50 static const void* (*gl_get_booleani_v)(GLenum, GLuint, GLboolean*);
51 static const void* (*gl_get_doublei_v)(GLenum, GLuint, GLdouble*);
52 static const void* (*gl_get_floati_v)(GLenum, GLuint, GLfloat*);
53 static const void* (*gl_get_integeri_v)(GLenum, GLuint, GLint*);
54 static const void* (*gl_get_integer64i_v)(GLenum, GLuint, GLint64*);*/
55
56 static struct cfgopt *cfglist;
57
58 static int init(void)
59 {
60         if(done_init) {
61                 return 0;
62         }
63
64         gl_get_string = dlsym(RTLD_NEXT, "glGetString");
65         gl_get_stringi = dlsym(RTLD_NEXT, "glGetStringi");
66         gl_get_integerv = dlsym(RTLD_NEXT, "glGetIntegerv");
67         gl_get_programiv = dlsym(RTLD_NEXT, "glGetProgramivARB");
68
69         if(init_valid_extensions() == -1) {
70                 fprintf(stderr, "GLIAR: failed to initialize the valid extension list, might end up with unavailable extensions!\n");
71         }
72
73         if(!(cfglist = gliar_load_cfg("gliar.conf"))) {
74                 struct passwd *pw;
75                 char *homedir, *path;
76
77                 if((pw = getpwuid(getuid()))) {
78                         homedir = pw->pw_dir;
79                 } else {
80                         homedir = getenv("HOME");
81                 }
82
83                 if(homedir) {
84                         path = alloca(strlen(homedir) + strlen(".gliar.conf") + 2);
85                         sprintf(path, "%s/.gliar.conf", homedir);
86
87                         cfglist = gliar_load_cfg(path);
88                 }
89         }
90
91         done_init = 1;
92         return 0;
93 }
94
95 static int init_valid_extensions(void)
96 {
97         int i, num_ext, prev_space = 0;
98         const char *gl_ext_str;
99         char *ext_str, *tok, *ptr, **ext_table;
100
101         /* initialize the list of valid extensions */
102         if(!(gl_ext_str = (const char*)gl_get_string(GL_EXTENSIONS))) {
103                 return -1;
104         }
105
106         if(!(ext_str = malloc(strlen(gl_ext_str) + 1))) {
107                 return -1;
108         }
109         strcpy(ext_str, gl_ext_str);
110
111         /* count the extensions */
112         num_ext = 0;
113         ptr = ext_str;
114         while(*ptr) {
115                 if(isspace(*ptr) && prev_space == 0) {
116                         prev_space = 1;
117                         num_ext++;
118                 } else {
119                         prev_space = 0;
120                 }
121                 ptr++;
122         }
123
124         /* allocate extension table */
125         if(!(ext_table = malloc(num_ext * sizeof *ext_table))) {
126                 free(ext_str);
127                 return -1;
128         }
129
130         /* setup the ext_table slots to point to the start of each substring (extension) */
131         for(i=0; i<num_ext; i++) {
132                 if(!(tok = strtok(i == 0 ? ext_str : 0, " \t\v\n\r"))) {
133                         fprintf(stderr, "DEBUG: strtok returned 0 at token %d\n", i);
134                         num_ext = i;
135                 }
136                 ext_table[i] = tok;
137         }
138
139         gliar_value_set("extensions", ext_table, num_ext);
140
141         free(ext_table);
142         free(ext_str);
143         return 0;
144 }
145
146 const GLubyte *glGetString(GLenum name)
147 {
148         const char *key;
149         const struct cfgopt *option;
150
151         init();
152
153         if(!gl_get_string) {
154                 fprintf(stderr, "Unable to fake the %s function. It is not supported by your OpenGL implementation.\n", __func__);
155                 return 0;
156         }
157
158         switch(name) {
159         case GL_VENDOR:
160                 key = "vendor";
161                 break;
162
163         case GL_VERSION:
164                 key = "version";
165                 break;
166
167         case GL_EXTENSIONS:
168                 key = "extensions";
169                 break;
170
171         case GL_RENDERER:
172                 key = "renderer";
173                 break;
174
175         case GL_SHADING_LANGUAGE_VERSION:
176                 key = "sl version";
177                 break;
178
179         default:
180                 key = 0;
181         }
182
183         if(key && (option = gliar_find_opt(cfglist, key))) {
184                 return (const GLubyte*)option->conc_vals;
185         }
186
187         return gl_get_string(name);
188 }
189
190 const GLubyte *glGetStringi(GLenum name, GLuint index)
191 {
192         char *key;
193         const struct cfgopt *option;
194
195         init();
196
197         if(!gl_get_stringi) {
198                 fprintf(stderr, "Unable to fake the %s function. It is not supported by your OpenGL implementation.\n", __func__);
199                 return 0;
200         }
201
202         switch(name) {
203         case GL_EXTENSIONS:
204                 key = "extensions";
205                 break;
206
207         case GL_SHADING_LANGUAGE_VERSION:
208                 key = "sl version";
209                 break;
210
211         default:
212                 key = 0;
213         }
214
215         if(key && (option = gliar_find_opt(cfglist, key))) {
216                 return (const GLubyte*)option->str_val[index];
217         }
218
219         return gl_get_stringi(name, index);
220 }
221
222 void glGetIntegerv(GLenum name, GLint *val)
223 {
224         char *key;
225         const struct cfgopt *option;
226
227         init();
228
229         if(!gl_get_integerv) {
230                 fprintf(stderr, "Unable to fake the %s function. It is not supported by your OpenGL implementation.\n", __func__);
231                 return;
232         }
233
234         switch(name) {
235         case GL_NUM_EXTENSIONS:
236                 if(1) {
237                         key = "extensions";
238                 } else {
239         case GL_NUM_SHADING_LANGUAGE_VERSIONS:
240                         key = "sl version";
241                 }
242                 if(key && (option = gliar_find_opt(cfglist, key))) {
243                         *val = option->str_count;
244                         return;
245                 }
246                 break;
247
248         case GL_MAJOR_VERSION:
249                 key = "major version";
250                 break;
251
252         case GL_MINOR_VERSION:
253                 key = "minor version";
254                 break;
255
256         case GL_MAX_TEXTURE_UNITS:
257                 key = "max texture units";
258                 break;
259
260         case GL_MAX_TEXTURE_IMAGE_UNITS:
261                 key = "max texture image units";
262                 break;
263
264         case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
265                 key = "max combined texture image units";
266                 break;
267
268         case GL_MAX_TEXTURE_SIZE:
269                 key = "max texture size";
270                 break;
271
272         case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
273                 key = "max cube map texture size";
274                 break;
275
276         case GL_MAX_TEXTURE_COORDS:
277                 key = "max texture coordinates";
278                 break;
279
280         case GL_MAX_VERTEX_ATTRIBS:
281                 key = "max vertex attributes";
282                 break;
283
284         case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
285                 key = "max vertex texture image units";
286                 break;
287
288         case GL_MAX_VERTEX_UNIFORM_VECTORS:
289                 key = "max vertex uniform vectors";
290                 break;
291
292         case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
293                 key = "max fragment uniform vectors";
294                 break;
295
296         case GL_MAX_VARYING_VECTORS:
297                 key = "max varying vectors";
298                 break;
299
300         case GL_MAX_COLOR_ATTACHMENTS_EXT:
301                 key = "max color attachments";
302                 break;
303
304         case GL_MAX_RENDERBUFFER_SIZE_EXT:
305                 key = "max renderbuffer size ext";
306                 break;
307
308         default:
309                 key = 0;
310         }
311
312         if(key && (option = gliar_find_opt(cfglist, key)) && option->type == GLIAR_NUMBER) {
313                 *val = option->num_val;
314                 return;
315         }
316
317         gl_get_integerv(name, val);
318 }
319
320 void glGetProgramivARB(GLuint program, GLenum pname, GLint *params)
321 {
322         char *key;
323         const struct cfgopt *option;
324
325         init();
326
327         if(!gl_get_programiv) {
328                 fprintf(stderr, "Unable to fake the %s function. It is not supported by your OpenGL implementation.\n", __func__);
329                 return;
330         }
331
332         switch(pname) {
333         case GL_MAX_PROGRAM_INSTRUCTIONS_ARB:
334                 key = "max program instructions arb";
335                 break;
336
337         case GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB:
338                 key = "max program native instructions arb";
339                 break;
340
341         case GL_MAX_PROGRAM_TEMPORARIES_ARB:
342                 key = "max program temporaries arb";
343                 break;
344
345         case GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB:
346                 key = "max program native temporaries arb";
347                 break;
348
349         case GL_MAX_PROGRAM_PARAMETERS_ARB:
350                 key = "max program parameters arb";
351                 break;
352
353         case GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB:
354                 key = "max program native parameters arb";
355                 break;
356
357         case GL_MAX_PROGRAM_ATTRIBS_ARB:
358                 key = "max program attribs arb";
359                 break;
360
361         case GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB:
362                 key = "max program native attribs arb";
363                 break;
364
365         case GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB:
366                 key = "max program address registers arb";
367                 break;
368
369         case GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB:
370                 key = "max program native address registers arb";
371                 break;
372
373         case GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB:
374                 key = "max program local parameters arb";
375                 break;
376
377         case GL_MAX_PROGRAM_ENV_PARAMETERS_ARB:
378                 key = "max program env parameters arb";
379                 break;
380
381         case GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB:
382                 key = "max program alu instructions arb";
383                 break;
384
385         case GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB:
386                 key = "max program native alu instructions arb";
387                 break;
388
389         case GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB:
390                 key = "max program tex instructions arb";
391                 break;
392
393         case GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB:
394                 key = "max program native tex instructions arb";
395                 break;
396
397         default:
398                 key = 0;
399         }
400
401         if(key && (option = gliar_find_opt(cfglist, key)) && option->type == GLIAR_NUMBER) {
402                 *params = option->num_val;
403                 return;
404         }
405
406         gl_get_programiv(program, pname, params);
407
408 }