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