]> git.cworth.org Git - apitrace/blob - glstate.py
Dump (the first face of) cube map textures.
[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 glGetProgramARB = StateGetter('glGetProgram', {I: 'iv', F: 'fv', S: 'Stringv'}, 'ARB')
176
177
178 class JsonWriter(Visitor):
179     '''Type visitor that will dump a value of the specified type through the
180     JSON writer.
181     
182     It expects a previously declared JSONWriter instance named "json".'''
183
184     def visit_literal(self, literal, instance):
185         if literal.format == 'Bool':
186             print '    json.writeBool(%s);' % instance
187         elif literal.format in ('SInt', 'Uint', 'Float', 'Double'):
188             print '    json.writeNumber(%s);' % instance
189         else:
190             raise NotImplementedError
191
192     def visit_string(self, string, instance):
193         assert string.length is None
194         print '    json.writeString((const char *)%s);' % instance
195
196     def visit_enum(self, enum, instance):
197         if enum.expr == 'GLenum':
198             print '    writeEnum(json, %s);' % instance
199         else:
200             print '    json.writeNumber(%s);' % instance
201
202     def visit_bitmask(self, bitmask, instance):
203         raise NotImplementedError
204
205     def visit_alias(self, alias, instance):
206         self.visit(alias.type, instance)
207
208     def visit_opaque(self, opaque, instance):
209         print '    json.writeNumber((size_t)%s);' % instance
210
211     __index = 0
212
213     def visit_array(self, array, instance):
214         index = '__i%u' % JsonWriter.__index
215         JsonWriter.__index += 1
216         print '    json.beginArray();'
217         print '    for (unsigned %s = 0; %s < %s; ++%s) {' % (index, index, array.length, index)
218         self.visit(array.type, '%s[%s]' % (instance, index))
219         print '    }'
220         print '    json.endArray();'
221
222
223
224 class StateDumper:
225     '''Class to generate code to dump all GL state in JSON format via
226     stdout.'''
227
228     def __init__(self):
229         pass
230
231     def dump(self):
232         print '#include <string.h>'
233         print '#include <iostream>'
234         print '#include <algorithm>'
235         print
236         print '#include "image.hpp"'
237         print '#include "json.hpp"'
238         print '#include "glimports.hpp"'
239         print '#include "glproc.hpp"'
240         print '#include "glsize.hpp"'
241         print '#include "glretrace.hpp"'
242         print
243
244         print 'static const char *'
245         print '_enum_string(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 'static const char *'
258         print 'enum_string(GLenum pname)'
259         print '{'
260         print '    const char *s = _enum_string(pname);'
261         print '    if (s) {'
262         print '        return s;'
263         print '    } else {'
264         print '        static char buf[16];'
265         print '        snprintf(buf, sizeof buf, "0x%04x", pname);'
266         print '        return buf;'
267         print '    }'
268         print '}'
269         print
270
271         print 'static inline void'
272         print 'writeEnum(JSONWriter &json, GLenum pname)'
273         print '{'
274         print '    const char *s = _enum_string(pname);'
275         print '    if (s) {'
276         print '        json.writeString(s);'
277         print '    } else {'
278         print '        json.writeNumber(pname);'
279         print '    }'
280         print '}'
281         print
282
283         # shaders
284         print '''
285 static void
286 writeShader(JSONWriter &json, GLuint shader)
287 {
288     if (!shader) {
289         return;
290     }
291
292     GLint shader_type = 0;
293     glGetShaderiv(shader, GL_SHADER_TYPE, &shader_type);
294     if (!shader_type) {
295         return;
296     }
297
298     GLint source_length = 0;
299     glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &source_length);
300     if (!source_length) {
301         return;
302     }
303
304     GLchar *source = new GLchar[source_length];
305     GLsizei length = 0;
306     source[0] = 0;
307     glGetShaderSource(shader, source_length, &length, source);
308
309     json.beginMember(enum_string(shader_type));
310     json.writeString(source);
311     json.endMember();
312
313     delete [] source;
314 }
315
316 static inline void
317 writeCurrentProgram(JSONWriter &json)
318 {
319     GLint program = 0;
320     glGetIntegerv(GL_CURRENT_PROGRAM, &program);
321     if (!program) {
322         return;
323     }
324
325     GLint attached_shaders = 0;
326     glGetProgramiv(program, GL_ATTACHED_SHADERS, &attached_shaders);
327     if (!attached_shaders) {
328         return;
329     }
330
331     GLuint *shaders = new GLuint[attached_shaders];
332     GLsizei count = 0;
333     glGetAttachedShaders(program, attached_shaders, &count, shaders);
334     for (GLsizei i = 0; i < count; ++ i) {
335        writeShader(json, shaders[i]);
336     }
337     delete [] shaders;
338 }
339
340 static inline void
341 writeArbProgram(JSONWriter &json, GLenum target)
342 {
343     if (!glIsEnabled(target)) {
344         return;
345     }
346
347     GLint program_length = 0;
348     glGetProgramivARB(target, GL_PROGRAM_LENGTH_ARB, &program_length);
349     if (!program_length) {
350         return;
351     }
352
353     GLchar *source = new GLchar[program_length + 1];
354     source[0] = 0;
355     glGetProgramStringARB(target, GL_PROGRAM_STRING_ARB, source);
356     source[program_length] = 0;
357
358     json.beginMember(enum_string(target));
359     json.writeString(source);
360     json.endMember();
361
362     delete [] source;
363 }
364 '''
365
366         # texture image
367         print '''
368 static inline void
369 writeTextureImage(JSONWriter &json, GLenum target, GLint level)
370 {
371     GLint width, height = 1, depth = 1;
372
373     width = 0;
374     glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &width);
375
376     if (target != GL_TEXTURE_1D) {
377         height = 0;
378         glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &height);
379         if (target == GL_TEXTURE_3D) {
380             depth = 0;
381             glGetTexLevelParameteriv(target, level, GL_TEXTURE_DEPTH, &depth);
382         }
383     }
384
385     if (width <= 0 || height <= 0 || depth <= 0) {
386         json.writeNull();
387     } else {
388         json.beginObject();
389
390         // Tell the GUI this is no ordinary object, but an image
391         json.writeStringMember("__class__", "image");
392
393         json.writeNumberMember("__width__", width);
394         json.writeNumberMember("__height__", height);
395         json.writeNumberMember("__depth__", depth);
396
397         // Hardcoded for now, but we could chose types more adequate to the
398         // texture internal format
399         json.writeStringMember("__type__", "uint8");
400         json.writeBoolMember("__normalized__", true);
401         json.writeNumberMember("__channels__", 4);
402         
403         GLubyte *pixels = new GLubyte[depth*width*height*4];
404
405         if (target == GL_TEXTURE_CUBE_MAP) {
406             // TODO: dump other faces too
407             target = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
408         }
409         
410         glGetTexImage(target, level, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
411
412         json.beginMember("__data__");
413         char *pngBuffer;
414         int pngBufferSize;
415         Image::writePixelsToBuffer(pixels, width, height, 4, false, &pngBuffer, &pngBufferSize);
416         json.writeBase64(pngBuffer, pngBufferSize);
417         free(pngBuffer);
418         json.endMember(); // __data__
419
420         delete [] pixels;
421         json.endObject();
422     }
423 }
424
425 static inline void
426 writeDrawBufferImage(JSONWriter &json, GLenum format)
427 {
428     GLint width  = glretrace::window_width;
429     GLint height = glretrace::window_height;
430
431     GLint channels = __gl_format_channels(format);
432
433     if (!width || !height) {
434         json.writeNull();
435     } else {
436         json.beginObject();
437
438         // Tell the GUI this is no ordinary object, but an image
439         json.writeStringMember("__class__", "image");
440
441         json.writeNumberMember("__width__", width);
442         json.writeNumberMember("__height__", height);
443         json.writeNumberMember("__depth__", 1);
444
445         // Hardcoded for now, but we could chose types more adequate to the
446         // texture internal format
447         json.writeStringMember("__type__", "uint8");
448         json.writeBoolMember("__normalized__", true);
449         json.writeNumberMember("__channels__", channels);
450
451         GLubyte *pixels = new GLubyte[width*height*channels];
452         
453         GLint drawbuffer = glretrace::double_buffer ? GL_BACK : GL_FRONT;
454         GLint readbuffer = glretrace::double_buffer ? GL_BACK : GL_FRONT;
455         glGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);
456         glGetIntegerv(GL_READ_BUFFER, &readbuffer);
457         glReadBuffer(drawbuffer);
458
459         glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
460         glPixelStorei(GL_PACK_ALIGNMENT, 1);
461
462         glReadPixels(0, 0, width, height, format, GL_UNSIGNED_BYTE, pixels);
463
464         glPopClientAttrib();
465         glReadBuffer(readbuffer);
466
467         json.beginMember("__data__");
468         char *pngBuffer;
469         int pngBufferSize;
470         Image::writePixelsToBuffer(pixels, width, height, channels, false, &pngBuffer, &pngBufferSize);
471         //std::cerr <<" Before = "<<(width * height * channels * sizeof *pixels)
472         //          <<", after = "<<pngBufferSize << ", ratio = " << double(width * height * channels * sizeof *pixels)/pngBufferSize;
473         json.writeBase64(pngBuffer, pngBufferSize);
474         free(pngBuffer);
475         json.endMember(); // __data__
476
477         delete [] pixels;
478         json.endObject();
479     }
480 }
481
482 static inline GLuint
483 downsampledFramebuffer(GLuint oldFbo, GLint drawbuffer,
484                        GLint colorRb, GLint depthRb, GLint stencilRb,
485                        GLuint *rbs, GLint *numRbs)
486 {
487     GLuint fbo;
488     GLint format;
489     GLint w, h;
490
491     *numRbs = 0;
492
493     glGenFramebuffers(1, &fbo);
494     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
495
496     glBindRenderbuffer(GL_RENDERBUFFER, colorRb);
497     glGetRenderbufferParameteriv(GL_RENDERBUFFER,
498                                  GL_RENDERBUFFER_WIDTH, &w);
499     glGetRenderbufferParameteriv(GL_RENDERBUFFER,
500                                  GL_RENDERBUFFER_HEIGHT, &h);
501     glGetRenderbufferParameteriv(GL_RENDERBUFFER,
502                                  GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
503
504     glGenRenderbuffers(1, &rbs[*numRbs]);
505     glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
506     glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
507     glFramebufferRenderbuffer(GL_FRAMEBUFFER, drawbuffer,
508                               GL_RENDERBUFFER, rbs[*numRbs]);
509
510     glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
511     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
512     glDrawBuffer(drawbuffer);
513     glReadBuffer(drawbuffer);
514     glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
515                       GL_COLOR_BUFFER_BIT, GL_NEAREST);
516     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
517     ++*numRbs;
518
519     if (stencilRb == depthRb && stencilRb) {
520         //combined depth and stencil buffer
521         glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
522         glGetRenderbufferParameteriv(GL_RENDERBUFFER,
523                                      GL_RENDERBUFFER_WIDTH, &w);
524         glGetRenderbufferParameteriv(GL_RENDERBUFFER,
525                                      GL_RENDERBUFFER_HEIGHT, &h);
526         glGetRenderbufferParameteriv(GL_RENDERBUFFER,
527                                      GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
528
529         glGenRenderbuffers(1, &rbs[*numRbs]);
530         glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
531         glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
532         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
533                                   GL_RENDERBUFFER, rbs[*numRbs]);
534         glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
535         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
536         glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
537                           GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
538         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
539         ++*numRbs;
540     } else {
541         if (depthRb) {
542             glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
543             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
544                                          GL_RENDERBUFFER_WIDTH, &w);
545             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
546                                          GL_RENDERBUFFER_HEIGHT, &h);
547             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
548                                          GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
549
550             glGenRenderbuffers(1, &rbs[*numRbs]);
551             glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
552             glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
553             glFramebufferRenderbuffer(GL_FRAMEBUFFER,
554                                       GL_DEPTH_ATTACHMENT,
555                                       GL_RENDERBUFFER, rbs[*numRbs]);
556             glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
557             glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
558             glDrawBuffer(GL_DEPTH_ATTACHMENT);
559             glReadBuffer(GL_DEPTH_ATTACHMENT);
560             glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
561                               GL_DEPTH_BUFFER_BIT, GL_NEAREST);
562             ++*numRbs;
563         }
564         if (stencilRb) {
565             glBindRenderbuffer(GL_RENDERBUFFER, stencilRb);
566             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
567                                          GL_RENDERBUFFER_WIDTH, &w);
568             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
569                                          GL_RENDERBUFFER_HEIGHT, &h);
570             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
571                                      GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
572
573             glGenRenderbuffers(1, &rbs[*numRbs]);
574             glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
575             glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
576             glFramebufferRenderbuffer(GL_FRAMEBUFFER,
577                                       GL_STENCIL_ATTACHMENT,
578                                       GL_RENDERBUFFER, rbs[*numRbs]);
579             glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
580             glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
581             glDrawBuffer(GL_STENCIL_ATTACHMENT);
582             glReadBuffer(GL_STENCIL_ATTACHMENT);
583             glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
584                               GL_STENCIL_BUFFER_BIT, GL_NEAREST);
585             ++*numRbs;
586         }
587     }
588
589     return fbo;
590 }
591
592 static void
593 writeDrawBuffers(JSONWriter &json, GLboolean writeDepth, GLboolean writeStencil)
594 {
595     json.beginMember("GL_RGBA");
596     writeDrawBufferImage(json, GL_RGBA);
597     json.endMember();
598
599     if (writeDepth) {
600         json.beginMember("GL_DEPTH_COMPONENT");
601         writeDrawBufferImage(json, GL_DEPTH_COMPONENT);
602         json.endMember();
603     }
604
605     if (writeStencil) {
606         json.beginMember("GL_STENCIL_INDEX");
607         writeDrawBufferImage(json, GL_STENCIL_INDEX);
608         json.endMember();
609     }
610 }
611
612 '''
613
614         # textures
615         print 'static inline void'
616         print 'writeTexture(JSONWriter &json, GLenum target, GLenum binding)'
617         print '{'
618         print '    GLint texture = 0;'
619         print '    glGetIntegerv(binding, &texture);'
620         print '    if (!glIsEnabled(target) && !texture) {'
621         print '        json.writeNull();'
622         print '        return;'
623         print '    }'
624         print
625         print '    json.beginObject();'
626         print '    json.beginMember("levels");'
627         print '    json.beginArray();'
628         print '    GLint level = 0;'
629         print '    do {'
630         print '        GLint width = 0, height = 0;'
631         print '        glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &width);'
632         print '        glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &height);'
633         print '        if (!width || !height) {'
634         print '            break;'
635         print '        }'
636         print '        json.beginObject();'
637         print
638         # FIXME: This is not the original texture name in the trace -- we need
639         # to do a reverse lookup of the texture mappings to find the original one
640         print '        json.beginMember("binding");'
641         print '        json.writeNumber(texture);'
642         print '        json.endMember();'
643         print
644         print '        json.beginMember("image");'
645         print '        writeTextureImage(json, target, level);'
646         print '        json.endMember();'
647         print
648         print '        json.endObject();'
649         print '        ++level;'
650         print '    } while(true);'
651         print '    json.endArray();'
652         print '    json.endMember(); // levels'
653         print
654         print '    json.endObject();'
655         print '}'
656         print
657
658         print 'void glretrace::state_dump(std::ostream &os)'
659         print '{'
660         print '    JSONWriter json(os);'
661         self.dump_parameters()
662         self.dump_current_program()
663         self.dump_textures()
664         self.dump_framebuffer()
665         print '}'
666         print
667
668     def dump_parameters(self):
669         print '    json.beginMember("parameters");'
670         print '    json.beginObject();'
671         
672         self.dump_atoms(glGet)
673         
674         self.dump_material_params()
675         self.dump_light_params()
676         self.dump_vertex_attribs()
677         self.dump_texenv_params()
678         self.dump_program_params()
679         self.dump_texture_parameters()
680
681         print '    json.endObject();'
682         print '    json.endMember(); // parameters'
683         print
684
685     def dump_material_params(self):
686         for face in ['GL_FRONT', 'GL_BACK']:
687             print '    json.beginMember("%s");' % face
688             print '    json.beginObject();'
689             self.dump_atoms(glGetMaterial, face)
690             print '    json.endObject();'
691         print
692
693     def dump_light_params(self):
694         print '    GLint max_lights = 0;'
695         print '    __glGetIntegerv(GL_MAX_LIGHTS, &max_lights);'
696         print '    for (GLint index = 0; index < max_lights; ++index) {'
697         print '        GLenum light = GL_LIGHT0 + index;'
698         print '        if (glIsEnabled(light)) {'
699         print '            char name[32];'
700         print '            snprintf(name, sizeof name, "GL_LIGHT%i", index);'
701         print '            json.beginMember(name);'
702         print '            json.beginObject();'
703         self.dump_atoms(glGetLight, '    GL_LIGHT0 + index')
704         print '            json.endObject();'
705         print '            json.endMember(); // GL_LIGHTi'
706         print '        }'
707         print '    }'
708         print
709
710     def dump_texenv_params(self):
711         for target in ['GL_TEXTURE_ENV', 'GL_TEXTURE_FILTER_CONTROL', 'GL_POINT_SPRITE']:
712             if target != 'GL_TEXTURE_FILTER_CONTROL':
713                 print '    if (glIsEnabled(%s)) {' % target
714             else:
715                 print '    {'
716             print '        json.beginMember("%s");' % target
717             print '        json.beginObject();'
718             self.dump_atoms(glGetTexEnv, target)
719             print '        json.endObject();'
720             print '    }'
721
722     def dump_vertex_attribs(self):
723         print '    GLint max_vertex_attribs = 0;'
724         print '    __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &max_vertex_attribs);'
725         print '    for (GLint index = 0; index < max_vertex_attribs; ++index) {'
726         print '        char name[32];'
727         print '        snprintf(name, sizeof name, "GL_VERTEX_ATTRIB_ARRAY%i", index);'
728         print '        json.beginMember(name);'
729         print '        json.beginObject();'
730         self.dump_atoms(glGetVertexAttrib, 'index')
731         print '        json.endObject();'
732         print '        json.endMember(); // GL_VERTEX_ATTRIB_ARRAYi'
733         print '    }'
734         print
735
736     program_targets = [
737         'GL_FRAGMENT_PROGRAM_ARB',
738         'GL_VERTEX_PROGRAM_ARB',
739     ]
740
741     def dump_program_params(self):
742         for target in self.program_targets:
743             print '    if (glIsEnabled(%s)) {' % target
744             print '        json.beginMember("%s");' % target
745             print '        json.beginObject();'
746             self.dump_atoms(glGetProgramARB, target)
747             print '        json.endObject();'
748             print '    }'
749
750     def dump_texture_parameters(self):
751         print '    {'
752         print '        GLint active_texture = GL_TEXTURE0;'
753         print '        glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);'
754         print '        GLint max_texture_coords = 0;'
755         print '        glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
756         print '        GLint max_combined_texture_image_units = 0;'
757         print '        glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_combined_texture_image_units);'
758         print '        GLint max_units = std::max(max_combined_texture_image_units, max_texture_coords);'
759         print '        for (GLint unit = 0; unit < max_units; ++unit) {'
760         print '            char name[32];'
761         print '            snprintf(name, sizeof name, "GL_TEXTURE%i", unit);'
762         print '            json.beginMember(name);'
763         print '            glActiveTexture(GL_TEXTURE0 + unit);'
764         print '            json.beginObject();'
765         print '            GLint texture;'
766         print
767         for target, binding in texture_targets:
768             print '            // %s' % target
769             print '            texture = 0;'
770             print '            glGetIntegerv(%s, &texture);' % binding
771             print '            if (glIsEnabled(%s) || texture) {' % target
772             print '                json.beginMember("%s");' % target
773             print '                json.beginObject();'
774             self.dump_atoms(glGetTexParameter, target)
775             # We only dump the first level parameters
776             self.dump_atoms(glGetTexLevelParameter, target, "0")
777             print '                json.endObject();'
778             print '                json.endMember(); // %s' % target
779             print '            }'
780             print
781         print '            json.endObject();'
782         print '            json.endMember(); // GL_TEXTUREi'
783         print '        }'
784         print '        glActiveTexture(active_texture);'
785         print '    }'
786         print
787
788     def dump_current_program(self):
789         print '    json.beginMember("shaders");'
790         print '    json.beginObject();'
791         print '    writeCurrentProgram(json);'
792         for target in self.program_targets:
793             print '    writeArbProgram(json, %s);' % target
794         print '    json.endObject();'
795         print '    json.endMember(); //shaders'
796         print
797
798     def dump_textures(self):
799         print '    {'
800         print '        json.beginMember("textures");'
801         print '        json.beginArray();'
802         print '        GLint active_texture = GL_TEXTURE0;'
803         print '        glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);'
804         print '        GLint max_texture_coords = 0;'
805         print '        glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
806         print '        GLint max_combined_texture_image_units = 0;'
807         print '        glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_combined_texture_image_units);'
808         print '        GLint max_units = std::max(max_combined_texture_image_units, max_texture_coords);'
809         print '        for (GLint unit = 0; unit < max_units; ++unit) {'
810         print '            glActiveTexture(GL_TEXTURE0 + unit);'
811         print '            json.beginObject();'
812         for target, binding in texture_targets:
813             print '            json.beginMember("%s");' % target
814             print '            writeTexture(json, %s, %s);' % (target, binding)
815             print '            json.endMember();'
816         print '            json.endObject();'
817         print '        }'
818         print '        glActiveTexture(active_texture);'
819         print '        json.endArray();'
820         print '        json.endMember(); // texture'
821         print '    }'
822         print
823
824     def dump_framebuffer(self):
825         print '    json.beginMember("framebuffer");'
826         print '    json.beginObject();'
827         # TODO: Handle real FBOs
828         print
829         print '    GLint boundDrawFbo = 0, boundReadFbo = 0;'
830         print '    glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &boundDrawFbo);'
831         print '    glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &boundReadFbo);'
832         print '    if (!boundDrawFbo) {'
833         print '        GLint depth_bits = 0;'
834         print '        glGetIntegerv(GL_DEPTH_BITS, &depth_bits);'
835         print '        GLint stencil_bits = 0;'
836         print '        glGetIntegerv(GL_STENCIL_BITS, &stencil_bits);'
837         print '        writeDrawBuffers(json, depth_bits, stencil_bits);'
838         print '    } else {'
839         print '        GLint colorRb, stencilRb, depthRb;'
840         print '        GLint boundRb;'
841         print '        glGetIntegerv(GL_RENDERBUFFER_BINDING, &boundRb);'
842         print '        GLint drawbuffer = glretrace::double_buffer ? GL_BACK : GL_FRONT;'
843         print '        glGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);'
844         print
845         print '        glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,'
846         print '                                              drawbuffer,'
847         print '                                              GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,'
848         print '                                              &colorRb);'
849         print '        glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,'
850         print '                                              GL_DEPTH_ATTACHMENT,'
851         print '                                              GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,'
852         print '                                              &depthRb);'
853         print '        glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,'
854         print '                                              GL_STENCIL_ATTACHMENT,'
855         print '                                              GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,'
856         print '                                              &stencilRb);'
857         print
858         print '        GLint colorSamples, depthSamples, stencilSamples;'
859         print '        GLuint rbs[3];'
860         print '        GLint numRbs = 0;'
861         print '        GLuint fboCopy = 0;'
862         print '        glBindRenderbuffer(GL_RENDERBUFFER, colorRb);'
863         print '        glGetRenderbufferParameteriv(GL_RENDERBUFFER,'
864         print '                                     GL_RENDERBUFFER_SAMPLES, &colorSamples);'
865         print '        glBindRenderbuffer(GL_RENDERBUFFER, depthRb);'
866         print '        glGetRenderbufferParameteriv(GL_RENDERBUFFER,'
867         print '                                     GL_RENDERBUFFER_SAMPLES, &depthSamples);'
868         print '        glBindRenderbuffer(GL_RENDERBUFFER, stencilRb);'
869         print '        glGetRenderbufferParameteriv(GL_RENDERBUFFER,'
870         print '                                     GL_RENDERBUFFER_SAMPLES, &stencilSamples);'
871         print '        glBindRenderbuffer(GL_RENDERBUFFER, boundRb);'
872         print
873         print '        if (colorSamples || depthSamples || stencilSamples) {'
874         print '            //glReadPixels doesnt support multisampled buffers so we need'
875         print '            // to blit the fbo to a temporary one'
876         print '            fboCopy = downsampledFramebuffer(boundDrawFbo, drawbuffer,'
877         print '                                             colorRb, depthRb, stencilRb,'
878         print '                                             rbs, &numRbs);'
879         print '        }'
880         print '        glDrawBuffer(drawbuffer);'
881         print '        glReadBuffer(drawbuffer);'
882         print
883         print '        writeDrawBuffers(json, depthRb, stencilRb);'
884         print
885         print '        if (fboCopy) {'
886         print '            glBindFramebuffer(GL_FRAMEBUFFER, boundDrawFbo);'
887         print '            glBindFramebuffer(GL_READ_FRAMEBUFFER, boundReadFbo);'
888         print '            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, boundDrawFbo);'
889         print '            glBindRenderbuffer(GL_RENDERBUFFER_BINDING, boundRb);'
890         print '            glDeleteRenderbuffers(numRbs, rbs);'
891         print '            glDeleteFramebuffers(1, &fboCopy);'
892         print '        }'
893         print '    }'
894         print
895         print '    json.endObject();'
896         print '    json.endMember(); // framebuffer'
897         pass
898
899     def dump_atoms(self, getter, *args):
900         for function, type, count, name in parameters:
901             inflection = getter.inflector.radical + getter.suffix
902             if inflection not in function.split(','):
903                 continue
904             if type is X:
905                 continue
906             print '        // %s' % name
907             print '        {'
908             type, value = getter(*(args + (name,)))
909             print '            if (glGetError() != GL_NO_ERROR) {'
910             #print '                std::cerr << "warning: %s(%s) failed\\n";' % (inflection, name)
911             print '            } else {'
912             print '                json.beginMember("%s");' % name
913             JsonWriter().visit(type, value)
914             print '                json.endMember();'
915             print '            }'
916             print '        }'
917             print
918
919
920 if __name__ == '__main__':
921     StateDumper().dump()