From c90a55959980f9ef9678a45b9c9ded906d637b34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Fri, 4 Nov 2016 17:39:14 +0100 Subject: [PATCH] [core] move framebuffer reading to gl::Context --- platform/android/src/native_map_view.cpp | 15 +-------- platform/default/offscreen_view.cpp | 15 +-------- platform/macos/src/MGLMapView.mm | 16 +-------- src/mbgl/gl/context.cpp | 26 +++++++++++++++ src/mbgl/gl/context.hpp | 10 ++++++ src/mbgl/gl/types.hpp | 4 +++ src/mbgl/renderer/painter_debug.cpp | 41 ++++-------------------- src/mbgl/util/offscreen_texture.cpp | 16 +-------- 8 files changed, 51 insertions(+), 92 deletions(-) diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp index 65e39b198..0026aaa70 100755 --- a/platform/android/src/native_map_view.cpp +++ b/platform/android/src/native_map_view.cpp @@ -10,8 +10,6 @@ #include -#include - #include #include #include @@ -204,18 +202,7 @@ void NativeMapView::render() { snapshot = false; // take snapshot - const unsigned int w = fbWidth; - const unsigned int h = fbHeight; - mbgl::PremultipliedImage image({ w, h }); - MBGL_CHECK_ERROR(glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, image.data.get())); - const size_t stride = image.stride(); - auto tmp = std::make_unique(stride); - uint8_t *rgba = image.data.get(); - for (int i = 0, j = h - 1; i < j; i++, j--) { - std::memcpy(tmp.get(), rgba + i * stride, stride); - std::memcpy(rgba + i * stride, rgba + j * stride, stride); - std::memcpy(rgba + j * stride, tmp.get(), stride); - } + auto image = getContext().readFramebuffer(getFramebufferSize()); // encode and convert to jbytes std::string string = encodePNG(image); diff --git a/platform/default/offscreen_view.cpp b/platform/default/offscreen_view.cpp index 613e00fc2..574686ebc 100644 --- a/platform/default/offscreen_view.cpp +++ b/platform/default/offscreen_view.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include @@ -25,19 +24,7 @@ void OffscreenView::bind() { } PremultipliedImage OffscreenView::readStillImage() { - PremultipliedImage image { size }; - MBGL_CHECK_ERROR(glReadPixels(0, 0, size.width, size.height, GL_RGBA, GL_UNSIGNED_BYTE, image.data.get())); - - const auto stride = image.stride(); - auto tmp = std::make_unique(stride); - uint8_t* rgba = image.data.get(); - for (int i = 0, j = size.height - 1; i < j; i++, j--) { - std::memcpy(tmp.get(), rgba + i * stride, stride); - std::memcpy(rgba + i * stride, rgba + j * stride, stride); - std::memcpy(rgba + j * stride, tmp.get(), stride); - } - - return image; + return context.readFramebuffer(size); } } // namespace mbgl diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm index 02f96ac3f..513687f94 100644 --- a/platform/macos/src/MGLMapView.mm +++ b/platform/macos/src/MGLMapView.mm @@ -24,7 +24,6 @@ #import #import #import -#import #import #import #import @@ -2608,20 +2607,7 @@ public: } mbgl::PremultipliedImage readStillImage() { - mbgl::PremultipliedImage image(nativeView.framebufferSize); - MBGL_CHECK_ERROR(glReadPixels(0, 0, image.size.width, image.size.height, GL_RGBA, - GL_UNSIGNED_BYTE, image.data.get())); - - const size_t stride = image.stride(); - auto tmp = std::make_unique(stride); - uint8_t *rgba = image.data.get(); - for (int i = 0, j = image.size.height - 1; i < j; i++, j--) { - std::memcpy(tmp.get(), rgba + i * stride, stride); - std::memcpy(rgba + i * stride, rgba + j * stride, stride); - std::memcpy(rgba + j * stride, tmp.get(), stride); - } - - return image; + return getContext().readFramebuffer(nativeView.framebufferSize); } private: diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index 1cd546f40..811a038ca 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -92,6 +92,32 @@ UniqueRenderbuffer Context::createRenderbuffer(const RenderbufferType type, cons return renderbuffer; } +std::unique_ptr Context::readFramebuffer(const Size size, const TextureFormat format, const bool flip) { + const size_t stride = size.width * (format == TextureFormat::RGBA ? 4 : 1); + auto data = std::make_unique(stride * size.height); + +#if not MBGL_USE_GLES2 + // When reading data from the framebuffer, make sure that we are storing the values + // tightly packed into the buffer to avoid buffer overruns. + pixelStorePack = { 1 }; +#endif // MBGL_USE_GLES2 + + MBGL_CHECK_ERROR(glReadPixels(0, 0, size.width, size.height, static_cast(format), + GL_UNSIGNED_BYTE, data.get())); + + if (flip) { + auto tmp = std::make_unique(stride); + uint8_t* rgba = data.get(); + for (int i = 0, j = size.height - 1; i < j; i++, j--) { + std::memcpy(tmp.get(), rgba + i * stride, stride); + std::memcpy(rgba + i * stride, rgba + j * stride, stride); + std::memcpy(rgba + j * stride, tmp.get(), stride); + } + } + + return data; +} + namespace { void checkFramebuffer() { diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index 9bfa54fa5..169aa5566 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -62,6 +62,15 @@ public: const Renderbuffer&); Framebuffer createFramebuffer(const Texture&); + template + Image readFramebuffer(const Size size, bool flip = true) { + static_assert(Image::channels == (format == TextureFormat::RGBA ? 4 : 1), + "image format mismatch"); + return { size, readFramebuffer(size, format, flip) }; + } + // Create a texture from an image with data. template Texture createTexture(const Image& image, TextureUnit unit = 0) { @@ -167,6 +176,7 @@ private: void updateTexture(TextureID, Size size, const void* data, TextureFormat, TextureUnit); UniqueFramebuffer createFramebuffer(); UniqueRenderbuffer createRenderbuffer(RenderbufferType, Size size); + std::unique_ptr readFramebuffer(Size, TextureFormat, bool flip); PrimitiveType operator()(const Points&); PrimitiveType operator()(const Lines&); diff --git a/src/mbgl/gl/types.hpp b/src/mbgl/gl/types.hpp index 6e1bc5f8e..169765646 100644 --- a/src/mbgl/gl/types.hpp +++ b/src/mbgl/gl/types.hpp @@ -50,6 +50,10 @@ enum class TextureWrap : bool { Clamp, Repeat }; enum class TextureFormat : uint32_t { RGBA = 0x1908, Alpha = 0x1906, +#if not MBGL_USE_GLES2 + Stencil = 0x1901, + Depth = 0x1902, +#endif // MBGL_USE_GLES2 }; enum class PrimitiveType { diff --git a/src/mbgl/renderer/painter_debug.cpp b/src/mbgl/renderer/painter_debug.cpp index bdc0b90bd..dfb1581ba 100644 --- a/src/mbgl/renderer/painter_debug.cpp +++ b/src/mbgl/renderer/painter_debug.cpp @@ -68,29 +68,16 @@ void Painter::renderClipMasks(PaintParameters&) { context.program = 0; #if not MBGL_USE_GLES2 - - // When reading data from the framebuffer, make sure that we are storing the depth values - // tightly packed into the buffer to avoid buffer overruns. Also see unpacking adjustment below. - context.pixelStorePack = { 1 }; - // Reset the value in case someone else changed it, or it's dirty. context.pixelTransferStencil = gl::value::PixelTransferStencil::Default; // Read the stencil buffer const auto viewport = context.viewport.getCurrentValue(); - auto pixels = std::make_unique(viewport.size.width * viewport.size.height); - MBGL_CHECK_ERROR(glReadPixels( - viewport.x, // GLint x - viewport.y, // GLint y - viewport.size.width, // GLsizei width - viewport.size.height, // GLsizei height - GL_STENCIL_INDEX, // GLenum format - GL_UNSIGNED_BYTE, // GLenum type - pixels.get() // GLvoid * data - )); + auto image = + context.readFramebuffer(viewport.size, false); // Scale the Stencil buffer to cover the entire color space. - auto it = pixels.get(); + auto it = image.data.get(); auto end = it + viewport.size.width * viewport.size.height; const auto factor = 255.0f / *std::max_element(it, end); for (; it != end; ++it) { @@ -101,7 +88,7 @@ void Painter::renderClipMasks(PaintParameters&) { context.rasterPos = { -1, -1, 0, 1 }; context.pixelStoreUnpack = { 1 }; MBGL_CHECK_ERROR(glDrawPixels(viewport.size.width, viewport.size.height, GL_LUMINANCE, - GL_UNSIGNED_BYTE, pixels.get())); + GL_UNSIGNED_BYTE, image.data.get())); #endif // MBGL_USE_GLES2 } @@ -112,11 +99,6 @@ void Painter::renderDepthBuffer(PaintParameters&) { context.program = 0; #if not MBGL_USE_GLES2 - - // When reading data from the framebuffer, make sure that we are storing the depth values - // tightly packed into the buffer to avoid buffer overruns. Also see unpacking adjustment below. - context.pixelStorePack = { 1 }; - // Scales the values in the depth buffer so that they cover the entire grayscale range. This // makes it easier to spot tiny differences. const float base = 1.0f / (1.0f - depthRangeSize); @@ -124,23 +106,14 @@ void Painter::renderDepthBuffer(PaintParameters&) { // Read the stencil buffer auto viewport = context.viewport.getCurrentValue(); - auto pixels = std::make_unique(viewport.size.width * viewport.size.height); - - MBGL_CHECK_ERROR(glReadPixels( - viewport.x, // GLint x - viewport.y, // GLint y - viewport.size.width, // GLsizei width - viewport.size.height, // GLsizei height - GL_DEPTH_COMPONENT, // GLenum format - GL_UNSIGNED_BYTE, // GLenum type - pixels.get() // GLvoid * data - )); + auto image = + context.readFramebuffer(viewport.size, false); context.pixelZoom = { 1, 1 }; context.rasterPos = { -1, -1, 0, 1 }; context.pixelStoreUnpack = { 1 }; MBGL_CHECK_ERROR(glDrawPixels(viewport.size.width, viewport.size.height, GL_LUMINANCE, - GL_UNSIGNED_BYTE, pixels.get())); + GL_UNSIGNED_BYTE, image.data.get())); #endif // MBGL_USE_GLES2 } #endif // NDEBUG diff --git a/src/mbgl/util/offscreen_texture.cpp b/src/mbgl/util/offscreen_texture.cpp index 6352e38ab..aad20e59d 100644 --- a/src/mbgl/util/offscreen_texture.cpp +++ b/src/mbgl/util/offscreen_texture.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include @@ -29,20 +28,7 @@ gl::Texture& OffscreenTexture::getTexture() { } PremultipliedImage OffscreenTexture::readStillImage() { - PremultipliedImage image { size }; - MBGL_CHECK_ERROR( - glReadPixels(0, 0, size.width, size.height, GL_RGBA, GL_UNSIGNED_BYTE, image.data.get())); - - const auto stride = image.stride(); - auto tmp = std::make_unique(stride); - uint8_t* rgba = image.data.get(); - for (int i = 0, j = size.height - 1; i < j; i++, j--) { - std::memcpy(tmp.get(), rgba + i * stride, stride); - std::memcpy(rgba + i * stride, rgba + j * stride, stride); - std::memcpy(rgba + j * stride, tmp.get(), stride); - } - - return image; + return context.readFramebuffer(size); }