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