Browse Source

DebugTools: support generic pixel formats in textureSubImage().

pull/233/head
Vladimír Vondruš 8 years ago
parent
commit
4a88b4633d
  1. 6
      doc/changelog.dox
  2. 59
      src/Magnum/DebugTools/Test/TextureImageGLTest.cpp
  3. 79
      src/Magnum/DebugTools/TextureImage.cpp
  4. 93
      src/Magnum/DebugTools/TextureImage.h

6
doc/changelog.dox

@ -123,6 +123,12 @@ See also:
a compatibility code path is implemented, the @ref GL library expects that
all parameters are at their defaults.
@subsubsection changelog-latest-changes-debugtools DebugTools library
- @ref DebugTools::textureSubImage() now accepts both GL-specific
@ref GL::PixelFormat / @ref GL::PixelType combination and the generic
@ref PixelFormat enum
@subsubsection changelog-latest-changes-gl GL library
- The @ref GL::Mesh::indexTypeSize() and @ref GL::MeshView::setIndexRange()

59
src/Magnum/DebugTools/Test/TextureImageGLTest.cpp

@ -26,6 +26,7 @@
#include <Corrade/TestSuite/Compare/Container.h>
#include "Magnum/Image.h"
#include "Magnum/PixelFormat.h"
#include "Magnum/DebugTools/TextureImage.h"
#include "Magnum/GL/CubeMapTexture.h"
#include "Magnum/GL/OpenGLTester.h"
@ -48,6 +49,7 @@ struct TextureImageGLTest: GL::OpenGLTester {
#ifndef MAGNUM_TARGET_GLES2
void subImage2DBuffer();
#endif
void subImage2DGeneric();
void subImageCube();
#ifndef MAGNUM_TARGET_GLES2
@ -57,6 +59,7 @@ struct TextureImageGLTest: GL::OpenGLTester {
#ifndef MAGNUM_TARGET_GLES2
void subImage2DUInt();
void subImage2DFloat();
void subImage2DFloatGeneric();
#endif
};
@ -65,6 +68,7 @@ TextureImageGLTest::TextureImageGLTest() {
#ifndef MAGNUM_TARGET_GLES2
&TextureImageGLTest::subImage2DBuffer,
#endif
&TextureImageGLTest::subImage2DGeneric,
&TextureImageGLTest::subImageCube,
#ifndef MAGNUM_TARGET_GLES2
@ -74,6 +78,7 @@ TextureImageGLTest::TextureImageGLTest() {
#ifndef MAGNUM_TARGET_GLES2
&TextureImageGLTest::subImage2DUInt,
&TextureImageGLTest::subImage2DFloat,
&TextureImageGLTest::subImage2DFloatGeneric,
#endif
});
}
@ -98,6 +103,9 @@ void TextureImageGLTest::subImage2D() {
Image2D image = textureSubImage(texture, 0, {{}, Vector2i{2}}, {GL::PixelFormat::RGBA, GL::PixelType::UnsignedByte});
MAGNUM_VERIFY_NO_GL_ERROR();
CORRADE_COMPARE(image.size(), Vector2i{2});
CORRADE_COMPARE(image.format(), pixelFormatWrap(GL::PixelFormat::RGBA));
CORRADE_COMPARE(GL::PixelType(image.formatExtra()), GL::PixelType::UnsignedByte);
CORRADE_COMPARE(image.pixelSize(), 4);
CORRADE_COMPARE_AS(Containers::arrayCast<UnsignedByte>(image.data()),
Containers::arrayView(Data2D), TestSuite::Compare::Container);
}
@ -111,11 +119,34 @@ void TextureImageGLTest::subImage2DBuffer() {
Containers::Array<UnsignedByte> data = bufferData<UnsignedByte>(image.buffer());
MAGNUM_VERIFY_NO_GL_ERROR();
CORRADE_COMPARE(image.size(), Vector2i{2});
CORRADE_COMPARE(image.format(), GL::PixelFormat::RGBA);
CORRADE_COMPARE(image.type(), GL::PixelType::UnsignedByte);
CORRADE_COMPARE(image.pixelSize(), 4);
CORRADE_COMPARE_AS(data, Containers::arrayView(Data2D),
TestSuite::Compare::Container);
}
#endif
void TextureImageGLTest::subImage2DGeneric() {
GL::Texture2D texture;
texture.setImage(0,
#if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL))
GL::TextureFormat::RGBA8,
#else
GL::TextureFormat::RGBA,
#endif
ImageView2D{PixelFormat::RGBA8Unorm, Vector2i{2}, Data2D});
Image2D image = textureSubImage(texture, 0, {{}, Vector2i{2}}, {PixelFormat::RGBA8Unorm});
MAGNUM_VERIFY_NO_GL_ERROR();
CORRADE_COMPARE(image.size(), Vector2i{2});
CORRADE_COMPARE(image.format(), PixelFormat::RGBA8Unorm);
CORRADE_COMPARE(image.formatExtra(), 0);
CORRADE_COMPARE(image.pixelSize(), 4);
CORRADE_COMPARE_AS(Containers::arrayCast<UnsignedByte>(image.data()),
Containers::arrayView(Data2D), TestSuite::Compare::Container);
}
void TextureImageGLTest::subImageCube() {
ImageView2D view{GL::PixelFormat::RGBA, GL::PixelType::UnsignedByte, Vector2i{2}, Data2D};
@ -136,6 +167,9 @@ void TextureImageGLTest::subImageCube() {
Image2D image = textureSubImage(texture, GL::CubeMapCoordinate::PositiveX, 0, {{}, Vector2i{2}}, {GL::PixelFormat::RGBA, GL::PixelType::UnsignedByte});
MAGNUM_VERIFY_NO_GL_ERROR();
CORRADE_COMPARE(image.size(), Vector2i{2});
CORRADE_COMPARE(image.format(), pixelFormatWrap(GL::PixelFormat::RGBA));
CORRADE_COMPARE(GL::PixelType(image.formatExtra()), GL::PixelType::UnsignedByte);
CORRADE_COMPARE(image.pixelSize(), 4);
CORRADE_COMPARE_AS(Containers::arrayCast<UnsignedByte>(image.data()),
Containers::arrayView(Data2D), TestSuite::Compare::Container);
}
@ -156,6 +190,9 @@ void TextureImageGLTest::subImageCubeBuffer() {
Containers::Array<UnsignedByte> data = bufferData<UnsignedByte>(image.buffer());
MAGNUM_VERIFY_NO_GL_ERROR();
CORRADE_COMPARE(image.size(), Vector2i{2});
CORRADE_COMPARE(image.format(), GL::PixelFormat::RGBA);
CORRADE_COMPARE(image.type(), GL::PixelType::UnsignedByte);
CORRADE_COMPARE(image.pixelSize(), 4);
CORRADE_COMPARE_AS(data, Containers::arrayView(Data2D),
TestSuite::Compare::Container);
}
@ -176,6 +213,9 @@ void TextureImageGLTest::subImage2DUInt() {
Image2D image = textureSubImage(texture, 0, {{}, Vector2i{2}}, {GL::PixelFormat::RedInteger, GL::PixelType::UnsignedInt});
MAGNUM_VERIFY_NO_GL_ERROR();
CORRADE_COMPARE(image.size(), Vector2i{2});
CORRADE_COMPARE(image.format(), pixelFormatWrap(GL::PixelFormat::RedInteger));
CORRADE_COMPARE(GL::PixelType(image.formatExtra()), GL::PixelType::UnsignedInt);
CORRADE_COMPARE(image.pixelSize(), 4);
CORRADE_COMPARE_AS(Containers::arrayCast<UnsignedInt>(image.data()),
Containers::arrayView(Data2DUInt),
TestSuite::Compare::Container);
@ -196,6 +236,25 @@ void TextureImageGLTest::subImage2DFloat() {
Image2D image = textureSubImage(texture, 0, {{}, Vector2i{2}}, {GL::PixelFormat::Red, GL::PixelType::Float});
MAGNUM_VERIFY_NO_GL_ERROR();
CORRADE_COMPARE(image.size(), Vector2i{2});
CORRADE_COMPARE(image.format(), pixelFormatWrap(GL::PixelFormat::Red));
CORRADE_COMPARE(GL::PixelType(image.formatExtra()), GL::PixelType::Float);
CORRADE_COMPARE(image.pixelSize(), 4);
CORRADE_COMPARE_AS(Containers::arrayCast<Float>(image.data()),
Containers::arrayView(Data2DFloat),
TestSuite::Compare::Container);
}
void TextureImageGLTest::subImage2DFloatGeneric() {
GL::Texture2D texture;
texture.setStorage(1, GL::TextureFormat::R32F, Vector2i{2})
.setSubImage(0, {}, ImageView2D{GL::PixelFormat::Red, GL::PixelType::Float, Vector2i{2}, Data2DFloat});
Image2D image = textureSubImage(texture, 0, {{}, Vector2i{2}}, {PixelFormat::R32F});
MAGNUM_VERIFY_NO_GL_ERROR();
CORRADE_COMPARE(image.size(), Vector2i{2});
CORRADE_COMPARE(image.format(), PixelFormat::R32F);
CORRADE_COMPARE(image.formatExtra(), 0);
CORRADE_COMPARE(image.pixelSize(), 4);
CORRADE_COMPARE_AS(Containers::arrayCast<Float>(image.data()),
Containers::arrayView(Data2DFloat),
TestSuite::Compare::Container);

79
src/Magnum/DebugTools/TextureImage.cpp

@ -56,11 +56,11 @@ namespace Magnum { namespace DebugTools {
#if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_GLES2)
namespace {
class FloatReinterpretShader: public AbstractShaderProgram {
class FloatReinterpretShader: public GL::AbstractShaderProgram {
public:
explicit FloatReinterpretShader();
FloatReinterpretShader& setTexture(Texture2D& texture, Int level) {
FloatReinterpretShader& setTexture(GL::Texture2D& texture, Int level) {
texture.bind(0);
setUniform(levelUniform, level);
return *this;
@ -78,12 +78,12 @@ FloatReinterpretShader::FloatReinterpretShader() {
#endif
Utility::Resource rs{"MagnumDebugTools"};
Shader vert{Version::GLES300, Shader::Type::Vertex};
Shader frag{Version::GLES300, Shader::Type::Fragment};
GL::Shader vert{GL::Version::GLES300, GL::Shader::Type::Vertex};
GL::Shader frag{GL::Version::GLES300, GL::Shader::Type::Fragment};
vert.addSource(rs.get("TextureImage.vert"));
frag.addSource(rs.get("TextureImage.frag"));
CORRADE_INTERNAL_ASSERT(Shader::compile({vert, frag}));
CORRADE_INTERNAL_ASSERT(GL::Shader::compile({vert, frag}));
attachShaders({vert, frag});
CORRADE_INTERNAL_ASSERT(link());
@ -97,68 +97,61 @@ FloatReinterpretShader::FloatReinterpretShader() {
void textureSubImage(GL::Texture2D& texture, const Int level, const Range2Di& range, Image2D& image) {
#ifndef MAGNUM_TARGET_GLES
if(Context::current().isExtensionSupported<GL::Extensions::ARB::get_texture_sub_image>()) {
if(GL::Context::current().isExtensionSupported<GL::Extensions::ARB::get_texture_sub_image>()) {
texture.subImage(level, range, image);
return;
}
#endif
#if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_GLES2)
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;
GL::PixelType type = GL::pixelType(image.format(), image.formatExtra());
if(type == GL::PixelType::Float) {
GL::TextureFormat textureFormat;
GL::PixelFormat reinterpretFormat;
GL::PixelFormat format = GL::pixelFormat(image.format());
switch(format) {
case GL::PixelFormat::Red:
textureFormat = GL::TextureFormat::R32UI;
reinterpretFormat = GL::PixelFormat::RedInteger;
break;
case PixelFormat::RG:
textureFormat = TextureFormat::RG32UI;
reinterpretFormat = PixelFormat::RGInteger;
case GL::PixelFormat::RG:
textureFormat = GL::TextureFormat::RG32UI;
reinterpretFormat = GL::PixelFormat::RGInteger;
break;
case PixelFormat::RGB:
textureFormat = TextureFormat::RGB32UI;
reinterpretFormat = PixelFormat::RGBInteger;
case GL::PixelFormat::RGB:
textureFormat = GL::TextureFormat::RGB32UI;
reinterpretFormat = GL::PixelFormat::RGBInteger;
break;
case PixelFormat::RGBA:
textureFormat = TextureFormat::RGBA32UI;
reinterpretFormat = PixelFormat::RGBAInteger;
case GL::PixelFormat::RGBA:
textureFormat = GL::TextureFormat::RGBA32UI;
reinterpretFormat = GL::PixelFormat::RGBAInteger;
break;
default:
CORRADE_ASSERT(false, "DebugTools::textureSubImage(): unsupported pixel format" << image.format(), );
CORRADE_ASSERT(false, "DebugTools::textureSubImage(): unsupported pixel format" << format, );
}
Texture2D output;
GL::Texture2D output;
output.setStorage(1, textureFormat, range.max());
Framebuffer fb{range};
fb.attachTexture(Framebuffer::ColorAttachment{0}, output, 0)
GL::Framebuffer fb{range};
fb.attachTexture(GL::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);
CORRADE_INTERNAL_ASSERT(fb.checkStatus(GL::FramebufferTarget::Draw) == GL::Framebuffer::Status::Complete);
CORRADE_INTERNAL_ASSERT(fb.checkStatus(GL::FramebufferTarget::Read) == GL::Framebuffer::Status::Complete);
FloatReinterpretShader shader;
shader.setTexture(texture, level);
Mesh mesh;
GL::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 = Image2D{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 = Image2D{image.storage(), imageFormat, PixelType::Float, imageSize, image.release()};
}
const Vector2i imageSize = image.size();
Image2D temp{image.storage(), reinterpretFormat, GL::PixelType::UnsignedInt, imageSize, image.release()};
fb.read(range, temp);
image = Image2D{image.storage(), image.format(), image.formatExtra(), image.pixelSize(), imageSize, temp.release()};
return;
}
#endif
@ -176,7 +169,7 @@ Image2D textureSubImage(GL::Texture2D& texture, const Int level, const Range2Di&
#ifndef MAGNUM_TARGET_GLES2
void textureSubImage(GL::Texture2D& texture, const Int level, const Range2Di& range, GL::BufferImage2D& image, const GL::BufferUsage usage) {
#ifndef MAGNUM_TARGET_GLES
if(Context::current().isExtensionSupported<GL::Extensions::ARB::get_texture_sub_image>()) {
if(GL::Context::current().isExtensionSupported<GL::Extensions::ARB::get_texture_sub_image>()) {
texture.subImage(level, range, image, usage);
return;
}

93
src/Magnum/DebugTools/TextureImage.h

@ -25,30 +25,38 @@
DEALINGS IN THE SOFTWARE.
*/
#ifdef MAGNUM_TARGET_GL
/** @file
* @brief Function @ref Magnum::DebugTools::textureSubImage()
*/
#endif
#include "Magnum/Magnum.h"
#include "Magnum/DebugTools/visibility.h"
#include "Magnum/GL/GL.h"
#ifdef MAGNUM_TARGET_GL
namespace Magnum { namespace DebugTools {
/**
@brief Read range of given texture mip level to image
Emulates @ref Texture2D::subImage() call on platforms that don't support it
Emulates @ref GL::Texture2D::subImage() call on platforms that don't support it
(such as OpenGL ES) by creating a framebuffer object and using
@ref Framebuffer::read(). On desktop OpenGL, if @extension{ARB,get_texture_sub_image}
is available, it's just an alias to @ref Texture2D::subImage().
Note that only @ref Magnum::PixelFormat "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.
@ref GL::Framebuffer::read(). On desktop OpenGL, if @extension{ARB,get_texture_sub_image}
is available, it's just an alias to @ref GL::Texture2D::subImage().
Note that only @ref GL::PixelFormat and @ref GL::PixelType values that are
marked as framebuffer readable are supported; their generic
@ref Magnum::PixelFormat "PixelFormat" counterparts are supported as well. In
addition, on OpenGL ES 3.0, images with @ref GL::PixelType::Float are supported
--- they are reinterpreted as @ref GL::PixelType::UnsignedInt using an
additional shader and the @glsl floatBitsToUint() @ce GLSL function and then
reinterpreted back to @ref GL::PixelType::Float when read to client memory.
@note This function is available only if Magnum is compiled with
@ref MAGNUM_TARGET_GL enabled (done by default). See @ref building-features
for more information.
*/
MAGNUM_DEBUGTOOLS_EXPORT void textureSubImage(GL::Texture2D& texture, Int level, const Range2Di& range, Image2D& image);
@ -60,18 +68,27 @@ Convenience alternative to the above, example usage:
@code{.cpp}
Image2D image = DebugTools::textureSubImage(texture, 0, rect, {PixelFormat::RGBA, PixelType::UnsignedByte});
@endcode
@note This function is available only if Magnum is compiled with
@ref MAGNUM_TARGET_GL enabled (done by default). See @ref building-features
for more information.
*/
MAGNUM_DEBUGTOOLS_EXPORT Image2D textureSubImage(GL::Texture2D& texture, Int level, const Range2Di& range, Image2D&& image);
/**
@brief Read range of given cube map texture coordinate mip level to image
Emulates @ref CubeMapTexture::subImage() call on platforms that don't support
it (such as OpenGL ES) by creating a framebuffer object and using
@ref Framebuffer::read().
Emulates @ref GL::CubeMapTexture::subImage() call on platforms that don't
support it (such as OpenGL ES) by creating a framebuffer object and using
@ref GL::Framebuffer::read().
Note that only @ref GL::PixelFormat and @ref GL::PixelType values that are
marked as framebuffer readable are supported; their generic
@ref Magnum::PixelFormat "PixelFormat" counterparts are supported as well.
Note that only @ref Magnum::PixelFormat "PixelFormat" and @ref PixelType values
that are marked as framebuffer readable are supported.
@note This function is available only if Magnum is compiled with
@ref MAGNUM_TARGET_GL enabled (done by default). See @ref building-features
for more information.
*/
MAGNUM_DEBUGTOOLS_EXPORT void textureSubImage(GL::CubeMapTexture& texture, GL::CubeMapCoordinate coordinate, Int level, const Range2Di& range, Image2D& image);
@ -83,6 +100,10 @@ Convenience alternative to the above, example usage:
@code{.cpp}
Image2D image = DebugTools::textureSubImage(texture, CubeMapCoordinate::PositiveX, 0, rect, {PixelFormat::RGBA, PixelType::UnsignedByte});
@endcode
@note This function is available only if Magnum is compiled with
@ref MAGNUM_TARGET_GL enabled (done by default). See @ref building-features
for more information.
*/
MAGNUM_DEBUGTOOLS_EXPORT Image2D textureSubImage(GL::CubeMapTexture& texture, GL::CubeMapCoordinate coordinate, Int level, const Range2Di& range, Image2D&& image);
@ -90,15 +111,21 @@ MAGNUM_DEBUGTOOLS_EXPORT Image2D textureSubImage(GL::CubeMapTexture& texture, GL
/**
@brief Read range of given texture mip level to buffer image
Emulates @ref Texture2D::subImage() call on platforms that don't support it
Emulates @ref GL::Texture2D::subImage() call on platforms that don't support it
(such as OpenGL ES) by creating a framebuffer object and using
@ref Framebuffer::read(). On desktop OpenGL, if @extension{ARB,get_texture_sub_image}
is available, it's just an alias to @ref Texture2D::subImage().
@ref GL::Framebuffer::read(). On desktop OpenGL, if
@extension{ARB,get_texture_sub_image} is available, it's just an alias to
@ref GL::Texture2D::subImage().
Note that only @ref Magnum::PixelFormat "PixelFormat" and @ref PixelType values
that are marked as framebuffer readable are supported.
Note that only @ref GL::PixelFormat and @ref GL::PixelType values that are
marked as framebuffer readable are supported; their generic
@ref Magnum::PixelFormat "PixelFormat" counterparts are supported as well.
@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.
@note This function is available only if Magnum is compiled with
@ref MAGNUM_TARGET_GL enabled (done by default). See @ref building-features
for more information.
*/
MAGNUM_DEBUGTOOLS_EXPORT void textureSubImage(GL::Texture2D& texture, Int level, const Range2Di& range, GL::BufferImage2D& image, GL::BufferUsage usage);
@ -110,20 +137,29 @@ Convenience alternative to the above, example usage:
@code{.cpp}
BufferImage2D image = DebugTools::textureSubImage(texture, 0, rect, {PixelFormat::RGBA, PixelType::UnsignedByte}, BufferUsage::StaticRead);
@endcode
@note This function is available only if Magnum is compiled with
@ref MAGNUM_TARGET_GL enabled (done by default). See @ref building-features
for more information.
*/
MAGNUM_DEBUGTOOLS_EXPORT GL::BufferImage2D textureSubImage(GL::Texture2D& texture, Int level, const Range2Di& range, GL::BufferImage2D&& image, GL::BufferUsage usage);
/**
@brief Read range of given cube map texture coordinate mip level to buffer image
Emulates @ref CubeMapTexture::subImage() call on platforms that don't support
it (such as OpenGL ES) by creating a framebuffer object and using
@ref Framebuffer::read().
Emulates @ref GL::CubeMapTexture::subImage() call on platforms that don't
support it (such as OpenGL ES) by creating a framebuffer object and using
@ref GL::Framebuffer::read().
Note that only @ref Magnum::PixelFormat "PixelFormat" and @ref PixelType values
that are marked as framebuffer readable are supported.
Note that only @ref GL::PixelFormat and @ref GL::PixelType values that are
marked as framebuffer readable are supported; their generic
@ref Magnum::PixelFormat "PixelFormat" counterparts are supported as well.
@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.
@note This function is available only if Magnum is compiled with
@ref MAGNUM_TARGET_GL enabled (done by default). See @ref building-features
for more information.
*/
MAGNUM_DEBUGTOOLS_EXPORT void textureSubImage(GL::CubeMapTexture& texture, GL::CubeMapCoordinate coordinate, Int level, const Range2Di& range, GL::BufferImage2D& image, GL::BufferUsage usage);
@ -135,9 +171,16 @@ Convenience alternative to the above, example usage:
@code{.cpp}
BufferImage2D image = DebugTools::textureSubImage(texture, CubeMapCoordinate::PositiveX, 0, rect, {PixelFormat::RGBA, PixelType::UnsignedByte}, BufferUsage::StaticRead);
@endcode
@note This function is available only if Magnum is compiled with
@ref MAGNUM_TARGET_GL enabled (done by default). See @ref building-features
for more information.
*/
MAGNUM_DEBUGTOOLS_EXPORT GL::BufferImage2D textureSubImage(GL::CubeMapTexture& texture, GL::CubeMapCoordinate coordinate, Int level, const Range2Di& range, GL::BufferImage2D&& image, GL::BufferUsage usage);
#endif
#else
#error this header is available only in the OpenGL build
#endif
}}

Loading…
Cancel
Save