Browse Source

TextureTools: no need for such massive test code duplication.

What was I thinking, ugh.
pull/674/head
Vladimír Vondruš 1 year ago
parent
commit
8264933a85
  1. 213
      src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp

213
src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp

@ -63,8 +63,7 @@ struct DistanceFieldGLTest: GL::OpenGLTester {
void constructCopy(); void constructCopy();
void constructMove(); void constructMove();
void runTexture(); void run();
void runFramebuffer();
void formatNotDrawable(); void formatNotDrawable();
void sizeRatioNotMultipleOfTwo(); void sizeRatioNotMultipleOfTwo();
@ -82,14 +81,27 @@ using namespace Math::Literals;
const struct { const struct {
const char* name; const char* name;
bool framebuffer;
Vector2i size; Vector2i size;
Vector2i offset; Vector2i offset;
bool flipX, flipY; bool flipX, flipY;
} RunData[]{ } RunData[]{
{"", {64, 64}, {}, false, false}, {"texture output",
{"flipped on X", {64, 64}, {}, true, false}, false, {64, 64}, {}, false, false},
{"flipped on Y", {64, 64}, {}, false, true}, {"texture output, flipped on X",
{"with offset", {128, 96}, {64, 32}, false, false}, false, {64, 64}, {}, true, false},
{"texture output, flipped on Y",
false, {64, 64}, {}, false, true},
{"texture output, with offset",
false, {128, 96}, {64, 32}, false, false},
{"framebuffer output",
true, {64, 64}, {}, false, false},
{"framebuffer output, flipped on X",
true, {64, 64}, {}, true, false},
{"framebuffer output, flipped on Y",
true, {64, 64}, {}, false, true},
{"framebuffer output, with offset",
true, {128, 96}, {64, 32}, false, false},
}; };
DistanceFieldGLTest::DistanceFieldGLTest() { DistanceFieldGLTest::DistanceFieldGLTest() {
@ -97,8 +109,7 @@ DistanceFieldGLTest::DistanceFieldGLTest() {
&DistanceFieldGLTest::constructCopy, &DistanceFieldGLTest::constructCopy,
&DistanceFieldGLTest::constructMove}); &DistanceFieldGLTest::constructMove});
addInstancedTests({&DistanceFieldGLTest::runTexture, addInstancedTests({&DistanceFieldGLTest::run},
&DistanceFieldGLTest::runFramebuffer},
Containers::arraySize(RunData)); Containers::arraySize(RunData));
addTests({&DistanceFieldGLTest::formatNotDrawable, addTests({&DistanceFieldGLTest::formatNotDrawable,
@ -156,7 +167,7 @@ void DistanceFieldGLTest::constructMove() {
CORRADE_VERIFY(std::is_nothrow_move_assignable<DistanceFieldGL>::value); CORRADE_VERIFY(std::is_nothrow_move_assignable<DistanceFieldGL>::value);
} }
void DistanceFieldGLTest::runTexture() { void DistanceFieldGLTest::run() {
auto&& data = RunData[testCaseInstanceId()]; auto&& data = RunData[testCaseInstanceId()];
setTestCaseDescription(data.name); setTestCaseDescription(data.name);
@ -223,183 +234,47 @@ void DistanceFieldGLTest::runTexture() {
#endif #endif
const GL::PixelType outputPixelType = GL::PixelType::UnsignedByte; const GL::PixelType outputPixelType = GL::PixelType::UnsignedByte;
GL::Texture2D output; GL::Texture2D outputTexture;
output.setMinificationFilter(GL::SamplerFilter::Nearest, GL::SamplerMipmap::Base) outputTexture.setMinificationFilter(GL::SamplerFilter::Nearest, GL::SamplerMipmap::Base)
.setMagnificationFilter(GL::SamplerFilter::Nearest) .setMagnificationFilter(GL::SamplerFilter::Nearest)
.setStorage(1, outputTextureFormat, data.size); .setStorage(1, outputTextureFormat, data.size);
/* Fill the texture with some data to verify they don't affect the output /* Fill the texture with some data to verify they don't affect the output
and aren't accidentally overwritten when running on just a and aren't accidentally overwritten when running on just a
subrectangle */ subrectangle */
output.setSubImage(0, {}, ImageView2D{outputPixelFormat, outputPixelType, data.size, outputTexture.setSubImage(0, {}, ImageView2D{outputPixelFormat, outputPixelType, data.size,
Containers::Array<char>{DirectInit, std::size_t(data.size.product()*GL::pixelFormatSize(outputPixelFormat, outputPixelType)), '\x66'}}); Containers::Array<char>{DirectInit, std::size_t(data.size.product()*GL::pixelFormatSize(outputPixelFormat, outputPixelType)), '\x66'}});
DistanceFieldGL distanceField{32}; GL::Framebuffer outputFramebuffer{NoCreate};
CORRADE_COMPARE(distanceField.radius(), 32); if(data.framebuffer) {
/* Deliberately making the viewport the whole framebuffer -- the tool
MAGNUM_VERIFY_NO_GL_ERROR(); should adjust it as appropriate and then revert back */
outputFramebuffer = GL::Framebuffer{{{}, data.size}};
distanceField(input, output, Range2Di::fromSize(data.offset, Vector2i{64}) outputFramebuffer.attachTexture(GL::Framebuffer::ColorAttachment(0), outputTexture, 0);
#ifdef MAGNUM_TARGET_GLES
, inputImage->size()
#endif
);
Containers::Optional<Image2D> actualOutputImage;
#ifndef MAGNUM_TARGET_GLES2
actualOutputImage = Image2D{PixelFormat::R8Unorm};
#elif !defined(MAGNUM_TARGET_WEBGL)
if(GL::Context::current().isExtensionSupported<GL::Extensions::EXT::texture_rg>())
actualOutputImage = Image2D{GL::PixelFormat::Red, GL::PixelType::UnsignedByte};
else
actualOutputImage = Image2D{PixelFormat::RGBA8Unorm};
#else
actualOutputImage = Image2D{PixelFormat::RGBA8Unorm};
#endif
/* Verify that the other data weren't overwritten if processing just a
subrange -- it should still have the original data kept */
if(data.offset.product()) {
DebugTools::textureSubImage(output, 0, Range2Di::fromSize({}, Vector2i{1}), *actualOutputImage);
MAGNUM_VERIFY_NO_GL_ERROR();
CORRADE_COMPARE(actualOutputImage->data()[0], '\x66');
}
DebugTools::textureSubImage(output, 0, Range2Di::fromSize(data.offset, Vector2i{64}), *actualOutputImage);
MAGNUM_VERIFY_NO_GL_ERROR();
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
/* Flip the output back */
Containers::StridedArrayView3D<char> pixels3 = actualOutputImage->pixels();
if(data.flipX)
Utility::flipInPlace<1>(pixels3);
if(data.flipY)
Utility::flipInPlace<0>(pixels3);
/* Use just the first channel if the format is RGBA */
Containers::StridedArrayView2D<UnsignedByte> pixels;
if(actualOutputImage->format() == PixelFormat::RGBA8Unorm)
pixels = Containers::arrayCast<2, Color4ub>(pixels3).slice(&Color4ub::r);
else
pixels = Containers::arrayCast<2, UnsignedByte>(pixels3);
CORRADE_COMPARE_WITH(
pixels,
Utility::Path::join(_testDir, "output.tga"),
/* Some mobile GPUs have slight (off-by-one) rounding errors compared
to the ground truth, but it's just a very small amount of pixels
(20-50 out of the total 4k pixels, iOS/WebGL has slightly more).
That's okay. It's also possible that the ground truth itself has
rounding errors ;) */
(DebugTools::CompareImageToFile{_manager, 1.0f, 0.178f}));
}
void DistanceFieldGLTest::runFramebuffer() {
auto&& data = RunData[testCaseInstanceId()];
setTestCaseDescription(data.name);
/* Like runTexture(), except that the it's using the framebuffer overload.
It should give the same results even without having to explicitly set
anything on the framebuffer. */
Containers::Pointer<Trade::AbstractImporter> importer;
if(!(importer = _manager.loadAndInstantiate("TgaImporter")))
CORRADE_SKIP("TgaImporter plugin not found.");
CORRADE_VERIFY(importer->openFile(Utility::Path::join(_testDir, "input.tga")));
CORRADE_COMPARE(importer->image2DCount(), 1);
Containers::Optional<Trade::ImageData2D> inputImage = importer->image2D(0);
CORRADE_VERIFY(inputImage);
CORRADE_COMPARE(inputImage->format(), PixelFormat::R8Unorm);
/* Flip the input if desired */
if(data.flipX)
Utility::flipInPlace<1>(inputImage->mutablePixels());
if(data.flipY)
Utility::flipInPlace<0>(inputImage->mutablePixels());
#ifndef MAGNUM_TARGET_GLES2
const GL::TextureFormat inputFormat = GL::TextureFormat::R8;
#elif !defined(MAGNUM_TARGET_WEBGL)
GL::TextureFormat inputFormat;
if(GL::Context::current().isExtensionSupported<GL::Extensions::EXT::texture_rg>()) {
CORRADE_INFO("Using" << GL::Extensions::EXT::texture_rg::string());
inputFormat = GL::TextureFormat::R8;
} else {
inputFormat = GL::TextureFormat::Luminance; /** @todo Luminance8 */
} }
#else
const GL::TextureFormat inputFormat = GL::TextureFormat::Luminance;
#endif
GL::Texture2D input;
input.setMinificationFilter(GL::SamplerFilter::Nearest, GL::SamplerMipmap::Base)
.setMagnificationFilter(GL::SamplerFilter::Nearest)
.setStorage(1, inputFormat, inputImage->size());
#if !defined(MAGNUM_TARGET_GLES2) || defined(MAGNUM_TARGET_WEBGL)
input.setSubImage(0, {}, *inputImage);
#else
if(GL::Context::current().isExtensionSupported<GL::Extensions::EXT::texture_rg>())
input.setSubImage(0, {}, ImageView2D{inputImage->storage(), GL::PixelFormat::Red, GL::PixelType::UnsignedByte, inputImage->size(), inputImage->data()});
else
input.setSubImage(0, {}, *inputImage);
#endif
#ifndef MAGNUM_TARGET_GLES2
const GL::TextureFormat outputFormat = GL::TextureFormat::R8;
#elif !defined(MAGNUM_TARGET_WEBGL)
GL::TextureFormat outputFormat;
if(GL::Context::current().isExtensionSupported<GL::Extensions::EXT::texture_rg>())
outputFormat = GL::TextureFormat::R8;
else
outputFormat = GL::TextureFormat::RGBA;
#else
const GL::TextureFormat outputFormat = GL::TextureFormat::RGBA;
#endif
GL::Texture2D outputTexture;
outputTexture.setMinificationFilter(GL::SamplerFilter::Nearest, GL::SamplerMipmap::Base)
.setMagnificationFilter(GL::SamplerFilter::Nearest)
.setStorage(1, outputFormat, data.size);
/* Deliberately making the viewport the whole framebuffer -- the tool
should adjust it as appropriate and then revert back */
GL::Framebuffer output{{{}, data.size}};
output.attachTexture(GL::Framebuffer::ColorAttachment(0), outputTexture, 0);
/* Clear the framebuffer to some data to verify it's not getting cleared
again inside, stomping on existing data. Use the statless clear command
if possible to avoid the clear color getting accidentally reused for a
clear inside, making the test wrongly pass */
#ifndef MAGNUM_TARGET_GLES2
output.clearColor(0, 0x667788_rgbf);
#else
GL::Renderer::setClearColor(0x667788_rgbf);
output.clear(GL::FramebufferClear::Color);
/* Same as in GL::Renderer::initializeContextBasedFunctionality() */
GL::Renderer::setClearColor(0x1f1f1f_rgbf);
#endif
DistanceFieldGL distanceField{32}; DistanceFieldGL distanceField{32};
CORRADE_COMPARE(distanceField.radius(), 32); CORRADE_COMPARE(distanceField.radius(), 32);
MAGNUM_VERIFY_NO_GL_ERROR(); MAGNUM_VERIFY_NO_GL_ERROR();
distanceField(input, output, Range2Di::fromSize(data.offset, Vector2i{64}) if(data.framebuffer) {
#ifdef MAGNUM_TARGET_GLES distanceField(input, outputFramebuffer, Range2Di::fromSize(data.offset, Vector2i{64})
, inputImage->size() #ifdef MAGNUM_TARGET_GLES
#endif , inputImage->size()
); #endif
);
} else {
distanceField(input, outputTexture, Range2Di::fromSize(data.offset, Vector2i{64})
#ifdef MAGNUM_TARGET_GLES
, inputImage->size()
#endif
);
}
/* The viewport should stay as it was before */ /* The viewport should stay as it was before */
CORRADE_COMPARE(output.viewport(), (Range2Di{{}, data.size})); if(data.framebuffer)
CORRADE_COMPARE(outputFramebuffer.viewport(), (Range2Di{{}, data.size}));
Containers::Optional<Image2D> actualOutputImage; Containers::Optional<Image2D> actualOutputImage;
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2

Loading…
Cancel
Save