Browse Source

DebugTools: add textureSubImage() overload for GL::Texture2DArray.

Wanted to add a proper variant that reads all layers at once into an
Image3D, but that requires the Image APIs to be made less crappy first.
So it's just this for noew because now I badly need it for
Text::DistanceFieldGlyphCacheArrayGL tests.
pull/674/head
Vladimír Vondruš 1 year ago
parent
commit
46c37f2795
  1. 2
      doc/changelog.dox
  2. 15
      doc/snippets/DebugTools-gl.cpp
  3. 80
      src/Magnum/DebugTools/Test/TextureImageGLTest.cpp
  4. 38
      src/Magnum/DebugTools/TextureImage.cpp
  5. 39
      src/Magnum/DebugTools/TextureImage.h

2
doc/changelog.dox

@ -641,6 +641,8 @@ See also:
- @ref DebugTools::textureSubImage() now checks that the framebuffer is
complete before attempting to read from it to avoid silent failures when
the texture format isn't framebuffer readable
- Added a @ref DebugTools::textureSubImage() overload for
@ref GL::Texture2DArray
@subsubsection changelog-latest-changes-gl GL library

15
doc/snippets/DebugTools-gl.cpp

@ -41,6 +41,9 @@
#include "Magnum/GL/Framebuffer.h"
#include "Magnum/GL/CubeMapTexture.h"
#include "Magnum/GL/Texture.h"
#ifndef MAGNUM_TARGET_GLES2
#include "Magnum/GL/TextureArray.h"
#endif
#include "Magnum/GL/TextureFormat.h"
#include "Magnum/Math/Range.h"
#include "Magnum/SceneGraph/Drawable.h"
@ -184,6 +187,18 @@ CORRADE_IGNORE_DEPRECATED_POP
}
#endif
#ifndef MAGNUM_TARGET_GLES2
{
GL::Texture2DArray texture;
Range2Di rect;
Int layer{};
/* [textureSubImage-array-rvalue] */
Image2D image = DebugTools::textureSubImage(texture, 0, layer, rect,
{PixelFormat::RGBA8Unorm});
/* [textureSubImage-array-rvalue] */
}
#endif
{
GL::CubeMapTexture texture;
Range2Di rect;

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

@ -37,6 +37,9 @@
#include "Magnum/GL/OpenGLTester.h"
#include "Magnum/GL/PixelFormat.h"
#include "Magnum/GL/Texture.h"
#ifndef MAGNUM_TARGET_GLES2
#include "Magnum/GL/TextureArray.h"
#endif
#include "Magnum/GL/TextureFormat.h"
#include "Magnum/Math/Half.h"
#include "Magnum/Math/Range.h"
@ -63,6 +66,15 @@ struct TextureImageGLTest: GL::OpenGLTester {
#endif
void subImage2DGeneric();
#ifndef MAGNUM_TARGET_GLES2
void subImage2DArray();
void subImage2DArrayNotReadable();
/* Unlike Texture2D the Texture2DArray overload has no codepath to
reinterpret float formats as integer, so no *Generic() test (that
verifies correct detection for generic formats as well) needs to
exist */
#endif
void subImageCube();
void subImageCubeNotReadable();
#if defined(MAGNUM_BUILD_DEPRECATED) && !defined(MAGNUM_TARGET_GLES2)
@ -91,6 +103,16 @@ const struct {
{"non-zero level", 3, 16},
};
const struct {
const char* name;
Int level, layer, sizeMultiplier;
} LevelLayerData[]{
{"", 0, 0, 1},
{"non-zero level", 3, 0, 16},
{"non-zero layer", 0, 2, 1},
{"non-zero level and layer", 3, 2, 16},
};
TextureImageGLTest::TextureImageGLTest() {
addInstancedTests({&TextureImageGLTest::subImage2D},
Containers::arraySize(LevelData));
@ -102,9 +124,17 @@ TextureImageGLTest::TextureImageGLTest() {
#endif
});
addInstancedTests({&TextureImageGLTest::subImage2DGeneric,
addInstancedTests({&TextureImageGLTest::subImage2DGeneric},
Containers::arraySize(LevelData));
&TextureImageGLTest::subImageCube},
#ifndef MAGNUM_TARGET_GLES2
addInstancedTests({&TextureImageGLTest::subImage2DArray},
Containers::arraySize(LevelLayerData));
addTests({&TextureImageGLTest::subImage2DArrayNotReadable});
#endif
addInstancedTests({&TextureImageGLTest::subImageCube},
Containers::arraySize(LevelData));
addTests({&TextureImageGLTest::subImageCubeNotReadable,
@ -278,6 +308,52 @@ void TextureImageGLTest::subImage2DGeneric() {
Containers::arrayView(Data2D), TestSuite::Compare::Container);
}
#ifndef MAGNUM_TARGET_GLES2
void TextureImageGLTest::subImage2DArray() {
auto&& data = LevelLayerData[testCaseInstanceId()];
setTestCaseDescription(data.name);
GL::Texture2DArray texture;
texture
.setStorage(data.level + 1, GL::TextureFormat::RGBA8, {Vector2i{2}*data.sizeMultiplier, data.layer + 1})
.setSubImage(data.level, {0, 0, data.layer}, ImageView2D{GL::PixelFormat::RGBA, GL::PixelType::UnsignedByte, Vector2i{2}, Data2D});
Image2D image = textureSubImage(texture, data.level, data.layer, {{}, 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);
}
void TextureImageGLTest::subImage2DArrayNotReadable() {
CORRADE_SKIP_IF_NO_ASSERT();
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::EXT::texture_shared_exponent>())
CORRADE_SKIP(GL::Extensions::EXT::texture_shared_exponent::string() << "not supported, can't test");
if(GL::Context::current().isExtensionSupported<GL::Extensions::ARB::get_texture_sub_image>())
CORRADE_SKIP(GL::Extensions::ARB::get_texture_sub_image::string() << "supported, can't test");
#endif
GL::Texture2DArray texture;
texture.setImage(0, GL::TextureFormat::RGB9E5, ImageView2D{GL::PixelFormat::RGB, GL::PixelType::UnsignedInt5999Rev, Vector2i{2}, Data2D});
Containers::String out;
Error redirectError{&out};
/* The read type doesn't have to match, it doesn't get that far */
textureSubImage(texture, 0, 0, {{}, Vector2i{2}}, {GL::PixelFormat::RGBA, GL::PixelType::UnsignedByte});
MAGNUM_VERIFY_NO_GL_ERROR();
#ifndef MAGNUM_TARGET_GLES
CORRADE_COMPARE(out, "DebugTools::textureSubImage(): texture format not framebuffer-readable: GL::Framebuffer::Status::Unsupported\n");
#else
CORRADE_COMPARE(out, "DebugTools::textureSubImage(): texture format not framebuffer-readable: GL::Framebuffer::Status::IncompleteAttachment\n");
#endif
}
#endif
void TextureImageGLTest::subImageCube() {
auto&& data = LevelData[testCaseInstanceId()];
setTestCaseDescription(data.name);

38
src/Magnum/DebugTools/TextureImage.cpp

@ -34,6 +34,9 @@
#include "Magnum/GL/Extensions.h"
#include "Magnum/GL/Framebuffer.h"
#include "Magnum/GL/Texture.h"
#ifndef MAGNUM_TARGET_GLES2
#include "Magnum/GL/TextureArray.h"
#endif
#if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_GLES2)
#include <Corrade/Containers/Iterable.h>
@ -238,6 +241,41 @@ GL::BufferImage2D textureSubImage(GL::Texture2D& texture, const Int level, const
}
#endif
#ifndef MAGNUM_TARGET_GLES2
void textureSubImage(GL::Texture2DArray& texture, const Int level, const Int layer, const Range2Di& range, Image2D& image) {
#ifndef MAGNUM_TARGET_GLES
if(GL::Context::current().isExtensionSupported<GL::Extensions::ARB::get_texture_sub_image>()) {
/* Make a temporary Image3D out of the input Image2D, read the pixels
into it, and then move its ownership back to the Image2D */
/** @todo have this on the Image APIs itself, in particular a
rvalue-only ability to "updimension", and similarly a rvalue-only
dimension slice */
Vector2i size = image.size();
Containers::Array<char> data = image.release();
Image3D image3{image.storage(), image.format(), image.formatExtra(), image.pixelSize(), {size, 1}, Utility::move(data)};
texture.subImage(level, {{range.min(), layer}, {range.max(), layer + 1}}, image3);
Vector3i size3 = image3.size();
Containers::Array<char> data3 = image3.release();
image = Image2D{image3.storage(), image3.format(), image3.formatExtra(), image3.pixelSize(), size3.xy(), Utility::move(data3)};
return;
}
#endif
GL::Framebuffer fb{range};
fb.attachTextureLayer(GL::Framebuffer::ColorAttachment{0}, texture, level, layer);
CORRADE_ASSERT(fb.checkStatus(GL::FramebufferTarget::Read) == GL::Framebuffer::Status::Complete,
"DebugTools::textureSubImage(): texture format not framebuffer-readable:" << fb.checkStatus(GL::FramebufferTarget::Read), );
fb.read(range, image);
}
Image2D textureSubImage(GL::Texture2DArray& texture, const Int level, const Int layer, const Range2Di& range, Image2D&& image) {
textureSubImage(texture, level, layer, range, image);
return Utility::move(image);
}
#endif
void textureSubImage(GL::CubeMapTexture& texture, const GL::CubeMapCoordinate coordinate, const Int level, const Range2Di& range, Image2D& image) {
/* Compared to textureSubImage(GL::CubeMapTexture&, ..., Image3D&), here's
no ARB_get_texture_sub_image code path because it only works with 3D

39
src/Magnum/DebugTools/TextureImage.h

@ -79,6 +79,45 @@ Convenience alternative to the above, example usage:
*/
MAGNUM_DEBUGTOOLS_EXPORT Image2D textureSubImage(GL::Texture2D& texture, Int level, const Range2Di& range, Image2D&& image);
#ifndef MAGNUM_TARGET_GLES2
/**
@brief Read a range of given texture array layer mip level to an image
@m_since_latest
Emulates @ref GL::Texture2DArray::subImage() on OpenGL ES and WebGL platforms
by creating a framebuffer object and using @ref GL::Framebuffer::read(). On
desktop OpenGL, if @gl_extension{ARB,get_texture_sub_image} is available, it's
just an alias to @ref GL::Texture2DArray::subImage().
The function expects that @p texture has a @ref GL::TextureFormat that's
framebuffer-readable and that the @ref GL::PixelFormat and @ref GL::PixelType
combination or the generic @relativeref{Magnum,PixelFormat} is compatible with
it.
@requires_gl30 Extension @gl_extension{EXT,texture_array}
@requires_gles30 Array textures are not available in OpenGL ES 2.0.
@requires_webgl20 Array textures are not available in WebGL 1.0.
@note This function is available only if Magnum is compiled with
@ref MAGNUM_TARGET_GL "TARGET_GL" enabled (done by default). See
@ref building-features for more information.
*/
MAGNUM_DEBUGTOOLS_EXPORT void textureSubImage(GL::Texture2DArray& texture, Int level, Int layer, const Range2Di& range, Image2D& image);
/**
@brief Read a range of given texture mip level to an image
@m_since_latest
Convenience alternative to the above, example usage:
@snippet DebugTools-gl.cpp textureSubImage-array-rvalue
@note This function is available only if Magnum is compiled with
@ref MAGNUM_TARGET_GL "TARGET_GL" enabled (done by default). See
@ref building-features for more information.
*/
MAGNUM_DEBUGTOOLS_EXPORT Image2D textureSubImage(GL::Texture2DArray& texture, Int level, Int layer, const Range2Di& range, Image2D&& image);
#endif
/**
@brief Read a range of given cube map texture coordinate mip level to an image
@m_since_latest

Loading…
Cancel
Save