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