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