]> git.cworth.org Git - apitrace/blobdiff - glstate.py
Quick hack to downsample multisampled framebuffers.
[apitrace] / glstate.py
index 0caba470130f7fbe10f2a6520684f70cf305a0b1..2c183762b7f7e8471bb8f4e41b8886f8f4dba0dc 100644 (file)
@@ -604,7 +604,7 @@ parameters = [
     ("glGet",  X,      1,      "GL_PROXY_TEXTURE_1D"), # 0x8063
     ("glGet",  X,      1,      "GL_PROXY_TEXTURE_2D"), # 0x8064
     ("glGet",  X,      1,      "GL_TEXTURE_TOO_LARGE_EXT"),    # 0x8065
-    ("glGetTexParameter",      I,      1,      "GL_TEXTURE_PRIORITY"), # 0x8066
+    ("glGetTexParameter",      F,      1,      "GL_TEXTURE_PRIORITY"), # 0x8066
     ("glGetTexParameter",      B,      1,      "GL_TEXTURE_RESIDENT"), # 0x8067
     ("glGet",  I,      1,      "GL_TEXTURE_BINDING_1D"),       # 0x8068
     ("glGet",  I,      1,      "GL_TEXTURE_BINDING_2D"),       # 0x8069
@@ -2866,19 +2866,6 @@ class GetInflector:
         return self.suffixes[type]
 
 
-glGet = GetInflector('glGet', {
-    B: 'Booleanv',
-    I: 'Integerv',
-    F: 'Floatv',
-    D: 'Doublev',
-    S: 'String',
-    P: 'Pointerv',
-})
-
-glGetTexParameter = GetInflector('glGetTexParameter', {I: 'iv', F: 'fv'})
-
-
-
 class StateGetter(Visitor):
     '''Type visitor that is able to extract the state via one of the glGet*
     functions.
@@ -2886,46 +2873,61 @@ class StateGetter(Visitor):
     It will declare any temporary variable
     '''
 
-    def __init__(self, inflector):
-        self.inflector = inflector
+    def __init__(self, radical, suffixes):
+        self.inflector = GetInflector(radical, suffixes)
+
+    def __call__(self, *args):
+        pname = args[-1]
 
-    def temp_name(self, pname):
+        for function, type, count, name in parameters:
+            if type is X:
+                continue
+            if name == pname:
+                if count != 1:
+                    type = Array(type, str(count))
+
+                return type, self.visit(type, args)
+
+        raise NotImplementedError
+
+    def temp_name(self, args):
         '''Return the name of a temporary variable to hold the state.'''
+        pname = args[-1]
 
         return pname[3:].lower()
 
-    def visit_const(self, const, pname):
-        return self.visit(const.type, pname)
+    def visit_const(self, const, args):
+        return self.visit(const.type, args)
 
-    def visit_scalar(self, type, pname):
-        temp_name = self.temp_name(pname)
+    def visit_scalar(self, type, args):
+        temp_name = self.temp_name(args)
         elem_type = self.inflector.reduced_type(type)
         inflection = self.inflector.inflect(type)
         if inflection.endswith('v'):
             print '    %s %s = 0;' % (elem_type, temp_name)
-            print '    %s(%s, &%s);' % (inflection, pname, temp_name)
+            print '    %s(%s, &%s);' % (inflection, ', '.join(args), temp_name)
         else:
-            print '    %s %s = %s(%s);' % (elem_type, temp_name, inflection, pname)
+            print '    %s %s = %s(%s);' % (elem_type, temp_name, inflection, ', '.join(args))
         return temp_name
 
-    def visit_string(self, string, pname):
-        temp_name = self.temp_name(pname)
+    def visit_string(self, string, args):
+        temp_name = self.temp_name(args)
         inflection = self.inflector.inflect(string)
         assert not inflection.endswith('v')
-        print '    %s %s = (%s)%s(%s);' % (string, temp_name, string, inflection, pname)
+        print '    %s %s = (%s)%s(%s);' % (string, temp_name, string, inflection, ', '.join(args))
         return temp_name
 
-    def visit_alias(self, alias, pname):
-        return self.visit_scalar(alias, pname)
+    def visit_alias(self, alias, args):
+        return self.visit_scalar(alias, args)
 
-    def visit_enum(self, enum, pname):
-        return self.visit(GLint, pname)
+    def visit_enum(self, enum, args):
+        return self.visit(GLint, args)
 
-    def visit_bitmask(self, bitmask, pname):
-        return self.visit(GLint, pname)
+    def visit_bitmask(self, bitmask, args):
+        return self.visit(GLint, args)
 
-    def visit_array(self, array, pname):
-        temp_name = self.temp_name(pname)
+    def visit_array(self, array, args):
+        temp_name = self.temp_name(args)
         if array.length == '1':
             return self.visit(array.type)
         elem_type = self.inflector.reduced_type(array.type)
@@ -2933,18 +2935,32 @@ class StateGetter(Visitor):
         assert inflection.endswith('v')
         print '    %s %s[%s];' % (elem_type, temp_name, array.length)
         print '    memset(%s, 0, %s * sizeof *%s);' % (temp_name, array.length, temp_name)
-        print '    %s(%s, %s);' % (inflection, pname, temp_name)
+        print '    %s(%s, %s);' % (inflection, ', '.join(args), temp_name)
         return temp_name
 
-    def visit_opaque(self, pointer, pname):
-        temp_name = self.temp_name(pname)
+    def visit_opaque(self, pointer, args):
+        temp_name = self.temp_name(args)
         inflection = self.inflector.inflect(pointer)
         assert inflection.endswith('v')
         print '    GLvoid *%s;' % temp_name
-        print '    %s(%s, &%s);' % (inflection, pname, temp_name)
+        print '    %s(%s, &%s);' % (inflection, ', '.join(args), temp_name)
         return temp_name
 
 
+glGet = StateGetter('glGet', {
+    B: 'Booleanv',
+    I: 'Integerv',
+    F: 'Floatv',
+    D: 'Doublev',
+    S: 'String',
+    P: 'Pointerv',
+})
+
+glGetVertexAttrib = StateGetter('glGetVertexAttrib', {I: 'iv', F: 'fv', D: 'dv', P: 'Pointerv'})
+glGetTexParameter = StateGetter('glGetTexParameter', {I: 'iv', F: 'fv'})
+glGetTexLevelParameter = StateGetter('glGetTexLevelParameter', {I: 'iv', F: 'fv'})
+
+
 class JsonWriter(Visitor):
     '''Type visitor that will dump a value of the specified type through the
     JSON writer.
@@ -3001,6 +3017,7 @@ class StateDumper:
     def dump(self):
         print '#include <string.h>'
         print '#include <iostream>'
+        print '#include <algorithm>'
         print
         print '#include "json.hpp"'
         print '#include "glimports.hpp"'
@@ -3232,6 +3249,136 @@ writeDrawBufferImage(JSONWriter &json, GLenum format)
     }
 }
 
+static inline GLuint
+downsampledFramebuffer(GLuint oldFbo, GLint drawbuffer,
+                       GLint colorRb, GLint depthRb, GLint stencilRb,
+                       GLuint *rbs, GLint *numRbs)
+{
+    GLuint fbo;
+    GLint format;
+    GLint w, h;
+
+    *numRbs = 0;
+
+    glGenFramebuffers(1, &fbo);
+    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+    glBindRenderbuffer(GL_RENDERBUFFER, colorRb);
+    glGetRenderbufferParameteriv(GL_RENDERBUFFER,
+                                 GL_RENDERBUFFER_WIDTH, &w);
+    glGetRenderbufferParameteriv(GL_RENDERBUFFER,
+                                 GL_RENDERBUFFER_HEIGHT, &h);
+    glGetRenderbufferParameteriv(GL_RENDERBUFFER,
+                                 GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
+
+    glGenRenderbuffers(1, &rbs[*numRbs]);
+    glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
+    glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
+    glFramebufferRenderbuffer(GL_FRAMEBUFFER, drawbuffer,
+                              GL_RENDERBUFFER, rbs[*numRbs]);
+
+    glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
+    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
+    glDrawBuffer(drawbuffer);
+    glReadBuffer(drawbuffer);
+    glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
+                      GL_COLOR_BUFFER_BIT, GL_NEAREST);
+    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+    ++*numRbs;
+
+    if (stencilRb == depthRb && stencilRb) {
+        //combined depth and stencil buffer
+        glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
+        glGetRenderbufferParameteriv(GL_RENDERBUFFER,
+                                     GL_RENDERBUFFER_WIDTH, &w);
+        glGetRenderbufferParameteriv(GL_RENDERBUFFER,
+                                     GL_RENDERBUFFER_HEIGHT, &h);
+        glGetRenderbufferParameteriv(GL_RENDERBUFFER,
+                                     GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
+
+        glGenRenderbuffers(1, &rbs[*numRbs]);
+        glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
+        glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
+        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
+                                  GL_RENDERBUFFER, rbs[*numRbs]);
+        glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
+        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
+        glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
+                          GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
+        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+        ++*numRbs;
+    } else {
+        if (depthRb) {
+            glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
+            glGetRenderbufferParameteriv(GL_RENDERBUFFER,
+                                         GL_RENDERBUFFER_WIDTH, &w);
+            glGetRenderbufferParameteriv(GL_RENDERBUFFER,
+                                         GL_RENDERBUFFER_HEIGHT, &h);
+            glGetRenderbufferParameteriv(GL_RENDERBUFFER,
+                                         GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
+
+            glGenRenderbuffers(1, &rbs[*numRbs]);
+            glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
+            glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
+            glFramebufferRenderbuffer(GL_FRAMEBUFFER,
+                                      GL_DEPTH_ATTACHMENT,
+                                      GL_RENDERBUFFER, rbs[*numRbs]);
+            glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
+            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
+            glDrawBuffer(GL_DEPTH_ATTACHMENT);
+            glReadBuffer(GL_DEPTH_ATTACHMENT);
+            glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
+                              GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+            ++*numRbs;
+        }
+        if (stencilRb) {
+            glBindRenderbuffer(GL_RENDERBUFFER, stencilRb);
+            glGetRenderbufferParameteriv(GL_RENDERBUFFER,
+                                         GL_RENDERBUFFER_WIDTH, &w);
+            glGetRenderbufferParameteriv(GL_RENDERBUFFER,
+                                         GL_RENDERBUFFER_HEIGHT, &h);
+            glGetRenderbufferParameteriv(GL_RENDERBUFFER,
+                                     GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
+
+            glGenRenderbuffers(1, &rbs[*numRbs]);
+            glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
+            glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
+            glFramebufferRenderbuffer(GL_FRAMEBUFFER,
+                                      GL_STENCIL_ATTACHMENT,
+                                      GL_RENDERBUFFER, rbs[*numRbs]);
+            glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
+            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
+            glDrawBuffer(GL_STENCIL_ATTACHMENT);
+            glReadBuffer(GL_STENCIL_ATTACHMENT);
+            glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
+                              GL_STENCIL_BUFFER_BIT, GL_NEAREST);
+            ++*numRbs;
+        }
+    }
+
+    return fbo;
+}
+
+static void
+writeDrawBuffers(JSONWriter &json, GLboolean writeDepth, GLboolean writeStencil)
+{
+    json.beginMember("GL_RGBA");
+    writeDrawBufferImage(json, GL_RGBA);
+    json.endMember();
+
+    if (writeDepth) {
+        json.beginMember("GL_DEPTH_COMPONENT");
+        writeDrawBufferImage(json, GL_DEPTH_COMPONENT);
+        json.endMember();
+    }
+
+    if (writeStencil) {
+        json.beginMember("GL_STENCIL_INDEX");
+        writeDrawBufferImage(json, GL_STENCIL_INDEX);
+        json.endMember();
+    }
+}
+
 '''
 
         # textures
@@ -3246,17 +3393,6 @@ writeDrawBufferImage(JSONWriter &json, GLenum format)
         print '    }'
         print
         print '    json.beginObject();'
-        print
-        print '    GLfloat param;'
-        for function, type, count, name in parameters:
-            if function != 'glGetTexParameter' or count != 1:
-                continue
-            print '        glGetTexParameterfv(target, %s, &param);' % name
-            print '        json.beginMember("%s");'  % name
-            JsonWriter().visit(type, 'param')
-            print '        json.endMember();'
-            print
-        print
         print '    json.beginMember("levels");'
         print '    json.beginArray();'
         print '    GLint level = 0;'
@@ -3275,15 +3411,6 @@ writeDrawBufferImage(JSONWriter &json, GLenum format)
         print '        json.writeNumber(texture);'
         print '        json.endMember();'
         print
-        # TODO: Generalize this
-        for function, type, count, name in parameters:
-            if function != 'glGetTexLevelParameter' or count != 1:
-                continue
-            print '        glGetTexLevelParameterfv(target, level, %s, &param);' % name
-            print '        json.beginMember("%s");'  % name
-            JsonWriter().visit(type, 'param')
-            print '        json.endMember();'
-            print
         print '        json.beginMember("image");'
         print '        writeTextureImage(json, target, level);'
         print '        json.endMember();'
@@ -3311,30 +3438,68 @@ writeDrawBufferImage(JSONWriter &json, GLenum format)
     def dump_parameters(self):
         print '    json.beginMember("parameters");'
         print '    json.beginObject();'
-        for function, type, count, name in parameters:
-            if function != 'glGet':
-                continue
-            if type is X:
-                continue
-            if count != 1:
-                type = Array(type, str(count))
-
-            print '    // %s' % name
-            print '    {'
-            value = StateGetter(glGet).visit(type, name)
-            print '        if (glGetError() != GL_NO_ERROR) {'
-            #print '            std::cerr << "warning: %s(%s) failed\\n";' % (glGet.radical, name)
-            print '        } else {'
-            print '            json.beginMember("%s");' % name
-            JsonWriter().visit(type, value)
-            print '            json.endMember();'
-            print '        }'
-            print '    }'
-            print
+        
+        self.dump_atoms(glGet)
+        
+        self.dump_vertex_attribs()
+        self.dump_texture_parameters()
+
         print '    json.endObject();'
         print '    json.endMember(); // parameters'
         print
 
+    def dump_vertex_attribs(self):
+        print '    GLint max_vertex_attribs = 0;'
+        print '    __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &max_vertex_attribs);'
+        print '    for (GLint index = 0; index < max_vertex_attribs; ++index) {'
+        print '        char name[32];'
+        print '        snprintf(name, sizeof name, "GL_VERTEX_ATTRIB_ARRAY%i", index);'
+        print '        json.beginMember(name);'
+        print '        json.beginObject();'
+        self.dump_atoms(glGetVertexAttrib, 'index')
+        print '        json.endObject();'
+        print '        json.endMember(); // GL_VERTEX_ATTRIB_ARRAYi'
+        print '    }'
+        print
+
+    def dump_texture_parameters(self):
+        print '    {'
+        print '        GLint active_texture = GL_TEXTURE0;'
+        print '        glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);'
+        print '        GLint max_texture_coords = 0;'
+        print '        glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
+        print '        GLint max_combined_texture_image_units = 0;'
+        print '        glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_combined_texture_image_units);'
+        print '        GLint max_units = std::max(max_combined_texture_image_units, max_texture_coords);'
+        print '        for (GLint unit = 0; unit < max_units; ++unit) {'
+        print '            char name[32];'
+        print '            snprintf(name, sizeof name, "GL_TEXTURE%i", unit);'
+        print '            json.beginMember(name);'
+        print '            glActiveTexture(GL_TEXTURE0 + unit);'
+        print '            json.beginObject();'
+        print '            GLint texture;'
+        print
+        for target, binding in texture_targets:
+            print '            // %s' % target
+            print '            texture = 0;'
+            print '            glGetIntegerv(%s, &texture);' % binding
+            print '            if (glIsEnabled(%s) || texture) {' % target
+            print '                json.beginMember("%s");' % target
+            print '                json.beginObject();'
+            self.dump_atoms(glGetTexParameter, target)
+            # We only dump the first level parameters
+            self.dump_atoms(glGetTexLevelParameter, target, "0")
+            print '                json.endObject();'
+            print '                json.endMember(); // %s' % target
+            print '            }'
+            print
+        print '            json.endObject();'
+        print '            json.endMember(); // GL_TEXTUREi'
+        print '        }'
+        print '        glActiveTexture(active_texture);'
+        print '    }'
+        print
+
     def dump_current_program(self):
         print '    json.beginMember("shaders");'
         print '    json.beginObject();'
@@ -3346,24 +3511,29 @@ writeDrawBufferImage(JSONWriter &json, GLenum format)
         print
 
     def dump_textures(self):
-        print '    json.beginMember("textures");'
-        print '    json.beginArray();'
-        print '    GLint active_texture = GL_TEXTURE0;'
-        print '    glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);'
-        print '    GLint max_texture_coords = 0;'
-        print '    glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
-        print '    for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
-        print '        glActiveTexture(GL_TEXTURE0 + unit);'
-        print '        json.beginObject();'
+        print '    {'
+        print '        json.beginMember("textures");'
+        print '        json.beginArray();'
+        print '        GLint active_texture = GL_TEXTURE0;'
+        print '        glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);'
+        print '        GLint max_texture_coords = 0;'
+        print '        glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
+        print '        GLint max_combined_texture_image_units = 0;'
+        print '        glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_combined_texture_image_units);'
+        print '        GLint max_units = std::max(max_combined_texture_image_units, max_texture_coords);'
+        print '        for (GLint unit = 0; unit < max_units; ++unit) {'
+        print '            glActiveTexture(GL_TEXTURE0 + unit);'
+        print '            json.beginObject();'
         for target, binding in texture_targets:
-            print '        json.beginMember("%s");' % target
-            print '        writeTexture(json, %s, %s);' % (target, binding)
-            print '        json.endMember();'
-        print '        json.endObject();'
+            print '            json.beginMember("%s");' % target
+            print '            writeTexture(json, %s, %s);' % (target, binding)
+            print '            json.endMember();'
+        print '            json.endObject();'
+        print '        }'
+        print '        glActiveTexture(active_texture);'
+        print '        json.endArray();'
+        print '        json.endMember(); // texture'
         print '    }'
-        print '    glActiveTexture(active_texture);'
-        print '    json.endArray();'
-        print '    json.endMember(); // texture'
         print
 
     def dump_framebuffer(self):
@@ -3371,30 +3541,95 @@ writeDrawBufferImage(JSONWriter &json, GLenum format)
         print '    json.beginObject();'
         # TODO: Handle real FBOs
         print
-        print '    json.beginMember("GL_RGBA");'
-        print '    writeDrawBufferImage(json, GL_RGBA);'
-        print '    json.endMember();'
+        print '    GLint boundDrawFbo = 0, boundReadFbo = 0;'
+        print '    glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &boundDrawFbo);'
+        print '    glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &boundReadFbo);'
+        print '    if (!boundDrawFbo) {'
+        print '        GLint depth_bits = 0;'
+        print '        glGetIntegerv(GL_DEPTH_BITS, &depth_bits);'
+        print '        GLint stencil_bits = 0;'
+        print '        glGetIntegerv(GL_STENCIL_BITS, &stencil_bits);'
+        print '        writeDrawBuffers(json, depth_bits, stencil_bits);'
+        print '    } else {'
+        print '        GLint colorRb, stencilRb, depthRb;'
+        print '        GLint boundRb;'
+        print '        glGetIntegerv(GL_RENDERBUFFER_BINDING, &boundRb);'
+        print '        GLint drawbuffer = glretrace::double_buffer ? GL_BACK : GL_FRONT;'
+        print '        glGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);'
         print
-        print '    GLint depth_bits = 0;'
-        print '    glGetIntegerv(GL_DEPTH_BITS, &depth_bits);'
-        print '    if (depth_bits) {'
-        print '        json.beginMember("GL_DEPTH_COMPONENT");'
-        print '        writeDrawBufferImage(json, GL_DEPTH_COMPONENT);'
-        print '        json.endMember();'
-        print '    }'
+        print '        glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,'
+        print '                                              drawbuffer,'
+        print '                                              GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,'
+        print '                                              &colorRb);'
+        print '        glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,'
+        print '                                              GL_DEPTH_ATTACHMENT,'
+        print '                                              GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,'
+        print '                                              &depthRb);'
+        print '        glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,'
+        print '                                              GL_STENCIL_ATTACHMENT,'
+        print '                                              GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,'
+        print '                                              &stencilRb);'
         print
-        print '    GLint stencil_bits = 0;'
-        print '    glGetIntegerv(GL_STENCIL_BITS, &stencil_bits);'
-        print '    if (stencil_bits) {'
-        print '        json.beginMember("GL_STENCIL_INDEX");'
-        print '        writeDrawBufferImage(json, GL_STENCIL_INDEX);'
-        print '        json.endMember();'
+        print '        GLint colorSamples, depthSamples, stencilSamples;'
+        print '        GLuint rbs[3];'
+        print '        GLint numRbs = 0;'
+        print '        GLuint fboCopy = 0;'
+        print '        glBindRenderbuffer(GL_RENDERBUFFER, colorRb);'
+        print '        glGetRenderbufferParameteriv(GL_RENDERBUFFER,'
+        print '                                     GL_RENDERBUFFER_SAMPLES, &colorSamples);'
+        print '        glBindRenderbuffer(GL_RENDERBUFFER, depthRb);'
+        print '        glGetRenderbufferParameteriv(GL_RENDERBUFFER,'
+        print '                                     GL_RENDERBUFFER_SAMPLES, &depthSamples);'
+        print '        glBindRenderbuffer(GL_RENDERBUFFER, stencilRb);'
+        print '        glGetRenderbufferParameteriv(GL_RENDERBUFFER,'
+        print '                                     GL_RENDERBUFFER_SAMPLES, &stencilSamples);'
+        print '        glBindRenderbuffer(GL_RENDERBUFFER, boundRb);'
+        print
+        print '        if (colorSamples || depthSamples || stencilSamples) {'
+        print '            //glReadPixels doesnt support multisampled buffers so we need'
+        print '            // to blit the fbo to a temporary one'
+        print '            fboCopy = downsampledFramebuffer(boundDrawFbo, drawbuffer,'
+        print '                                             colorRb, depthRb, stencilRb,'
+        print '                                             rbs, &numRbs);'
+        print '        }'
+        print '        glDrawBuffer(drawbuffer);'
+        print '        glReadBuffer(drawbuffer);'
+        print
+        print '        writeDrawBuffers(json, depthRb, stencilRb);'
+        print
+        print '        if (fboCopy) {'
+        print '            glBindFramebuffer(GL_FRAMEBUFFER, boundDrawFbo);'
+        print '            glBindFramebuffer(GL_READ_FRAMEBUFFER, boundReadFbo);'
+        print '            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, boundDrawFbo);'
+        print '            glBindRenderbuffer(GL_RENDERBUFFER_BINDING, boundRb);'
+        print '            glDeleteRenderbuffers(numRbs, rbs);'
+        print '            glDeleteFramebuffers(1, &fboCopy);'
+        print '        }'
         print '    }'
         print
         print '    json.endObject();'
         print '    json.endMember(); // framebuffer'
         pass
 
+    def dump_atoms(self, getter, *args):
+        for function, type, count, name in parameters:
+            if function != getter.inflector.radical:
+                continue
+            if type is X:
+                continue
+            print '        // %s' % name
+            print '        {'
+            type, value = getter(*(args + (name,)))
+            print '            if (glGetError() != GL_NO_ERROR) {'
+            #print '                std::cerr << "warning: %s(%s) failed\\n";' % (glGet.radical, name)
+            print '            } else {'
+            print '                json.beginMember("%s");' % name
+            JsonWriter().visit(type, value)
+            print '                json.endMember();'
+            print '            }'
+            print '        }'
+            print
+
     def write_line(s):
         self.write('  '*self.level + s + '\n')