/** * Dump the image of the currently bound read buffer. */ static inline void dumpReadBufferImage(JSONWriter &json, GLint width, GLint height, GLenum format, GLint internalFormat = GL_NONE) { GLint channels = _gl_format_channels(format); if (internalFormat == GL_NONE) { internalFormat = format; } Context context; json.beginObject(); // Tell the GUI this is no ordinary object, but an image json.writeStringMember("__class__", "image"); json.writeNumberMember("__width__", width); json.writeNumberMember("__height__", height); json.writeNumberMember("__depth__", 1); json.writeStringMember("__format__", enumToString(internalFormat)); // Hardcoded for now, but we could chose types more adequate to the // texture internal format json.writeStringMember("__type__", "uint8"); json.writeBoolMember("__normalized__", true); json.writeNumberMember("__channels__", channels); GLenum type = GL_UNSIGNED_BYTE; #if DEPTH_AS_RGBA if (format == GL_DEPTH_COMPONENT) { type = GL_UNSIGNED_INT; channels = 4; } #endif GLubyte *pixels = new GLubyte[width*height*channels]; // TODO: reset imaging state too context.resetPixelPackState(); glReadPixels(0, 0, width, height, format, type, pixels); context.restorePixelPackState(); json.beginMember("__data__"); char *pngBuffer; int pngBufferSize; image::writePixelsToBuffer(pixels, width, height, channels, true, &pngBuffer, &pngBufferSize); //std::cerr <<" Before = "<<(width * height * channels * sizeof *pixels) // <<", after = "<<pngBufferSize << ", ratio = " << double(width * height * channels * sizeof *pixels)/pngBufferSize; json.writeBase64(pngBuffer, pngBufferSize); free(pngBuffer); json.endMember(); // __data__ delete [] pixels; json.endObject(); }
static inline unsigned _gl_format_size(GLenum format, GLenum type) { unsigned num_elements = _gl_format_channels(format); switch (type) { case GL_BITMAP: return 1; case GL_BYTE: case GL_UNSIGNED_BYTE: return 8 * num_elements; case GL_SHORT: case GL_UNSIGNED_SHORT: case GL_HALF_FLOAT: return 16 * num_elements; case GL_INT: case GL_UNSIGNED_INT: case GL_FLOAT: return 32 * num_elements; case GL_UNSIGNED_BYTE_3_3_2: case GL_UNSIGNED_BYTE_2_3_3_REV: return 8; case GL_UNSIGNED_SHORT_4_4_4_4: case GL_UNSIGNED_SHORT_4_4_4_4_REV: case GL_UNSIGNED_SHORT_5_5_5_1: case GL_UNSIGNED_SHORT_1_5_5_5_REV: case GL_UNSIGNED_SHORT_5_6_5: case GL_UNSIGNED_SHORT_5_6_5_REV: case GL_UNSIGNED_SHORT_8_8_MESA: case GL_UNSIGNED_SHORT_8_8_REV_MESA: return 16; case GL_UNSIGNED_INT_8_8_8_8: case GL_UNSIGNED_INT_8_8_8_8_REV: case GL_UNSIGNED_INT_10_10_10_2: case GL_UNSIGNED_INT_2_10_10_10_REV: case GL_UNSIGNED_INT_24_8: case GL_UNSIGNED_INT_10F_11F_11F_REV: case GL_UNSIGNED_INT_5_9_9_9_REV: case GL_UNSIGNED_INT_S8_S8_8_8_NV: case GL_UNSIGNED_INT_8_8_S8_S8_REV_NV: return 32; case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: assert(num_elements == 2); return 32 * 2; default: os::log("apitrace: warning: %s: unexpected type GLenum 0x%04X\n", __FUNCTION__, type); return 0; } }
void getImageFormat(GLenum format, GLenum type, GLuint & channels, image::ChannelType & channelType) { channels = _gl_format_channels(format); switch (type) { case GL_UNSIGNED_BYTE: channelType = image::TYPE_UNORM8; break; case GL_FLOAT: channelType = image::TYPE_FLOAT; break; default: assert(0); } }
static inline void _gl_format_size(GLenum format, GLenum type, unsigned & bits_per_element, unsigned & bits_per_pixel) { unsigned num_channels = _gl_format_channels(format); switch (type) { case GL_BITMAP: bits_per_pixel = bits_per_element = 1; break; case GL_BYTE: case GL_UNSIGNED_BYTE: bits_per_element = 8; bits_per_pixel = bits_per_element * num_channels; break; case GL_SHORT: case GL_UNSIGNED_SHORT: case GL_HALF_FLOAT: bits_per_element = 16; bits_per_pixel = bits_per_element * num_channels; break; case GL_INT: case GL_UNSIGNED_INT: case GL_FLOAT: bits_per_element = 32; bits_per_pixel = bits_per_element * num_channels; break; case GL_UNSIGNED_BYTE_3_3_2: case GL_UNSIGNED_BYTE_2_3_3_REV: bits_per_pixel = bits_per_element = 8; break; case GL_UNSIGNED_SHORT_4_4_4_4: case GL_UNSIGNED_SHORT_4_4_4_4_REV: case GL_UNSIGNED_SHORT_5_5_5_1: case GL_UNSIGNED_SHORT_1_5_5_5_REV: case GL_UNSIGNED_SHORT_5_6_5: case GL_UNSIGNED_SHORT_5_6_5_REV: case GL_UNSIGNED_SHORT_8_8_MESA: case GL_UNSIGNED_SHORT_8_8_REV_MESA: bits_per_pixel = bits_per_element = 16; break; case GL_UNSIGNED_INT_8_8_8_8: case GL_UNSIGNED_INT_8_8_8_8_REV: case GL_UNSIGNED_INT_10_10_10_2: case GL_UNSIGNED_INT_2_10_10_10_REV: case GL_UNSIGNED_INT_24_8: case GL_UNSIGNED_INT_10F_11F_11F_REV: case GL_UNSIGNED_INT_5_9_9_9_REV: case GL_UNSIGNED_INT_S8_S8_8_8_NV: case GL_UNSIGNED_INT_8_8_S8_S8_REV_NV: bits_per_pixel = bits_per_element = 32; break; case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: bits_per_pixel = bits_per_element = 64; break; default: os::log("apitrace: warning: %s: unexpected type GLenum 0x%04X\n", __FUNCTION__, type); bits_per_pixel = bits_per_element = 0; break; } }
static inline size_t _gl_image_size(GLenum format, GLenum type, GLsizei width, GLsizei height, GLsizei depth, GLboolean has_unpack_subimage) { unsigned num_channels = _gl_format_channels(format); unsigned bits_per_element; unsigned bits_per_pixel; switch (type) { case GL_BITMAP: bits_per_pixel = bits_per_element = 1; break; case GL_BYTE: case GL_UNSIGNED_BYTE: bits_per_element = 8; bits_per_pixel = bits_per_element * num_channels; break; case GL_SHORT: case GL_UNSIGNED_SHORT: case GL_HALF_FLOAT: bits_per_element = 16; bits_per_pixel = bits_per_element * num_channels; break; case GL_INT: case GL_UNSIGNED_INT: case GL_FLOAT: bits_per_element = 32; bits_per_pixel = bits_per_element * num_channels; break; case GL_UNSIGNED_BYTE_3_3_2: case GL_UNSIGNED_BYTE_2_3_3_REV: bits_per_pixel = bits_per_element = 8; break; case GL_UNSIGNED_SHORT_4_4_4_4: case GL_UNSIGNED_SHORT_4_4_4_4_REV: case GL_UNSIGNED_SHORT_5_5_5_1: case GL_UNSIGNED_SHORT_1_5_5_5_REV: case GL_UNSIGNED_SHORT_5_6_5: case GL_UNSIGNED_SHORT_5_6_5_REV: case GL_UNSIGNED_SHORT_8_8_MESA: case GL_UNSIGNED_SHORT_8_8_REV_MESA: bits_per_pixel = bits_per_element = 16; break; case GL_UNSIGNED_INT_8_8_8_8: case GL_UNSIGNED_INT_8_8_8_8_REV: case GL_UNSIGNED_INT_10_10_10_2: case GL_UNSIGNED_INT_2_10_10_10_REV: case GL_UNSIGNED_INT_24_8: case GL_UNSIGNED_INT_10F_11F_11F_REV: case GL_UNSIGNED_INT_5_9_9_9_REV: case GL_UNSIGNED_INT_S8_S8_8_8_NV: case GL_UNSIGNED_INT_8_8_S8_S8_REV_NV: bits_per_pixel = bits_per_element = 32; break; case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: bits_per_pixel = bits_per_element = 64; break; default: os::log("apitrace: warning: %s: unexpected type GLenum 0x%04X\n", __FUNCTION__, type); bits_per_pixel = bits_per_element = 0; break; } GLint alignment = 4; GLint row_length = 0; GLint image_height = 0; GLint skip_rows = 0; GLint skip_pixels = 0; GLint skip_images = 0; _glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment); if (has_unpack_subimage) { _glGetIntegerv(GL_UNPACK_ROW_LENGTH, &row_length); _glGetIntegerv(GL_UNPACK_IMAGE_HEIGHT, &image_height); _glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skip_rows); _glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skip_pixels); _glGetIntegerv(GL_UNPACK_SKIP_IMAGES, &skip_images); } if (row_length <= 0) { row_length = width; } size_t row_stride = (row_length*bits_per_pixel + 7)/8; if ((bits_per_element == 1*8 || bits_per_element == 2*8 || bits_per_element == 4*8 || bits_per_element == 8*8) && (GLint)bits_per_element < alignment*8) { row_stride = _align(row_stride, alignment); } if (image_height <= 0) { image_height = height; } /* XXX: GL_UNPACK_IMAGE_HEIGHT and GL_UNPACK_SKIP_IMAGES should probably * not be considered for pixel rectangles. */ size_t image_stride = image_height*row_stride; size_t size = depth*image_stride; size += (skip_pixels*bits_per_pixel + 7)/8; size += skip_rows*row_stride; size += skip_images*image_stride; return size; }
image::Image * getDrawBufferImage() { GLenum format = GL_RGB; GLint channels = _gl_format_channels(format); if (channels > 4) { return NULL; } Context context; GLenum framebuffer_binding; GLenum framebuffer_target; if (context.ES) { framebuffer_binding = GL_FRAMEBUFFER_BINDING; framebuffer_target = GL_FRAMEBUFFER; } else { framebuffer_binding = GL_DRAW_FRAMEBUFFER_BINDING; framebuffer_target = GL_DRAW_FRAMEBUFFER; } GLint draw_framebuffer = 0; glGetIntegerv(framebuffer_binding, &draw_framebuffer); GLint draw_buffer = GL_NONE; ImageDesc desc; if (draw_framebuffer) { if (context.ARB_draw_buffers) { glGetIntegerv(GL_DRAW_BUFFER0, &draw_buffer); if (draw_buffer == GL_NONE) { return NULL; } } if (!getFramebufferAttachmentDesc(context, framebuffer_target, draw_buffer, desc)) { return NULL; } } else { if (!context.ES) { glGetIntegerv(GL_DRAW_BUFFER, &draw_buffer); if (draw_buffer == GL_NONE) { return NULL; } } if (!getDrawableBounds(&desc.width, &desc.height)) { return NULL; } desc.depth = 1; } GLenum type = GL_UNSIGNED_BYTE; #if DEPTH_AS_RGBA if (format == GL_DEPTH_COMPONENT) { type = GL_UNSIGNED_INT; channels = 4; } #endif image::Image *image = new image::Image(desc.width, desc.height, channels, true); if (!image) { return NULL; } while (glGetError() != GL_NO_ERROR) {} GLint read_framebuffer = 0; GLint read_buffer = GL_NONE; if (!context.ES) { glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &read_framebuffer); glBindFramebuffer(GL_READ_FRAMEBUFFER, draw_framebuffer); glGetIntegerv(GL_READ_BUFFER, &read_buffer); glReadBuffer(draw_buffer); } // TODO: reset imaging state too context.resetPixelPackState(); glReadPixels(0, 0, desc.width, desc.height, format, type, image->pixels); context.restorePixelPackState(); if (!context.ES) { glReadBuffer(read_buffer); glBindFramebuffer(GL_READ_FRAMEBUFFER, read_framebuffer); } GLenum error = glGetError(); if (error != GL_NO_ERROR) { do { std::cerr << "warning: " << enumToString(error) << " while getting snapshot\n"; error = glGetError(); } while(error != GL_NO_ERROR); delete image; return NULL; } return image; }