]> git.cworth.org Git - apitrace/blob - glstate.cpp
Dump ARB program uniforms.
[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
29 #include <algorithm>
30 #include <iostream>
31 #include <map>
32 #include <sstream>
33
34 #include "image.hpp"
35 #include "json.hpp"
36 #include "glproc.hpp"
37 #include "glsize.hpp"
38 #include "glstate.hpp"
39
40
41 #ifdef __APPLE__
42
43 #include <Carbon/Carbon.h>
44
45 #ifdef __cplusplus
46 extern "C" {
47 #endif
48
49 OSStatus CGSGetSurfaceBounds(CGSConnectionID, CGWindowID, CGSSurfaceID, CGRect *);
50
51 #ifdef __cplusplus
52 }
53 #endif
54
55 #endif /* __APPLE__ */
56
57
58 namespace glstate {
59
60
61 static inline void
62 resetPixelPackState(void) {
63     glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
64     glPixelStorei(GL_PACK_SWAP_BYTES, GL_FALSE);
65     glPixelStorei(GL_PACK_LSB_FIRST, GL_FALSE);
66     glPixelStorei(GL_PACK_ROW_LENGTH, 0);
67     glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0);
68     glPixelStorei(GL_PACK_SKIP_ROWS, 0);
69     glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
70     glPixelStorei(GL_PACK_SKIP_IMAGES, 0);
71     glPixelStorei(GL_PACK_ALIGNMENT, 1);
72     glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
73 }
74
75
76 static inline void
77 restorePixelPackState(void) {
78     glPopClientAttrib();
79 }
80
81
82 // Mapping from shader type to shader source, used to accumulated the sources
83 // of different shaders with same type.
84 typedef std::map<std::string, std::string> ShaderMap;
85
86
87 static void
88 getShaderSource(ShaderMap &shaderMap, GLuint shader)
89 {
90     if (!shader) {
91         return;
92     }
93
94     GLint shader_type = 0;
95     glGetShaderiv(shader, GL_SHADER_TYPE, &shader_type);
96     if (!shader_type) {
97         return;
98     }
99
100     GLint source_length = 0;
101     glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &source_length);
102     if (!source_length) {
103         return;
104     }
105
106     GLchar *source = new GLchar[source_length];
107     GLsizei length = 0;
108     source[0] = 0;
109     glGetShaderSource(shader, source_length, &length, source);
110
111     shaderMap[enumToString(shader_type)] += source;
112
113     delete [] source;
114 }
115
116
117 static void
118 getShaderObjSource(ShaderMap &shaderMap, GLhandleARB shaderObj)
119 {
120     if (!shaderObj) {
121         return;
122     }
123
124     GLint shader_type = 0;
125     glGetObjectParameterivARB(shaderObj, GL_OBJECT_TYPE_ARB, &shader_type);
126     if (!shader_type) {
127         return;
128     }
129
130     GLint source_length = 0;
131     glGetObjectParameterivARB(shaderObj, GL_OBJECT_SHADER_SOURCE_LENGTH_ARB, &source_length);
132     if (!source_length) {
133         return;
134     }
135
136     GLcharARB *source = new GLcharARB[source_length];
137     GLsizei length = 0;
138     source[0] = 0;
139     glGetShaderSource(shaderObj, source_length, &length, source);
140
141     shaderMap[enumToString(shader_type)] += source;
142
143     delete [] source;
144 }
145
146
147 static inline void
148 dumpCurrentProgram(JSONWriter &json)
149 {
150     GLint program = 0;
151     glGetIntegerv(GL_CURRENT_PROGRAM, &program);
152     if (!program) {
153         return;
154     }
155
156     GLint attached_shaders = 0;
157     glGetProgramiv(program, GL_ATTACHED_SHADERS, &attached_shaders);
158     if (!attached_shaders) {
159         return;
160     }
161
162     ShaderMap shaderMap;
163
164     GLuint *shaders = new GLuint[attached_shaders];
165     GLsizei count = 0;
166     glGetAttachedShaders(program, attached_shaders, &count, shaders);
167     std::sort(shaders, shaders + count);
168     for (GLsizei i = 0; i < count; ++ i) {
169        getShaderSource(shaderMap, shaders[i]);
170     }
171     delete [] shaders;
172
173     for (ShaderMap::const_iterator it = shaderMap.begin(); it != shaderMap.end(); ++it) {
174         json.beginMember(it->first);
175         json.writeString(it->second);
176         json.endMember();
177     }
178 }
179
180
181 static inline void
182 dumpCurrentProgramObj(JSONWriter &json)
183 {
184     GLhandleARB programObj = glGetHandleARB(GL_PROGRAM_OBJECT_ARB);
185     if (!programObj) {
186         return;
187     }
188
189     GLint attached_shaders = 0;
190     glGetObjectParameterivARB(programObj, GL_OBJECT_ATTACHED_OBJECTS_ARB, &attached_shaders);
191     if (!attached_shaders) {
192         return;
193     }
194
195     ShaderMap shaderMap;
196
197     GLhandleARB *shaderObjs = new GLhandleARB[attached_shaders];
198     GLsizei count = 0;
199     glGetAttachedObjectsARB(programObj, attached_shaders, &count, shaderObjs);
200     std::sort(shaderObjs, shaderObjs + count);
201     for (GLsizei i = 0; i < count; ++ i) {
202        getShaderObjSource(shaderMap, shaderObjs[i]);
203     }
204     delete [] shaderObjs;
205
206     for (ShaderMap::const_iterator it = shaderMap.begin(); it != shaderMap.end(); ++it) {
207         json.beginMember(it->first);
208         json.writeString(it->second);
209         json.endMember();
210     }
211 }
212
213
214 static void
215 dumpUniform(JSONWriter &json, GLint program, GLint size, GLenum type, const GLchar *name) {
216     
217     GLenum elemType;
218     GLint numElems;
219     __gl_uniform_size(type, elemType, numElems);
220     if (elemType == GL_NONE) {
221         return;
222     }
223
224     GLfloat fvalues[4*4];
225     GLdouble dvalues[4*4];
226     GLint ivalues[4*4];
227     GLuint uivalues[4*4];
228
229     GLint i, j;
230
231     for (i = 0; i < size; ++i) {
232         std::stringstream ss;
233         ss << name;
234
235         if (size > 1) {
236             ss << '[' << i << ']';
237         }
238
239         std::string elemName = ss.str();
240
241         json.beginMember(elemName);
242
243         GLint location = glGetUniformLocation(program, elemName.c_str());
244
245         if (numElems > 1) {
246             json.beginArray();
247         }
248
249         switch (elemType) {
250         case GL_FLOAT:
251             glGetUniformfv(program, location, fvalues);
252             for (j = 0; j < numElems; ++j) {
253                 json.writeNumber(fvalues[j]);
254             }
255             break;
256         case GL_DOUBLE:
257             glGetUniformdv(program, location, dvalues);
258             for (j = 0; j < numElems; ++j) {
259                 json.writeNumber(dvalues[j]);
260             }
261             break;
262         case GL_INT:
263             glGetUniformiv(program, location, ivalues);
264             for (j = 0; j < numElems; ++j) {
265                 json.writeNumber(ivalues[j]);
266             }
267             break;
268         case GL_UNSIGNED_INT:
269             glGetUniformuiv(program, location, uivalues);
270             for (j = 0; j < numElems; ++j) {
271                 json.writeNumber(uivalues[j]);
272             }
273             break;
274         case GL_BOOL:
275             glGetUniformiv(program, location, ivalues);
276             for (j = 0; j < numElems; ++j) {
277                 json.writeBool(ivalues[j]);
278             }
279             break;
280         default:
281             assert(0);
282             break;
283         }
284
285         if (numElems > 1) {
286             json.endArray();
287         }
288
289         json.endMember();
290     }
291 }
292
293
294 static void
295 dumpUniformARB(JSONWriter &json, GLhandleARB programObj, GLint size, GLenum type, const GLchar *name) {
296
297     GLenum elemType;
298     GLint numElems;
299     __gl_uniform_size(type, elemType, numElems);
300     if (elemType == GL_NONE) {
301         return;
302     }
303
304     GLfloat fvalues[4*4];
305     GLint ivalues[4*4];
306
307     GLint i, j;
308
309     for (i = 0; i < size; ++i) {
310         std::stringstream ss;
311         ss << name;
312
313         if (size > 1) {
314             ss << '[' << i << ']';
315         }
316
317         std::string elemName = ss.str();
318
319         json.beginMember(elemName);
320
321         GLint location = glGetUniformLocationARB(programObj, elemName.c_str());
322
323         if (numElems > 1) {
324             json.beginArray();
325         }
326
327         switch (elemType) {
328         case GL_DOUBLE:
329             // glGetUniformdvARB does not exists
330         case GL_FLOAT:
331             glGetUniformfvARB(programObj, location, fvalues);
332             for (j = 0; j < numElems; ++j) {
333                 json.writeNumber(fvalues[j]);
334             }
335             break;
336         case GL_UNSIGNED_INT:
337             // glGetUniformuivARB does not exists
338         case GL_INT:
339             glGetUniformivARB(programObj, location, ivalues);
340             for (j = 0; j < numElems; ++j) {
341                 json.writeNumber(ivalues[j]);
342             }
343             break;
344         case GL_BOOL:
345             glGetUniformivARB(programObj, location, ivalues);
346             for (j = 0; j < numElems; ++j) {
347                 json.writeBool(ivalues[j]);
348             }
349             break;
350         default:
351             assert(0);
352             break;
353         }
354
355         if (numElems > 1) {
356             json.endArray();
357         }
358
359         json.endMember();
360     }
361 }
362
363
364 static inline void
365 dumpCurrentProgramUniforms(JSONWriter &json)
366 {
367     GLint program = 0;
368     glGetIntegerv(GL_CURRENT_PROGRAM, &program);
369     if (!program) {
370         return;
371     }
372
373     GLint active_uniforms = 0;
374     glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &active_uniforms);
375     if (!active_uniforms) {
376         return;
377     }
378
379     GLint active_uniform_max_length = 0;
380     glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &active_uniform_max_length);
381     GLchar *name = new GLchar[active_uniform_max_length];
382     if (!name) {
383         return;
384     }
385
386     for (GLint index = 0; index < active_uniforms; ++index) {
387         GLsizei length = 0;
388         GLint size = 0;
389         GLenum type = GL_NONE;
390         glGetActiveUniform(program, index, active_uniform_max_length, &length, &size, &type, name);
391
392         dumpUniform(json, program, size, type, name);
393     }
394
395     delete [] name;
396 }
397
398
399 static inline void
400 dumpCurrentProgramUniformsARB(JSONWriter &json)
401 {
402     GLhandleARB programObj = glGetHandleARB(GL_PROGRAM_OBJECT_ARB);
403     if (!programObj) {
404         return;
405     }
406
407     GLint active_uniforms = 0;
408     glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &active_uniforms);
409     if (!active_uniforms) {
410         return;
411     }
412
413     GLint active_uniform_max_length = 0;
414     glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB, &active_uniform_max_length);
415     GLchar *name = new GLchar[active_uniform_max_length];
416     if (!name) {
417         return;
418     }
419
420     for (GLint index = 0; index < active_uniforms; ++index) {
421         GLsizei length = 0;
422         GLint size = 0;
423         GLenum type = GL_NONE;
424         glGetActiveUniformARB(programObj, index, active_uniform_max_length, &length, &size, &type, name);
425
426         dumpUniformARB(json, programObj, size, type, name);
427     }
428
429     delete [] name;
430 }
431
432
433 static inline void
434 dumpArbProgram(JSONWriter &json, GLenum target)
435 {
436     if (!glIsEnabled(target)) {
437         return;
438     }
439
440     GLint program_length = 0;
441     glGetProgramivARB(target, GL_PROGRAM_LENGTH_ARB, &program_length);
442     if (!program_length) {
443         return;
444     }
445
446     GLchar *source = new GLchar[program_length + 1];
447     source[0] = 0;
448     glGetProgramStringARB(target, GL_PROGRAM_STRING_ARB, source);
449     source[program_length] = 0;
450
451     json.beginMember(enumToString(target));
452     json.writeString(source);
453     json.endMember();
454
455     delete [] source;
456 }
457
458
459 static inline void
460 dumpProgramUniformsARB(JSONWriter &json, GLenum target, const char *prefix)
461 {
462     if (!glIsEnabled(target)) {
463         return;
464     }
465
466     GLint program_parameters = 0;
467     glGetProgramivARB(target, GL_PROGRAM_PARAMETERS_ARB, &program_parameters);
468     if (!program_parameters) {
469         return;
470     }
471
472     GLint max_program_local_parameters = 0;
473     glGetProgramivARB(target, GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB, &max_program_local_parameters);
474     for (GLuint index = 0; index < max_program_local_parameters; ++index) {
475         GLdouble params[4] = {0, 0, 0, 0};
476         glGetProgramLocalParameterdvARB(target, index, params);
477
478         if (!params[0] && !params[1] && !params[2] && !params[3]) {
479             continue;
480         }
481
482         char name[256];
483         snprintf(name, sizeof name, "%sprogram.local[%u]", prefix, index);
484
485         json.beginMember(name);
486         json.beginArray();
487         json.writeNumber(params[0]);
488         json.writeNumber(params[1]);
489         json.writeNumber(params[2]);
490         json.writeNumber(params[3]);
491         json.endArray();
492         json.endMember();
493     }
494
495     GLint max_program_env_parameters = 0;
496     glGetProgramivARB(target, GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, &max_program_env_parameters);
497     for (GLuint index = 0; index < max_program_env_parameters; ++index) {
498         GLdouble params[4] = {0, 0, 0, 0};
499         glGetProgramEnvParameterdvARB(target, index, params);
500
501         if (!params[0] && !params[1] && !params[2] && !params[3]) {
502             continue;
503         }
504
505         char name[256];
506         snprintf(name, sizeof name, "%sprogram.env[%u]", prefix, index);
507
508         json.beginMember(name);
509         json.beginArray();
510         json.writeNumber(params[0]);
511         json.writeNumber(params[1]);
512         json.writeNumber(params[2]);
513         json.writeNumber(params[3]);
514         json.endArray();
515         json.endMember();
516     }
517 }
518
519
520 static inline void
521 dumpShaders(JSONWriter &json)
522 {
523     json.beginMember("shaders");
524     json.beginObject();
525     dumpCurrentProgram(json);
526     dumpCurrentProgramObj(json);
527     dumpArbProgram(json, GL_FRAGMENT_PROGRAM_ARB);
528     dumpArbProgram(json, GL_VERTEX_PROGRAM_ARB);
529     json.endObject();
530     json.endMember(); // shaders
531 }
532
533
534 static inline void
535 dumpUniforms(JSONWriter &json)
536 {
537     json.beginMember("uniforms");
538     json.beginObject();
539     dumpCurrentProgramUniforms(json);
540     dumpCurrentProgramUniformsARB(json);
541     dumpProgramUniformsARB(json, GL_FRAGMENT_PROGRAM_ARB, "fp.");
542     dumpProgramUniformsARB(json, GL_VERTEX_PROGRAM_ARB, "vp.");
543     json.endObject();
544     json.endMember(); // uniforms
545 }
546
547
548 static inline void
549 dumpTextureImage(JSONWriter &json, GLenum target, GLint level)
550 {
551     GLint width, height = 1, depth = 1;
552
553     width = 0;
554     glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &width);
555
556     if (target != GL_TEXTURE_1D) {
557         height = 0;
558         glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &height);
559         if (target == GL_TEXTURE_3D) {
560             depth = 0;
561             glGetTexLevelParameteriv(target, level, GL_TEXTURE_DEPTH, &depth);
562         }
563     }
564
565     if (width <= 0 || height <= 0 || depth <= 0) {
566         return;
567     } else {
568         char label[512];
569
570         GLint active_texture = GL_TEXTURE0;
571         glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
572         snprintf(label, sizeof label, "%s, %s, level = %i", enumToString(active_texture), enumToString(target), level);
573
574         json.beginMember(label);
575
576         json.beginObject();
577
578         // Tell the GUI this is no ordinary object, but an image
579         json.writeStringMember("__class__", "image");
580
581         json.writeNumberMember("__width__", width);
582         json.writeNumberMember("__height__", height);
583         json.writeNumberMember("__depth__", depth);
584
585         // Hardcoded for now, but we could chose types more adequate to the
586         // texture internal format
587         json.writeStringMember("__type__", "uint8");
588         json.writeBoolMember("__normalized__", true);
589         json.writeNumberMember("__channels__", 4);
590
591         GLubyte *pixels = new GLubyte[depth*width*height*4];
592
593         resetPixelPackState();
594
595         glGetTexImage(target, level, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
596
597         restorePixelPackState();
598
599         json.beginMember("__data__");
600         char *pngBuffer;
601         int pngBufferSize;
602         Image::writePixelsToBuffer(pixels, width, height, 4, false, &pngBuffer, &pngBufferSize);
603         json.writeBase64(pngBuffer, pngBufferSize);
604         free(pngBuffer);
605         json.endMember(); // __data__
606
607         delete [] pixels;
608         json.endObject();
609     }
610 }
611
612
613 static inline void
614 dumpTexture(JSONWriter &json, GLenum target, GLenum binding)
615 {
616     GLint texture_binding = 0;
617     glGetIntegerv(binding, &texture_binding);
618     if (!glIsEnabled(target) && !texture_binding) {
619         return;
620     }
621
622     GLint level = 0;
623     do {
624         GLint width = 0, height = 0;
625         glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &width);
626         glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &height);
627         if (!width || !height) {
628             break;
629         }
630
631         if (target == GL_TEXTURE_CUBE_MAP) {
632             for (int face = 0; face < 6; ++face) {
633                 dumpTextureImage(json, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
634             }
635         } else {
636             dumpTextureImage(json, target, level);
637         }
638
639         ++level;
640     } while(true);
641 }
642
643
644 static inline void
645 dumpTextures(JSONWriter &json)
646 {
647     json.beginMember("textures");
648     json.beginObject();
649     GLint active_texture = GL_TEXTURE0;
650     glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
651     GLint max_texture_coords = 0;
652     glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);
653     GLint max_combined_texture_image_units = 0;
654     glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_combined_texture_image_units);
655     GLint max_units = std::max(max_combined_texture_image_units, max_texture_coords);
656     for (GLint unit = 0; unit < max_units; ++unit) {
657         GLenum texture = GL_TEXTURE0 + unit;
658         glActiveTexture(texture);
659         dumpTexture(json, GL_TEXTURE_1D, GL_TEXTURE_BINDING_1D);
660         dumpTexture(json, GL_TEXTURE_2D, GL_TEXTURE_BINDING_2D);
661         dumpTexture(json, GL_TEXTURE_3D, GL_TEXTURE_BINDING_3D);
662         dumpTexture(json, GL_TEXTURE_RECTANGLE, GL_TEXTURE_BINDING_RECTANGLE);
663         dumpTexture(json, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BINDING_CUBE_MAP);
664     }
665     glActiveTexture(active_texture);
666     json.endObject();
667     json.endMember(); // textures
668 }
669
670
671 static bool
672 getDrawableBounds(GLint *width, GLint *height) {
673 #if defined(_WIN32)
674
675     HDC hDC = wglGetCurrentDC();
676     if (!hDC) {
677         return false;
678     }
679
680     HWND hWnd = WindowFromDC(hDC);
681     RECT rect;
682
683     if (!GetClientRect(hWnd, &rect)) {
684        return false;
685     }
686
687     *width  = rect.right  - rect.left;
688     *height = rect.bottom - rect.top;
689
690 #elif defined(__APPLE__)
691
692     CGLContextObj ctx = CGLGetCurrentContext();
693     if (ctx == NULL) {
694         return false;
695     }
696
697     CGSConnectionID cid;
698     CGSWindowID wid;
699     CGSSurfaceID sid;
700
701     if (CGLGetSurface(ctx, &cid, &wid, &sid) != kCGLNoError) {
702         return false;
703     }
704
705     CGRect rect;
706
707     if (CGSGetSurfaceBounds(cid, wid, sid, &rect) != 0) {
708         return false;
709     }
710
711     *width = rect.size.width;
712     *height = rect.size.height;
713
714 #else
715
716     Display *display;
717     Drawable drawable;
718     Window root;
719     int x, y;
720     unsigned int w, h, bw, depth;
721
722     display = glXGetCurrentDisplay();
723     if (!display) {
724         return false;
725     }
726
727     drawable = glXGetCurrentDrawable();
728     if (drawable == None) {
729         return false;
730     }
731
732     if (!XGetGeometry(display, drawable, &root, &x, &y, &w, &h, &bw, &depth)) {
733         return false;
734     }
735
736     *width = w;
737     *height = h;
738
739 #endif
740
741     return true;
742 }
743
744
745 static const GLenum texture_bindings[][2] = {
746     {GL_TEXTURE_1D, GL_TEXTURE_BINDING_1D},
747     {GL_TEXTURE_2D, GL_TEXTURE_BINDING_2D},
748     {GL_TEXTURE_3D, GL_TEXTURE_BINDING_3D},
749     {GL_TEXTURE_RECTANGLE, GL_TEXTURE_BINDING_RECTANGLE},
750     {GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BINDING_CUBE_MAP}
751 };
752
753
754 static bool
755 bindTexture(GLint texture, GLenum &target, GLint &bound_texture)
756 {
757
758     for (unsigned i = 0; i < sizeof(texture_bindings)/sizeof(texture_bindings[0]); ++i) {
759         target  = texture_bindings[i][0];
760
761         GLenum binding = texture_bindings[i][1];
762
763         while (glGetError() != GL_NO_ERROR)
764             ;
765
766         glGetIntegerv(binding, &bound_texture);
767         glBindTexture(target, texture);
768
769         if (glGetError() == GL_NO_ERROR) {
770             return true;
771         }
772
773         glBindTexture(target, bound_texture);
774     }
775
776     target = GL_NONE;
777
778     return false;
779 }
780
781
782 static bool
783 getTextureLevelSize(GLint texture, GLint level, GLint *width, GLint *height)
784 {
785     *width = 0;
786     *height = 0;
787
788     GLenum target;
789     GLint bound_texture = 0;
790     if (!bindTexture(texture, target, bound_texture)) {
791         return false;
792     }
793
794     glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, width);
795     glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, height);
796
797     glBindTexture(target, bound_texture);
798
799     return *width > 0 && *height > 0;
800 }
801
802
803 static bool
804 getRenderbufferSize(GLint renderbuffer, GLint *width, GLint *height)
805 {
806     GLint bound_renderbuffer = 0;
807     glGetIntegerv(GL_RENDERBUFFER_BINDING, &bound_renderbuffer);
808     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
809
810     *width = 0;
811     *height = 0;
812     glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, width);
813     glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, height);
814
815     glBindRenderbuffer(GL_RENDERBUFFER, bound_renderbuffer);
816     
817     return *width > 0 && *height > 0;
818 }
819
820
821 static bool
822 getFramebufferAttachmentSize(GLenum target, GLenum attachment, GLint *width, GLint *height)
823 {
824     GLint object_type = GL_NONE;
825     glGetFramebufferAttachmentParameteriv(target, attachment,
826                                           GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
827                                           &object_type);
828     if (object_type == GL_NONE) {
829         return false;
830     }
831
832     GLint object_name = 0;
833     glGetFramebufferAttachmentParameteriv(target, attachment,
834                                           GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
835                                           &object_name);
836     if (object_name == 0) {
837         return false;
838     }
839
840     if (object_type == GL_RENDERBUFFER) {
841         return getRenderbufferSize(object_name, width, height);
842     } else if (object_type == GL_TEXTURE) {
843         GLint texture_level = 0;
844         glGetFramebufferAttachmentParameteriv(target, attachment,
845                                               GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL,
846                                               &texture_level);
847         return getTextureLevelSize(object_name, texture_level, width, height);
848     } else {
849         std::cerr << "warning: unexpected GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = " << object_type << "\n";
850         return false;
851     }
852 }
853
854
855 Image::Image *
856 getDrawBufferImage(GLenum format) {
857     GLint channels = __gl_format_channels(format);
858     if (channels > 4) {
859         return NULL;
860     }
861
862     GLint draw_framebuffer = 0;
863     glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &draw_framebuffer);
864
865     GLint draw_buffer = GL_NONE;
866     GLint width, height;
867     if (draw_framebuffer) {
868         glGetIntegerv(GL_DRAW_BUFFER0, &draw_buffer);
869         if (draw_buffer == GL_NONE) {
870             return NULL;
871         }
872
873         if (!getFramebufferAttachmentSize(GL_DRAW_FRAMEBUFFER, draw_buffer, &width, &height)) {
874             return NULL;
875         }
876     } else {
877         glGetIntegerv(GL_DRAW_BUFFER, &draw_buffer);
878         if (draw_buffer == GL_NONE) {
879             return NULL;
880         }
881
882         if (!getDrawableBounds(&width, &height)) {
883             return NULL;
884         }
885     }
886
887     Image::Image *image = new Image::Image(width, height, channels, true);
888     if (!image) {
889         return NULL;
890     }
891
892     while (glGetError() != GL_NO_ERROR) {}
893
894     GLint read_framebuffer = 0;
895     glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &read_framebuffer);
896     glBindFramebuffer(GL_READ_FRAMEBUFFER, draw_framebuffer);
897
898     GLint read_buffer = 0;
899     glGetIntegerv(GL_READ_BUFFER, &read_buffer);
900     glReadBuffer(draw_buffer);
901
902     // TODO: reset imaging state too
903     resetPixelPackState();
904
905     glReadPixels(0, 0, width, height, format, GL_UNSIGNED_BYTE, image->pixels);
906
907     restorePixelPackState();
908     glReadBuffer(read_buffer);
909     glBindFramebuffer(GL_READ_FRAMEBUFFER, read_framebuffer);
910
911     GLenum error = glGetError();
912     if (error != GL_NO_ERROR) {
913         do {
914             std::cerr << "warning: " << enumToString(error) << " while getting snapshot\n";
915             error = glGetError();
916         } while(error != GL_NO_ERROR);
917         delete image;
918         return NULL;
919     }
920      
921     return image;
922 }
923
924
925 /**
926  * Dump the image of the currently bound read buffer.
927  */
928 static inline void
929 dumpReadBufferImage(JSONWriter &json, GLint width, GLint height, GLenum format)
930 {
931     GLint channels = __gl_format_channels(format);
932
933     json.beginObject();
934
935     // Tell the GUI this is no ordinary object, but an image
936     json.writeStringMember("__class__", "image");
937
938     json.writeNumberMember("__width__", width);
939     json.writeNumberMember("__height__", height);
940     json.writeNumberMember("__depth__", 1);
941
942     // Hardcoded for now, but we could chose types more adequate to the
943     // texture internal format
944     json.writeStringMember("__type__", "uint8");
945     json.writeBoolMember("__normalized__", true);
946     json.writeNumberMember("__channels__", channels);
947
948     GLubyte *pixels = new GLubyte[width*height*channels];
949
950     // TODO: reset imaging state too
951     resetPixelPackState();
952
953     glReadPixels(0, 0, width, height, format, GL_UNSIGNED_BYTE, pixels);
954
955     restorePixelPackState();
956
957     json.beginMember("__data__");
958     char *pngBuffer;
959     int pngBufferSize;
960     Image::writePixelsToBuffer(pixels, width, height, channels, false, &pngBuffer, &pngBufferSize);
961     //std::cerr <<" Before = "<<(width * height * channels * sizeof *pixels)
962     //          <<", after = "<<pngBufferSize << ", ratio = " << double(width * height * channels * sizeof *pixels)/pngBufferSize;
963     json.writeBase64(pngBuffer, pngBufferSize);
964     free(pngBuffer);
965     json.endMember(); // __data__
966
967     delete [] pixels;
968     json.endObject();
969 }
970
971
972 static inline GLuint
973 downsampledFramebuffer(GLuint oldFbo, GLint drawbuffer,
974                        GLint colorRb, GLint depthRb, GLint stencilRb,
975                        GLuint *rbs, GLint *numRbs)
976 {
977     GLuint fbo;
978     GLint format;
979     GLint w, h;
980
981     *numRbs = 0;
982
983     glGenFramebuffers(1, &fbo);
984     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
985
986     glBindRenderbuffer(GL_RENDERBUFFER, colorRb);
987     glGetRenderbufferParameteriv(GL_RENDERBUFFER,
988                                  GL_RENDERBUFFER_WIDTH, &w);
989     glGetRenderbufferParameteriv(GL_RENDERBUFFER,
990                                  GL_RENDERBUFFER_HEIGHT, &h);
991     glGetRenderbufferParameteriv(GL_RENDERBUFFER,
992                                  GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
993
994     glGenRenderbuffers(1, &rbs[*numRbs]);
995     glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
996     glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
997     glFramebufferRenderbuffer(GL_FRAMEBUFFER, drawbuffer,
998                               GL_RENDERBUFFER, rbs[*numRbs]);
999
1000     glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
1001     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
1002     glDrawBuffer(drawbuffer);
1003     glReadBuffer(drawbuffer);
1004     glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
1005                       GL_COLOR_BUFFER_BIT, GL_NEAREST);
1006     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1007     ++*numRbs;
1008
1009     if (stencilRb == depthRb && stencilRb) {
1010         //combined depth and stencil buffer
1011         glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
1012         glGetRenderbufferParameteriv(GL_RENDERBUFFER,
1013                                      GL_RENDERBUFFER_WIDTH, &w);
1014         glGetRenderbufferParameteriv(GL_RENDERBUFFER,
1015                                      GL_RENDERBUFFER_HEIGHT, &h);
1016         glGetRenderbufferParameteriv(GL_RENDERBUFFER,
1017                                      GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
1018
1019         glGenRenderbuffers(1, &rbs[*numRbs]);
1020         glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
1021         glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
1022         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
1023                                   GL_RENDERBUFFER, rbs[*numRbs]);
1024         glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
1025         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
1026         glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
1027                           GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
1028         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1029         ++*numRbs;
1030     } else {
1031         if (depthRb) {
1032             glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
1033             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
1034                                          GL_RENDERBUFFER_WIDTH, &w);
1035             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
1036                                          GL_RENDERBUFFER_HEIGHT, &h);
1037             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
1038                                          GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
1039
1040             glGenRenderbuffers(1, &rbs[*numRbs]);
1041             glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
1042             glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
1043             glFramebufferRenderbuffer(GL_FRAMEBUFFER,
1044                                       GL_DEPTH_ATTACHMENT,
1045                                       GL_RENDERBUFFER, rbs[*numRbs]);
1046             glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
1047             glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
1048             glDrawBuffer(GL_DEPTH_ATTACHMENT);
1049             glReadBuffer(GL_DEPTH_ATTACHMENT);
1050             glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
1051                               GL_DEPTH_BUFFER_BIT, GL_NEAREST);
1052             ++*numRbs;
1053         }
1054         if (stencilRb) {
1055             glBindRenderbuffer(GL_RENDERBUFFER, stencilRb);
1056             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
1057                                          GL_RENDERBUFFER_WIDTH, &w);
1058             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
1059                                          GL_RENDERBUFFER_HEIGHT, &h);
1060             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
1061                                      GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
1062
1063             glGenRenderbuffers(1, &rbs[*numRbs]);
1064             glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
1065             glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
1066             glFramebufferRenderbuffer(GL_FRAMEBUFFER,
1067                                       GL_STENCIL_ATTACHMENT,
1068                                       GL_RENDERBUFFER, rbs[*numRbs]);
1069             glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
1070             glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
1071             glDrawBuffer(GL_STENCIL_ATTACHMENT);
1072             glReadBuffer(GL_STENCIL_ATTACHMENT);
1073             glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
1074                               GL_STENCIL_BUFFER_BIT, GL_NEAREST);
1075             ++*numRbs;
1076         }
1077     }
1078
1079     return fbo;
1080 }
1081
1082
1083 /**
1084  * Dump images of current draw drawable/window.
1085  */
1086 static void
1087 dumpDrawableImages(JSONWriter &json)
1088 {
1089     GLint width, height;
1090
1091     if (!getDrawableBounds(&width, &height)) {
1092         return;
1093     }
1094
1095     GLint draw_buffer = GL_NONE;
1096     glGetIntegerv(GL_DRAW_BUFFER, &draw_buffer);
1097     glReadBuffer(draw_buffer);
1098
1099     if (draw_buffer != GL_NONE) {
1100         GLint read_buffer = GL_NONE;
1101         glGetIntegerv(GL_READ_BUFFER, &read_buffer);
1102
1103         GLint alpha_bits = 0;
1104         glGetIntegerv(GL_ALPHA_BITS, &alpha_bits);
1105         GLenum format = alpha_bits ? GL_RGBA : GL_RGB;
1106         json.beginMember(enumToString(draw_buffer));
1107         dumpReadBufferImage(json, width, height, format);
1108         json.endMember();
1109
1110         glReadBuffer(read_buffer);
1111     }
1112
1113     GLint depth_bits = 0;
1114     glGetIntegerv(GL_DEPTH_BITS, &depth_bits);
1115     if (depth_bits) {
1116         json.beginMember("GL_DEPTH_COMPONENT");
1117         dumpReadBufferImage(json, width, height, GL_DEPTH_COMPONENT);
1118         json.endMember();
1119     }
1120
1121     GLint stencil_bits = 0;
1122     glGetIntegerv(GL_STENCIL_BITS, &stencil_bits);
1123     if (stencil_bits) {
1124         json.beginMember("GL_STENCIL_INDEX");
1125         dumpReadBufferImage(json, width, height, GL_STENCIL_INDEX);
1126         json.endMember();
1127     }
1128 }
1129 /**
1130  * Dump the specified framebuffer attachment.
1131  *
1132  * In the case of a color attachment, it assumes it is already bound for read.
1133  */
1134 static void
1135 dumpFramebufferAttachment(JSONWriter &json, GLenum target, GLenum attachment, GLenum format)
1136 {
1137     GLint width = 0, height = 0;
1138     if (!getFramebufferAttachmentSize(target, attachment, &width, &height)) {
1139         return;
1140     }
1141
1142     json.beginMember(enumToString(attachment));
1143     dumpReadBufferImage(json, width, height, format);
1144     json.endMember();
1145 }
1146
1147
1148 static void
1149 dumpFramebufferAttachments(JSONWriter &json, GLenum target)
1150 {
1151     GLint read_framebuffer = 0;
1152     glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &read_framebuffer);
1153
1154     GLint read_buffer = GL_NONE;
1155     glGetIntegerv(GL_READ_BUFFER, &read_buffer);
1156
1157     GLint max_draw_buffers = 1;
1158     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &max_draw_buffers);
1159     GLint max_color_attachments = 0;
1160     glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &max_color_attachments);
1161
1162     for (GLint i = 0; i < max_draw_buffers; ++i) {
1163         GLint draw_buffer = GL_NONE;
1164         glGetIntegerv(GL_DRAW_BUFFER0 + i, &draw_buffer);
1165         if (draw_buffer != GL_NONE) {
1166             glReadBuffer(draw_buffer);
1167             GLint attachment;
1168             if (draw_buffer >= GL_COLOR_ATTACHMENT0 && draw_buffer < GL_COLOR_ATTACHMENT0 + max_color_attachments) {
1169                 attachment = draw_buffer;
1170             } else {
1171                 std::cerr << "warning: unexpected GL_DRAW_BUFFER" << i << " = " << draw_buffer << "\n";
1172                 attachment = GL_COLOR_ATTACHMENT0;
1173             }
1174             GLint alpha_size = 0;
1175             glGetFramebufferAttachmentParameteriv(target, attachment,
1176                                                   GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE,
1177                                                   &alpha_size);
1178             GLenum format = alpha_size ? GL_RGBA : GL_RGB;
1179             dumpFramebufferAttachment(json, target, attachment, format);
1180         }
1181     }
1182
1183     glReadBuffer(read_buffer);
1184
1185     dumpFramebufferAttachment(json, target, GL_DEPTH_ATTACHMENT, GL_DEPTH_COMPONENT);
1186     dumpFramebufferAttachment(json, target, GL_STENCIL_ATTACHMENT, GL_STENCIL_INDEX);
1187
1188     glBindFramebuffer(GL_READ_FRAMEBUFFER, read_framebuffer);
1189 }
1190
1191
1192 static void
1193 dumpFramebuffer(JSONWriter &json)
1194 {
1195     json.beginMember("framebuffer");
1196     json.beginObject();
1197
1198     GLint boundDrawFbo = 0, boundReadFbo = 0;
1199     glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &boundDrawFbo);
1200     glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &boundReadFbo);
1201     if (!boundDrawFbo) {
1202         dumpDrawableImages(json);
1203     } else {
1204         GLint colorRb = 0, stencilRb = 0, depthRb = 0;
1205         GLint draw_buffer0 = GL_NONE;
1206         glGetIntegerv(GL_DRAW_BUFFER0, &draw_buffer0);
1207         bool multisample = false;
1208
1209         GLint boundRb = 0;
1210         glGetIntegerv(GL_RENDERBUFFER_BINDING, &boundRb);
1211
1212         GLint object_type;
1213         glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, draw_buffer0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &object_type);
1214         if (object_type == GL_RENDERBUFFER) {
1215             glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, draw_buffer0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &colorRb);
1216             glBindRenderbuffer(GL_RENDERBUFFER, colorRb);
1217             GLint samples = 0;
1218             glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
1219             if (samples) {
1220                 multisample = true;
1221             }
1222         }
1223
1224         glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &object_type);
1225         if (object_type == GL_RENDERBUFFER) {
1226             glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &depthRb);
1227             glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
1228             GLint samples = 0;
1229             glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
1230             if (samples) {
1231                 multisample = true;
1232             }
1233         }
1234
1235         glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &object_type);
1236         if (object_type == GL_RENDERBUFFER) {
1237             glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &stencilRb);
1238             glBindRenderbuffer(GL_RENDERBUFFER, stencilRb);
1239             GLint samples = 0;
1240             glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
1241             if (samples) {
1242                 multisample = true;
1243             }
1244         }
1245
1246         glBindRenderbuffer(GL_RENDERBUFFER, boundRb);
1247
1248         GLuint rbs[3];
1249         GLint numRbs = 0;
1250         GLuint fboCopy = 0;
1251
1252         if (multisample) {
1253             // glReadPixels doesnt support multisampled buffers so we need
1254             // to blit the fbo to a temporary one
1255             fboCopy = downsampledFramebuffer(boundDrawFbo, draw_buffer0,
1256                                              colorRb, depthRb, stencilRb,
1257                                              rbs, &numRbs);
1258         }
1259
1260         dumpFramebufferAttachments(json, GL_DRAW_FRAMEBUFFER);
1261
1262         if (multisample) {
1263             glBindRenderbuffer(GL_RENDERBUFFER_BINDING, boundRb);
1264             glDeleteRenderbuffers(numRbs, rbs);
1265             glDeleteFramebuffers(1, &fboCopy);
1266         }
1267
1268         glBindFramebuffer(GL_READ_FRAMEBUFFER, boundReadFbo);
1269         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, boundDrawFbo);
1270     }
1271
1272     json.endObject();
1273     json.endMember(); // framebuffer
1274 }
1275
1276
1277 static const GLenum bindings[] = {
1278     GL_DRAW_BUFFER,
1279     GL_READ_BUFFER,
1280     GL_PIXEL_PACK_BUFFER_BINDING,
1281     GL_PIXEL_UNPACK_BUFFER_BINDING,
1282     GL_TEXTURE_BINDING_1D,
1283     GL_TEXTURE_BINDING_2D,
1284     GL_TEXTURE_BINDING_3D,
1285     GL_TEXTURE_BINDING_RECTANGLE,
1286     GL_TEXTURE_BINDING_CUBE_MAP,
1287     GL_DRAW_FRAMEBUFFER_BINDING,
1288     GL_READ_FRAMEBUFFER_BINDING,
1289     GL_RENDERBUFFER_BINDING,
1290     GL_DRAW_BUFFER0,
1291     GL_DRAW_BUFFER1,
1292     GL_DRAW_BUFFER2,
1293     GL_DRAW_BUFFER3,
1294     GL_DRAW_BUFFER4,
1295     GL_DRAW_BUFFER5,
1296     GL_DRAW_BUFFER6,
1297     GL_DRAW_BUFFER7,
1298 };
1299
1300
1301 #define NUM_BINDINGS sizeof(bindings)/sizeof(bindings[0])
1302
1303
1304 void dumpCurrentContext(std::ostream &os)
1305 {
1306     JSONWriter json(os);
1307
1308 #ifndef NDEBUG
1309     GLint old_bindings[NUM_BINDINGS];
1310     for (unsigned i = 0; i < NUM_BINDINGS; ++i) {
1311         old_bindings[i] = 0;
1312         glGetIntegerv(bindings[i], &old_bindings[i]);
1313     }
1314 #endif
1315
1316     dumpParameters(json);
1317     dumpShaders(json);
1318     dumpUniforms(json);
1319     dumpTextures(json);
1320     dumpFramebuffer(json);
1321
1322 #ifndef NDEBUG
1323     for (unsigned i = 0; i < NUM_BINDINGS; ++i) {
1324         GLint new_binding = 0;
1325         glGetIntegerv(bindings[i], &new_binding);
1326         if (new_binding != old_bindings[i]) {
1327             std::cerr << "warning: " << enumToString(bindings[i]) << " was clobbered\n";
1328         }
1329     }
1330 #endif
1331
1332 }
1333
1334
1335 } /* namespace glstate */