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