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