1 /**************************************************************************
3 * Copyright 2011 Jose Fonseca
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
24 **************************************************************************/
36 #include "glstate.hpp"
37 #include "glstate_internal.hpp"
42 #include <Carbon/Carbon.h>
48 OSStatus CGSGetSurfaceBounds(CGSConnectionID, CGWindowID, CGSSurfaceID, CGRect *);
54 #endif /* __APPLE__ */
57 /* Change thi to one to force interpreting depth buffers as RGBA, which enables
58 * visualizing full dynamic range, until we can transmit HDR images to the GUI */
59 #define DEPTH_AS_RGBA 0
66 dumpTextureImage(JSONWriter &json, Context &context, GLenum target, GLint level)
68 GLint width, height = 1, depth = 1;
71 glGetTexLevelParameteriv(target, level, GL_TEXTURE_INTERNAL_FORMAT, &format);
74 glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &width);
76 if (target != GL_TEXTURE_1D) {
78 glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &height);
79 if (target == GL_TEXTURE_3D) {
81 glGetTexLevelParameteriv(target, level, GL_TEXTURE_DEPTH, &depth);
85 if (width <= 0 || height <= 0 || depth <= 0) {
90 GLint active_texture = GL_TEXTURE0;
91 glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
92 snprintf(label, sizeof label, "%s, %s, level = %d",
93 enumToString(active_texture), enumToString(target), level);
95 json.beginMember(label);
99 // Tell the GUI this is no ordinary object, but an image
100 json.writeStringMember("__class__", "image");
102 json.writeNumberMember("__width__", width);
103 json.writeNumberMember("__height__", height);
104 json.writeNumberMember("__depth__", depth);
106 json.writeStringMember("__format__", enumToString(format));
108 // Hardcoded for now, but we could chose types more adequate to the
109 // texture internal format
110 json.writeStringMember("__type__", "uint8");
111 json.writeBoolMember("__normalized__", true);
112 json.writeNumberMember("__channels__", 4);
114 GLubyte *pixels = new GLubyte[depth*width*height*4];
116 context.resetPixelPackState();
118 glGetTexImage(target, level, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
120 context.restorePixelPackState();
122 json.beginMember("__data__");
125 image::writePixelsToBuffer(pixels, width, height, 4, true, &pngBuffer, &pngBufferSize);
126 json.writeBase64(pngBuffer, pngBufferSize);
128 json.endMember(); // __data__
137 dumpTexture(JSONWriter &json, Context &context, GLenum target, GLenum binding)
139 GLint texture_binding = 0;
140 glGetIntegerv(binding, &texture_binding);
141 if (!glIsEnabled(target) && !texture_binding) {
147 GLint width = 0, height = 0;
148 glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &width);
149 glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &height);
150 if (!width || !height) {
154 if (target == GL_TEXTURE_CUBE_MAP) {
155 for (int face = 0; face < 6; ++face) {
156 dumpTextureImage(json, context, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
159 dumpTextureImage(json, context, target, level);
168 dumpTextures(JSONWriter &json, Context &context)
170 json.beginMember("textures");
172 GLint active_texture = GL_TEXTURE0;
173 glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
174 GLint max_texture_coords = 0;
175 glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);
176 GLint max_combined_texture_image_units = 0;
177 glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_combined_texture_image_units);
178 GLint max_units = std::max(max_combined_texture_image_units, max_texture_coords);
179 for (GLint unit = 0; unit < max_units; ++unit) {
180 GLenum texture = GL_TEXTURE0 + unit;
181 glActiveTexture(texture);
182 dumpTexture(json, context, GL_TEXTURE_1D, GL_TEXTURE_BINDING_1D);
183 dumpTexture(json, context, GL_TEXTURE_2D, GL_TEXTURE_BINDING_2D);
184 dumpTexture(json, context, GL_TEXTURE_3D, GL_TEXTURE_BINDING_3D);
185 dumpTexture(json, context, GL_TEXTURE_RECTANGLE, GL_TEXTURE_BINDING_RECTANGLE);
186 dumpTexture(json, context, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BINDING_CUBE_MAP);
188 glActiveTexture(active_texture);
190 json.endMember(); // textures
195 getDrawableBounds(GLint *width, GLint *height) {
196 #if defined(TRACE_EGL)
198 EGLContext currentContext = eglGetCurrentContext();
199 if (currentContext == EGL_NO_CONTEXT) {
203 EGLSurface currentSurface = eglGetCurrentSurface(EGL_DRAW);
204 if (currentSurface == EGL_NO_SURFACE) {
208 EGLDisplay currentDisplay = eglGetCurrentDisplay();
209 if (currentDisplay == EGL_NO_DISPLAY) {
213 if (!eglQuerySurface(currentDisplay, currentSurface, EGL_WIDTH, width) ||
214 !eglQuerySurface(currentDisplay, currentSurface, EGL_HEIGHT, height)) {
220 #elif defined(_WIN32)
222 HDC hDC = wglGetCurrentDC();
227 HWND hWnd = WindowFromDC(hDC);
230 if (!GetClientRect(hWnd, &rect)) {
234 *width = rect.right - rect.left;
235 *height = rect.bottom - rect.top;
238 #elif defined(__APPLE__)
240 CGLContextObj ctx = CGLGetCurrentContext();
249 if (CGLGetSurface(ctx, &cid, &wid, &sid) != kCGLNoError) {
255 if (CGSGetSurfaceBounds(cid, wid, sid, &rect) != 0) {
259 *width = rect.size.width;
260 *height = rect.size.height;
263 #elif defined(HAVE_X11)
269 unsigned int w, h, bw, depth;
271 display = glXGetCurrentDisplay();
276 drawable = glXGetCurrentDrawable();
277 if (drawable == None) {
281 if (!XGetGeometry(display, drawable, &root, &x, &y, &w, &h, &bw, &depth)) {
297 static const GLenum texture_bindings[][2] = {
298 {GL_TEXTURE_1D, GL_TEXTURE_BINDING_1D},
299 {GL_TEXTURE_2D, GL_TEXTURE_BINDING_2D},
300 {GL_TEXTURE_3D, GL_TEXTURE_BINDING_3D},
301 {GL_TEXTURE_RECTANGLE, GL_TEXTURE_BINDING_RECTANGLE},
302 {GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BINDING_CUBE_MAP}
307 bindTexture(GLint texture, GLenum &target, GLint &bound_texture)
310 for (unsigned i = 0; i < sizeof(texture_bindings)/sizeof(texture_bindings[0]); ++i) {
311 target = texture_bindings[i][0];
313 GLenum binding = texture_bindings[i][1];
315 while (glGetError() != GL_NO_ERROR)
318 glGetIntegerv(binding, &bound_texture);
319 glBindTexture(target, texture);
321 if (glGetError() == GL_NO_ERROR) {
325 glBindTexture(target, bound_texture);
335 getTextureLevelSize(GLint texture, GLint level, GLint *width, GLint *height)
341 GLint bound_texture = 0;
342 if (!bindTexture(texture, target, bound_texture)) {
346 glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, width);
347 glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, height);
349 glBindTexture(target, bound_texture);
351 return *width > 0 && *height > 0;
356 getTextureLevelFormat(GLint texture, GLint level)
359 GLint bound_texture = 0;
360 if (!bindTexture(texture, target, bound_texture)) {
364 GLint format = GL_NONE;
365 glGetTexLevelParameteriv(target, level, GL_TEXTURE_INTERNAL_FORMAT, &format);
367 glBindTexture(target, bound_texture);
375 getRenderbufferSize(GLint renderbuffer, GLint *width, GLint *height)
377 GLint bound_renderbuffer = 0;
378 glGetIntegerv(GL_RENDERBUFFER_BINDING, &bound_renderbuffer);
379 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
383 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, width);
384 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, height);
386 glBindRenderbuffer(GL_RENDERBUFFER, bound_renderbuffer);
388 return *width > 0 && *height > 0;
393 getRenderbufferFormat(GLint renderbuffer)
395 GLint bound_renderbuffer = 0;
396 glGetIntegerv(GL_RENDERBUFFER_BINDING, &bound_renderbuffer);
397 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
399 GLint format = GL_NONE;
400 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
402 glBindRenderbuffer(GL_RENDERBUFFER, bound_renderbuffer);
409 getFramebufferAttachmentSize(GLenum target, GLenum attachment, GLint *width, GLint *height)
411 GLint object_type = GL_NONE;
412 glGetFramebufferAttachmentParameteriv(target, attachment,
413 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
415 if (object_type == GL_NONE) {
419 GLint object_name = 0;
420 glGetFramebufferAttachmentParameteriv(target, attachment,
421 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
423 if (object_name == 0) {
427 if (object_type == GL_RENDERBUFFER) {
428 return getRenderbufferSize(object_name, width, height);
429 } else if (object_type == GL_TEXTURE) {
430 GLint texture_level = 0;
431 glGetFramebufferAttachmentParameteriv(target, attachment,
432 GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL,
434 return getTextureLevelSize(object_name, texture_level, width, height);
436 std::cerr << "warning: unexpected GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = " << object_type << "\n";
444 getFramebufferAttachmentFormat(GLenum target, GLenum attachment)
446 GLint object_type = GL_NONE;
447 glGetFramebufferAttachmentParameteriv(target, attachment,
448 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
450 if (object_type == GL_NONE) {
454 GLint object_name = 0;
455 glGetFramebufferAttachmentParameteriv(target, attachment,
456 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
458 if (object_name == 0) {
462 if (object_type == GL_RENDERBUFFER) {
463 return getRenderbufferFormat(object_name);
464 } else if (object_type == GL_TEXTURE) {
465 GLint texture_level = 0;
466 glGetFramebufferAttachmentParameteriv(target, attachment,
467 GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL,
469 return getTextureLevelFormat(object_name, texture_level);
471 std::cerr << "warning: unexpected GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = " << object_type << "\n";
479 getDrawBufferImage() {
480 GLenum format = GL_RGB;
481 GLint channels = __gl_format_channels(format);
488 GLenum framebuffer_binding;
489 GLenum framebuffer_target;
491 framebuffer_binding = GL_FRAMEBUFFER_BINDING;
492 framebuffer_target = GL_FRAMEBUFFER;
494 framebuffer_binding = GL_DRAW_FRAMEBUFFER_BINDING;
495 framebuffer_target = GL_DRAW_FRAMEBUFFER;
498 GLint draw_framebuffer = 0;
499 glGetIntegerv(framebuffer_binding, &draw_framebuffer);
501 GLint draw_buffer = GL_NONE;
503 if (draw_framebuffer) {
504 if (context.ARB_draw_buffers) {
505 glGetIntegerv(GL_DRAW_BUFFER0, &draw_buffer);
506 if (draw_buffer == GL_NONE) {
511 if (!getFramebufferAttachmentSize(framebuffer_target, draw_buffer, &width, &height)) {
516 glGetIntegerv(GL_DRAW_BUFFER, &draw_buffer);
517 if (draw_buffer == GL_NONE) {
522 if (!getDrawableBounds(&width, &height)) {
527 GLenum type = GL_UNSIGNED_BYTE;
530 if (format == GL_DEPTH_COMPONENT) {
531 type = GL_UNSIGNED_INT;
536 image::Image *image = new image::Image(width, height, channels, true);
541 while (glGetError() != GL_NO_ERROR) {}
543 GLint read_framebuffer = 0;
544 GLint read_buffer = GL_NONE;
546 glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &read_framebuffer);
547 glBindFramebuffer(GL_READ_FRAMEBUFFER, draw_framebuffer);
549 glGetIntegerv(GL_READ_BUFFER, &read_buffer);
550 glReadBuffer(draw_buffer);
553 // TODO: reset imaging state too
554 context.resetPixelPackState();
556 glReadPixels(0, 0, width, height, format, type, image->pixels);
558 context.restorePixelPackState();
561 glReadBuffer(read_buffer);
562 glBindFramebuffer(GL_READ_FRAMEBUFFER, read_framebuffer);
565 GLenum error = glGetError();
566 if (error != GL_NO_ERROR) {
568 std::cerr << "warning: " << enumToString(error) << " while getting snapshot\n";
569 error = glGetError();
570 } while(error != GL_NO_ERROR);
580 * Dump the image of the currently bound read buffer.
583 dumpReadBufferImage(JSONWriter &json, GLint width, GLint height, GLenum format,
584 GLint internalFormat = GL_NONE)
586 GLint channels = __gl_format_channels(format);
592 // Tell the GUI this is no ordinary object, but an image
593 json.writeStringMember("__class__", "image");
595 json.writeNumberMember("__width__", width);
596 json.writeNumberMember("__height__", height);
597 json.writeNumberMember("__depth__", 1);
599 json.writeStringMember("__format__", enumToString(internalFormat));
601 // Hardcoded for now, but we could chose types more adequate to the
602 // texture internal format
603 json.writeStringMember("__type__", "uint8");
604 json.writeBoolMember("__normalized__", true);
605 json.writeNumberMember("__channels__", channels);
607 GLenum type = GL_UNSIGNED_BYTE;
610 if (format == GL_DEPTH_COMPONENT) {
611 type = GL_UNSIGNED_INT;
616 GLubyte *pixels = new GLubyte[width*height*channels];
618 // TODO: reset imaging state too
619 context.resetPixelPackState();
621 glReadPixels(0, 0, width, height, format, type, pixels);
623 context.restorePixelPackState();
625 json.beginMember("__data__");
628 image::writePixelsToBuffer(pixels, width, height, channels, true, &pngBuffer, &pngBufferSize);
629 //std::cerr <<" Before = "<<(width * height * channels * sizeof *pixels)
630 // <<", after = "<<pngBufferSize << ", ratio = " << double(width * height * channels * sizeof *pixels)/pngBufferSize;
631 json.writeBase64(pngBuffer, pngBufferSize);
633 json.endMember(); // __data__
641 downsampledFramebuffer(GLuint oldFbo, GLint drawbuffer,
642 GLint colorRb, GLint depthRb, GLint stencilRb,
643 GLuint *rbs, GLint *numRbs)
651 glGenFramebuffers(1, &fbo);
652 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
654 glBindRenderbuffer(GL_RENDERBUFFER, colorRb);
655 glGetRenderbufferParameteriv(GL_RENDERBUFFER,
656 GL_RENDERBUFFER_WIDTH, &w);
657 glGetRenderbufferParameteriv(GL_RENDERBUFFER,
658 GL_RENDERBUFFER_HEIGHT, &h);
659 glGetRenderbufferParameteriv(GL_RENDERBUFFER,
660 GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
662 glGenRenderbuffers(1, &rbs[*numRbs]);
663 glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
664 glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
665 glFramebufferRenderbuffer(GL_FRAMEBUFFER, drawbuffer,
666 GL_RENDERBUFFER, rbs[*numRbs]);
668 glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
669 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
670 glDrawBuffer(drawbuffer);
671 glReadBuffer(drawbuffer);
672 glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
673 GL_COLOR_BUFFER_BIT, GL_NEAREST);
674 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
677 if (stencilRb == depthRb && stencilRb) {
678 //combined depth and stencil buffer
679 glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
680 glGetRenderbufferParameteriv(GL_RENDERBUFFER,
681 GL_RENDERBUFFER_WIDTH, &w);
682 glGetRenderbufferParameteriv(GL_RENDERBUFFER,
683 GL_RENDERBUFFER_HEIGHT, &h);
684 glGetRenderbufferParameteriv(GL_RENDERBUFFER,
685 GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
687 glGenRenderbuffers(1, &rbs[*numRbs]);
688 glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
689 glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
690 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
691 GL_RENDERBUFFER, rbs[*numRbs]);
692 glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
693 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
694 glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
695 GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
696 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
700 glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
701 glGetRenderbufferParameteriv(GL_RENDERBUFFER,
702 GL_RENDERBUFFER_WIDTH, &w);
703 glGetRenderbufferParameteriv(GL_RENDERBUFFER,
704 GL_RENDERBUFFER_HEIGHT, &h);
705 glGetRenderbufferParameteriv(GL_RENDERBUFFER,
706 GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
708 glGenRenderbuffers(1, &rbs[*numRbs]);
709 glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
710 glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
711 glFramebufferRenderbuffer(GL_FRAMEBUFFER,
713 GL_RENDERBUFFER, rbs[*numRbs]);
714 glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
715 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
716 glDrawBuffer(GL_DEPTH_ATTACHMENT);
717 glReadBuffer(GL_DEPTH_ATTACHMENT);
718 glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
719 GL_DEPTH_BUFFER_BIT, GL_NEAREST);
723 glBindRenderbuffer(GL_RENDERBUFFER, stencilRb);
724 glGetRenderbufferParameteriv(GL_RENDERBUFFER,
725 GL_RENDERBUFFER_WIDTH, &w);
726 glGetRenderbufferParameteriv(GL_RENDERBUFFER,
727 GL_RENDERBUFFER_HEIGHT, &h);
728 glGetRenderbufferParameteriv(GL_RENDERBUFFER,
729 GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
731 glGenRenderbuffers(1, &rbs[*numRbs]);
732 glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
733 glRenderbufferStorage(GL_RENDERBUFFER, format, w, h);
734 glFramebufferRenderbuffer(GL_FRAMEBUFFER,
735 GL_STENCIL_ATTACHMENT,
736 GL_RENDERBUFFER, rbs[*numRbs]);
737 glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
738 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
739 glDrawBuffer(GL_STENCIL_ATTACHMENT);
740 glReadBuffer(GL_STENCIL_ATTACHMENT);
741 glBlitFramebuffer(0, 0, w, h, 0, 0, w, h,
742 GL_STENCIL_BUFFER_BIT, GL_NEAREST);
752 * Dump images of current draw drawable/window.
755 dumpDrawableImages(JSONWriter &json, Context &context)
759 if (!getDrawableBounds(&width, &height)) {
763 GLint draw_buffer = GL_NONE;
765 draw_buffer = GL_BACK;
767 glGetIntegerv(GL_DRAW_BUFFER, &draw_buffer);
768 glReadBuffer(draw_buffer);
771 if (draw_buffer != GL_NONE) {
772 GLint read_buffer = GL_NONE;
774 glGetIntegerv(GL_READ_BUFFER, &read_buffer);
777 GLint alpha_bits = 0;
779 // XXX: Ignore alpha until we are able to match the traced visual
780 glGetIntegerv(GL_ALPHA_BITS, &alpha_bits);
782 GLenum format = alpha_bits ? GL_RGBA : GL_RGB;
783 json.beginMember(enumToString(draw_buffer));
784 dumpReadBufferImage(json, width, height, format);
788 glReadBuffer(read_buffer);
793 GLint depth_bits = 0;
794 glGetIntegerv(GL_DEPTH_BITS, &depth_bits);
796 json.beginMember("GL_DEPTH_COMPONENT");
797 dumpReadBufferImage(json, width, height, GL_DEPTH_COMPONENT);
801 GLint stencil_bits = 0;
802 glGetIntegerv(GL_STENCIL_BITS, &stencil_bits);
804 json.beginMember("GL_STENCIL_INDEX");
805 dumpReadBufferImage(json, width, height, GL_STENCIL_INDEX);
813 * Dump the specified framebuffer attachment.
815 * In the case of a color attachment, it assumes it is already bound for read.
818 dumpFramebufferAttachment(JSONWriter &json, GLenum target, GLenum attachment, GLenum format)
820 GLint width = 0, height = 0;
821 if (!getFramebufferAttachmentSize(target, attachment, &width, &height)) {
825 GLint internalFormat = getFramebufferAttachmentFormat(target, attachment);
827 json.beginMember(enumToString(attachment));
828 dumpReadBufferImage(json, width, height, format, internalFormat);
834 dumpFramebufferAttachments(JSONWriter &json, Context &context, GLenum target)
836 GLint read_framebuffer = 0;
837 glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &read_framebuffer);
839 GLint read_buffer = GL_NONE;
840 glGetIntegerv(GL_READ_BUFFER, &read_buffer);
842 GLint max_draw_buffers = 1;
843 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &max_draw_buffers);
844 GLint max_color_attachments = 0;
845 glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &max_color_attachments);
847 for (GLint i = 0; i < max_draw_buffers; ++i) {
848 GLint draw_buffer = GL_NONE;
849 glGetIntegerv(GL_DRAW_BUFFER0 + i, &draw_buffer);
850 if (draw_buffer != GL_NONE) {
851 glReadBuffer(draw_buffer);
853 if (draw_buffer >= GL_COLOR_ATTACHMENT0 && draw_buffer < GL_COLOR_ATTACHMENT0 + max_color_attachments) {
854 attachment = draw_buffer;
856 std::cerr << "warning: unexpected GL_DRAW_BUFFER" << i << " = " << draw_buffer << "\n";
857 attachment = GL_COLOR_ATTACHMENT0;
859 GLint alpha_size = 0;
860 glGetFramebufferAttachmentParameteriv(target, attachment,
861 GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE,
863 GLenum format = alpha_size ? GL_RGBA : GL_RGB;
864 dumpFramebufferAttachment(json, target, attachment, format);
868 glReadBuffer(read_buffer);
871 dumpFramebufferAttachment(json, target, GL_DEPTH_ATTACHMENT, GL_DEPTH_COMPONENT);
872 dumpFramebufferAttachment(json, target, GL_STENCIL_ATTACHMENT, GL_STENCIL_INDEX);
875 glBindFramebuffer(GL_READ_FRAMEBUFFER, read_framebuffer);
880 dumpFramebuffer(JSONWriter &json, Context &context)
882 json.beginMember("framebuffer");
885 GLint boundDrawFbo = 0, boundReadFbo = 0;
886 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &boundDrawFbo);
887 glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &boundReadFbo);
889 dumpDrawableImages(json, context);
890 } else if (context.ES) {
891 dumpFramebufferAttachments(json, context, GL_FRAMEBUFFER);
893 GLint colorRb = 0, stencilRb = 0, depthRb = 0;
894 GLint draw_buffer0 = GL_NONE;
895 glGetIntegerv(GL_DRAW_BUFFER0, &draw_buffer0);
896 bool multisample = false;
899 glGetIntegerv(GL_RENDERBUFFER_BINDING, &boundRb);
902 glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, draw_buffer0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &object_type);
903 if (object_type == GL_RENDERBUFFER) {
904 glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, draw_buffer0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &colorRb);
905 glBindRenderbuffer(GL_RENDERBUFFER, colorRb);
907 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
913 glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &object_type);
914 if (object_type == GL_RENDERBUFFER) {
915 glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &depthRb);
916 glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
918 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
924 glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &object_type);
925 if (object_type == GL_RENDERBUFFER) {
926 glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &stencilRb);
927 glBindRenderbuffer(GL_RENDERBUFFER, stencilRb);
929 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
935 glBindRenderbuffer(GL_RENDERBUFFER, boundRb);
942 // glReadPixels doesnt support multisampled buffers so we need
943 // to blit the fbo to a temporary one
944 fboCopy = downsampledFramebuffer(boundDrawFbo, draw_buffer0,
945 colorRb, depthRb, stencilRb,
949 dumpFramebufferAttachments(json, context, GL_DRAW_FRAMEBUFFER);
952 glBindRenderbuffer(GL_RENDERBUFFER_BINDING, boundRb);
953 glDeleteRenderbuffers(numRbs, rbs);
954 glDeleteFramebuffers(1, &fboCopy);
957 glBindFramebuffer(GL_READ_FRAMEBUFFER, boundReadFbo);
958 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, boundDrawFbo);
962 json.endMember(); // framebuffer
966 } /* namespace glstate */