]> git.cworth.org Git - apitrace/blob - glstate.cpp
Add missing call to dumpCurrentProgramObj.
[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
33 #include "image.hpp"
34 #include "json.hpp"
35 #include "glproc.hpp"
36 #include "glsize.hpp"
37 #include "glstate.hpp"
38
39
40 #ifdef __APPLE__
41
42 #include <Carbon/Carbon.h>
43
44 #ifdef __cplusplus
45 extern "C" {
46 #endif
47
48 OSStatus CGSGetSurfaceBounds(CGSConnectionID, CGWindowID, CGSSurfaceID, CGRect *);
49
50 #ifdef __cplusplus
51 }
52 #endif
53
54 #endif /* __APPLE__ */
55
56
57 namespace glstate {
58
59
60 static inline void
61 resetPixelPackState(void) {
62     glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
63     glPixelStorei(GL_PACK_SWAP_BYTES, GL_FALSE);
64     glPixelStorei(GL_PACK_LSB_FIRST, GL_FALSE);
65     glPixelStorei(GL_PACK_ROW_LENGTH, 0);
66     glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0);
67     glPixelStorei(GL_PACK_SKIP_ROWS, 0);
68     glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
69     glPixelStorei(GL_PACK_SKIP_IMAGES, 0);
70     glPixelStorei(GL_PACK_ALIGNMENT, 1);
71     glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
72 }
73
74
75 static inline void
76 restorePixelPackState(void) {
77     glPopClientAttrib();
78 }
79
80
81 // Mapping from shader type to shader source, used to accumulated the sources
82 // of different shaders with same type.
83 typedef std::map<std::string, std::string> ShaderMap;
84
85
86 static void
87 getShaderSource(ShaderMap &shaderMap, GLuint shader)
88 {
89     if (!shader) {
90         return;
91     }
92
93     GLint shader_type = 0;
94     glGetShaderiv(shader, GL_SHADER_TYPE, &shader_type);
95     if (!shader_type) {
96         return;
97     }
98
99     GLint source_length = 0;
100     glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &source_length);
101     if (!source_length) {
102         return;
103     }
104
105     GLchar *source = new GLchar[source_length];
106     GLsizei length = 0;
107     source[0] = 0;
108     glGetShaderSource(shader, source_length, &length, source);
109
110     shaderMap[enumToString(shader_type)] += source;
111
112     delete [] source;
113 }
114
115
116 static void
117 getShaderObjSource(ShaderMap &shaderMap, GLhandleARB shaderObj)
118 {
119     if (!shaderObj) {
120         return;
121     }
122
123     GLint shader_type = 0;
124     glGetObjectParameterivARB(shaderObj, GL_OBJECT_TYPE_ARB, &shader_type);
125     if (!shader_type) {
126         return;
127     }
128
129     GLint source_length = 0;
130     glGetObjectParameterivARB(shaderObj, GL_OBJECT_SHADER_SOURCE_LENGTH_ARB, &source_length);
131     if (!source_length) {
132         return;
133     }
134
135     GLcharARB *source = new GLcharARB[source_length];
136     GLsizei length = 0;
137     source[0] = 0;
138     glGetShaderSource(shaderObj, source_length, &length, source);
139
140     shaderMap[enumToString(shader_type)] += source;
141
142     delete [] source;
143 }
144
145
146 static inline void
147 dumpCurrentProgram(JSONWriter &json)
148 {
149     GLint program = 0;
150     glGetIntegerv(GL_CURRENT_PROGRAM, &program);
151     if (!program) {
152         return;
153     }
154
155     GLint attached_shaders = 0;
156     glGetProgramiv(program, GL_ATTACHED_SHADERS, &attached_shaders);
157     if (!attached_shaders) {
158         return;
159     }
160
161     ShaderMap shaderMap;
162
163     GLuint *shaders = new GLuint[attached_shaders];
164     GLsizei count = 0;
165     glGetAttachedShaders(program, attached_shaders, &count, shaders);
166     for (GLsizei i = 0; i < count; ++ i) {
167        getShaderSource(shaderMap, shaders[i]);
168     }
169     delete [] shaders;
170
171     for (ShaderMap::const_iterator it = shaderMap.begin(); it != shaderMap.end(); ++it) {
172         json.beginMember(it->first);
173         json.writeString(it->second);
174         json.endMember();
175     }
176 }
177
178
179 static inline void
180 dumpCurrentProgramObj(JSONWriter &json)
181 {
182     GLhandleARB programObj = glGetHandleARB(GL_PROGRAM_OBJECT_ARB);
183     if (!programObj) {
184         return;
185     }
186
187     GLint attached_shaders = 0;
188     glGetProgramivARB(programObj, GL_OBJECT_ATTACHED_OBJECTS_ARB, &attached_shaders);
189     if (!attached_shaders) {
190         return;
191     }
192
193     ShaderMap shaderMap;
194
195     GLhandleARB *shaderObjs = new GLhandleARB[attached_shaders];
196     GLsizei count = 0;
197     glGetAttachedObjectsARB(programObj, attached_shaders, &count, shaderObjs);
198     for (GLsizei i = 0; i < count; ++ i) {
199        getShaderObjSource(shaderMap, shaderObjs[i]);
200     }
201     delete [] shaderObjs;
202
203     for (ShaderMap::const_iterator it = shaderMap.begin(); it != shaderMap.end(); ++it) {
204         json.beginMember(it->first);
205         json.writeString(it->second);
206         json.endMember();
207     }
208 }
209
210
211 static inline void
212 dumpArbProgram(JSONWriter &json, GLenum target)
213 {
214     if (!glIsEnabled(target)) {
215         return;
216     }
217
218     GLint program_length = 0;
219     glGetProgramivARB(target, GL_PROGRAM_LENGTH_ARB, &program_length);
220     if (!program_length) {
221         return;
222     }
223
224     GLchar *source = new GLchar[program_length + 1];
225     source[0] = 0;
226     glGetProgramStringARB(target, GL_PROGRAM_STRING_ARB, source);
227     source[program_length] = 0;
228
229     json.beginMember(enumToString(target));
230     json.writeString(source);
231     json.endMember();
232
233     delete [] source;
234 }
235
236
237 static inline void
238 dumpShaders(JSONWriter &json)
239 {
240     json.beginMember("shaders");
241     json.beginObject();
242     dumpCurrentProgram(json);
243     dumpCurrentProgramObj(json);
244     dumpArbProgram(json, GL_FRAGMENT_PROGRAM_ARB);
245     dumpArbProgram(json, GL_VERTEX_PROGRAM_ARB);
246     json.endObject();
247     json.endMember(); //shaders
248 }
249
250
251 static inline void
252 dumpTextureImage(JSONWriter &json, GLenum target, GLint level)
253 {
254     GLint width, height = 1, depth = 1;
255
256     width = 0;
257     glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &width);
258
259     if (target != GL_TEXTURE_1D) {
260         height = 0;
261         glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &height);
262         if (target == GL_TEXTURE_3D) {
263             depth = 0;
264             glGetTexLevelParameteriv(target, level, GL_TEXTURE_DEPTH, &depth);
265         }
266     }
267
268     if (width <= 0 || height <= 0 || depth <= 0) {
269         return;
270     } else {
271         char label[512];
272
273         GLint active_texture = GL_TEXTURE0;
274         glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
275         snprintf(label, sizeof label, "%s, %s, level = %i", enumToString(active_texture), enumToString(target), level);
276
277         json.beginMember(label);
278
279         json.beginObject();
280
281         // Tell the GUI this is no ordinary object, but an image
282         json.writeStringMember("__class__", "image");
283
284         json.writeNumberMember("__width__", width);
285         json.writeNumberMember("__height__", height);
286         json.writeNumberMember("__depth__", depth);
287
288         // Hardcoded for now, but we could chose types more adequate to the
289         // texture internal format
290         json.writeStringMember("__type__", "uint8");
291         json.writeBoolMember("__normalized__", true);
292         json.writeNumberMember("__channels__", 4);
293
294         GLubyte *pixels = new GLubyte[depth*width*height*4];
295
296         resetPixelPackState();
297
298         glGetTexImage(target, level, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
299
300         restorePixelPackState();
301
302         json.beginMember("__data__");
303         char *pngBuffer;
304         int pngBufferSize;
305         Image::writePixelsToBuffer(pixels, width, height, 4, false, &pngBuffer, &pngBufferSize);
306         json.writeBase64(pngBuffer, pngBufferSize);
307         free(pngBuffer);
308         json.endMember(); // __data__
309
310         delete [] pixels;
311         json.endObject();
312     }
313 }
314
315
316 static inline void
317 dumpTexture(JSONWriter &json, GLenum target, GLenum binding)
318 {
319     GLint texture_binding = 0;
320     glGetIntegerv(binding, &texture_binding);
321     if (!glIsEnabled(target) && !texture_binding) {
322         return;
323     }
324
325     GLint level = 0;
326     do {
327         GLint width = 0, height = 0;
328         glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &width);
329         glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &height);
330         if (!width || !height) {
331             break;
332         }
333
334         if (target == GL_TEXTURE_CUBE_MAP) {
335             for (int face = 0; face < 6; ++face) {
336                 dumpTextureImage(json, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
337             }
338         } else {
339             dumpTextureImage(json, target, level);
340         }
341
342         ++level;
343     } while(true);
344 }
345
346
347 static inline void
348 dumpTextures(JSONWriter &json)
349 {
350     json.beginMember("textures");
351     json.beginObject();
352     GLint active_texture = GL_TEXTURE0;
353     glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
354     GLint max_texture_coords = 0;
355     glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);
356     GLint max_combined_texture_image_units = 0;
357     glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_combined_texture_image_units);
358     GLint max_units = std::max(max_combined_texture_image_units, max_texture_coords);
359     for (GLint unit = 0; unit < max_units; ++unit) {
360         GLenum texture = GL_TEXTURE0 + unit;
361         glActiveTexture(texture);
362         dumpTexture(json, GL_TEXTURE_1D, GL_TEXTURE_BINDING_1D);
363         dumpTexture(json, GL_TEXTURE_2D, GL_TEXTURE_BINDING_2D);
364         dumpTexture(json, GL_TEXTURE_3D, GL_TEXTURE_BINDING_3D);
365         dumpTexture(json, GL_TEXTURE_RECTANGLE, GL_TEXTURE_BINDING_RECTANGLE);
366         dumpTexture(json, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BINDING_CUBE_MAP);
367     }
368     glActiveTexture(active_texture);
369     json.endObject();
370     json.endMember(); // textures
371 }
372
373
374 static bool
375 getDrawableBounds(GLint *width, GLint *height) {
376 #if defined(_WIN32)
377
378     HDC hDC = wglGetCurrentDC();
379     if (!hDC) {
380         return false;
381     }
382
383     HWND hWnd = WindowFromDC(hDC);
384     RECT rect;
385
386     if (!GetClientRect(hWnd, &rect)) {
387        return false;
388     }
389
390     *width  = rect.right  - rect.left;
391     *height = rect.bottom - rect.top;
392
393 #elif defined(__APPLE__)
394
395     CGLContextObj ctx = CGLGetCurrentContext();
396     if (ctx == NULL) {
397         return false;
398     }
399
400     CGSConnectionID cid;
401     CGSWindowID wid;
402     CGSSurfaceID sid;
403
404     if (CGLGetSurface(ctx, &cid, &wid, &sid) != kCGLNoError) {
405         return false;
406     }
407
408     CGRect rect;
409
410     if (CGSGetSurfaceBounds(cid, wid, sid, &rect) != 0) {
411         return false;
412     }
413
414     *width = rect.size.width;
415     *height = rect.size.height;
416
417 #else
418
419     Display *display;
420     Drawable drawable;
421     Window root;
422     int x, y;
423     unsigned int w, h, bw, depth;
424
425     display = glXGetCurrentDisplay();
426     if (!display) {
427         return false;
428     }
429
430     drawable = glXGetCurrentDrawable();
431     if (drawable == None) {
432         return false;
433     }
434
435     if (!XGetGeometry(display, drawable, &root, &x, &y, &w, &h, &bw, &depth)) {
436         return false;
437     }
438
439     *width = w;
440     *height = h;
441
442 #endif
443
444     return true;
445 }
446
447
448 static const GLenum texture_bindings[][2] = {
449     {GL_TEXTURE_1D, GL_TEXTURE_BINDING_1D},
450     {GL_TEXTURE_2D, GL_TEXTURE_BINDING_2D},
451     {GL_TEXTURE_3D, GL_TEXTURE_BINDING_3D},
452     {GL_TEXTURE_RECTANGLE, GL_TEXTURE_BINDING_RECTANGLE},
453     {GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BINDING_CUBE_MAP}
454 };
455
456
457 static bool
458 bindTexture(GLint texture, GLenum &target, GLint &bound_texture)
459 {
460
461     for (unsigned i = 0; i < sizeof(texture_bindings)/sizeof(texture_bindings[0]); ++i) {
462         target  = texture_bindings[i][0];
463
464         GLenum binding = texture_bindings[i][1];
465
466         while (glGetError() != GL_NO_ERROR)
467             ;
468
469         glGetIntegerv(binding, &bound_texture);
470         glBindTexture(target, texture);
471
472         if (glGetError() == GL_NO_ERROR) {
473             return true;
474         }
475
476         glBindTexture(target, bound_texture);
477     }
478
479     target = GL_NONE;
480
481     return false;
482 }
483
484
485 static bool
486 getTextureLevelSize(GLint texture, GLint level, GLint *width, GLint *height)
487 {
488     *width = 0;
489     *height = 0;
490
491     GLenum target;
492     GLint bound_texture = 0;
493     if (!bindTexture(texture, target, bound_texture)) {
494         return false;
495     }
496
497     glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, width);
498     glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, height);
499
500     glBindTexture(target, bound_texture);
501
502     return *width > 0 && *height > 0;
503 }
504
505
506 static bool
507 getRenderbufferSize(GLint renderbuffer, GLint *width, GLint *height)
508 {
509     GLint bound_renderbuffer = 0;
510     glGetIntegerv(GL_RENDERBUFFER_BINDING, &bound_renderbuffer);
511     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
512
513     *width = 0;
514     *height = 0;
515     glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, width);
516     glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, height);
517
518     glBindRenderbuffer(GL_RENDERBUFFER, bound_renderbuffer);
519     
520     return *width > 0 && *height > 0;
521 }
522
523
524 static bool
525 getFramebufferAttachmentSize(GLenum target, GLenum attachment, GLint *width, GLint *height)
526 {
527     GLint object_type = GL_NONE;
528     glGetFramebufferAttachmentParameteriv(target, attachment,
529                                           GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
530                                           &object_type);
531     if (object_type == GL_NONE) {
532         return false;
533     }
534
535     GLint object_name = 0;
536     glGetFramebufferAttachmentParameteriv(target, attachment,
537                                           GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
538                                           &object_name);
539     if (object_name == 0) {
540         return false;
541     }
542
543     if (object_type == GL_RENDERBUFFER) {
544         return getRenderbufferSize(object_name, width, height);
545     } else if (object_type == GL_TEXTURE) {
546         GLint texture_level = 0;
547         glGetFramebufferAttachmentParameteriv(target, attachment,
548                                               GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL,
549                                               &texture_level);
550         return getTextureLevelSize(object_name, texture_level, width, height);
551     } else {
552         std::cerr << "warning: unexpected GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = " << object_type << "\n";
553         return false;
554     }
555 }
556
557
558 Image::Image *
559 getDrawBufferImage(GLenum format) {
560     GLint channels = __gl_format_channels(format);
561     if (channels > 4) {
562         return NULL;
563     }
564
565     GLint draw_framebuffer = 0;
566     glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &draw_framebuffer);
567
568     GLint draw_buffer = GL_NONE;
569     GLint width, height;
570     if (draw_framebuffer) {
571         glGetIntegerv(GL_DRAW_BUFFER0, &draw_buffer);
572         if (draw_buffer == GL_NONE) {
573             return NULL;
574         }
575
576         if (!getFramebufferAttachmentSize(GL_DRAW_FRAMEBUFFER, draw_buffer, &width, &height)) {
577             return NULL;
578         }
579     } else {
580         glGetIntegerv(GL_DRAW_BUFFER, &draw_buffer);
581         if (draw_buffer == GL_NONE) {
582             return NULL;
583         }
584
585         if (!getDrawableBounds(&width, &height)) {
586             return NULL;
587         }
588     }
589
590     Image::Image *image = new Image::Image(width, height, channels, true);
591     if (!image) {
592         return NULL;
593     }
594
595     while (glGetError() != GL_NO_ERROR) {}
596
597     GLint read_framebuffer = 0;
598     glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &read_framebuffer);
599     glBindFramebuffer(GL_READ_FRAMEBUFFER, draw_framebuffer);
600
601     GLint read_buffer = 0;
602     glGetIntegerv(GL_READ_BUFFER, &read_buffer);
603     glReadBuffer(draw_buffer);
604
605     // TODO: reset imaging state too
606     resetPixelPackState();
607
608     glReadPixels(0, 0, width, height, format, GL_UNSIGNED_BYTE, image->pixels);
609
610     restorePixelPackState();
611     glReadBuffer(read_buffer);
612     glBindFramebuffer(GL_READ_FRAMEBUFFER, read_framebuffer);
613
614     GLenum error = glGetError();
615     if (error != GL_NO_ERROR) {
616         do {
617             std::cerr << "warning: " << enumToString(error) << " while getting snapshot\n";
618             error = glGetError();
619         } while(error != GL_NO_ERROR);
620         delete image;
621         return NULL;
622     }
623      
624     return image;
625 }
626
627
628 /**
629  * Dump the image of the currently bound read buffer.
630  */
631 static inline void
632 dumpReadBufferImage(JSONWriter &json, GLint width, GLint height, GLenum format)
633 {
634     GLint channels = __gl_format_channels(format);
635
636     json.beginObject();
637
638     // Tell the GUI this is no ordinary object, but an image
639     json.writeStringMember("__class__", "image");
640
641     json.writeNumberMember("__width__", width);
642     json.writeNumberMember("__height__", height);
643     json.writeNumberMember("__depth__", 1);
644
645     // Hardcoded for now, but we could chose types more adequate to the
646     // texture internal format
647     json.writeStringMember("__type__", "uint8");
648     json.writeBoolMember("__normalized__", true);
649     json.writeNumberMember("__channels__", channels);
650
651     GLubyte *pixels = new GLubyte[width*height*channels];
652
653     // TODO: reset imaging state too
654     resetPixelPackState();
655
656     glReadPixels(0, 0, width, height, format, GL_UNSIGNED_BYTE, pixels);
657
658     restorePixelPackState();
659
660     json.beginMember("__data__");
661     char *pngBuffer;
662     int pngBufferSize;
663     Image::writePixelsToBuffer(pixels, width, height, channels, false, &pngBuffer, &pngBufferSize);
664     //std::cerr <<" Before = "<<(width * height * channels * sizeof *pixels)
665     //          <<", after = "<<pngBufferSize << ", ratio = " << double(width * height * channels * sizeof *pixels)/pngBufferSize;
666     json.writeBase64(pngBuffer, pngBufferSize);
667     free(pngBuffer);
668     json.endMember(); // __data__
669
670     delete [] pixels;
671     json.endObject();
672 }
673
674
675 static inline GLuint
676 downsampledFramebuffer(GLuint oldFbo, GLint drawbuffer,
677                        GLint colorRb, GLint depthRb, GLint stencilRb,
678                        GLuint *rbs, GLint *numRbs)
679 {
680     GLuint fbo;
681     GLint format;
682     GLint w, h;
683
684     *numRbs = 0;
685
686     glGenFramebuffers(1, &fbo);
687     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
688
689     glBindRenderbuffer(GL_RENDERBUFFER, colorRb);
690     glGetRenderbufferParameteriv(GL_RENDERBUFFER,
691                                  GL_RENDERBUFFER_WIDTH, &w);
692     glGetRenderbufferParameteriv(GL_RENDERBUFFER,
693                                  GL_RENDERBUFFER_HEIGHT, &h);
694     glGetRenderbufferParameteriv(GL_RENDERBUFFER,
695                                  GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
696
697     glGenRenderbuffers(1, &rbs[*numRbs]);
698     glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
699     glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
700     glFramebufferRenderbuffer(GL_FRAMEBUFFER, drawbuffer,
701                               GL_RENDERBUFFER, rbs[*numRbs]);
702
703     glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
704     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
705     glDrawBuffer(drawbuffer);
706     glReadBuffer(drawbuffer);
707     glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
708                       GL_COLOR_BUFFER_BIT, GL_NEAREST);
709     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
710     ++*numRbs;
711
712     if (stencilRb == depthRb && stencilRb) {
713         //combined depth and stencil buffer
714         glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
715         glGetRenderbufferParameteriv(GL_RENDERBUFFER,
716                                      GL_RENDERBUFFER_WIDTH, &w);
717         glGetRenderbufferParameteriv(GL_RENDERBUFFER,
718                                      GL_RENDERBUFFER_HEIGHT, &h);
719         glGetRenderbufferParameteriv(GL_RENDERBUFFER,
720                                      GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
721
722         glGenRenderbuffers(1, &rbs[*numRbs]);
723         glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
724         glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
725         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
726                                   GL_RENDERBUFFER, rbs[*numRbs]);
727         glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
728         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
729         glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
730                           GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
731         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
732         ++*numRbs;
733     } else {
734         if (depthRb) {
735             glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
736             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
737                                          GL_RENDERBUFFER_WIDTH, &w);
738             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
739                                          GL_RENDERBUFFER_HEIGHT, &h);
740             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
741                                          GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
742
743             glGenRenderbuffers(1, &rbs[*numRbs]);
744             glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
745             glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
746             glFramebufferRenderbuffer(GL_FRAMEBUFFER,
747                                       GL_DEPTH_ATTACHMENT,
748                                       GL_RENDERBUFFER, rbs[*numRbs]);
749             glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
750             glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
751             glDrawBuffer(GL_DEPTH_ATTACHMENT);
752             glReadBuffer(GL_DEPTH_ATTACHMENT);
753             glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
754                               GL_DEPTH_BUFFER_BIT, GL_NEAREST);
755             ++*numRbs;
756         }
757         if (stencilRb) {
758             glBindRenderbuffer(GL_RENDERBUFFER, stencilRb);
759             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
760                                          GL_RENDERBUFFER_WIDTH, &w);
761             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
762                                          GL_RENDERBUFFER_HEIGHT, &h);
763             glGetRenderbufferParameteriv(GL_RENDERBUFFER,
764                                      GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
765
766             glGenRenderbuffers(1, &rbs[*numRbs]);
767             glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
768             glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
769             glFramebufferRenderbuffer(GL_FRAMEBUFFER,
770                                       GL_STENCIL_ATTACHMENT,
771                                       GL_RENDERBUFFER, rbs[*numRbs]);
772             glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
773             glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
774             glDrawBuffer(GL_STENCIL_ATTACHMENT);
775             glReadBuffer(GL_STENCIL_ATTACHMENT);
776             glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
777                               GL_STENCIL_BUFFER_BIT, GL_NEAREST);
778             ++*numRbs;
779         }
780     }
781
782     return fbo;
783 }
784
785
786 /**
787  * Dump images of current draw drawable/window.
788  */
789 static void
790 dumpDrawableImages(JSONWriter &json)
791 {
792     GLint width, height;
793
794     if (!getDrawableBounds(&width, &height)) {
795         return;
796     }
797
798     GLint draw_buffer = GL_NONE;
799     glGetIntegerv(GL_DRAW_BUFFER, &draw_buffer);
800     glReadBuffer(draw_buffer);
801
802     if (draw_buffer != GL_NONE) {
803         GLint read_buffer = GL_NONE;
804         glGetIntegerv(GL_READ_BUFFER, &read_buffer);
805
806         GLint alpha_bits = 0;
807         glGetIntegerv(GL_ALPHA_BITS, &alpha_bits);
808         GLenum format = alpha_bits ? GL_RGBA : GL_RGB;
809         json.beginMember(enumToString(draw_buffer));
810         dumpReadBufferImage(json, width, height, format);
811         json.endMember();
812
813         glReadBuffer(read_buffer);
814     }
815
816     GLint depth_bits = 0;
817     glGetIntegerv(GL_DEPTH_BITS, &depth_bits);
818     if (depth_bits) {
819         json.beginMember("GL_DEPTH_COMPONENT");
820         dumpReadBufferImage(json, width, height, GL_DEPTH_COMPONENT);
821         json.endMember();
822     }
823
824     GLint stencil_bits = 0;
825     glGetIntegerv(GL_STENCIL_BITS, &stencil_bits);
826     if (stencil_bits) {
827         json.beginMember("GL_STENCIL_INDEX");
828         dumpReadBufferImage(json, width, height, GL_STENCIL_INDEX);
829         json.endMember();
830     }
831 }
832 /**
833  * Dump the specified framebuffer attachment.
834  *
835  * In the case of a color attachment, it assumes it is already bound for read.
836  */
837 static void
838 dumpFramebufferAttachment(JSONWriter &json, GLenum target, GLenum attachment, GLenum format)
839 {
840     GLint width = 0, height = 0;
841     if (!getFramebufferAttachmentSize(target, attachment, &width, &height)) {
842         return;
843     }
844
845     json.beginMember(enumToString(attachment));
846     dumpReadBufferImage(json, width, height, format);
847     json.endMember();
848 }
849
850
851 static void
852 dumpFramebufferAttachments(JSONWriter &json, GLenum target)
853 {
854     GLint read_framebuffer = 0;
855     glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &read_framebuffer);
856
857     GLint read_buffer = GL_NONE;
858     glGetIntegerv(GL_READ_BUFFER, &read_buffer);
859
860     GLint max_draw_buffers = 1;
861     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &max_draw_buffers);
862     GLint max_color_attachments = 0;
863     glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &max_color_attachments);
864
865     for (GLint i = 0; i < max_draw_buffers; ++i) {
866         GLint draw_buffer = GL_NONE;
867         glGetIntegerv(GL_DRAW_BUFFER0 + i, &draw_buffer);
868         if (draw_buffer != GL_NONE) {
869             glReadBuffer(draw_buffer);
870             GLint attachment;
871             if (draw_buffer >= GL_COLOR_ATTACHMENT0 && draw_buffer < GL_COLOR_ATTACHMENT0 + max_color_attachments) {
872                 attachment = draw_buffer;
873             } else {
874                 std::cerr << "warning: unexpected GL_DRAW_BUFFER" << i << " = " << draw_buffer << "\n";
875                 attachment = GL_COLOR_ATTACHMENT0;
876             }
877             GLint alpha_size = 0;
878             glGetFramebufferAttachmentParameteriv(target, attachment,
879                                                   GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE,
880                                                   &alpha_size);
881             GLenum format = alpha_size ? GL_RGBA : GL_RGB;
882             dumpFramebufferAttachment(json, target, attachment, format);
883         }
884     }
885
886     glReadBuffer(read_buffer);
887
888     dumpFramebufferAttachment(json, target, GL_DEPTH_ATTACHMENT, GL_DEPTH_COMPONENT);
889     dumpFramebufferAttachment(json, target, GL_STENCIL_ATTACHMENT, GL_STENCIL_INDEX);
890
891     glBindFramebuffer(GL_READ_FRAMEBUFFER, read_framebuffer);
892 }
893
894
895 static void
896 dumpFramebuffer(JSONWriter &json)
897 {
898     json.beginMember("framebuffer");
899     json.beginObject();
900
901     GLint boundDrawFbo = 0, boundReadFbo = 0;
902     glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &boundDrawFbo);
903     glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &boundReadFbo);
904     if (!boundDrawFbo) {
905         dumpDrawableImages(json);
906     } else {
907         GLint colorRb = 0, stencilRb = 0, depthRb = 0;
908         GLint draw_buffer0 = GL_NONE;
909         glGetIntegerv(GL_DRAW_BUFFER0, &draw_buffer0);
910         bool multisample = false;
911
912         GLint boundRb = 0;
913         glGetIntegerv(GL_RENDERBUFFER_BINDING, &boundRb);
914
915         GLint object_type;
916         glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, draw_buffer0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &object_type);
917         if (object_type == GL_RENDERBUFFER) {
918             glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, draw_buffer0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &colorRb);
919             glBindRenderbuffer(GL_RENDERBUFFER, colorRb);
920             GLint samples = 0;
921             glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
922             if (samples) {
923                 multisample = true;
924             }
925         }
926
927         glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &object_type);
928         if (object_type == GL_RENDERBUFFER) {
929             glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &depthRb);
930             glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
931             GLint samples = 0;
932             glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
933             if (samples) {
934                 multisample = true;
935             }
936         }
937
938         glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &object_type);
939         if (object_type == GL_RENDERBUFFER) {
940             glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &stencilRb);
941             glBindRenderbuffer(GL_RENDERBUFFER, stencilRb);
942             GLint samples = 0;
943             glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
944             if (samples) {
945                 multisample = true;
946             }
947         }
948
949         glBindRenderbuffer(GL_RENDERBUFFER, boundRb);
950
951         GLuint rbs[3];
952         GLint numRbs = 0;
953         GLuint fboCopy = 0;
954
955         if (multisample) {
956             // glReadPixels doesnt support multisampled buffers so we need
957             // to blit the fbo to a temporary one
958             fboCopy = downsampledFramebuffer(boundDrawFbo, draw_buffer0,
959                                              colorRb, depthRb, stencilRb,
960                                              rbs, &numRbs);
961         }
962
963         dumpFramebufferAttachments(json, GL_DRAW_FRAMEBUFFER);
964
965         if (multisample) {
966             glBindRenderbuffer(GL_RENDERBUFFER_BINDING, boundRb);
967             glDeleteRenderbuffers(numRbs, rbs);
968             glDeleteFramebuffers(1, &fboCopy);
969         }
970
971         glBindFramebuffer(GL_READ_FRAMEBUFFER, boundReadFbo);
972         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, boundDrawFbo);
973     }
974
975     json.endObject();
976     json.endMember(); // framebuffer
977 }
978
979
980 static const GLenum bindings[] = {
981     GL_DRAW_BUFFER,
982     GL_READ_BUFFER,
983     GL_PIXEL_PACK_BUFFER_BINDING,
984     GL_PIXEL_UNPACK_BUFFER_BINDING,
985     GL_TEXTURE_BINDING_1D,
986     GL_TEXTURE_BINDING_2D,
987     GL_TEXTURE_BINDING_3D,
988     GL_TEXTURE_BINDING_RECTANGLE,
989     GL_TEXTURE_BINDING_CUBE_MAP,
990     GL_DRAW_FRAMEBUFFER_BINDING,
991     GL_READ_FRAMEBUFFER_BINDING,
992     GL_RENDERBUFFER_BINDING,
993     GL_DRAW_BUFFER0,
994     GL_DRAW_BUFFER1,
995     GL_DRAW_BUFFER2,
996     GL_DRAW_BUFFER3,
997     GL_DRAW_BUFFER4,
998     GL_DRAW_BUFFER5,
999     GL_DRAW_BUFFER6,
1000     GL_DRAW_BUFFER7,
1001 };
1002
1003
1004 #define NUM_BINDINGS sizeof(bindings)/sizeof(bindings[0])
1005
1006
1007 void dumpCurrentContext(std::ostream &os)
1008 {
1009     JSONWriter json(os);
1010
1011 #ifndef NDEBUG
1012     GLint old_bindings[NUM_BINDINGS];
1013     for (unsigned i = 0; i < NUM_BINDINGS; ++i) {
1014         old_bindings[i] = 0;
1015         glGetIntegerv(bindings[i], &old_bindings[i]);
1016     }
1017 #endif
1018
1019     dumpParameters(json);
1020     dumpShaders(json);
1021     dumpTextures(json);
1022     dumpFramebuffer(json);
1023
1024 #ifndef NDEBUG
1025     for (unsigned i = 0; i < NUM_BINDINGS; ++i) {
1026         GLint new_binding = 0;
1027         glGetIntegerv(bindings[i], &new_binding);
1028         if (new_binding != old_bindings[i]) {
1029             std::cerr << "warning: " << enumToString(bindings[i]) << " was clobbered\n";
1030         }
1031     }
1032 #endif
1033
1034 }
1035
1036
1037 } /* namespace glstate */