1 /**************************************************************************
2  *
3  * Copyright 2011-2014 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 <assert.h>
28 #include <string.h>
29 
30 #include <algorithm>
31 #include <iostream>
32 #include <sstream>
33 #include <vector>
34 
35 #include "image.hpp"
36 #include "state_writer.hpp"
37 #include "retrace.hpp"
38 #include "glproc.hpp"
39 #include "glsize.hpp"
40 #include "glstate.hpp"
41 #include "glstate_internal.hpp"
42 
43 
44 #ifdef __unix__
45 #include <dlfcn.h>
46 #endif
47 
48 #ifdef __APPLE__
49 
50 #include <Carbon/Carbon.h>
51 
52 #ifdef __cplusplus
53 extern "C" {
54 #endif
55 
56 OSStatus CGSGetSurfaceBounds(CGSConnectionID, CGWindowID, CGSSurfaceID, CGRect *);
57 
58 #ifdef __cplusplus
59 }
60 #endif
61 
62 #endif /* __APPLE__ */
63 
64 
65 namespace retrace {
66     extern bool resolveMSAA;
67 }
68 
69 namespace glstate {
70 
71 
72 struct ImageDesc
73 {
74     GLint width;
75     GLint height;
76     GLint depth;
77     GLint samples;
78     GLint internalFormat;
79 
80     inline
ImageDescglstate::ImageDesc81     ImageDesc() :
82         width(0),
83         height(0),
84         depth(0),
85         samples(0),
86         internalFormat(GL_NONE)
87     {}
88 
89     inline bool
operator ==glstate::ImageDesc90     operator == (const ImageDesc &other) const {
91         return width == other.width &&
92                height == other.height &&
93                depth == other.depth &&
94                samples == other.samples &&
95                internalFormat == other.internalFormat;
96     }
97 
98     inline bool
validglstate::ImageDesc99     valid(void) const {
100         return width > 0 && height > 0 && depth > 0;
101     }
102 };
103 
104 
105 static GLenum
106 getTextureTarget(Context &context, GLuint texture);
107 
108 
109 /**
110  * OpenGL ES does not support glGetTexLevelParameteriv, but it is possible to
111  * probe whether a texture has a given size by crafting a dummy glTexSubImage()
112  * call.
113  */
114 static bool
probeTextureLevelSizeOES(GLenum target,GLint level,const GLint size[3],GLenum internalFormat,GLenum type)115 probeTextureLevelSizeOES(GLenum target, GLint level, const GLint size[3],
116                          GLenum internalFormat, GLenum type)
117 {
118     flushErrors();
119 
120     GLint dummy = 0;
121 
122     switch (target) {
123     case GL_TEXTURE_2D:
124     case GL_TEXTURE_CUBE_MAP:
125     case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
126     case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
127     case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
128     case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
129     case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
130     case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
131         glTexSubImage2D(target, level, size[0], size[1], 0, 0, internalFormat, type, &dummy);
132         break;
133     case GL_TEXTURE_3D_OES:
134         glTexSubImage3DOES(target, level, size[0], size[1], size[2], 0, 0, 0, internalFormat, type, &dummy);
135         break;
136     default:
137         assert(0);
138         return false;
139     }
140 
141     GLenum error = glGetError();
142 
143     if (0) {
144         std::cerr << "(" << size[0] << ", " << size[1] << ", " << size[2] << ") = " << enumToString(error) << "\n";
145     }
146 
147     if (error == GL_NO_ERROR) {
148         return true;
149     }
150 
151     flushErrors();
152 
153     return false;
154 }
155 
156 
157 static bool
probeTextureFormatOES(GLenum target,GLint level,GLenum * internalFormat,GLenum * type)158 probeTextureFormatOES(GLenum target, GLint level,
159                       GLenum *internalFormat, GLenum *type)
160 {
161     static const struct {
162         GLenum internalFormat;
163         GLenum type;
164     } info[] = {
165         /* internalFormat */        /* type */
166         { GL_RGBA,                  GL_UNSIGNED_BYTE },
167         { GL_DEPTH_STENCIL,         GL_FLOAT_32_UNSIGNED_INT_24_8_REV },
168         { GL_DEPTH_STENCIL,         GL_UNSIGNED_INT_24_8 },
169         { GL_DEPTH_COMPONENT,       GL_FLOAT },
170         { GL_DEPTH_COMPONENT,       GL_UNSIGNED_SHORT },
171         { GL_STENCIL_INDEX,         GL_UNSIGNED_BYTE },
172         /* others? */
173         { 0, 0 },
174     };
175     static const GLint size[3] = {1, 1, 1};
176 
177     for (int i = 0; info[i].internalFormat; i++) {
178         if (probeTextureLevelSizeOES(target, level, size,
179                                      info[i].internalFormat,
180                                      info[i].type)) {
181             *internalFormat = info[i].internalFormat;
182             *type = info[i].type;
183             return true;
184         }
185     }
186 
187     return false;
188 }
189 
190 
191 /**
192  * Bisect the texture size along an axis.
193  *
194  * It is assumed that the texture exists.
195  */
196 static GLint
bisectTextureLevelSizeOES(GLenum target,GLint level,GLint axis,GLint max,GLenum internalFormat,GLenum type)197 bisectTextureLevelSizeOES(GLenum target, GLint level, GLint axis, GLint max,
198                           GLenum internalFormat, GLenum type)
199 {
200     GLint size[3] = {0, 0, 0};
201 
202     assert(axis < 3);
203     assert(max >= 0);
204 
205     GLint min = 0;
206     while (true) {
207         GLint test = (min + max) / 2;
208         if (test == min) {
209             return min;
210         }
211 
212         size[axis] = test;
213 
214         if (probeTextureLevelSizeOES(target, level, size, internalFormat, type)) {
215             min = test;
216         } else {
217             max = test;
218         }
219     }
220 }
221 
222 
223 /**
224  * Special path to obtain texture size on OpenGL ES, that does not rely on
225  * glGetTexLevelParameteriv
226  */
227 static bool
getActiveTextureLevelDescOES(Context & context,GLenum target,GLint level,ImageDesc & desc)228 getActiveTextureLevelDescOES(Context &context, GLenum target, GLint level, ImageDesc &desc)
229 {
230     if (target == GL_TEXTURE_1D) {
231         // OpenGL ES does not support 1D textures
232         return false;
233     }
234     GLenum internalFormat, type;
235 
236     if (!probeTextureFormatOES(target, level, &internalFormat, &type)) {
237         return false;
238     }
239 
240     desc.internalFormat = internalFormat;
241 
242     GLint maxSize = 0;
243     switch (target) {
244     case GL_TEXTURE_2D:
245         glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize);
246         desc.width = bisectTextureLevelSizeOES(target, level, 0, maxSize, internalFormat, type);
247         desc.height = bisectTextureLevelSizeOES(target, level, 1, maxSize, internalFormat, type);
248         desc.depth = 1;
249         break;
250     case GL_TEXTURE_CUBE_MAP:
251     case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
252     case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
253     case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
254     case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
255     case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
256     case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
257         glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &maxSize);
258         desc.width = bisectTextureLevelSizeOES(target, level, 0, maxSize, internalFormat, type);
259         desc.height = desc.width;
260         desc.depth = 1;
261         break;
262     case GL_TEXTURE_3D_OES:
263         glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE_OES, &maxSize);
264         desc.width = bisectTextureLevelSizeOES(target, level, 0, maxSize, internalFormat, type);
265         desc.width = bisectTextureLevelSizeOES(target, level, 1, maxSize, internalFormat, type);
266         desc.depth = bisectTextureLevelSizeOES(target, level, 2, maxSize, internalFormat, type);
267         break;
268     default:
269         return false;
270     }
271 
272     if (0) {
273         std::cerr
274             << enumToString(target) << " "
275             << level << " "
276             << desc.width << "x" << desc.height << "x" << desc.depth
277             << "\n";
278     }
279 
280     return desc.valid();
281 }
282 
283 
284 static inline bool
getActiveTextureLevelDesc(Context & context,GLenum target,GLint level,ImageDesc & desc)285 getActiveTextureLevelDesc(Context &context, GLenum target, GLint level, ImageDesc &desc)
286 {
287     assert(target != GL_TEXTURE_CUBE_MAP);
288 
289     if (context.ES) {
290         return getActiveTextureLevelDescOES(context, target, level, desc);
291     }
292 
293     if (target == GL_TEXTURE_BUFFER) {
294         assert(level == 0);
295 
296         GLint buffer = 0;
297         glGetIntegerv(GL_TEXTURE_BUFFER_DATA_STORE_BINDING, &buffer);
298         if (!buffer) {
299             return false;
300         }
301 
302         // This is the general binding point, not the texture's
303         GLint active_buffer = 0;
304         glGetIntegerv(GL_TEXTURE_BUFFER, &active_buffer);
305         glBindBuffer(GL_TEXTURE_BUFFER, buffer);
306 
307         GLint buffer_size = 0;
308         glGetBufferParameteriv(GL_TEXTURE_BUFFER, GL_BUFFER_SIZE, &buffer_size);
309 
310         glBindBuffer(GL_TEXTURE_BUFFER, active_buffer);
311 
312         glGetIntegerv(GL_TEXTURE_BUFFER_FORMAT_ARB, &desc.internalFormat);
313 
314         const InternalFormatDesc &formatDesc = getInternalFormatDesc(desc.internalFormat);
315         if (formatDesc.type == GL_NONE) {
316             std::cerr << "error: unexpected GL_TEXTURE_BUFFER internal format "
317                       << enumToString(desc.internalFormat)
318                       << " (https://github.com/apitrace/apitrace/issues/426)\n";
319             return false;
320         }
321 
322         unsigned bits_per_pixel = _gl_format_size(formatDesc.format, formatDesc.type);
323 
324         desc.width = buffer_size * 8 / bits_per_pixel;
325         desc.height = 1;
326         desc.depth = 1;
327 
328         return desc.valid();
329     }
330 
331     glGetTexLevelParameteriv(target, level, GL_TEXTURE_INTERNAL_FORMAT, &desc.internalFormat);
332 
333     desc.width = 0;
334     glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &desc.width);
335 
336     if (target == GL_TEXTURE_BUFFER ||
337         target == GL_TEXTURE_1D) {
338         desc.height = 1;
339         desc.depth = 1;
340     } else {
341         desc.height = 0;
342         glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &desc.height);
343         if (target != GL_TEXTURE_3D &&
344             target != GL_TEXTURE_2D_ARRAY &&
345             target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY &&
346             target != GL_TEXTURE_CUBE_MAP_ARRAY) {
347             desc.depth = 1;
348         } else {
349             desc.depth = 0;
350             glGetTexLevelParameteriv(target, level, GL_TEXTURE_DEPTH, &desc.depth);
351         }
352     }
353 
354     glGetTexLevelParameteriv(target, level, GL_TEXTURE_SAMPLES, &desc.samples);
355 
356     return desc.valid();
357 }
358 
359 
360 const GLenum
361 textureTargets[] = {
362     GL_TEXTURE_2D,
363     GL_TEXTURE_1D,
364     GL_TEXTURE_RECTANGLE,
365     GL_TEXTURE_CUBE_MAP,
366     GL_TEXTURE_3D,
367     GL_TEXTURE_2D_MULTISAMPLE,
368     GL_TEXTURE_2D_ARRAY,
369     GL_TEXTURE_2D_MULTISAMPLE_ARRAY,
370     GL_TEXTURE_1D_ARRAY,
371     GL_TEXTURE_CUBE_MAP_ARRAY,
372     GL_TEXTURE_BUFFER,
373 };
374 
375 const unsigned
376 numTextureTargets = ARRAYSIZE(textureTargets);
377 
378 
379 GLenum
getTextureBinding(GLenum target)380 getTextureBinding(GLenum target)
381 {
382     switch (target) {
383     case GL_TEXTURE_1D:
384         return GL_TEXTURE_BINDING_1D;
385     case GL_TEXTURE_1D_ARRAY:
386         return GL_TEXTURE_BINDING_1D_ARRAY;
387     case GL_TEXTURE_2D:
388         return GL_TEXTURE_BINDING_2D;
389     case GL_TEXTURE_2D_ARRAY:
390         return GL_TEXTURE_BINDING_2D_ARRAY;
391     case GL_TEXTURE_2D_MULTISAMPLE:
392         return GL_TEXTURE_BINDING_2D_MULTISAMPLE;
393     case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
394         return GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY;
395     case GL_TEXTURE_RECTANGLE:
396         return GL_TEXTURE_BINDING_RECTANGLE;
397     case GL_TEXTURE_CUBE_MAP:
398     case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
399     case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
400     case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
401     case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
402     case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
403     case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
404         return GL_TEXTURE_BINDING_CUBE_MAP;
405     case GL_TEXTURE_CUBE_MAP_ARRAY:
406         return GL_TEXTURE_BINDING_CUBE_MAP_ARRAY;
407     case GL_TEXTURE_3D:
408         return GL_TEXTURE_BINDING_3D;
409     case GL_TEXTURE_BUFFER:
410         return GL_TEXTURE_BINDING_BUFFER;
411     default:
412         assert(false);
413         return GL_NONE;
414     }
415 }
416 
417 
418 /**
419  * OpenGL ES does not support glGetTexImage. Obtain the pixels by attaching the
420  * texture to a framebuffer.
421  */
422 static inline void
getTexImageOES(GLenum target,GLint level,GLenum format,GLenum type,ImageDesc & desc,GLubyte * pixels)423 getTexImageOES(GLenum target, GLint level, GLenum format, GLenum type,
424                ImageDesc &desc, GLubyte *pixels)
425 {
426     memset(pixels, 0x80, desc.height * desc.width * 4);
427 
428     GLenum texture_binding = getTextureBinding(target);
429     if (texture_binding == GL_NONE) {
430         return;
431     }
432 
433     GLint texture = 0;
434     glGetIntegerv(texture_binding, &texture);
435     if (!texture) {
436         return;
437     }
438 
439     GLint prev_fbo = 0;
440     GLuint fbo = 0;
441     glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prev_fbo);
442     glGenFramebuffers(1, &fbo);
443     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
444 
445     GLenum status;
446 
447     switch (target) {
448     case GL_TEXTURE_2D:
449     case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
450     case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
451     case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
452     case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
453     case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
454     case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
455         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, level);
456         status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
457         if (status != GL_FRAMEBUFFER_COMPLETE) {
458             std::cerr << __FUNCTION__ << ": " << enumToString(status) << "\n";
459         }
460         glReadPixels(0, 0, desc.width, desc.height, format, type, pixels);
461         break;
462     case GL_TEXTURE_3D_OES:
463         for (int i = 0; i < desc.depth; i++) {
464             glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, texture, level, i);
465             glReadPixels(0, 0, desc.width, desc.height, format, type, pixels + 4 * i * desc.width * desc.height);
466         }
467         break;
468     }
469 
470     glBindFramebuffer(GL_FRAMEBUFFER, prev_fbo);
471 
472     glDeleteFramebuffers(1, &fbo);
473 }
474 
475 /**
476  * Simple Shader compile
477  */
478 static inline int
compileShader(const GLchar * shaderSource,GLenum shaderType)479 compileShader(const GLchar* shaderSource, GLenum shaderType )
480 {
481 
482     GLuint id;
483     GLint result;
484     int logLength;
485     char logInfo[1000];
486 
487     id = glCreateShader(shaderType);
488     glShaderSource(id, 1, (const GLchar**)&shaderSource, NULL);
489     glCompileShader(id);
490     glGetShaderiv(id, GL_COMPILE_STATUS, &result);
491 
492     if (result == GL_FALSE) {
493         glGetShaderiv(id, GL_INFO_LOG_LENGTH, &logLength);
494         glGetShaderInfoLog(id, logLength, NULL, &logInfo[0]);
495         std::cerr << std::endl << logInfo << std::endl;
496         return -1;
497     }
498 
499     return id;
500 }
501 
502 /**
503  * Program Creation / Linking.
504  */
505 static inline void
createProgram(GLuint program_id,const GLchar * vShaderSource,const GLchar * pShaderSource)506 createProgram(GLuint program_id, const GLchar* vShaderSource, const GLchar* pShaderSource)
507 {
508     GLint result;
509     int logLength;
510     char logInfo[1000];
511 
512     GLint vshaderID = compileShader(vShaderSource, GL_VERTEX_SHADER);
513     GLint pshaderID = compileShader(pShaderSource, GL_FRAGMENT_SHADER);
514 
515     glAttachShader(program_id, vshaderID);
516     glAttachShader(program_id, pshaderID);
517     glLinkProgram(program_id);
518     glGetProgramiv(program_id, GL_LINK_STATUS, &result);
519 
520     if (result == GL_FALSE) {
521         glGetShaderiv(program_id, GL_INFO_LOG_LENGTH, &logLength);
522         glGetShaderInfoLog(program_id, logLength, NULL, &logInfo[0]);
523         std::cerr << std::endl << logInfo << std::endl;
524     }
525 
526     glDeleteShader(vshaderID);
527     glDeleteShader(pshaderID);
528     return;
529 }
530 
531 /**
532  * Obtain unresolved/resolved MSAA surface by attaching the
533  * texture to a framebuffer and using a multisample texel fetch inside custom shader.
534  */
535 static inline void
getTexImageMSAA(GLenum target,GLenum format,GLenum type,ImageDesc & desc,GLubyte * pixels,bool resolve)536 getTexImageMSAA(GLenum target, GLenum format, GLenum type,
537                ImageDesc &desc, GLubyte *pixels, bool resolve)
538 {
539     TempId prog = TempId(GL_PROGRAM);
540     TempId vao = TempId(GL_VERTEX_ARRAY);
541     TempId vbo = TempId(GL_ARRAY_BUFFER);
542 
543     /*
544      * Vertices for 2 tri strip
545      */
546     const GLint channels = 4;
547     const GLint vertices = 4;
548     static const float vertArray[vertices][channels] = {
549         {  1.0f, -1.0f, 0.0f, 1.0f },
550         {  1.0f,  1.0f, 0.0f, 1.0f },
551         { -1.0f, -1.0f, 0.0f, 1.0f },
552         { -1.0f,  1.0f, 0.0f, 1.0f },
553     };
554 
555     /*
556      * Create an empty texture + fbo of correct size.
557      */
558     TempId tex = TempId(GL_TEXTURE);
559     TextureBinding bt = TextureBinding(GL_TEXTURE_2D, tex.ID());
560 
561     TempId fbo = TempId(GL_FRAMEBUFFER);
562     BufferBinding fb = BufferBinding(GL_FRAMEBUFFER, fbo.ID());
563     BufferBinding Db = BufferBinding(GL_DRAW_BUFFER, GL_COLOR_ATTACHMENT0);
564     BufferBinding Rb = BufferBinding(GL_READ_BUFFER, GL_COLOR_ATTACHMENT0);
565 
566     GLint savedProgram;
567     glGetIntegerv(GL_CURRENT_PROGRAM, &savedProgram);
568 
569     GLint savedViewport[4];
570     glGetIntegerv(GL_VIEWPORT, savedViewport);
571     GLuint viewport_height = desc.height;
572 
573     if (resolve){
574 
575         /*
576          * Create blitting program to perform resolve.
577          */
578 
579         const GLchar* const vShaderSource =
580             "in vec4 Position;\n            "
581             "void main() {\n                "
582             "     gl_Position = Position;\n "
583             "}\n                            ";
584 
585         const GLchar* const pShaderSource =
586             "#version 430\n;                                          "
587             "uniform ivec3 texDim; // Width, Height, samples\n        "
588             "uniform sampler2DMS Sampler;\n                           "
589             "layout(location = 0) out vec4 FragColor;\n               "
590             "void main() {\n                                          "
591             "   ivec2 coord = ivec2(gl_FragCoord.xy);\n               "
592             "   coord.x = texDim.x - coord.x - 1;\n                   "
593             "   vec4 outColor = { 0, 0, 0, 0 }; \n                    "
594             "   for (int i=0; i<int(texDim.z); i++) {                 "
595             "       outColor += texelFetch(Sampler, coord, i);\n      "
596             "   } \n                                                  "
597             "   FragColor = outColor / float(texDim.z); \n            "
598             "}\n                                                      ";
599 
600         createProgram(prog.ID(), vShaderSource, pShaderSource);
601         glUseProgram(prog.ID());
602 
603         /*
604          * Pass uniform for texture dimensions and number of samples
605          */
606         GLint myLoc = glGetUniformLocation(prog.ID(), "texDim");
607         glProgramUniform3i(prog.ID(), myLoc, desc.width, desc.height, desc.samples);
608 
609     } else { /* no resolve */
610 
611         /*
612          * Read out each individual sample surface with border for MSAA surface
613          * Create blitting program to copy unresolved samples into tall texture.
614          */
615         const GLchar* const vShaderSource =
616             "in vec4 Position;\n            "
617             "void main() {\n                "
618             "     gl_Position = Position;\n "
619             "}\n                            ";
620 
621         const GLchar* const pShaderSource =
622             "#version 430\n;                                          "
623             "uniform ivec2 texDim; // Width, Height\n                 "
624             "uniform sampler2DMS Sampler;\n                           "
625             "layout(location = 0) out vec4 FragColor;\n               "
626             "void main() {\n                                          "
627             "   ivec2 coord = ivec2(gl_FragCoord.xy);\n               "
628             "   int height = int(gl_FragCoord.y / texDim.y);\n        "
629             "   coord.y = (coord.y % texDim.y);\n                     "
630             "   coord.x = texDim.x - coord.x - 1;\n                   "
631             "   FragColor = texelFetch(Sampler, coord, height);\n     "
632             "}\n                                                      ";
633 
634 
635         createProgram(prog.ID(), vShaderSource, pShaderSource);
636         glUseProgram(prog.ID());
637 
638         /*
639          * Pass uniform for texture dimensions and viewport height
640          * Add bottom border to each sample window only (in-between samples)
641          */
642         viewport_height = desc.height * desc.samples;
643         GLint myLoc = glGetUniformLocation(prog.ID(), "texDim");
644         glProgramUniform2i(prog.ID(), myLoc, desc.width, desc.height);
645     }
646 
647     glViewport(0, 0, desc.width, viewport_height);
648     glBufferData(GL_ARRAY_BUFFER, sizeof(vertArray), vertArray, GL_STATIC_DRAW);
649     glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
650     glEnableVertexAttribArray(0);
651 
652     glTexImage2D(GL_TEXTURE_2D, 0, desc.internalFormat, desc.width, viewport_height, 0, format, type, NULL);
653 
654     GLuint clearBufferBit;
655     switch(format)
656     {
657         case GL_DEPTH_COMPONENT:
658             glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, bt.ID(), 0);
659             clearBufferBit = GL_DEPTH_BUFFER_BIT;
660             break;
661         case GL_STENCIL_INDEX:
662             glFramebufferTexture(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, bt.ID(), 0);
663             clearBufferBit = GL_STENCIL_BUFFER_BIT;
664             break;
665         default:
666             glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, bt.ID(), 0);
667             clearBufferBit = GL_COLOR_BUFFER_BIT;
668             break;
669     }
670 
671     GLuint result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
672     if (result != GL_FRAMEBUFFER_COMPLETE)
673     {
674         std::cerr << "Framebuffer not done..." << std::endl;
675         goto exit_clean;
676     }
677 
678     glClearColor(0.1f, 0.2f, 0.3f, 1.0f);
679     glClear( clearBufferBit );
680 
681     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
682     glReadPixels(0, 0, desc.width, viewport_height, format, type, pixels);
683 
684 exit_clean:
685     // Put back state
686     glUseProgram(savedProgram);
687     glDisableVertexAttribArray(0);
688     glViewport(savedViewport[0],savedViewport[1],savedViewport[2],savedViewport[3]);
689 
690     return;
691 }
692 
693 static inline void
dumpActiveTextureLevel(StateWriter & writer,Context & context,GLenum target,GLint level,const std::string & label,const char * userLabel)694 dumpActiveTextureLevel(StateWriter &writer, Context &context,
695                        GLenum target, GLint level,
696                        const std::string & label,
697                        const char *userLabel)
698 {
699 
700     bool multiSample = (target == GL_TEXTURE_2D_MULTISAMPLE
701                         || target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) ? true : false;
702 
703     ImageDesc desc;
704     if (!getActiveTextureLevelDesc(context, target, level, desc)) {
705         return;
706     }
707 
708     const InternalFormatDesc &formatDesc = getInternalFormatDesc(desc.internalFormat);
709 
710     GLenum format;
711     GLenum type;
712     const PixelFormat *pixelFormat = nullptr;
713 
714     if (target == GL_TEXTURE_BUFFER) {
715         pixelFormat = getPixelFormat(desc.internalFormat);
716         if (!pixelFormat) {
717             std::cerr << "warning: unsupported texture buffer internal format " << formatToString(desc.internalFormat) << "\n";
718             return;
719         }
720         format = GL_RGBA;
721         type = GL_FLOAT;
722     } else {
723         chooseReadBackFormat(formatDesc, format, type);
724     }
725 
726     writer.beginMember(label);
727 
728     if (context.ES && format == GL_DEPTH_COMPONENT) {
729         format = GL_RED;
730     }
731 
732     GLuint channels;
733     image::ChannelType channelType;
734     getImageFormat(format, type, channels, channelType);
735 
736     if (0) {
737         std::cerr << std::endl << std::endl;
738         std::cerr << label << ", " << userLabel << std::endl;
739         std::cerr << enumToString(desc.internalFormat) << ", " << enumToString(format) << ", " << enumToString(type) << std::endl;
740         std::cerr << "desc (w,h,d) (" << desc.width << ", " << desc.height << ", " << desc.depth << "), "
741                   << "channels: " << channels << ", channelType: " << channelType << std::endl;
742     }
743 
744     image::Image *image;
745     PixelPackState pps(context);
746 
747     if (target == GL_TEXTURE_BUFFER) {
748         assert(desc.height == 1);
749         assert(desc.depth == 1);
750         assert(pixelFormat);
751         assert(format == GL_RGBA);
752         assert(type == GL_FLOAT);
753 
754         image = new image::Image(desc.width, desc.height * desc.depth, channels, true, channelType);
755         assert(image->bytesPerPixel == sizeof(float[4]));
756 
757         GLint buffer = 0;
758         glGetIntegerv(GL_TEXTURE_BUFFER_DATA_STORE_BINDING, &buffer);
759         assert(buffer);
760 
761         BufferMapping bm;
762 
763         const GLvoid *map = bm.map(GL_TEXTURE_BUFFER, buffer);
764         if (map) {
765             pixelFormat->unpackSpan(static_cast<const uint8_t *>(map),
766                                     reinterpret_cast<float *>(image->pixels), image->width);
767         }
768     } else if (multiSample) {
769         // Perform multisample retrieval here.
770 
771         if (retrace::resolveMSAA){
772             // For resolved MSAA...
773             image = new image::Image(desc.width, desc.height, channels, true, channelType);
774             memset(image->pixels, 0x0, desc.width * desc.height * sizeof(int));
775             getTexImageMSAA(target, format, type, desc, image->pixels, true);
776         }
777         else {
778             // For unresolved MSAA...
779             GLuint samples = std::max(desc.samples, 1);
780             GLuint total_height = desc.height * samples;
781             image = new image::Image(desc.width, total_height, channels, true, channelType);
782             memset(image->pixels, 0x0, desc.width * total_height * sizeof(int));
783             getTexImageMSAA(target, format, type, desc, image->pixels, false);
784         }
785     }
786     else {
787         // Create a simple image single sample size.
788         image = new image::Image(desc.width, desc.height * desc.depth, channels, true, channelType);
789 
790         if (context.ES) {
791             getTexImageOES(target, level, format, type, desc, image->pixels);
792         } else {
793             glGetTexImage(target, level, format, type, image->pixels);
794         }
795     }
796 
797     if (userLabel) {
798         image->label = userLabel;
799     }
800 
801     StateWriter::ImageDesc imageDesc;
802     imageDesc.depth = desc.depth;
803     imageDesc.format = formatToString(desc.internalFormat);
804     writer.writeImage(image, imageDesc);
805 
806     delete image;
807 
808     writer.endMember(); // label
809 }
810 
811 
812 static inline void
dumpActiveTexture(StateWriter & writer,Context & context,GLenum target,GLuint texture)813 dumpActiveTexture(StateWriter &writer, Context &context, GLenum target, GLuint texture)
814 {
815     char *object_label = getObjectLabel(context, GL_TEXTURE, texture);
816 
817     GLint active_texture = GL_TEXTURE0;
818     glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
819     assert(active_texture >= GL_TEXTURE0);
820 
821     GLenum start_subtarget;
822     GLenum stop_subtarget;
823     if (target == GL_TEXTURE_CUBE_MAP) {
824         start_subtarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
825         stop_subtarget = start_subtarget + 6;
826     } else {
827         start_subtarget = target;
828         stop_subtarget = start_subtarget + 1;
829     }
830 
831     GLboolean allowMipmaps = target != GL_TEXTURE_RECTANGLE &&
832                              target != GL_TEXTURE_BUFFER &&
833                              target != GL_TEXTURE_2D_MULTISAMPLE &&
834                              target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
835 
836     GLint level = 0;
837     do {
838         ImageDesc desc;
839 
840         for (GLenum subtarget = start_subtarget; subtarget < stop_subtarget; ++subtarget) {
841             std::stringstream label;
842             label << "GL_TEXTURE" << (active_texture - GL_TEXTURE0) << ", "
843                   << enumToString(subtarget);
844             if (allowMipmaps) {
845                 label << ", level = " << level;
846             }
847 
848             if (!getActiveTextureLevelDesc(context, subtarget, level, desc)) {
849                 goto finished;
850             }
851             dumpActiveTextureLevel(writer, context, subtarget, level, label.str(), object_label);
852         }
853 
854         if (!allowMipmaps) {
855             // no mipmaps
856             break;
857         }
858 
859         ++level;
860     } while(true);
861 
862 finished:
863     free(object_label);
864 }
865 
866 static void
dumpTextureImages(StateWriter & writer,Context & context)867 dumpTextureImages(StateWriter &writer, Context &context)
868 {
869     if (!context.ARB_shader_image_load_store) {
870         return;
871     }
872 
873     GLint maxImageUnits = 0;
874     glGetIntegerv(GL_MAX_IMAGE_UNITS, &maxImageUnits);
875     glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
876 
877     for (GLint imageUnit = 0; imageUnit < maxImageUnits; ++imageUnit) {
878         GLint texture = 0;
879         glGetIntegeri_v(GL_IMAGE_BINDING_NAME, imageUnit, &texture);
880         if (texture) {
881             GLint level = 0;
882             glGetIntegeri_v(GL_IMAGE_BINDING_LEVEL, imageUnit, &level);
883             GLint isLayered = 0;
884             glGetIntegeri_v(GL_IMAGE_BINDING_LAYERED, imageUnit, &isLayered);
885             GLint layer = 0;
886             glGetIntegeri_v(GL_IMAGE_BINDING_LAYER, imageUnit, &layer);
887             std::stringstream label;
888             label << "Image Unit " << imageUnit;
889             if (level) {
890                 label << ", level = " << level;
891             }
892             if (isLayered) {
893                 label << ", layer = " << layer;
894             }
895             GLenum target = getTextureTarget(context, texture);
896             GLint previousTexture = 0;
897             glGetIntegerv(getTextureBinding(target), &previousTexture);
898 
899             glBindTexture(target, texture);
900             char *object_label = getObjectLabel(context, GL_TEXTURE, texture);
901             dumpActiveTextureLevel(writer, context, target, level, label.str(),
902                                    object_label);
903             free(object_label);
904             glBindTexture(target, previousTexture);
905         }
906     }
907 }
908 
909 
910 void
dumpTextures(StateWriter & writer,Context & context)911 dumpTextures(StateWriter &writer, Context &context)
912 {
913     writer.beginMember("textures");
914     writer.beginObject();
915 
916     GLint max_texture_coords = 0;
917     if (!context.core) {
918         glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);
919     }
920 
921     GLint max_combined_texture_image_units = 0;
922     glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_combined_texture_image_units);
923 
924     /*
925      * At least the Android software GL implementation doesn't return the
926      * proper value for this, but rather returns 0. The GL(ES) specification
927      * mandates a minimum value of 2, so use this as a fall-back value.
928      */
929     max_combined_texture_image_units = std::max(max_combined_texture_image_units, 2);
930 
931     GLint max_units = std::max(max_combined_texture_image_units, max_texture_coords);
932 
933     GLint active_texture = GL_TEXTURE0;
934     glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
935 
936     for (GLint unit = 0; unit < max_units; ++unit) {
937         GLenum texture = GL_TEXTURE0 + unit;
938         glActiveTexture(texture);
939 
940         for (auto target : textureTargets) {
941 
942             // Whether this fixed-function stage is enabled
943             GLboolean enabled = GL_FALSE;
944             if (unit < max_texture_coords &&
945                 (target == GL_TEXTURE_1D ||
946                  target == GL_TEXTURE_2D ||
947                  target == GL_TEXTURE_3D ||
948                  target == GL_TEXTURE_CUBE_MAP ||
949                  target == GL_TEXTURE_RECTANGLE)) {
950                 glGetBooleanv(target, &enabled);
951             }
952 
953             // Whether a texture object is bound
954             GLint texture = 0;
955             if (unit < max_combined_texture_image_units) {
956                 GLenum binding = getTextureBinding(target);
957                 glGetIntegerv(binding, &texture);
958             }
959 
960             if (enabled || texture) {
961                 dumpActiveTexture(writer, context, target, texture);
962             }
963         }
964     }
965 
966     glActiveTexture(active_texture);
967 
968     dumpTextureImages(writer, context);
969 
970     writer.endObject();
971     writer.endMember(); // textures
972 }
973 
974 
975 bool
getDrawableBounds(GLint * width,GLint * height)976 getDrawableBounds(GLint *width, GLint *height) {
977 #if defined(__unix__)
978     if (_getPublicProcAddress("eglGetCurrentContext")) {
979         EGLContext currentContext = eglGetCurrentContext();
980         if (currentContext != EGL_NO_CONTEXT) {
981             EGLSurface currentSurface = eglGetCurrentSurface(EGL_DRAW);
982             if (currentSurface == EGL_NO_SURFACE) {
983                 return false;
984             }
985 
986             EGLDisplay currentDisplay = eglGetCurrentDisplay();
987             if (currentDisplay == EGL_NO_DISPLAY) {
988                 return false;
989             }
990 
991             if (!eglQuerySurface(currentDisplay, currentSurface, EGL_WIDTH, width) ||
992                 !eglQuerySurface(currentDisplay, currentSurface, EGL_HEIGHT, height)) {
993                 return false;
994             }
995 
996             return true;
997         }
998     }
999 #endif
1000 
1001 #if defined(_WIN32)
1002 
1003     HDC hDC = wglGetCurrentDC();
1004     if (!hDC) {
1005         return false;
1006     }
1007 
1008     HWND hWnd = WindowFromDC(hDC);
1009     RECT rect;
1010 
1011     if (!GetClientRect(hWnd, &rect)) {
1012        return false;
1013     }
1014 
1015     *width  = rect.right  - rect.left;
1016     *height = rect.bottom - rect.top;
1017     return true;
1018 
1019 #elif defined(__APPLE__)
1020 
1021     CGLContextObj ctx = CGLGetCurrentContext();
1022     if (ctx == NULL) {
1023         return false;
1024     }
1025 
1026     CGSConnectionID cid;
1027     CGSWindowID wid;
1028     CGSSurfaceID sid;
1029 
1030     if (CGLGetSurface(ctx, &cid, &wid, &sid) != kCGLNoError) {
1031         return false;
1032     }
1033 
1034     CGRect rect;
1035 
1036     if (CGSGetSurfaceBounds(cid, wid, sid, &rect) != 0) {
1037         return false;
1038     }
1039 
1040     *width = rect.size.width;
1041     *height = rect.size.height;
1042     return true;
1043 
1044 #elif defined(HAVE_X11)
1045 
1046     Display *display;
1047     GLXDrawable drawable;
1048 
1049     display = glXGetCurrentDisplay();
1050     if (!display) {
1051         return false;
1052     }
1053 
1054     drawable = glXGetCurrentDrawable();
1055     if (drawable == None) {
1056         return false;
1057     }
1058 
1059     int major = 0, minor = 0;
1060     if (!glXQueryVersion(display, &major, &minor)) {
1061         return false;
1062     }
1063 
1064     // XGetGeometry will fail for PBuffers, whereas glXQueryDrawable should not.
1065     unsigned w = 0;
1066     unsigned h = 0;
1067     if (major > 1 || (major == 1 && minor >= 3)) {
1068         glXQueryDrawable(display, drawable, GLX_WIDTH, &w);
1069         glXQueryDrawable(display, drawable, GLX_HEIGHT, &h);
1070     } else {
1071         Window root;
1072         int x, y;
1073         unsigned bw, depth;
1074         XGetGeometry(display, drawable,  &root, &x, &y, &w, &h, &bw, &depth);
1075     }
1076 
1077     *width = w;
1078     *height = h;
1079     return true;
1080 
1081 #else
1082 
1083     return false;
1084 
1085 #endif
1086 }
1087 
1088 
1089 static GLenum
getTextureTarget(Context & context,GLuint texture)1090 getTextureTarget(Context &context, GLuint texture)
1091 {
1092     if (!glIsTexture(texture)) {
1093         return GL_NONE;
1094     }
1095 
1096     /*
1097      * GL_ARB_direct_state_access's glGetTextureParameteriv(GL_TEXTURE_TARGET)
1098      * would be perfect, except the fact it's not supported for
1099      * TEXTURE_BUFFERS...
1100      */
1101 
1102     GLint result = GL_NONE;
1103 
1104     flushErrors();
1105 
1106     // Temporarily disable debug messages
1107     GLDEBUGPROC prevDebugCallbackFunction = 0;
1108     void *prevDebugCallbackUserParam = 0;
1109     if (context.KHR_debug) {
1110         glGetPointerv(GL_DEBUG_CALLBACK_FUNCTION, (GLvoid **) &prevDebugCallbackFunction);
1111         glGetPointerv(GL_DEBUG_CALLBACK_USER_PARAM, &prevDebugCallbackUserParam);
1112         glDebugMessageCallback(NULL, NULL);
1113     }
1114 
1115     for (auto target : textureTargets) {
1116         GLenum binding = getTextureBinding(target);
1117 
1118         GLint bound_texture = 0;
1119         glGetIntegerv(binding, &bound_texture);
1120         glBindTexture(target, texture);
1121 
1122         bool succeeded = glGetError() == GL_NO_ERROR;
1123 
1124         glBindTexture(target, bound_texture);
1125 
1126         if (succeeded) {
1127             result = target;
1128             break;
1129         }
1130 
1131         flushErrors();
1132     }
1133 
1134     if (context.KHR_debug) {
1135         glDebugMessageCallback(prevDebugCallbackFunction, prevDebugCallbackUserParam);
1136     }
1137 
1138     return result;
1139 }
1140 
1141 
1142 static bool
getBoundRenderbufferDesc(Context & context,ImageDesc & desc)1143 getBoundRenderbufferDesc(Context &context, ImageDesc &desc)
1144 {
1145     glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &desc.width);
1146     glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &desc.height);
1147     desc.depth = 1;
1148 
1149     glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &desc.samples);
1150 
1151     glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_INTERNAL_FORMAT, &desc.internalFormat);
1152 
1153     return desc.valid();
1154 }
1155 
1156 
1157 static bool
getRenderbufferDesc(Context & context,GLint renderbuffer,ImageDesc & desc)1158 getRenderbufferDesc(Context &context, GLint renderbuffer, ImageDesc &desc)
1159 {
1160     GLint bound_renderbuffer = 0;
1161     glGetIntegerv(GL_RENDERBUFFER_BINDING, &bound_renderbuffer);
1162     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
1163 
1164     getBoundRenderbufferDesc(context, desc);
1165 
1166     glBindRenderbuffer(GL_RENDERBUFFER, bound_renderbuffer);
1167 
1168     return desc.valid();
1169 }
1170 
1171 
1172 static bool
getFramebufferAttachmentDesc(Context & context,GLenum target,GLenum attachment,ImageDesc & desc)1173 getFramebufferAttachmentDesc(Context &context, GLenum target, GLenum attachment, ImageDesc &desc)
1174 {
1175     GLint object_type = GL_NONE;
1176     glGetFramebufferAttachmentParameteriv(target, attachment,
1177                                           GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
1178                                           &object_type);
1179     if (object_type == GL_NONE) {
1180         return false;
1181     }
1182 
1183     GLint object_name = 0;
1184     glGetFramebufferAttachmentParameteriv(target, attachment,
1185                                           GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
1186                                           &object_name);
1187     if (object_name == 0) {
1188         return false;
1189     }
1190 
1191     if (object_type == GL_RENDERBUFFER) {
1192         return getRenderbufferDesc(context, object_name, desc);
1193     } else if (object_type == GL_TEXTURE) {
1194         GLint texture_face = 0;
1195         glGetFramebufferAttachmentParameteriv(target, attachment,
1196                                               GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE,
1197                                               &texture_face);
1198 
1199         GLint texture_level = 0;
1200         glGetFramebufferAttachmentParameteriv(target, attachment,
1201                                               GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL,
1202                                               &texture_level);
1203 
1204         GLint bound_texture = 0;
1205         if (texture_face != 0) {
1206             glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &bound_texture);
1207             glBindTexture(GL_TEXTURE_CUBE_MAP, object_name);
1208             getActiveTextureLevelDesc(context, texture_face, texture_level, desc);
1209             glBindTexture(GL_TEXTURE_CUBE_MAP, bound_texture);
1210         } else {
1211             GLenum texture_target = getTextureTarget(context, object_name);
1212             GLenum texture_binding = getTextureBinding(texture_target);
1213             glGetIntegerv(texture_binding, &bound_texture);
1214             glBindTexture(texture_target, object_name);
1215             getActiveTextureLevelDesc(context, texture_target, texture_level, desc);
1216             glBindTexture(texture_target, bound_texture);
1217         }
1218 
1219         return desc.valid();
1220     } else {
1221         std::cerr << "warning: unexpected GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = " << enumToString(object_type) << "\n";
1222         return false;
1223     }
1224 }
1225 
1226 
1227 int
getDrawBufferImageCount()1228 getDrawBufferImageCount()
1229 {
1230     Context context;
1231     GLint count;
1232 
1233     if (context.framebuffer_object) {
1234         glGetIntegerv(GL_MAX_DRAW_BUFFERS, &count);
1235         flushErrors();
1236     } else {
1237         return 0;
1238     }
1239 
1240     return count;
1241 }
1242 
1243 
1244 image::Image *
getDrawBufferImage(int n)1245 getDrawBufferImage(int n)
1246 {
1247     Context context;
1248 
1249     GLenum format = GL_RGB;
1250     GLenum type = GL_UNSIGNED_BYTE;
1251     if (context.ES) {
1252         format = GL_RGBA;
1253         if (n < 0 && !context.NV_read_depth_stencil) {
1254             return nullptr;
1255         }
1256     }
1257 
1258     GLenum framebuffer_binding;
1259     GLenum framebuffer_target;
1260     if (context.read_framebuffer_object) {
1261         framebuffer_binding = GL_DRAW_FRAMEBUFFER_BINDING;
1262         framebuffer_target = GL_DRAW_FRAMEBUFFER;
1263     } else {
1264         framebuffer_binding = GL_FRAMEBUFFER_BINDING;
1265         framebuffer_target = GL_FRAMEBUFFER;
1266     }
1267     GLint draw_framebuffer = 0;
1268     if (context.framebuffer_object) {
1269         glGetIntegerv(framebuffer_binding, &draw_framebuffer);
1270     }
1271 
1272     /*
1273      * TODO: Use alpha for non-FBOs once we are able to match the traced
1274      * visuals.
1275      */
1276     if (draw_framebuffer) {
1277         format = GL_RGBA;
1278     }
1279 
1280     if (n == -2) {
1281         /* read stencil */
1282         format = GL_STENCIL_INDEX;
1283         n = 0;
1284     } else if (n == -1) {
1285         /* read depth */
1286         format = GL_DEPTH_COMPONENT;
1287         n = 0;
1288     }
1289 
1290     GLint draw_buffer = GL_NONE;
1291     ImageDesc desc;
1292     if (draw_framebuffer) {
1293         if (context.ARB_draw_buffers) {
1294             glGetIntegerv(GL_DRAW_BUFFER0 + n, &draw_buffer);
1295             if (draw_buffer == GL_NONE) {
1296                 return NULL;
1297             }
1298         } else {
1299             // GL_COLOR_ATTACHMENT0 is implied
1300             draw_buffer = GL_COLOR_ATTACHMENT0 + n;
1301         }
1302 
1303         if (!getFramebufferAttachmentDesc(context, framebuffer_target, draw_buffer, desc)) {
1304             return NULL;
1305         }
1306     } else if (n == 0) {
1307         if (context.ES) {
1308             // XXX: Draw buffer is always FRONT for single buffer context, BACK
1309             // for double buffered contexts. There is no way to know which (as
1310             // GL_DOUBLEBUFFER state is also unavailable), so always assume
1311             // double-buffering.
1312             draw_buffer = GL_BACK;
1313         } else {
1314             glGetIntegerv(GL_DRAW_BUFFER, &draw_buffer);
1315             if (draw_buffer == GL_NONE) {
1316                 return NULL;
1317             }
1318         }
1319 
1320         if (!getDrawableBounds(&desc.width, &desc.height)) {
1321             return NULL;
1322         }
1323 
1324         desc.depth = 1;
1325     } else {
1326         return NULL;
1327     }
1328 
1329     GLint channels = _gl_format_channels(format);
1330     if (channels > 4) {
1331         return NULL;
1332     }
1333 
1334     image::ChannelType channelType = image::TYPE_UNORM8;
1335 
1336     if (format == GL_DEPTH_COMPONENT) {
1337         type = GL_FLOAT;
1338         channels = 1;
1339         channelType = image::TYPE_FLOAT;
1340     }
1341 
1342     image::Image *image = new image::Image(desc.width, desc.height, channels, true, channelType);
1343     if (!image) {
1344         return NULL;
1345     }
1346 
1347     flushErrors();
1348 
1349     GLint read_framebuffer = 0;
1350     GLint read_buffer = GL_NONE;
1351     if (context.read_framebuffer_object) {
1352         glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &read_framebuffer);
1353         glBindFramebuffer(GL_READ_FRAMEBUFFER, draw_framebuffer);
1354     }
1355 
1356     if (context.read_buffer) {
1357         glGetIntegerv(GL_READ_BUFFER, &read_buffer);
1358         glReadBuffer(draw_buffer);
1359     }
1360 
1361     {
1362         // TODO: reset imaging state too
1363         PixelPackState pps(context);
1364         glReadPixels(0, 0, desc.width, desc.height, format, type, image->pixels);
1365     }
1366 
1367 
1368     if (context.read_buffer) {
1369         glReadBuffer(read_buffer);
1370     }
1371     if (context.read_framebuffer_object) {
1372         glBindFramebuffer(GL_READ_FRAMEBUFFER, read_framebuffer);
1373     }
1374 
1375     GLenum error = glGetError();
1376     if (error != GL_NO_ERROR) {
1377         do {
1378             std::cerr << "warning: " << enumToString(error) << " while getting snapshot\n";
1379             error = glGetError();
1380         } while(error != GL_NO_ERROR);
1381         delete image;
1382         return NULL;
1383     }
1384 
1385     return image;
1386 }
1387 
1388 
1389 /**
1390  * Dump the image of the currently bound read buffer.
1391  */
1392 static inline void
dumpReadBufferImage(StateWriter & writer,Context & context,const char * label,const char * userLabel,GLint width,GLint height,GLenum format,GLenum type,GLenum internalFormat=GL_NONE)1393 dumpReadBufferImage(StateWriter &writer,
1394                     Context & context,
1395                     const char *label,
1396                     const char *userLabel,
1397                     GLint width, GLint height,
1398                     GLenum format, GLenum type,
1399                     GLenum internalFormat = GL_NONE)
1400 {
1401     if (internalFormat == GL_NONE) {
1402         internalFormat = format;
1403     }
1404 
1405     if (context.ES) {
1406         switch (format) {
1407         case GL_DEPTH_COMPONENT:
1408         case GL_DEPTH_STENCIL:
1409             if (!context.NV_read_depth_stencil) {
1410                 return;
1411             }
1412             /* FIXME: NV_read_depth_stencil states that type must match the
1413              * internal format, whereas we always request GL_FLOAT, as that's
1414              * what we want.  To fix this we should probe the adequate type
1415              * here, and then manually convert the pixels to float after
1416              * glReadPixels */
1417             break;
1418         case GL_STENCIL_INDEX:
1419             if (!context.NV_read_depth_stencil) {
1420                 return;
1421             }
1422             type = GL_UNSIGNED_BYTE;
1423             break;
1424         default:
1425             // Color formats -- GLES glReadPixels only supports the following combinations:
1426             // - GL_RGBA and GL_UNSIGNED_BYTE
1427             // - values of IMPLEMENTATION_COLOR_READ_FORMAT and IMPLEMENTATION_COLOR_READ_TYPE
1428             format = GL_RGBA;
1429             type = GL_UNSIGNED_BYTE;
1430             break;
1431         }
1432     }
1433 
1434     GLuint channels;
1435     image::ChannelType channelType;
1436     getImageFormat(format, type, channels, channelType);
1437 
1438     if (0) {
1439         std::cerr << enumToString(internalFormat) << " "
1440                   << enumToString(format) << " "
1441                   << enumToString(type) << "\n";
1442     }
1443 
1444     image::Image *image = new image::Image(width, height, channels, true, channelType);
1445 
1446     flushErrors();
1447 
1448     {
1449         // TODO: reset imaging state too
1450         PixelPackState pps(context);
1451 
1452         glReadPixels(0, 0, width, height, format, type, image->pixels);
1453     }
1454 
1455     GLenum error = glGetError();
1456     if (error != GL_NO_ERROR) {
1457         do {
1458             std::cerr << "warning: " << enumToString(error) << " while reading framebuffer\n";
1459             error = glGetError();
1460         } while(error != GL_NO_ERROR);
1461     } else {
1462         if (userLabel) {
1463             image->label = userLabel;
1464         }
1465 
1466         StateWriter::ImageDesc imageDesc;
1467         imageDesc.format = formatToString(internalFormat);
1468         writer.beginMember(label);
1469         writer.writeImage(image, imageDesc);
1470         writer.endMember();
1471     }
1472 
1473     delete image;
1474 }
1475 
1476 
1477 static inline GLuint
downsampledFramebuffer(Context & context,GLuint oldFbo,GLint drawbuffer,const ImageDesc & colorDesc,const ImageDesc & depthDesc,const ImageDesc & stencilDesc,GLuint * rbs,GLint * numRbs)1478 downsampledFramebuffer(Context &context,
1479                        GLuint oldFbo, GLint drawbuffer,
1480                        const ImageDesc &colorDesc,
1481                        const ImageDesc &depthDesc,
1482                        const ImageDesc &stencilDesc,
1483                        GLuint *rbs, GLint *numRbs)
1484 {
1485     GLuint fbo;
1486 
1487     *numRbs = 0;
1488 
1489     glGenFramebuffers(1, &fbo);
1490     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1491 
1492     GLboolean scissor_test = glIsEnabled(GL_SCISSOR_TEST);
1493     if (scissor_test) {
1494         glDisable(GL_SCISSOR_TEST);
1495     }
1496 
1497     {
1498         // color buffer
1499         GLint maxColorAtt = 0;
1500         glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxColorAtt);
1501         std::vector<GLenum> drawbufs(maxColorAtt);
1502         for (int iColorAtt = 0; iColorAtt < maxColorAtt; ++iColorAtt) {
1503             GLenum colorAtt = GL_COLOR_ATTACHMENT0 + iColorAtt;
1504             drawbufs[iColorAtt] = colorAtt;
1505 
1506             glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
1507             GLint objType = GL_NONE;
1508             glGetFramebufferAttachmentParameteriv(GL_READ_FRAMEBUFFER, colorAtt,
1509                                                   GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &objType);
1510             if (objType != GL_NONE) {
1511                glGenRenderbuffers(1, &rbs[*numRbs]);
1512 
1513                glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
1514                glRenderbufferStorage(GL_RENDERBUFFER, colorDesc.internalFormat, colorDesc.width, colorDesc.height);
1515                glFramebufferRenderbuffer(GL_FRAMEBUFFER, colorAtt,
1516                                          GL_RENDERBUFFER, rbs[*numRbs]);
1517 
1518                glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
1519                glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
1520                glReadBuffer(colorAtt);
1521                glDrawBuffer(colorAtt);
1522 
1523                glBlitFramebuffer(0, 0, colorDesc.width, colorDesc.height, 0, 0, colorDesc.width, colorDesc.height,
1524                                  GL_COLOR_BUFFER_BIT, GL_NEAREST);
1525                glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1526                ++*numRbs;
1527             }
1528         }
1529         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1530         glDrawBuffers(maxColorAtt, &drawbufs[0]);
1531     }
1532 
1533     if (stencilDesc == depthDesc &&
1534         depthDesc.valid()) {
1535         //combined depth and stencil buffer
1536         glGenRenderbuffers(1, &rbs[*numRbs]);
1537         glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
1538         glRenderbufferStorage(GL_RENDERBUFFER, depthDesc.internalFormat, depthDesc.width, depthDesc.height);
1539         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
1540                                   GL_RENDERBUFFER, rbs[*numRbs]);
1541         glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
1542         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
1543         glDrawBuffer(drawbuffer);
1544         glReadBuffer(drawbuffer);
1545         glBlitFramebuffer(0, 0, depthDesc.width, depthDesc.height, 0, 0, depthDesc.width, depthDesc.height,
1546                           GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
1547         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1548         ++*numRbs;
1549     } else {
1550         if (depthDesc.valid()) {
1551             glGenRenderbuffers(1, &rbs[*numRbs]);
1552             glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
1553             glRenderbufferStorage(GL_RENDERBUFFER, depthDesc.internalFormat, depthDesc.width, depthDesc.height);
1554             glFramebufferRenderbuffer(GL_FRAMEBUFFER,
1555                                       GL_DEPTH_ATTACHMENT,
1556                                       GL_RENDERBUFFER, rbs[*numRbs]);
1557             glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
1558             glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
1559             glDrawBuffer(drawbuffer);
1560             glReadBuffer(drawbuffer);
1561             glBlitFramebuffer(0, 0, depthDesc.width, depthDesc.height, 0, 0, depthDesc.width, depthDesc.height,
1562                               GL_DEPTH_BUFFER_BIT, GL_NEAREST);
1563             glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1564             ++*numRbs;
1565         }
1566         if (stencilDesc.valid()) {
1567             glGenRenderbuffers(1, &rbs[*numRbs]);
1568             glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
1569             glRenderbufferStorage(GL_RENDERBUFFER, stencilDesc.internalFormat, stencilDesc.width, stencilDesc.height);
1570             glFramebufferRenderbuffer(GL_FRAMEBUFFER,
1571                                       GL_STENCIL_ATTACHMENT,
1572                                       GL_RENDERBUFFER, rbs[*numRbs]);
1573             glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
1574             glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
1575             glDrawBuffer(drawbuffer);
1576             glReadBuffer(drawbuffer);
1577             glBlitFramebuffer(0, 0, stencilDesc.width, stencilDesc.height, 0, 0, stencilDesc.width, stencilDesc.height,
1578                               GL_STENCIL_BUFFER_BIT, GL_NEAREST);
1579             glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1580             ++*numRbs;
1581         }
1582     }
1583 
1584     if (scissor_test) {
1585         glEnable(GL_SCISSOR_TEST);
1586     }
1587 
1588     return fbo;
1589 }
1590 
1591 
1592 /**
1593  * Dump images of current draw drawable/window.
1594  */
1595 static void
dumpDrawableImages(StateWriter & writer,Context & context)1596 dumpDrawableImages(StateWriter &writer, Context &context)
1597 {
1598     GLint width, height;
1599 
1600     if (!getDrawableBounds(&width, &height)) {
1601         return;
1602     }
1603 
1604     GLint draw_buffer = GL_NONE;
1605     if (context.ES) {
1606         // XXX: Draw buffer is always FRONT for single buffer context, BACK for
1607         // double buffered contexts. There is no way to know which (as
1608         // GL_DOUBLEBUFFER state is also unavailable), so always assume
1609         // double-buffering.
1610         draw_buffer = GL_BACK;
1611     } else {
1612         glGetIntegerv(GL_DRAW_BUFFER, &draw_buffer);
1613     }
1614 
1615     // Reset read framebuffer
1616     GLint read_framebuffer = 0;
1617     if (context.read_framebuffer_object) {
1618         glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &read_framebuffer);
1619         glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
1620     } else if (context.framebuffer_object) {
1621         glGetIntegerv(GL_FRAMEBUFFER_BINDING, &read_framebuffer);
1622         glBindFramebuffer(GL_FRAMEBUFFER, 0);
1623     }
1624 
1625     if (draw_buffer != GL_NONE) {
1626         // Read from current draw buffer
1627         GLint read_buffer = GL_NONE;
1628         if (context.read_buffer) {
1629             glGetIntegerv(GL_READ_BUFFER, &read_buffer);
1630             glReadBuffer(draw_buffer);
1631         }
1632 
1633         GLint alpha_bits = 0;
1634 #if 0
1635         // XXX: Ignore alpha until we are able to match the traced visual
1636         glGetIntegerv(GL_ALPHA_BITS, &alpha_bits);
1637 #endif
1638         GLenum format = alpha_bits ? GL_RGBA : GL_RGB;
1639         GLenum type = GL_UNSIGNED_BYTE;
1640 
1641         dumpReadBufferImage(writer, context, enumToString(draw_buffer), NULL, width, height, format, type);
1642 
1643         // Restore original read buffer
1644         if (context.read_buffer) {
1645             glReadBuffer(read_buffer);
1646         }
1647     }
1648 
1649     if (!context.ES || context.NV_read_depth_stencil) {
1650         GLint depth_bits = 0;
1651         if (context.core) {
1652             glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_DEPTH, GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE, &depth_bits);
1653         } else {
1654             glGetIntegerv(GL_DEPTH_BITS, &depth_bits);
1655         }
1656         if (depth_bits) {
1657             dumpReadBufferImage(writer, context, "GL_DEPTH_COMPONENT", NULL, width, height, GL_DEPTH_COMPONENT, GL_FLOAT);
1658         }
1659 
1660         GLint stencil_bits = 0;
1661         if (context.core) {
1662             glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_STENCIL, GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, &stencil_bits);
1663         } else {
1664             glGetIntegerv(GL_STENCIL_BITS, &stencil_bits);
1665         }
1666         if (stencil_bits) {
1667             assert(stencil_bits <= 8);
1668             dumpReadBufferImage(writer, context, "GL_STENCIL_INDEX", NULL, width, height, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE);
1669         }
1670     }
1671 
1672     // Restore original read framebuffer
1673     if (context.read_framebuffer_object) {
1674         glBindFramebuffer(GL_READ_FRAMEBUFFER, read_framebuffer);
1675     } else if (context.framebuffer_object) {
1676         glBindFramebuffer(GL_FRAMEBUFFER, read_framebuffer);
1677     }
1678 }
1679 
1680 
1681 /**
1682  * Dump the specified framebuffer attachment.
1683  *
1684  * In the case of a color attachment, it assumes it is already bound for read.
1685  */
1686 static void
dumpFramebufferAttachment(StateWriter & writer,Context & context,GLenum target,GLenum attachment)1687 dumpFramebufferAttachment(StateWriter &writer, Context &context, GLenum target, GLenum attachment)
1688 {
1689     ImageDesc desc;
1690     if (!getFramebufferAttachmentDesc(context, target, attachment, desc)) {
1691         return;
1692     }
1693 
1694     assert(desc.samples == 0);
1695 
1696     GLenum format;
1697     GLenum type;
1698     switch (attachment) {
1699     case GL_DEPTH_ATTACHMENT:
1700         format = GL_DEPTH_COMPONENT;
1701         type = GL_FLOAT;
1702         break;
1703     case GL_STENCIL_ATTACHMENT:
1704         format = GL_STENCIL_INDEX;
1705         type = GL_UNSIGNED_BYTE;
1706         break;
1707     default:
1708         assert(desc.internalFormat != GL_NONE);
1709         const InternalFormatDesc &formatDesc = getInternalFormatDesc(desc.internalFormat);
1710         chooseReadBackFormat(formatDesc, format, type);
1711     }
1712 
1713     GLint object_type = GL_NONE;
1714     glGetFramebufferAttachmentParameteriv(target, attachment,
1715                                           GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
1716                                           &object_type);
1717     GLint object_name = 0;
1718     glGetFramebufferAttachmentParameteriv(target, attachment,
1719                                           GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
1720                                           &object_name);
1721     char *object_label = getObjectLabel(context, object_type, object_name);
1722 
1723     const char *label = enumToString(attachment);
1724 
1725     if (object_type == GL_TEXTURE) {
1726         GLint layered = GL_FALSE;
1727         glGetFramebufferAttachmentParameteriv(target, attachment,
1728                                               GL_FRAMEBUFFER_ATTACHMENT_LAYERED,
1729                                               &layered);
1730         if (layered &&
1731             isGeometryShaderBound(context)) {
1732             /*
1733              * Dump the whole texture array.
1734              *
1735              * Unfortunately we can't tell whether the bound GS writes or not gl_Layer.
1736              */
1737 
1738             GLint level = 0;
1739             glGetFramebufferAttachmentParameteriv(target, attachment,
1740                                                   GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL,
1741                                                   &level);
1742 
1743             GLenum texture_target = getTextureTarget(context, object_name);
1744             GLenum texture_binding = getTextureBinding(texture_target);
1745 
1746             GLint bound_texture = 0;
1747             glGetIntegerv(texture_binding, &bound_texture);
1748             glBindTexture(texture_target, object_name);
1749 
1750             dumpActiveTextureLevel(writer, context, texture_target, level, label, object_label);
1751 
1752             glBindTexture(texture_target, bound_texture);
1753 
1754             free(object_label);
1755             return;
1756         }
1757     }
1758 
1759 
1760     dumpReadBufferImage(writer, context,
1761                         label, object_label,
1762                         desc.width, desc.height,
1763                         format, type, desc.internalFormat);
1764     free(object_label);
1765 }
1766 
1767 
1768 static void
dumpFramebufferAttachments(StateWriter & writer,Context & context,GLenum target)1769 dumpFramebufferAttachments(StateWriter &writer, Context &context, GLenum target)
1770 {
1771     GLenum status = glCheckFramebufferStatus(target);
1772     if (status != GL_FRAMEBUFFER_COMPLETE) {
1773         std::cerr
1774             << "warning: incomplete " << enumToString(target)
1775             << " (" << enumToString(status) << ")\n";
1776         return;
1777     }
1778 
1779     GLint read_framebuffer = 0;
1780     glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &read_framebuffer);
1781 
1782     GLint read_buffer = GL_NONE;
1783     glGetIntegerv(GL_READ_BUFFER, &read_buffer);
1784 
1785     GLint max_draw_buffers = 1;
1786     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &max_draw_buffers);
1787     GLint max_color_attachments = 0;
1788     glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &max_color_attachments);
1789 
1790     for (GLint i = 0; i < max_draw_buffers; ++i) {
1791         GLint draw_buffer = GL_NONE;
1792         glGetIntegerv(GL_DRAW_BUFFER0 + i, &draw_buffer);
1793         if (draw_buffer != GL_NONE) {
1794             glReadBuffer(draw_buffer);
1795             GLint attachment;
1796             if (draw_buffer >= GL_COLOR_ATTACHMENT0 && draw_buffer < GL_COLOR_ATTACHMENT0 + max_color_attachments) {
1797                 attachment = draw_buffer;
1798             } else {
1799                 std::cerr << "warning: unexpected GL_DRAW_BUFFER" << i << " = " << draw_buffer << "\n";
1800                 attachment = GL_COLOR_ATTACHMENT0;
1801             }
1802             dumpFramebufferAttachment(writer, context, target, attachment);
1803         }
1804     }
1805 
1806     glReadBuffer(read_buffer);
1807 
1808     if (!context.ES || context.NV_read_depth_stencil) {
1809         dumpFramebufferAttachment(writer, context, target, GL_DEPTH_ATTACHMENT);
1810         dumpFramebufferAttachment(writer, context, target, GL_STENCIL_ATTACHMENT);
1811     }
1812 
1813     glBindFramebuffer(GL_READ_FRAMEBUFFER, read_framebuffer);
1814 }
1815 
1816 
1817 void
dumpFramebuffer(StateWriter & writer,Context & context)1818 dumpFramebuffer(StateWriter &writer, Context &context)
1819 {
1820     writer.beginMember("framebuffer");
1821     writer.beginObject();
1822 
1823     GLint boundDrawFbo = 0, boundReadFbo = 0;
1824     glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &boundDrawFbo);
1825     glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &boundReadFbo);
1826     if (!boundDrawFbo) {
1827         dumpDrawableImages(writer, context);
1828     } else if (context.ES) {
1829         dumpFramebufferAttachments(writer, context, GL_FRAMEBUFFER);
1830     } else {
1831         GLint draw_buffer0 = GL_NONE;
1832         glGetIntegerv(GL_DRAW_BUFFER0, &draw_buffer0);
1833         bool multisample = false;
1834 
1835         GLint boundRb = 0;
1836         glGetIntegerv(GL_RENDERBUFFER_BINDING, &boundRb);
1837 
1838         ImageDesc colorDesc;
1839         /* If a draw buffer is not bound then we shouldn't query the attachment. */
1840         if (draw_buffer0 != 0) {
1841             if (getFramebufferAttachmentDesc(context, GL_DRAW_FRAMEBUFFER, draw_buffer0, colorDesc)) {
1842                 if (colorDesc.samples) {
1843                     multisample = true;
1844                 }
1845             }
1846         }
1847 
1848         ImageDesc depthDesc;
1849         if (getFramebufferAttachmentDesc(context, GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthDesc)) {
1850             if (depthDesc.samples) {
1851                 multisample = true;
1852             }
1853         }
1854 
1855         ImageDesc stencilDesc;
1856         if (getFramebufferAttachmentDesc(context, GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, stencilDesc)) {
1857             if (stencilDesc.samples) {
1858                 multisample = true;
1859             }
1860         }
1861 
1862         GLuint rbs[2 + 8];
1863         GLint numRbs = 0;
1864         GLuint fboCopy = 0;
1865 
1866         if (multisample) {
1867             // glReadPixels doesnt support multisampled buffers so we need
1868             // to blit the fbo to a temporary one
1869             fboCopy = downsampledFramebuffer(context,
1870                                              boundDrawFbo, draw_buffer0,
1871                                              colorDesc, depthDesc, stencilDesc,
1872                                              rbs, &numRbs);
1873         } else {
1874             glBindFramebuffer(GL_READ_FRAMEBUFFER, boundDrawFbo);
1875         }
1876 
1877         dumpFramebufferAttachments(writer, context, GL_READ_FRAMEBUFFER);
1878 
1879         if (multisample) {
1880             glBindRenderbuffer(GL_RENDERBUFFER, boundRb);
1881             assert(numRbs < sizeof rbs / sizeof rbs[0]);
1882             glDeleteRenderbuffers(numRbs, rbs);
1883             glDeleteFramebuffers(1, &fboCopy);
1884         }
1885 
1886         glBindFramebuffer(GL_READ_FRAMEBUFFER, boundReadFbo);
1887         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, boundDrawFbo);
1888     }
1889 
1890     writer.endObject();
1891     writer.endMember(); // framebuffer
1892 }
1893 
1894 
1895 } /* namespace glstate */
1896