]> git.cworth.org Git - apitrace/blob - glstate.py
Use double buffer visuals by default.
[apitrace] / glstate.py
1 ##########################################################################
2 #
3 # Copyright 2011 Jose Fonseca
4 # All Rights Reserved.
5 #
6 # Permission is hereby granted, free of charge, to any person obtaining a copy
7 # of this software and associated documentation files (the "Software"), to deal
8 # in the Software without restriction, including without limitation the rights
9 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 # copies of the Software, and to permit persons to whom the Software is
11 # furnished to do so, subject to the following conditions:
12 #
13 # The above copyright notice and this permission notice shall be included in
14 # all copies or substantial portions of the Software.
15 #
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 # THE SOFTWARE.
23 #
24 ##########################################################################/
25
26
27 '''Generate code to dump most GL state into JSON.'''
28
29
30 from stdapi import *
31
32 from gltypes import *
33 from glparams import *
34
35
36 texture_targets = [
37     ('GL_TEXTURE_1D', 'GL_TEXTURE_BINDING_1D'),
38     ('GL_TEXTURE_2D', 'GL_TEXTURE_BINDING_2D'),
39     ('GL_TEXTURE_3D', 'GL_TEXTURE_BINDING_3D'),
40     ('GL_TEXTURE_RECTANGLE', 'GL_TEXTURE_BINDING_RECTANGLE'),
41     ('GL_TEXTURE_CUBE_MAP', 'GL_TEXTURE_BINDING_CUBE_MAP')
42 ]
43
44
45 class GetInflector:
46     '''Objects that describes how to inflect.'''
47
48     reduced_types = {
49         B: I,
50         E: I,
51         I: F,
52     }
53
54     def __init__(self, radical, inflections, suffix = ''):
55         self.radical = radical
56         self.inflections = inflections
57         self.suffix = suffix
58
59     def reduced_type(self, type):
60         if type in self.inflections:
61             return type
62         if type in self.reduced_types:
63             return self.reduced_type(self.reduced_types[type])
64         raise NotImplementedError
65
66     def inflect(self, type):
67         return self.radical + self.inflection(type) + self.suffix
68
69     def inflection(self, type):
70         type = self.reduced_type(type)
71         assert type in self.inflections
72         return self.inflections[type]
73
74     def __str__(self):
75         return self.radical + self.suffix
76
77
78 class StateGetter(Visitor):
79     '''Type visitor that is able to extract the state via one of the glGet*
80     functions.
81
82     It will declare any temporary variable
83     '''
84
85     def __init__(self, radical, inflections, suffix=''):
86         self.inflector = GetInflector(radical, inflections)
87         self.suffix = suffix
88
89     def __call__(self, *args):
90         pname = args[-1]
91
92         for function, type, count, name in parameters:
93             if type is X:
94                 continue
95             if name == pname:
96                 if count != 1:
97                     type = Array(type, str(count))
98
99                 return type, self.visit(type, args)
100
101         raise NotImplementedError
102
103     def temp_name(self, args):
104         '''Return the name of a temporary variable to hold the state.'''
105         pname = args[-1]
106
107         return pname[3:].lower()
108
109     def visit_const(self, const, args):
110         return self.visit(const.type, args)
111
112     def visit_scalar(self, type, args):
113         temp_name = self.temp_name(args)
114         elem_type = self.inflector.reduced_type(type)
115         inflection = self.inflector.inflect(type)
116         if inflection.endswith('v'):
117             print '    %s %s = 0;' % (elem_type, temp_name)
118             print '    %s(%s, &%s);' % (inflection + self.suffix, ', '.join(args), temp_name)
119         else:
120             print '    %s %s = %s(%s);' % (elem_type, temp_name, inflection + self.suffix, ', '.join(args))
121         return temp_name
122
123     def visit_string(self, string, args):
124         temp_name = self.temp_name(args)
125         inflection = self.inflector.inflect(string)
126         assert not inflection.endswith('v')
127         print '    %s %s = (%s)%s(%s);' % (string, temp_name, string, inflection + self.suffix, ', '.join(args))
128         return temp_name
129
130     def visit_alias(self, alias, args):
131         return self.visit_scalar(alias, args)
132
133     def visit_enum(self, enum, args):
134         return self.visit(GLint, args)
135
136     def visit_bitmask(self, bitmask, args):
137         return self.visit(GLint, args)
138
139     def visit_array(self, array, args):
140         temp_name = self.temp_name(args)
141         if array.length == '1':
142             return self.visit(array.type)
143         elem_type = self.inflector.reduced_type(array.type)
144         inflection = self.inflector.inflect(array.type)
145         assert inflection.endswith('v')
146         print '    %s %s[%s];' % (elem_type, temp_name, array.length)
147         print '    memset(%s, 0, %s * sizeof *%s);' % (temp_name, array.length, temp_name)
148         print '    %s(%s, %s);' % (inflection + self.suffix, ', '.join(args), temp_name)
149         return temp_name
150
151     def visit_opaque(self, pointer, args):
152         temp_name = self.temp_name(args)
153         inflection = self.inflector.inflect(pointer)
154         assert inflection.endswith('v')
155         print '    GLvoid *%s;' % temp_name
156         print '    %s(%s, &%s);' % (inflection + self.suffix, ', '.join(args), temp_name)
157         return temp_name
158
159
160 glGet = StateGetter('glGet', {
161     B: 'Booleanv',
162     I: 'Integerv',
163     F: 'Floatv',
164     D: 'Doublev',
165     S: 'String',
166     P: 'Pointerv',
167 })
168
169 glGetMaterial = StateGetter('glGetMaterial', {I: 'iv', F: 'fv'})
170 glGetLight = StateGetter('glGetLight', {I: 'iv', F: 'fv'})
171 glGetVertexAttrib = StateGetter('glGetVertexAttrib', {I: 'iv', F: 'fv', D: 'dv', P: 'Pointerv'})
172 glGetTexParameter = StateGetter('glGetTexParameter', {I: 'iv', F: 'fv'})
173 glGetTexEnv = StateGetter('glGetTexEnv', {I: 'iv', F: 'fv'})
174 glGetTexLevelParameter = StateGetter('glGetTexLevelParameter', {I: 'iv', F: 'fv'})
175 glGetShader = StateGetter('glGetShaderiv', {I: 'iv'})
176 glGetProgram = StateGetter('glGetProgram', {I: 'iv'})
177 glGetProgramARB = StateGetter('glGetProgram', {I: 'iv', F: 'fv', S: 'Stringv'}, 'ARB')
178
179
180 class JsonWriter(Visitor):
181     '''Type visitor that will dump a value of the specified type through the
182     JSON writer.
183     
184     It expects a previously declared JSONWriter instance named "json".'''
185
186     def visit_literal(self, literal, instance):
187         if literal.format == 'Bool':
188             print '    json.writeBool(%s);' % instance
189         elif literal.format in ('SInt', 'Uint', 'Float', 'Double'):
190             print '    json.writeNumber(%s);' % instance
191         else:
192             raise NotImplementedError
193
194     def visit_string(self, string, instance):
195         assert string.length is None
196         print '    json.writeString((const char *)%s);' % instance
197
198     def visit_enum(self, enum, instance):
199         if enum.expr == 'GLenum':
200             print '    dumpEnum(json, %s);' % instance
201         else:
202             print '    json.writeNumber(%s);' % instance
203
204     def visit_bitmask(self, bitmask, instance):
205         raise NotImplementedError
206
207     def visit_alias(self, alias, instance):
208         self.visit(alias.type, instance)
209
210     def visit_opaque(self, opaque, instance):
211         print '    json.writeNumber((size_t)%s);' % instance
212
213     __index = 0
214
215     def visit_array(self, array, instance):
216         index = '__i%u' % JsonWriter.__index
217         JsonWriter.__index += 1
218         print '    json.beginArray();'
219         print '    for (unsigned %s = 0; %s < %s; ++%s) {' % (index, index, array.length, index)
220         self.visit(array.type, '%s[%s]' % (instance, index))
221         print '    }'
222         print '    json.endArray();'
223
224
225
226 class StateDumper:
227     '''Class to generate code to dump all GL state in JSON format via
228     stdout.'''
229
230     def __init__(self):
231         pass
232
233     def dump(self):
234         print '#include <string.h>'
235         print
236         print '#include "json.hpp"'
237         print '#include "glproc.hpp"'
238         print '#include "glsize.hpp"'
239         print '#include "glstate.hpp"'
240         print
241         print 'namespace glstate {'
242         print
243
244         print 'const char *'
245         print 'enumToString(GLenum pname)'
246         print '{'
247         print '    switch(pname) {'
248         for name in GLenum.values:
249             print '    case %s:' % name
250             print '        return "%s";' % name
251         print '    default:'
252         print '        return NULL;'
253         print '    }'
254         print '}'
255         print
256
257         print 'void'
258         print 'dumpEnum(JSONWriter &json, GLenum pname)'
259         print '{'
260         print '    const char *s = enumToString(pname);'
261         print '    if (s) {'
262         print '        json.writeString(s);'
263         print '    } else {'
264         print '        json.writeNumber(pname);'
265         print '    }'
266         print '}'
267         print
268
269         print 'void dumpParameters(JSONWriter &json)'
270         print '{'
271         print '    json.beginMember("parameters");'
272         print '    json.beginObject();'
273         
274         self.dump_atoms(glGet)
275         
276         self.dump_material_params()
277         self.dump_light_params()
278         self.dump_vertex_attribs()
279         self.dump_texenv_params()
280         self.dump_program_params()
281         self.dump_texture_parameters()
282
283         print '    json.endObject();'
284         print '    json.endMember(); // parameters'
285         print '}'
286         print
287         
288         print '} /*namespace glstate */'
289
290     def dump_material_params(self):
291         for face in ['GL_FRONT', 'GL_BACK']:
292             print '    json.beginMember("%s");' % face
293             print '    json.beginObject();'
294             self.dump_atoms(glGetMaterial, face)
295             print '    json.endObject();'
296         print
297
298     def dump_light_params(self):
299         print '    GLint max_lights = 0;'
300         print '    __glGetIntegerv(GL_MAX_LIGHTS, &max_lights);'
301         print '    for (GLint index = 0; index < max_lights; ++index) {'
302         print '        GLenum light = GL_LIGHT0 + index;'
303         print '        if (glIsEnabled(light)) {'
304         print '            char name[32];'
305         print '            snprintf(name, sizeof name, "GL_LIGHT%i", index);'
306         print '            json.beginMember(name);'
307         print '            json.beginObject();'
308         self.dump_atoms(glGetLight, '    GL_LIGHT0 + index')
309         print '            json.endObject();'
310         print '            json.endMember(); // GL_LIGHTi'
311         print '        }'
312         print '    }'
313         print
314
315     def dump_texenv_params(self):
316         for target in ['GL_TEXTURE_ENV', 'GL_TEXTURE_FILTER_CONTROL', 'GL_POINT_SPRITE']:
317             if target != 'GL_TEXTURE_FILTER_CONTROL':
318                 print '    if (glIsEnabled(%s)) {' % target
319             else:
320                 print '    {'
321             print '        json.beginMember("%s");' % target
322             print '        json.beginObject();'
323             self.dump_atoms(glGetTexEnv, target)
324             print '        json.endObject();'
325             print '    }'
326
327     def dump_vertex_attribs(self):
328         print '    GLint max_vertex_attribs = 0;'
329         print '    __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &max_vertex_attribs);'
330         print '    for (GLint index = 0; index < max_vertex_attribs; ++index) {'
331         print '        char name[32];'
332         print '        snprintf(name, sizeof name, "GL_VERTEX_ATTRIB_ARRAY%i", index);'
333         print '        json.beginMember(name);'
334         print '        json.beginObject();'
335         self.dump_atoms(glGetVertexAttrib, 'index')
336         print '        json.endObject();'
337         print '        json.endMember(); // GL_VERTEX_ATTRIB_ARRAYi'
338         print '    }'
339         print
340
341     program_targets = [
342         'GL_FRAGMENT_PROGRAM_ARB',
343         'GL_VERTEX_PROGRAM_ARB',
344     ]
345
346     def dump_program_params(self):
347         for target in self.program_targets:
348             print '    if (glIsEnabled(%s)) {' % target
349             print '        json.beginMember("%s");' % target
350             print '        json.beginObject();'
351             self.dump_atoms(glGetProgramARB, target)
352             print '        json.endObject();'
353             print '    }'
354
355     def dump_texture_parameters(self):
356         print '    {'
357         print '        GLint active_texture = GL_TEXTURE0;'
358         print '        glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);'
359         print '        GLint max_texture_coords = 0;'
360         print '        glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
361         print '        GLint max_combined_texture_image_units = 0;'
362         print '        glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_combined_texture_image_units);'
363         print '        GLint max_units = std::max(max_combined_texture_image_units, max_texture_coords);'
364         print '        for (GLint unit = 0; unit < max_units; ++unit) {'
365         print '            char name[32];'
366         print '            snprintf(name, sizeof name, "GL_TEXTURE%i", unit);'
367         print '            json.beginMember(name);'
368         print '            glActiveTexture(GL_TEXTURE0 + unit);'
369         print '            json.beginObject();'
370         print '            GLint texture;'
371         print
372         for target, binding in texture_targets:
373             print '            // %s' % target
374             print '            texture = 0;'
375             print '            glGetIntegerv(%s, &texture);' % binding
376             print '            if (glIsEnabled(%s) || texture) {' % target
377             print '                json.beginMember("%s");' % target
378             print '                json.beginObject();'
379             self.dump_atoms(glGetTexParameter, target)
380             # We only dump the first level parameters
381             self.dump_atoms(glGetTexLevelParameter, target, "0")
382             print '                json.endObject();'
383             print '                json.endMember(); // %s' % target
384             print '            }'
385             print
386         print '            json.endObject();'
387         print '            json.endMember(); // GL_TEXTUREi'
388         print '        }'
389         print '        glActiveTexture(active_texture);'
390         print '    }'
391         print
392
393     def dump_atoms(self, getter, *args):
394         for function, type, count, name in parameters:
395             inflection = getter.inflector.radical + getter.suffix
396             if inflection not in function.split(','):
397                 continue
398             if type is X:
399                 continue
400             print '        // %s' % name
401             print '        {'
402             type, value = getter(*(args + (name,)))
403             print '            if (glGetError() != GL_NO_ERROR) {'
404             #print '                std::cerr << "warning: %s(%s) failed\\n";' % (inflection, name)
405             print '            } else {'
406             print '                json.beginMember("%s");' % name
407             JsonWriter().visit(type, value)
408             print '                json.endMember();'
409             print '            }'
410             print '        }'
411             print
412
413
414 if __name__ == '__main__':
415     StateDumper().dump()