From c9271da28c3c49357fb5ad196dbfb141c9f1ae98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 9 Apr 2016 11:13:46 +0200 Subject: [PATCH] DebugTools: support reading float textures in textureImage() on ES3. --- src/Magnum/DebugTools/CMakeLists.txt | 5 + .../DebugTools/Test/TextureImageGLTest.cpp | 53 +++++++- src/Magnum/DebugTools/TextureImage.cpp | 121 +++++++++++++++++- src/Magnum/DebugTools/TextureImage.frag | 12 ++ src/Magnum/DebugTools/TextureImage.h | 16 ++- src/Magnum/DebugTools/TextureImage.vert | 4 + src/Magnum/DebugTools/resources.conf | 7 + 7 files changed, 212 insertions(+), 6 deletions(-) create mode 100644 src/Magnum/DebugTools/TextureImage.frag create mode 100644 src/Magnum/DebugTools/TextureImage.vert create mode 100644 src/Magnum/DebugTools/resources.conf diff --git a/src/Magnum/DebugTools/CMakeLists.txt b/src/Magnum/DebugTools/CMakeLists.txt index 1eaf37f50..76ca9163d 100644 --- a/src/Magnum/DebugTools/CMakeLists.txt +++ b/src/Magnum/DebugTools/CMakeLists.txt @@ -38,6 +38,11 @@ set(MagnumDebugTools_HEADERS # Header files to display in project view of IDEs only set(MagnumDebugTools_PRIVATE_HEADERS ) +if(MAGNUM_TARGET_GLES AND NOT MAGNUM_TARGET_GLES2) + corrade_add_resource(MagnumDebugTools_RESOURCES resources.conf) + list(APPEND MagnumDebugTools_SRCS ${MagnumDebugTools_RESOURCES}) +endif() + if(NOT MAGNUM_TARGET_WEBGL) list(APPEND MagnumDebugTools_SRCS BufferData.cpp) diff --git a/src/Magnum/DebugTools/Test/TextureImageGLTest.cpp b/src/Magnum/DebugTools/Test/TextureImageGLTest.cpp index a948ed968..7781e9077 100644 --- a/src/Magnum/DebugTools/Test/TextureImageGLTest.cpp +++ b/src/Magnum/DebugTools/Test/TextureImageGLTest.cpp @@ -50,6 +50,11 @@ struct TextureImageGLTest: Magnum::Test::AbstractOpenGLTester { #ifndef MAGNUM_TARGET_GLES2 void subImageCubeBuffer(); #endif + + #ifndef MAGNUM_TARGET_GLES2 + void subImage2DUInt(); + void subImage2DFloat(); + #endif }; TextureImageGLTest::TextureImageGLTest() { @@ -60,7 +65,12 @@ TextureImageGLTest::TextureImageGLTest() { &TextureImageGLTest::subImageCube, #ifndef MAGNUM_TARGET_GLES2 - &TextureImageGLTest::subImageCubeBuffer + &TextureImageGLTest::subImageCubeBuffer, + #endif + + #ifndef MAGNUM_TARGET_GLES2 + &TextureImageGLTest::subImage2DUInt, + &TextureImageGLTest::subImage2DFloat, #endif }); } @@ -142,6 +152,47 @@ void TextureImageGLTest::subImageCubeBuffer() { } #endif +namespace { + constexpr UnsignedInt Data2DUInt[] = { 0xcafebabe, + 0xdeadbeef, + 0xbadf00d, + 0xdeadbabe }; +} + +void TextureImageGLTest::subImage2DUInt() { + Texture2D texture; + texture.setImage(0, TextureFormat::R32UI, ImageView2D{PixelFormat::RedInteger, PixelType::UnsignedInt, Vector2i{2}, Data2DUInt}); + + Image2D image = textureSubImage(texture, 0, {{}, Vector2i{2}}, {PixelFormat::RedInteger, PixelType::UnsignedInt}); + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_COMPARE(image.size(), Vector2i{2}); + CORRADE_COMPARE_AS( + (Containers::ArrayView{image.data(), image.data().size()/4}), + Containers::ArrayView{Data2DUInt}, + TestSuite::Compare::Container); +} + +namespace { + constexpr Float Data2DFloat[] = { 1.0f, + 0.14159f, + 0.71828f, + 0.41421f }; +} + +void TextureImageGLTest::subImage2DFloat() { + Texture2D texture; + texture.setStorage(1, TextureFormat::R32F, Vector2i{2}) + .setSubImage(0, {}, ImageView2D{PixelFormat::Red, PixelType::Float, Vector2i{2}, Data2DFloat}); + + Image2D image = textureSubImage(texture, 0, {{}, Vector2i{2}}, {PixelFormat::Red, PixelType::Float}); + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_COMPARE(image.size(), Vector2i{2}); + CORRADE_COMPARE_AS( + (Containers::ArrayView{image.data(), image.data().size()/4}), + Containers::ArrayView{Data2DFloat}, + TestSuite::Compare::Container); +} + }}} MAGNUM_GL_TEST_MAIN(Magnum::DebugTools::Test::TextureImageGLTest) diff --git a/src/Magnum/DebugTools/TextureImage.cpp b/src/Magnum/DebugTools/TextureImage.cpp index 22725bf2e..6515f678e 100644 --- a/src/Magnum/DebugTools/TextureImage.cpp +++ b/src/Magnum/DebugTools/TextureImage.cpp @@ -27,12 +27,131 @@ #include "Magnum/BufferImage.h" #include "Magnum/Framebuffer.h" -#include "Magnum/Texture.h" #include "Magnum/Image.h" +#include "Magnum/Texture.h" + +#if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_GLES2) +#include + +#include "Magnum/AbstractShaderProgram.h" +#include "Magnum/Mesh.h" +#include "Magnum/PixelFormat.h" +#include "Magnum/Shader.h" +#include "Magnum/TextureFormat.h" +#include "Magnum/Version.h" + +#ifdef MAGNUM_BUILD_STATIC +static void importDebugToolsResources() { + CORRADE_RESOURCE_INITIALIZE(MagnumDebugTools_RESOURCES) +} +#endif +#endif namespace Magnum { namespace DebugTools { +#if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_GLES2) +namespace { + +class FloatReinterpretShader: public AbstractShaderProgram { + public: + explicit FloatReinterpretShader(); + + FloatReinterpretShader& setTexture(Texture2D& texture, Int level) { + texture.bind(0); + setUniform(levelUniform, level); + return *this; + } + + private: + Int levelUniform; +}; + +FloatReinterpretShader::FloatReinterpretShader() { + #ifdef MAGNUM_BUILD_STATIC + /* Import resources on static build, if not already */ + if(!Utility::Resource::hasGroup("MagnumDebugTools")) + importShaderResources(); + #endif + Utility::Resource rs{"MagnumDebugTools"}; + + Shader vert{Version::GLES300, Shader::Type::Vertex}; + Shader frag{Version::GLES300, Shader::Type::Fragment}; + vert.addSource(rs.get("TextureImage.vert")); + frag.addSource(rs.get("TextureImage.frag")); + + CORRADE_INTERNAL_ASSERT(Shader::compile({vert, frag})); + attachShaders({vert, frag}); + + CORRADE_INTERNAL_ASSERT(link()); + + levelUniform = uniformLocation("level"); + setUniform(uniformLocation("textureData"), 0); +} + +} +#endif + void textureSubImage(Texture2D& texture, const Int level, const Range2Di& range, Image2D& image) { + #ifdef MAGNUM_TARGET_GLES + if(image.type() == PixelType::Float) { + const PixelFormat imageFormat = image.format(); + TextureFormat textureFormat; + PixelFormat reinterpretFormat; + switch(imageFormat) { + case PixelFormat::Red: + textureFormat = TextureFormat::R32UI; + reinterpretFormat = PixelFormat::RedInteger; + break; + case PixelFormat::RG: + textureFormat = TextureFormat::RG32UI; + reinterpretFormat = PixelFormat::RGInteger; + break; + case PixelFormat::RGB: + textureFormat = TextureFormat::RGB32UI; + reinterpretFormat = PixelFormat::RGBInteger; + break; + case PixelFormat::RGBA: + textureFormat = TextureFormat::RGBA32UI; + reinterpretFormat = PixelFormat::RGBAInteger; + break; + default: + CORRADE_ASSERT(false, "DebugTools::textureSubImage(): unsupported pixel format" << image.format(), ); + } + + Texture2D output; + output.setStorage(1, textureFormat, range.max()); + + Framebuffer fb{range}; + fb.attachTexture(Framebuffer::ColorAttachment{0}, output, 0) + .bind(); + + CORRADE_INTERNAL_ASSERT(fb.checkStatus(FramebufferTarget::Draw) == Framebuffer::Status::Complete); + CORRADE_INTERNAL_ASSERT(fb.checkStatus(FramebufferTarget::Read) == Framebuffer::Status::Complete); + + FloatReinterpretShader shader; + shader.setTexture(texture, level); + + Mesh mesh; + mesh.setCount(3) + .draw(shader); + + /* release() needs to be called after querying the size to avoid zeroing it out */ + { + Vector2i imageSize = image.size(); + image.setData(image.storage(), reinterpretFormat, PixelType::UnsignedInt, imageSize, image.release()); + } + + fb.read(range, image); + + /* release() needs to be called after querying the size to avoid zeroing it out */ + { + Vector2i imageSize = image.size(); + image.setData(image.storage(), imageFormat, PixelType::Float, imageSize, image.release()); + } + return; + } + #endif + Framebuffer fb{range}; fb.attachTexture(Framebuffer::ColorAttachment{0}, texture, level) .read(range, image); diff --git a/src/Magnum/DebugTools/TextureImage.frag b/src/Magnum/DebugTools/TextureImage.frag new file mode 100644 index 000000000..836a03aa1 --- /dev/null +++ b/src/Magnum/DebugTools/TextureImage.frag @@ -0,0 +1,12 @@ +uniform highp int level; +uniform highp sampler2D textureData; + +layout(pixel_center_integer) in highp vec4 gl_FragCoord; + +out highp uvec4 fragmentOutput; + +void main() { + ivec2 pos = ivec2(gl_FragCoord.xy); + + fragmentOutput = floatBitsToUint(texelFetch(textureData, pos, level)); +} diff --git a/src/Magnum/DebugTools/TextureImage.h b/src/Magnum/DebugTools/TextureImage.h index c6d67fa01..54c1895f3 100644 --- a/src/Magnum/DebugTools/TextureImage.h +++ b/src/Magnum/DebugTools/TextureImage.h @@ -39,8 +39,14 @@ namespace Magnum { namespace DebugTools { Emulates @ref Texture::subImage() "*Texture::subImage()" call on platforms that don't support it (such as OpenGL ES) by creating a framebuffer object and using -@ref Framebuffer::read(). Note that only @ref PixelFormat and @ref PixelType -values that are marked as framebuffer readable are supported. +@ref Framebuffer::read(). + +Note that only @ref PixelFormat and @ref PixelType values that are marked as +framebuffer readable are supported. In addition, on OpenGL ES 3.0, images with +@ref PixelType::Float are supported -- they are reinterpreted as +@ref PixelType::UnsignedInt using additional shader and `floatBitsToUint()` +GLSL function and then reinterpreted back to @ref PixelType::Float when read to +client memory. */ MAGNUM_DEBUGTOOLS_EXPORT void textureSubImage(Texture2D& texture, Int level, const Range2Di& range, Image2D& image); @@ -66,8 +72,10 @@ MAGNUM_DEBUGTOOLS_EXPORT Image2D textureSubImage(CubeMapTexture& texture, CubeMa Emulates @ref Texture::subImage() "*Texture::subImage()" call on platforms that don't support it (such as OpenGL ES) by creating a framebuffer object and using -@ref Framebuffer::read(). Note that only @ref PixelFormat and @ref PixelType -values that are marked as framebuffer readable are supported. +@ref Framebuffer::read(). + +Note that only @ref PixelFormat and @ref PixelType values that are marked as +framebuffer readable are supported. @requires_gles30 Pixel buffer objects are not available in OpenGL ES 2.0. @requires_webgl20 Pixel buffer objects are not available in WebGL 1.0. */ diff --git a/src/Magnum/DebugTools/TextureImage.vert b/src/Magnum/DebugTools/TextureImage.vert new file mode 100644 index 000000000..325b2e733 --- /dev/null +++ b/src/Magnum/DebugTools/TextureImage.vert @@ -0,0 +1,4 @@ +void main() { + gl_Position = vec4((gl_VertexID == 2) ? 3.0 : -1.0, + (gl_VertexID == 1) ? -3.0 : 1.0, 0.0, 1.0); +} diff --git a/src/Magnum/DebugTools/resources.conf b/src/Magnum/DebugTools/resources.conf new file mode 100644 index 000000000..f9d480144 --- /dev/null +++ b/src/Magnum/DebugTools/resources.conf @@ -0,0 +1,7 @@ +group=MagnumDebugTools + +[file] +filename=TextureImage.vert + +[file] +filename=TextureImage.frag