Browse Source

DebugTools: support reading float textures in textureImage() on ES3.

pull/141/head
Vladimír Vondruš 10 years ago
parent
commit
c9271da28c
  1. 5
      src/Magnum/DebugTools/CMakeLists.txt
  2. 53
      src/Magnum/DebugTools/Test/TextureImageGLTest.cpp
  3. 121
      src/Magnum/DebugTools/TextureImage.cpp
  4. 12
      src/Magnum/DebugTools/TextureImage.frag
  5. 16
      src/Magnum/DebugTools/TextureImage.h
  6. 4
      src/Magnum/DebugTools/TextureImage.vert
  7. 7
      src/Magnum/DebugTools/resources.conf

5
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)

53
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<const UnsignedInt>{image.data<UnsignedInt>(), image.data().size()/4}),
Containers::ArrayView<const UnsignedInt>{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<const Float>{image.data<Float>(), image.data().size()/4}),
Containers::ArrayView<const Float>{Data2DFloat},
TestSuite::Compare::Container);
}
}}}
MAGNUM_GL_TEST_MAIN(Magnum::DebugTools::Test::TextureImageGLTest)

121
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 <Corrade/Utility/Resource.h>
#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);

12
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));
}

16
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.
*/

4
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);
}

7
src/Magnum/DebugTools/resources.conf

@ -0,0 +1,7 @@
group=MagnumDebugTools
[file]
filename=TextureImage.vert
[file]
filename=TextureImage.frag
Loading…
Cancel
Save