]> git.cworth.org Git - apitrace/blob - glstate.cpp
Reorganize glstate code.
[apitrace] / glstate.cpp
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 #include <string.h>
28 #include <iostream>
29 #include <algorithm>
30
31 #include "image.hpp"
32 #include "json.hpp"
33 #include "glproc.hpp"
34 #include "glsize.hpp"
35 #include "glstate.hpp"
36
37
38 namespace glstate {
39
40
41 static void
42 dumpShader(JSONWriter &json, GLuint shader)
43 {
44     if (!shader) {
45         return;
46     }
47
48     GLint shader_type = 0;
49     glGetShaderiv(shader, GL_SHADER_TYPE, &shader_type);
50     if (!shader_type) {
51         return;
52     }
53
54     GLint source_length = 0;
55     glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &source_length);
56     if (!source_length) {
57         return;
58     }
59
60     GLchar *source = new GLchar[source_length];
61     GLsizei length = 0;
62     source[0] = 0;
63     glGetShaderSource(shader, source_length, &length, source);
64
65     json.beginMember(enumToString(shader_type));
66     json.writeString(source);
67     json.endMember();
68
69     delete [] source;
70 }
71
72
73 static void
74 dumpShaderObj(JSONWriter &json, GLhandleARB shaderObj)
75 {
76     if (!shaderObj) {
77         return;
78     }
79
80     GLint shader_type = 0;
81     glGetObjectParameterivARB(shaderObj, GL_OBJECT_TYPE_ARB, &shader_type);
82     if (!shader_type) {
83         return;
84     }
85
86     GLint source_length = 0;
87     glGetObjectParameterivARB(shaderObj, GL_OBJECT_SHADER_SOURCE_LENGTH_ARB, &source_length);
88     if (!source_length) {
89         return;
90     }
91
92     GLcharARB *source = new GLcharARB[source_length];
93     GLsizei length = 0;
94     source[0] = 0;
95     glGetShaderSource(shaderObj, source_length, &length, source);
96
97     json.beginMember(enumToString(shader_type));
98     json.writeString(source);
99     json.endMember();
100
101     delete [] source;
102 }
103
104
105 static inline void
106 dumpCurrentProgram(JSONWriter &json)
107 {
108     GLint program = 0;
109     glGetIntegerv(GL_CURRENT_PROGRAM, &program);
110     if (!program) {
111         return;
112     }
113
114     GLint attached_shaders = 0;
115     glGetProgramiv(program, GL_ATTACHED_SHADERS, &attached_shaders);
116     if (!attached_shaders) {
117         return;
118     }
119
120     GLuint *shaders = new GLuint[attached_shaders];
121     GLsizei count = 0;
122     glGetAttachedShaders(program, attached_shaders, &count, shaders);
123     for (GLsizei i = 0; i < count; ++ i) {
124        dumpShader(json, shaders[i]);
125     }
126     delete [] shaders;
127 }
128
129
130 static inline void
131 dumpCurrentProgramObj(JSONWriter &json)
132 {
133     GLhandleARB programObj = glGetHandleARB(GL_PROGRAM_OBJECT_ARB);
134     if (!programObj) {
135         return;
136     }
137
138     GLint attached_shaders = 0;
139     glGetProgramivARB(programObj, GL_OBJECT_ATTACHED_OBJECTS_ARB, &attached_shaders);
140     if (!attached_shaders) {
141         return;
142     }
143
144     GLhandleARB *shaderObjs = new GLhandleARB[attached_shaders];
145     GLsizei count = 0;
146     glGetAttachedObjectsARB(programObj, attached_shaders, &count, shaderObjs);
147     for (GLsizei i = 0; i < count; ++ i) {
148        dumpShaderObj(json, shaderObjs[i]);
149     }
150     delete [] shaderObjs;
151 }
152
153
154 static inline void
155 dumpArbProgram(JSONWriter &json, GLenum target)
156 {
157     if (!glIsEnabled(target)) {
158         return;
159     }
160
161     GLint program_length = 0;
162     glGetProgramivARB(target, GL_PROGRAM_LENGTH_ARB, &program_length);
163     if (!program_length) {
164         return;
165     }
166
167     GLchar *source = new GLchar[program_length + 1];
168     source[0] = 0;
169     glGetProgramStringARB(target, GL_PROGRAM_STRING_ARB, source);
170     source[program_length] = 0;
171
172     json.beginMember(enumToString(target));
173     json.writeString(source);
174     json.endMember();
175
176     delete [] source;
177 }
178
179
180 static inline void
181 dumpShaders(JSONWriter &json)
182 {
183     json.beginMember("shaders");
184     json.beginObject();
185     dumpCurrentProgram(json);
186     dumpArbProgram(json, GL_FRAGMENT_PROGRAM_ARB);
187     dumpArbProgram(json, GL_VERTEX_PROGRAM_ARB);
188     json.endObject();
189     json.endMember(); //shaders
190 }
191
192
193 static inline void
194 dumpTextureImage(JSONWriter &json, GLenum target, GLint level)
195 {
196     GLint width, height = 1, depth = 1;
197
198     width = 0;
199     glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &width);
200
201     if (target != GL_TEXTURE_1D) {
202         height = 0;
203         glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &height);
204         if (target == GL_TEXTURE_3D) {
205             depth = 0;
206             glGetTexLevelParameteriv(target, level, GL_TEXTURE_DEPTH, &depth);
207         }
208     }
209
210     if (width <= 0 || height <= 0 || depth <= 0) {
211         return;
212     } else {
213         char label[512];
214
215         GLint active_texture = GL_TEXTURE0;
216         glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
217         snprintf(label, sizeof label, "%s, %s, level = %i", enumToString(active_texture), enumToString(target), level);
218
219         json.beginMember(label);
220
221         json.beginObject();
222
223         // Tell the GUI this is no ordinary object, but an image
224         json.writeStringMember("__class__", "image");
225
226         json.writeNumberMember("__width__", width);
227         json.writeNumberMember("__height__", height);
228         json.writeNumberMember("__depth__", depth);
229
230         // Hardcoded for now, but we could chose types more adequate to the
231         // texture internal format
232         json.writeStringMember("__type__", "uint8");
233         json.writeBoolMember("__normalized__", true);
234         json.writeNumberMember("__channels__", 4);
235
236         GLubyte *pixels = new GLubyte[depth*width*height*4];
237
238         glGetTexImage(target, level, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
239
240         json.beginMember("__data__");
241         char *pngBuffer;
242         int pngBufferSize;
243         Image::writePixelsToBuffer(pixels, width, height, 4, false, &pngBuffer, &pngBufferSize);
244         json.writeBase64(pngBuffer, pngBufferSize);
245         free(pngBuffer);
246         json.endMember(); // __data__
247
248         delete [] pixels;
249         json.endObject();
250     }
251 }
252
253
254 static inline void
255 dumpTexture(JSONWriter &json, GLenum target, GLenum binding)
256 {
257     GLint texture_binding = 0;
258     glGetIntegerv(binding, &texture_binding);
259     if (!glIsEnabled(target) && !texture_binding) {
260         return;
261     }
262
263     GLint level = 0;
264     do {
265         GLint width = 0, height = 0;
266         glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &width);
267         glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &height);
268         if (!width || !height) {
269             break;
270         }
271
272         if (target == GL_TEXTURE_CUBE_MAP) {
273             for (int face = 0; face < 6; ++face) {
274                 dumpTextureImage(json, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
275             }
276         } else {
277             dumpTextureImage(json, target, level);
278         }
279
280         ++level;
281     } while(true);
282 }
283
284
285 static inline void
286 dumpTextures(JSONWriter &json)
287 {
288     json.beginMember("textures");
289     json.beginObject();
290     GLint active_texture = GL_TEXTURE0;
291     glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
292     GLint max_texture_coords = 0;
293     glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);
294     GLint max_combined_texture_image_units = 0;
295     glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_combined_texture_image_units);
296     GLint max_units = std::max(max_combined_texture_image_units, max_texture_coords);
297     for (GLint unit = 0; unit < max_units; ++unit) {
298         GLenum texture = GL_TEXTURE0 + unit;
299         glActiveTexture(texture);
300         dumpTexture(json, GL_TEXTURE_1D, GL_TEXTURE_BINDING_1D);
301         dumpTexture(json, GL_TEXTURE_2D, GL_TEXTURE_BINDING_2D);
302         dumpTexture(json, GL_TEXTURE_3D, GL_TEXTURE_BINDING_3D);
303         dumpTexture(json, GL_TEXTURE_RECTANGLE, GL_TEXTURE_BINDING_RECTANGLE);
304         dumpTexture(json, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BINDING_CUBE_MAP);
305     }
306     glActiveTexture(active_texture);
307     json.endObject();
308     json.endMember(); // textures
309 }
310
311
312 static bool
313 getDrawableBounds(GLint *width, GLint *height) {
314 #if defined(_WIN32)
315
316     HDC hDC = wglGetCurrentDC();
317     if (!hDC) {
318         return false;
319     }
320
321     HWND hWnd = WindowFromDC(hDC);
322     RECT rect;
323
324     if (!GetClientRect(hWnd, &rect)) {
325        return false;
326     }
327
328     *width  = rect.right  - rect.left;
329     *height = rect.bottom - rect.top;
330
331 #elif 0 /* __APPLE__ */
332
333     CGLError CGLGetSurface(CGLContextObj, CGSConnectionID*, CGSWindowID*, CGSSurfaceID*);
334     CGError CGSGetWindowBounds(CGSConnectionID, CGWindowID, CGRect *ret);
335
336 #else
337
338     Display *display;
339     Drawable drawable;
340     Window root;
341     int x, y;
342     unsigned int w, h, bw, depth;
343
344     display = glXGetCurrentDisplay();
345     if (!display) {
346         return false;
347     }
348
349     drawable = glXGetCurrentDrawable();
350     if (drawable == None) {
351         return false;
352     }
353
354     if (!XGetGeometry(display, drawable, &root, &x, &y, &w, &h, &bw, &depth)) {
355         return false;
356     }
357
358     *width = w;
359     *height = h;
360
361 #endif
362
363     return true;
364 }
365
366
367 static inline void
368 dumpDrawBufferImage(JSONWriter &json, GLenum format)
369 {
370     GLint channels = __gl_format_channels(format);
371
372     GLint width, height;
373
374     if (!getDrawableBounds(&width, &height)) {
375         json.writeNull();
376     } else {
377         json.beginObject();
378
379         // Tell the GUI this is no ordinary object, but an image
380         json.writeStringMember("__class__", "image");
381
382         json.writeNumberMember("__width__", width);
383         json.writeNumberMember("__height__", height);
384         json.writeNumberMember("__depth__", 1);
385
386         // Hardcoded for now, but we could chose types more adequate to the
387         // texture internal format
388         json.writeStringMember("__type__", "uint8");
389         json.writeBoolMember("__normalized__", true);
390         json.writeNumberMember("__channels__", channels);
391
392         GLubyte *pixels = new GLubyte[width*height*channels];
393
394         GLint drawbuffer = GL_NONE;
395         GLint readbuffer = GL_NONE;
396         glGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);
397         glGetIntegerv(GL_READ_BUFFER, &readbuffer);
398         glReadBuffer(drawbuffer);
399
400         glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
401         glPixelStorei(GL_PACK_ALIGNMENT, 1);
402
403         glReadPixels(0, 0, width, height, format, GL_UNSIGNED_BYTE, pixels);
404
405         glPopClientAttrib();
406         glReadBuffer(readbuffer);
407
408         json.beginMember("__data__");
409         char *pngBuffer;
410         int pngBufferSize;
411         Image::writePixelsToBuffer(pixels, width, height, channels, false, &pngBuffer, &pngBufferSize);
412         //std::cerr <<" Before = "<<(width * height * channels * sizeof *pixels)
413         //          <<", after = "<<pngBufferSize << ", ratio = " << double(width * height * channels * sizeof *pixels)/pngBufferSize;
414         json.writeBase64(pngBuffer, pngBufferSize);
415         free(pngBuffer);
416         json.endMember(); // __data__
417
418         delete [] pixels;
419         json.endObject();
420     }
421 }
422
423
424 static inline GLuint
425 downsampledFramebuffer(GLuint oldFbo, GLint drawbuffer,
426                        GLint colorRb, GLint depthRb, GLint stencilRb,
427                        GLuint *rbs, GLint *numRbs)
428 {
429     GLuint fbo;
430     GLint format;
431     GLint w, h;
432
433     *numRbs = 0;
434
435     glGenFramebuffers(1, &fbo);
436     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
437
438     glBindRenderbuffer(GL_RENDERBUFFER, colorRb);
439     glGetRenderbufferParameteriv(GL_RENDERBUFFER,
440                                  GL_RENDERBUFFER_WIDTH, &w);
441     glGetRenderbufferParameteriv(GL_RENDERBUFFER,
442                                  GL_RENDERBUFFER_HEIGHT, &h);
443     glGetRenderbufferParameteriv(GL_RENDERBUFFER,
444                                  GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
445
446     glGenRenderbuffers(1, &rbs[*numRbs]);
447     glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
448     glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
449     glFramebufferRenderbuffer(GL_FRAMEBUFFER, drawbuffer,
450                               GL_RENDERBUFFER, rbs[*numRbs]);
451
452     glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
453     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
454     glDrawBuffer(drawbuffer);
455     glReadBuffer(drawbuffer);
456     glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
457                       GL_COLOR_BUFFER_BIT, GL_NEAREST);
458     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
459     ++*numRbs;
460
461     if (stencilRb == depthRb && stencilRb) {
462         //combined depth and stencil buffer
463         glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
464         glGetRenderbufferParameteriv(GL_RENDERBUFFER,
465                                      GL_RENDERBUFFER_WIDTH, &w);
466         glGetRenderbufferParameteriv(GL_RENDERBUFFER,
467                                      GL_RENDERBUFFER_HEIGHT, &h);
468         glGetRenderbufferParameteriv(GL_RENDERBUFFER,
469                                      GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
470
471         glGenRenderbuffers(1, &rbs[*numRbs]);
472         glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
473         glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
474         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
475                                   GL_RENDERBUFFER, rbs[*numRbs]);
476         glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
477         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
478         glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
479                           GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
480         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
481         ++*numRbs;
482     } else {
483         if (depthRb) {
484             glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
485             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
486                                          GL_RENDERBUFFER_WIDTH, &w);
487             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
488                                          GL_RENDERBUFFER_HEIGHT, &h);
489             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
490                                          GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
491
492             glGenRenderbuffers(1, &rbs[*numRbs]);
493             glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
494             glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
495             glFramebufferRenderbuffer(GL_FRAMEBUFFER,
496                                       GL_DEPTH_ATTACHMENT,
497                                       GL_RENDERBUFFER, rbs[*numRbs]);
498             glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
499             glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
500             glDrawBuffer(GL_DEPTH_ATTACHMENT);
501             glReadBuffer(GL_DEPTH_ATTACHMENT);
502             glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
503                               GL_DEPTH_BUFFER_BIT, GL_NEAREST);
504             ++*numRbs;
505         }
506         if (stencilRb) {
507             glBindRenderbuffer(GL_RENDERBUFFER, stencilRb);
508             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
509                                          GL_RENDERBUFFER_WIDTH, &w);
510             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
511                                          GL_RENDERBUFFER_HEIGHT, &h);
512             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
513                                      GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
514
515             glGenRenderbuffers(1, &rbs[*numRbs]);
516             glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
517             glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
518             glFramebufferRenderbuffer(GL_FRAMEBUFFER,
519                                       GL_STENCIL_ATTACHMENT,
520                                       GL_RENDERBUFFER, rbs[*numRbs]);
521             glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
522             glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
523             glDrawBuffer(GL_STENCIL_ATTACHMENT);
524             glReadBuffer(GL_STENCIL_ATTACHMENT);
525             glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
526                               GL_STENCIL_BUFFER_BIT, GL_NEAREST);
527             ++*numRbs;
528         }
529     }
530
531     return fbo;
532 }
533
534
535 static void
536 dumpDrawBuffers(JSONWriter &json, GLboolean dumpDepth, GLboolean dumpStencil)
537 {
538     json.beginMember("GL_RGBA");
539     dumpDrawBufferImage(json, GL_RGBA);
540     json.endMember();
541
542     if (dumpDepth) {
543         json.beginMember("GL_DEPTH_COMPONENT");
544         dumpDrawBufferImage(json, GL_DEPTH_COMPONENT);
545         json.endMember();
546     }
547
548     if (dumpStencil) {
549         json.beginMember("GL_STENCIL_INDEX");
550         dumpDrawBufferImage(json, GL_STENCIL_INDEX);
551         json.endMember();
552     }
553 }
554
555
556 static void
557 dumpFramebuffer(JSONWriter &json)
558 {
559     json.beginMember("framebuffer");
560     json.beginObject();
561
562     GLint boundDrawFbo = 0, boundReadFbo = 0;
563     glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &boundDrawFbo);
564     glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &boundReadFbo);
565     if (!boundDrawFbo) {
566         GLint depth_bits = 0;
567         glGetIntegerv(GL_DEPTH_BITS, &depth_bits);
568         GLint stencil_bits = 0;
569         glGetIntegerv(GL_STENCIL_BITS, &stencil_bits);
570         dumpDrawBuffers(json, depth_bits, stencil_bits);
571     } else {
572         GLint colorRb, stencilRb, depthRb;
573         GLint boundRb;
574         glGetIntegerv(GL_RENDERBUFFER_BINDING, &boundRb);
575         GLint drawbuffer = GL_NONE;
576         glGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);
577
578         glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
579                                               drawbuffer,
580                                               GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
581                                               &colorRb);
582         glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
583                                               GL_DEPTH_ATTACHMENT,
584                                               GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
585                                               &depthRb);
586         glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
587                                               GL_STENCIL_ATTACHMENT,
588                                               GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
589                                               &stencilRb);
590
591         GLint colorSamples, depthSamples, stencilSamples;
592         GLuint rbs[3];
593         GLint numRbs = 0;
594         GLuint fboCopy = 0;
595         glBindRenderbuffer(GL_RENDERBUFFER, colorRb);
596         glGetRenderbufferParameteriv(GL_RENDERBUFFER,
597                                      GL_RENDERBUFFER_SAMPLES, &colorSamples);
598         glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
599         glGetRenderbufferParameteriv(GL_RENDERBUFFER,
600                                      GL_RENDERBUFFER_SAMPLES, &depthSamples);
601         glBindRenderbuffer(GL_RENDERBUFFER, stencilRb);
602         glGetRenderbufferParameteriv(GL_RENDERBUFFER,
603                                      GL_RENDERBUFFER_SAMPLES, &stencilSamples);
604         glBindRenderbuffer(GL_RENDERBUFFER, boundRb);
605
606         if (colorSamples || depthSamples || stencilSamples) {
607             //glReadPixels doesnt support multisampled buffers so we need
608             // to blit the fbo to a temporary one
609             fboCopy = downsampledFramebuffer(boundDrawFbo, drawbuffer,
610                                              colorRb, depthRb, stencilRb,
611                                              rbs, &numRbs);
612         }
613         glDrawBuffer(drawbuffer);
614         glReadBuffer(drawbuffer);
615
616         dumpDrawBuffers(json, depthRb, stencilRb);
617
618         if (fboCopy) {
619             glBindFramebuffer(GL_FRAMEBUFFER, boundDrawFbo);
620             glBindFramebuffer(GL_READ_FRAMEBUFFER, boundReadFbo);
621             glBindFramebuffer(GL_DRAW_FRAMEBUFFER, boundDrawFbo);
622             glBindRenderbuffer(GL_RENDERBUFFER_BINDING, boundRb);
623             glDeleteRenderbuffers(numRbs, rbs);
624             glDeleteFramebuffers(1, &fboCopy);
625         }
626     }
627
628     json.endObject();
629     json.endMember(); // framebuffer
630 }
631
632
633 void dumpCurrentContext(std::ostream &os)
634 {
635     JSONWriter json(os);
636     dumpParameters(json);
637     dumpShaders(json);
638     dumpTextures(json);
639     dumpFramebuffer(json);
640 }
641
642
643 } /* namespace glstate */