]> git.cworth.org Git - glenv/blob - glwrap.c
Implement all the extension-related options of glenv
[glenv] / glwrap.c
1 /* Copyright © 2013, Intel Corporation
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to deal
5  * in the Software without restriction, including without limitation the rights
6  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7  * copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19  * THE SOFTWARE.
20  */
21
22 #define GL_GLEXT_PROTOTYPES
23 #include <GL/gl.h>
24
25 #include <glaze.h>
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 typedef GLubyte * (get_string_type_t) (GLenum);
32
33 static char *glenv_gl_extensions;
34 static char **glenv_gl_extensions_array;
35 static unsigned int glenv_num_gl_extensions;
36
37 static char *
38 xstrdup (const char *str)
39 {
40         char *ret;
41
42         ret = strdup (str);
43         if (ret == NULL) {
44                 fprintf (stderr, "Out of memory.\n");
45                 exit (1);
46         }
47
48         return ret;
49 }
50
51 static int
52 extension_list_count (const char *list)
53 {
54         int count = 0;
55
56         if (list == NULL)
57                 return 0;
58
59         while (list && *list) {
60                 /* Skip consecutive spaces before and between extensions */
61                 while (*list == ' ')
62                         list++;
63                 if (*list)
64                         count++;
65                 /* Skip to next space */
66                 list = strchr (list, ' ');
67         }
68
69         return count;
70 }
71
72 static void
73 extension_list_append (char **list, const char *extension)
74 {
75         char *new_list;
76
77         /* Nothing to do if extension is empty. */
78         if (extension == NULL || strlen (extension) == 0)
79                 return;
80
81         /* If initial list is empty, just copy extension */
82         if (*list == NULL) {
83                 *list = xstrdup (extension);
84                 return;
85         }
86
87         /* Append one space, then extension onto current list. */
88         new_list = malloc (strlen (*list) + 1 + strlen (extension) + 1);
89         if (new_list == NULL) {
90                 fprintf (stderr, "Out of memory.\n");
91                 exit (1);
92         }
93
94         strcpy (new_list, *list);
95         strcat (new_list, " ");
96         strcat (new_list, extension);
97
98         free (*list);
99         *list = new_list;
100 }
101
102 static int
103 extension_list_contains (const char *list, const char *extension)
104 {
105         const char *match;
106         int length = strlen (extension);
107
108         while (1) {
109                 match = strstr (list, extension);
110                 if (match == NULL)
111                         return 0;
112                 if (match[length] == ' ' || match[length] == '\0')
113                         return 1;
114                 list = match + length;
115         }
116
117         return 0;
118 }
119
120 /* When the first GL call is made, (that is, after the OpenGL context
121  * has been initialized with glX or some other system), then we can
122  * finally implement the "glenv --query" option if it was specified.
123  *
124  * Similarly, at this point, we can read the original extensions
125  * string from the OpenGL environment and modify it according to the
126  * blacklist or whitelist that the user may have specified.
127  */
128 void glenv_first_gl_call (void);
129
130 void
131 glenv_first_gl_call (void)
132 {
133         get_string_type_t *get_string = glaze_lookup ("glGetString");
134         char *orig_extensions;
135         const char *extension;
136
137         orig_extensions = xstrdup ((char *) get_string (GL_EXTENSIONS));
138
139         if (getenv ("GLENV_GL_EXTENSIONS"))
140         {
141                 glenv_gl_extensions = getenv ("GLENV_GL_EXTENSIONS");
142         }
143         else if (getenv ("GLENV_GL_EXTENSIONS_BLACKLIST"))
144         {
145                 const char *blacklist = getenv ("GLENV_GL_EXTENSIONS_BLACKLIST");
146
147                 for (extension = strtok (orig_extensions, " ");
148                      extension;
149                      extension = strtok (NULL, " "))
150                 {
151                         if (! extension_list_contains (blacklist, extension))
152                                 extension_list_append (&glenv_gl_extensions, extension);
153                 }
154         }
155         else if (getenv ("GLENV_GL_EXTENSIONS_WHITELIST"))
156         {
157                 const char *whitelist = getenv ("GLENV_GL_EXTENSIONS_WHITELIST");
158
159                 for (extension = strtok (orig_extensions, " ");
160                      extension;
161                      extension = strtok (NULL, " "))
162                 {
163                         if (extension_list_contains (whitelist, extension))
164                                 extension_list_append (&glenv_gl_extensions, extension);
165                 }
166         }
167
168         free (orig_extensions);
169
170         if (glenv_gl_extensions) {
171                 int i;
172                 char *extensions_copy;
173
174                 glenv_num_gl_extensions = extension_list_count (glenv_gl_extensions);
175
176                 glenv_gl_extensions_array = malloc (sizeof (char *) * glenv_num_gl_extensions);
177
178                 extensions_copy = xstrdup (glenv_gl_extensions);
179
180                 for (i = 0, extension = strtok (extensions_copy, " ");
181                      extension;
182                      i++, extension = strtok (NULL, " "))
183                 {
184                         glenv_gl_extensions_array[i] = xstrdup (extension);
185                 }
186
187                 free (extensions_copy);
188         }
189
190         /* We deliberately call glGetString directly here rather than
191          * use the get_string function pointer to the underlying
192          * glGetString function. That's because we want --query to
193          * reflect any modifications the user made with other
194          * options. */
195         if (getenv ("GLENV_QUERY")) {
196                 printf ("--vendor=\"%s\"\n", glGetString (GL_VENDOR));
197                 printf ("--renderer=\"%s\"\n", glGetString (GL_RENDERER));
198                 printf ("--version=\"%s\"\n", glGetString (GL_VERSION));
199                 printf ("--shading-language-version=\"%s\"\n", glGetString (GL_SHADING_LANGUAGE_VERSION));
200                 printf ("--extensions=\"%s\"\n", glGetString (GL_EXTENSIONS));
201
202                 exit (0);
203         }
204 }
205
206 static int
207 glenv_major_version (void)
208 {
209         const char *version = getenv ("GLENV_GL_VERSION");
210         if (version == NULL)
211                 return 0;
212
213         return atoi (version);
214 }
215
216 static int
217 glenv_minor_version (void)
218 {
219         const char *version = getenv ("GLENV_GL_VERSION");
220         const char *decimal;
221
222         if (version == NULL)
223                 return 0;
224
225         decimal = strchr (version, '.');
226
227         if (decimal == NULL)
228                 return 0;
229
230         return atoi (decimal + 1);
231 }
232
233 void
234 glGetDoublev (GLenum pname, GLdouble *params)
235 {
236         switch (pname) {
237         case GL_NUM_EXTENSIONS:
238                 if (glenv_gl_extensions) {
239                         *params = glenv_num_gl_extensions;
240                         return;
241                 }
242                 break;
243         case GL_MAJOR_VERSION:
244                 if (getenv ("GLENV_GL_VERSION")) {
245                         *params = glenv_major_version();
246                         return;
247                 }
248                 break;
249         case GL_MINOR_VERSION:
250                 if (getenv ("GLENV_GL_VERSION")) {
251                         *params = glenv_minor_version();
252                         return;
253                 }
254                 break;
255         }
256
257         GLAZE_DEFER (glGetDoublev, pname, params);
258 }
259
260 void
261 glGetFloatv (GLenum pname, GLfloat *params)
262 {
263         switch (pname) {
264         case GL_NUM_EXTENSIONS:
265                 if (glenv_gl_extensions) {
266                         *params = glenv_num_gl_extensions;
267                         return;
268                 }
269                 break;
270         case GL_MAJOR_VERSION:
271                 if (getenv ("GLENV_GL_VERSION")) {
272                         *params = glenv_major_version();
273                         return;
274                 }
275                 break;
276         case GL_MINOR_VERSION:
277                 if (getenv ("GLENV_GL_VERSION")) {
278                         *params = glenv_minor_version();
279                         return;
280                 }
281                 break;
282         }
283
284         GLAZE_DEFER (glGetFloatv, pname, params);
285 }
286
287 void
288 glGetIntegerv (GLenum pname, GLint *params)
289 {
290         switch (pname) {
291         case GL_NUM_EXTENSIONS:
292                 if (glenv_gl_extensions) {
293                         *params = glenv_num_gl_extensions;
294                         return;
295                 }
296                 break;
297         case GL_MAJOR_VERSION:
298                 if (getenv ("GLENV_GL_VERSION")) {
299                         *params = glenv_major_version();
300                         return;
301                 }
302                 break;
303         case GL_MINOR_VERSION:
304                 if (getenv ("GLENV_GL_VERSION")) {
305                         *params = glenv_minor_version();
306                         return;
307                 }
308                 break;
309         }
310
311         GLAZE_DEFER (glGetIntegerv, pname, params);
312 }
313
314 void
315 glGetInteger64v (GLenum pname, GLint64 * params)
316 {
317         switch (pname) {
318         case GL_NUM_EXTENSIONS:
319                 if (glenv_gl_extensions) {
320                         *params = glenv_num_gl_extensions;
321                         return;
322                 }
323                 break;
324         case GL_MAJOR_VERSION:
325                 if (getenv ("GLENV_GL_VERSION")) {
326                         *params = glenv_major_version();
327                         return;
328                 }
329                 break;
330         case GL_MINOR_VERSION:
331                 if (getenv ("GLENV_GL_VERSION")) {
332                         *params = glenv_minor_version();
333                         return;
334                 }
335                 break;
336         }
337
338         GLAZE_DEFER (glGetInteger64v, pname, params);
339 }
340
341 const GLubyte *
342 glGetString (GLenum name)
343 {
344         const GLubyte *ret;
345
346         switch (name) {
347         case GL_VENDOR:
348                 ret = (GLubyte *) getenv ("GLENV_GL_VENDOR");
349                 if (ret)
350                         return ret;
351                 break;
352         case GL_RENDERER:
353                 ret = (GLubyte *) getenv ("GLENV_GL_RENDERER");
354                 if (ret)
355                         return ret;
356                 break;
357         case GL_VERSION:
358                 ret = (GLubyte *) getenv ("GLENV_GL_VERSION");
359                 if (ret)
360                         return ret;
361                 break;
362         case GL_SHADING_LANGUAGE_VERSION:
363                 ret = (GLubyte *) getenv ("GLENV_GL_SHADING_LANGUAGE_VERSION");
364                 if (ret)
365                         return ret;
366                 break;
367         case GL_EXTENSIONS:
368                 if (glenv_gl_extensions)
369                         return (GLubyte *) glenv_gl_extensions;
370                 break;
371         }
372
373         GLAZE_DEFER_WITH_RETURN (ret, glGetString, name);
374
375         return ret;
376 }
377
378 const GLubyte *
379 glGetStringi (GLenum name, GLuint index)
380 {
381         const GLubyte *ret;
382
383         switch (name) {
384         case GL_EXTENSIONS:
385                 if (glenv_gl_extensions) {
386                         if (index < glenv_num_gl_extensions) {
387                                 return (GLubyte *) glenv_gl_extensions_array[index];
388                         } else {
389                                 /* Force index to an value that will
390                                  * guarantee an INVALID_VALUE value
391                                  * from the underlying glGetStringi.
392                                  */
393                                 index = (GLuint) -1;
394                         }
395                 }
396                 break;
397         case GL_SHADING_LANGUAGE_VERSION:
398                 if (index == 0) {
399                         ret = (GLubyte *) getenv ("GLENV_GL_SHADING_LANGUAGE_VERSION");
400                         if (ret)
401                                 return ret;
402                 }
403                 break;
404         }
405
406         GLAZE_DEFER_WITH_RETURN (ret, glGetStringi, name, index);
407
408         return ret;
409 }