]> git.cworth.org Git - apitrace/blob - glstate.py
859b3df189180f49c93fe68c8d4d0e9d01efb552
[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 "glstate.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
485 static bool
486 getDrawableBounds(GLint *width, GLint *height) {
487 #if defined(_WIN32)
488
489     HDC hDC = wglGetCurrentDC();
490     if (!hDC) {
491         return false;
492     }
493
494     HWND hWnd = WindowFromDC(hDC);
495     RECT rect;
496
497     if (!GetClientRect(hWnd, &rect)) {
498        return false;
499     }
500
501     *width  = rect.right  - rect.left;
502     *height = rect.bottom - rect.top;
503
504 #elif 0 /* __APPLE__ */
505
506     CGLError CGLGetSurface(CGLContextObj, CGSConnectionID*, CGSWindowID*, CGSSurfaceID*);
507     CGError CGSGetWindowBounds(CGSConnectionID, CGWindowID, CGRect *ret);
508
509 #else
510
511     Display *display;
512     Drawable drawable;
513     Window root;
514     int x, y;
515     unsigned int w, h, bw, depth;
516
517     display = glXGetCurrentDisplay();
518     if (!display) {
519         return false;
520     }
521
522     drawable = glXGetCurrentDrawable();
523     if (drawable == None) {
524         return false;
525     }
526
527     if (!XGetGeometry(display, drawable, &root, &x, &y, &w, &h, &bw, &depth)) {
528         return false;
529     }
530
531     *width = w;
532     *height = h;
533
534 #endif
535
536     return true;
537 }
538
539
540 static inline void
541 writeDrawBufferImage(JSONWriter &json, GLenum format)
542 {
543     GLint channels = __gl_format_channels(format);
544
545     GLint width, height;
546
547     if (!getDrawableBounds(&width, &height)) {
548         json.writeNull();
549     } else {
550         json.beginObject();
551
552         // Tell the GUI this is no ordinary object, but an image
553         json.writeStringMember("__class__", "image");
554
555         json.writeNumberMember("__width__", width);
556         json.writeNumberMember("__height__", height);
557         json.writeNumberMember("__depth__", 1);
558
559         // Hardcoded for now, but we could chose types more adequate to the
560         // texture internal format
561         json.writeStringMember("__type__", "uint8");
562         json.writeBoolMember("__normalized__", true);
563         json.writeNumberMember("__channels__", channels);
564
565         GLubyte *pixels = new GLubyte[width*height*channels];
566         
567         GLint drawbuffer = GL_NONE;
568         GLint readbuffer = GL_NONE;
569         glGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);
570         glGetIntegerv(GL_READ_BUFFER, &readbuffer);
571         glReadBuffer(drawbuffer);
572
573         glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
574         glPixelStorei(GL_PACK_ALIGNMENT, 1);
575
576         glReadPixels(0, 0, width, height, format, GL_UNSIGNED_BYTE, pixels);
577
578         glPopClientAttrib();
579         glReadBuffer(readbuffer);
580
581         json.beginMember("__data__");
582         char *pngBuffer;
583         int pngBufferSize;
584         Image::writePixelsToBuffer(pixels, width, height, channels, false, &pngBuffer, &pngBufferSize);
585         //std::cerr <<" Before = "<<(width * height * channels * sizeof *pixels)
586         //          <<", after = "<<pngBufferSize << ", ratio = " << double(width * height * channels * sizeof *pixels)/pngBufferSize;
587         json.writeBase64(pngBuffer, pngBufferSize);
588         free(pngBuffer);
589         json.endMember(); // __data__
590
591         delete [] pixels;
592         json.endObject();
593     }
594 }
595
596 static inline GLuint
597 downsampledFramebuffer(GLuint oldFbo, GLint drawbuffer,
598                        GLint colorRb, GLint depthRb, GLint stencilRb,
599                        GLuint *rbs, GLint *numRbs)
600 {
601     GLuint fbo;
602     GLint format;
603     GLint w, h;
604
605     *numRbs = 0;
606
607     glGenFramebuffers(1, &fbo);
608     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
609
610     glBindRenderbuffer(GL_RENDERBUFFER, colorRb);
611     glGetRenderbufferParameteriv(GL_RENDERBUFFER,
612                                  GL_RENDERBUFFER_WIDTH, &w);
613     glGetRenderbufferParameteriv(GL_RENDERBUFFER,
614                                  GL_RENDERBUFFER_HEIGHT, &h);
615     glGetRenderbufferParameteriv(GL_RENDERBUFFER,
616                                  GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
617
618     glGenRenderbuffers(1, &rbs[*numRbs]);
619     glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
620     glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
621     glFramebufferRenderbuffer(GL_FRAMEBUFFER, drawbuffer,
622                               GL_RENDERBUFFER, rbs[*numRbs]);
623
624     glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
625     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
626     glDrawBuffer(drawbuffer);
627     glReadBuffer(drawbuffer);
628     glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
629                       GL_COLOR_BUFFER_BIT, GL_NEAREST);
630     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
631     ++*numRbs;
632
633     if (stencilRb == depthRb && stencilRb) {
634         //combined depth and stencil buffer
635         glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
636         glGetRenderbufferParameteriv(GL_RENDERBUFFER,
637                                      GL_RENDERBUFFER_WIDTH, &w);
638         glGetRenderbufferParameteriv(GL_RENDERBUFFER,
639                                      GL_RENDERBUFFER_HEIGHT, &h);
640         glGetRenderbufferParameteriv(GL_RENDERBUFFER,
641                                      GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
642
643         glGenRenderbuffers(1, &rbs[*numRbs]);
644         glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
645         glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
646         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
647                                   GL_RENDERBUFFER, rbs[*numRbs]);
648         glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
649         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
650         glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
651                           GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
652         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
653         ++*numRbs;
654     } else {
655         if (depthRb) {
656             glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
657             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
658                                          GL_RENDERBUFFER_WIDTH, &w);
659             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
660                                          GL_RENDERBUFFER_HEIGHT, &h);
661             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
662                                          GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
663
664             glGenRenderbuffers(1, &rbs[*numRbs]);
665             glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
666             glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
667             glFramebufferRenderbuffer(GL_FRAMEBUFFER,
668                                       GL_DEPTH_ATTACHMENT,
669                                       GL_RENDERBUFFER, rbs[*numRbs]);
670             glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
671             glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
672             glDrawBuffer(GL_DEPTH_ATTACHMENT);
673             glReadBuffer(GL_DEPTH_ATTACHMENT);
674             glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
675                               GL_DEPTH_BUFFER_BIT, GL_NEAREST);
676             ++*numRbs;
677         }
678         if (stencilRb) {
679             glBindRenderbuffer(GL_RENDERBUFFER, stencilRb);
680             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
681                                          GL_RENDERBUFFER_WIDTH, &w);
682             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
683                                          GL_RENDERBUFFER_HEIGHT, &h);
684             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
685                                      GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
686
687             glGenRenderbuffers(1, &rbs[*numRbs]);
688             glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
689             glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
690             glFramebufferRenderbuffer(GL_FRAMEBUFFER,
691                                       GL_STENCIL_ATTACHMENT,
692                                       GL_RENDERBUFFER, rbs[*numRbs]);
693             glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
694             glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
695             glDrawBuffer(GL_STENCIL_ATTACHMENT);
696             glReadBuffer(GL_STENCIL_ATTACHMENT);
697             glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
698                               GL_STENCIL_BUFFER_BIT, GL_NEAREST);
699             ++*numRbs;
700         }
701     }
702
703     return fbo;
704 }
705
706 static void
707 writeDrawBuffers(JSONWriter &json, GLboolean writeDepth, GLboolean writeStencil)
708 {
709     json.beginMember("GL_RGBA");
710     writeDrawBufferImage(json, GL_RGBA);
711     json.endMember();
712
713     if (writeDepth) {
714         json.beginMember("GL_DEPTH_COMPONENT");
715         writeDrawBufferImage(json, GL_DEPTH_COMPONENT);
716         json.endMember();
717     }
718
719     if (writeStencil) {
720         json.beginMember("GL_STENCIL_INDEX");
721         writeDrawBufferImage(json, GL_STENCIL_INDEX);
722         json.endMember();
723     }
724 }
725
726 '''
727
728         # textures
729         print 'static inline void'
730         print 'writeTexture(JSONWriter &json, GLenum target, GLenum binding)'
731         print '{'
732         print '    GLint texture_binding = 0;'
733         print '    glGetIntegerv(binding, &texture_binding);'
734         print '    if (!glIsEnabled(target) && !texture_binding) {'
735         print '        return;'
736         print '    }'
737         print
738         print '    GLint level = 0;'
739         print '    do {'
740         print '        GLint width = 0, height = 0;'
741         print '        glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &width);'
742         print '        glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &height);'
743         print '        if (!width || !height) {'
744         print '            break;'
745         print '        }'
746         print
747         print '        if (target == GL_TEXTURE_CUBE_MAP) {'
748         print '            for (int face = 0; face < 6; ++face) {'
749         print '                writeTextureImage(json, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);'
750         print '            }'
751         print '        } else {'
752         print '            writeTextureImage(json, target, level);'
753         print '        }'
754         print
755         print '        ++level;'
756         print '    } while(true);'
757         print '}'
758         print
759
760         print 'void glstate::state_dump(std::ostream &os)'
761         print '{'
762         print '    JSONWriter json(os);'
763         self.dump_parameters()
764         self.dump_current_program()
765         self.dump_textures()
766         self.dump_framebuffer()
767         print '}'
768         print
769
770     def dump_parameters(self):
771         print '    json.beginMember("parameters");'
772         print '    json.beginObject();'
773         
774         self.dump_atoms(glGet)
775         
776         self.dump_material_params()
777         self.dump_light_params()
778         self.dump_vertex_attribs()
779         self.dump_texenv_params()
780         self.dump_program_params()
781         self.dump_texture_parameters()
782
783         print '    json.endObject();'
784         print '    json.endMember(); // parameters'
785         print
786
787     def dump_material_params(self):
788         for face in ['GL_FRONT', 'GL_BACK']:
789             print '    json.beginMember("%s");' % face
790             print '    json.beginObject();'
791             self.dump_atoms(glGetMaterial, face)
792             print '    json.endObject();'
793         print
794
795     def dump_light_params(self):
796         print '    GLint max_lights = 0;'
797         print '    __glGetIntegerv(GL_MAX_LIGHTS, &max_lights);'
798         print '    for (GLint index = 0; index < max_lights; ++index) {'
799         print '        GLenum light = GL_LIGHT0 + index;'
800         print '        if (glIsEnabled(light)) {'
801         print '            char name[32];'
802         print '            snprintf(name, sizeof name, "GL_LIGHT%i", index);'
803         print '            json.beginMember(name);'
804         print '            json.beginObject();'
805         self.dump_atoms(glGetLight, '    GL_LIGHT0 + index')
806         print '            json.endObject();'
807         print '            json.endMember(); // GL_LIGHTi'
808         print '        }'
809         print '    }'
810         print
811
812     def dump_texenv_params(self):
813         for target in ['GL_TEXTURE_ENV', 'GL_TEXTURE_FILTER_CONTROL', 'GL_POINT_SPRITE']:
814             if target != 'GL_TEXTURE_FILTER_CONTROL':
815                 print '    if (glIsEnabled(%s)) {' % target
816             else:
817                 print '    {'
818             print '        json.beginMember("%s");' % target
819             print '        json.beginObject();'
820             self.dump_atoms(glGetTexEnv, target)
821             print '        json.endObject();'
822             print '    }'
823
824     def dump_vertex_attribs(self):
825         print '    GLint max_vertex_attribs = 0;'
826         print '    __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &max_vertex_attribs);'
827         print '    for (GLint index = 0; index < max_vertex_attribs; ++index) {'
828         print '        char name[32];'
829         print '        snprintf(name, sizeof name, "GL_VERTEX_ATTRIB_ARRAY%i", index);'
830         print '        json.beginMember(name);'
831         print '        json.beginObject();'
832         self.dump_atoms(glGetVertexAttrib, 'index')
833         print '        json.endObject();'
834         print '        json.endMember(); // GL_VERTEX_ATTRIB_ARRAYi'
835         print '    }'
836         print
837
838     program_targets = [
839         'GL_FRAGMENT_PROGRAM_ARB',
840         'GL_VERTEX_PROGRAM_ARB',
841     ]
842
843     def dump_program_params(self):
844         for target in self.program_targets:
845             print '    if (glIsEnabled(%s)) {' % target
846             print '        json.beginMember("%s");' % target
847             print '        json.beginObject();'
848             self.dump_atoms(glGetProgramARB, target)
849             print '        json.endObject();'
850             print '    }'
851
852     def dump_texture_parameters(self):
853         print '    {'
854         print '        GLint active_texture = GL_TEXTURE0;'
855         print '        glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);'
856         print '        GLint max_texture_coords = 0;'
857         print '        glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
858         print '        GLint max_combined_texture_image_units = 0;'
859         print '        glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_combined_texture_image_units);'
860         print '        GLint max_units = std::max(max_combined_texture_image_units, max_texture_coords);'
861         print '        for (GLint unit = 0; unit < max_units; ++unit) {'
862         print '            char name[32];'
863         print '            snprintf(name, sizeof name, "GL_TEXTURE%i", unit);'
864         print '            json.beginMember(name);'
865         print '            glActiveTexture(GL_TEXTURE0 + unit);'
866         print '            json.beginObject();'
867         print '            GLint texture;'
868         print
869         for target, binding in texture_targets:
870             print '            // %s' % target
871             print '            texture = 0;'
872             print '            glGetIntegerv(%s, &texture);' % binding
873             print '            if (glIsEnabled(%s) || texture) {' % target
874             print '                json.beginMember("%s");' % target
875             print '                json.beginObject();'
876             self.dump_atoms(glGetTexParameter, target)
877             # We only dump the first level parameters
878             self.dump_atoms(glGetTexLevelParameter, target, "0")
879             print '                json.endObject();'
880             print '                json.endMember(); // %s' % target
881             print '            }'
882             print
883         print '            json.endObject();'
884         print '            json.endMember(); // GL_TEXTUREi'
885         print '        }'
886         print '        glActiveTexture(active_texture);'
887         print '    }'
888         print
889
890     def dump_current_program(self):
891         print '    json.beginMember("shaders");'
892         print '    json.beginObject();'
893         print '    writeCurrentProgram(json);'
894         for target in self.program_targets:
895             print '    writeArbProgram(json, %s);' % target
896         print '    json.endObject();'
897         print '    json.endMember(); //shaders'
898         print
899
900     def dump_textures(self):
901         print '    {'
902         print '        json.beginMember("textures");'
903         print '        json.beginObject();'
904         print '        GLint active_texture = GL_TEXTURE0;'
905         print '        glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);'
906         print '        GLint max_texture_coords = 0;'
907         print '        glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
908         print '        GLint max_combined_texture_image_units = 0;'
909         print '        glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_combined_texture_image_units);'
910         print '        GLint max_units = std::max(max_combined_texture_image_units, max_texture_coords);'
911         print '        for (GLint unit = 0; unit < max_units; ++unit) {'
912         print '            GLenum texture = GL_TEXTURE0 + unit;'
913         print '            glActiveTexture(texture);'
914         for target, binding in texture_targets:
915             print '            writeTexture(json, %s, %s);' % (target, binding)
916         print '        }'
917         print '        glActiveTexture(active_texture);'
918         print '        json.endObject();'
919         print '        json.endMember(); // textures'
920         print '    }'
921         print
922
923     def dump_framebuffer(self):
924         print '    json.beginMember("framebuffer");'
925         print '    json.beginObject();'
926         # TODO: Handle real FBOs
927         print
928         print '    GLint boundDrawFbo = 0, boundReadFbo = 0;'
929         print '    glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &boundDrawFbo);'
930         print '    glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &boundReadFbo);'
931         print '    if (!boundDrawFbo) {'
932         print '        GLint depth_bits = 0;'
933         print '        glGetIntegerv(GL_DEPTH_BITS, &depth_bits);'
934         print '        GLint stencil_bits = 0;'
935         print '        glGetIntegerv(GL_STENCIL_BITS, &stencil_bits);'
936         print '        writeDrawBuffers(json, depth_bits, stencil_bits);'
937         print '    } else {'
938         print '        GLint colorRb, stencilRb, depthRb;'
939         print '        GLint boundRb;'
940         print '        glGetIntegerv(GL_RENDERBUFFER_BINDING, &boundRb);'
941         print '        GLint drawbuffer = GL_NONE;'
942         print '        glGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);'
943         print
944         print '        glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,'
945         print '                                              drawbuffer,'
946         print '                                              GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,'
947         print '                                              &colorRb);'
948         print '        glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,'
949         print '                                              GL_DEPTH_ATTACHMENT,'
950         print '                                              GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,'
951         print '                                              &depthRb);'
952         print '        glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,'
953         print '                                              GL_STENCIL_ATTACHMENT,'
954         print '                                              GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,'
955         print '                                              &stencilRb);'
956         print
957         print '        GLint colorSamples, depthSamples, stencilSamples;'
958         print '        GLuint rbs[3];'
959         print '        GLint numRbs = 0;'
960         print '        GLuint fboCopy = 0;'
961         print '        glBindRenderbuffer(GL_RENDERBUFFER, colorRb);'
962         print '        glGetRenderbufferParameteriv(GL_RENDERBUFFER,'
963         print '                                     GL_RENDERBUFFER_SAMPLES, &colorSamples);'
964         print '        glBindRenderbuffer(GL_RENDERBUFFER, depthRb);'
965         print '        glGetRenderbufferParameteriv(GL_RENDERBUFFER,'
966         print '                                     GL_RENDERBUFFER_SAMPLES, &depthSamples);'
967         print '        glBindRenderbuffer(GL_RENDERBUFFER, stencilRb);'
968         print '        glGetRenderbufferParameteriv(GL_RENDERBUFFER,'
969         print '                                     GL_RENDERBUFFER_SAMPLES, &stencilSamples);'
970         print '        glBindRenderbuffer(GL_RENDERBUFFER, boundRb);'
971         print
972         print '        if (colorSamples || depthSamples || stencilSamples) {'
973         print '            //glReadPixels doesnt support multisampled buffers so we need'
974         print '            // to blit the fbo to a temporary one'
975         print '            fboCopy = downsampledFramebuffer(boundDrawFbo, drawbuffer,'
976         print '                                             colorRb, depthRb, stencilRb,'
977         print '                                             rbs, &numRbs);'
978         print '        }'
979         print '        glDrawBuffer(drawbuffer);'
980         print '        glReadBuffer(drawbuffer);'
981         print
982         print '        writeDrawBuffers(json, depthRb, stencilRb);'
983         print
984         print '        if (fboCopy) {'
985         print '            glBindFramebuffer(GL_FRAMEBUFFER, boundDrawFbo);'
986         print '            glBindFramebuffer(GL_READ_FRAMEBUFFER, boundReadFbo);'
987         print '            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, boundDrawFbo);'
988         print '            glBindRenderbuffer(GL_RENDERBUFFER_BINDING, boundRb);'
989         print '            glDeleteRenderbuffers(numRbs, rbs);'
990         print '            glDeleteFramebuffers(1, &fboCopy);'
991         print '        }'
992         print '    }'
993         print
994         print '    json.endObject();'
995         print '    json.endMember(); // framebuffer'
996         pass
997
998     def dump_atoms(self, getter, *args):
999         for function, type, count, name in parameters:
1000             inflection = getter.inflector.radical + getter.suffix
1001             if inflection not in function.split(','):
1002                 continue
1003             if type is X:
1004                 continue
1005             print '        // %s' % name
1006             print '        {'
1007             type, value = getter(*(args + (name,)))
1008             print '            if (glGetError() != GL_NO_ERROR) {'
1009             #print '                std::cerr << "warning: %s(%s) failed\\n";' % (inflection, name)
1010             print '            } else {'
1011             print '                json.beginMember("%s");' % name
1012             JsonWriter().visit(type, value)
1013             print '                json.endMember();'
1014             print '            }'
1015             print '        }'
1016             print
1017
1018
1019 if __name__ == '__main__':
1020     StateDumper().dump()