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 constructMove();
void runTexture();
void runFramebuffer();
void run();
void formatNotDrawable();
void sizeRatioNotMultipleOfTwo();
@ -82,14 +81,27 @@ using namespace Math::Literals;
const struct {
const char* name;
bool framebuffer;
Vector2i size;
Vector2i offset;
bool flipX, flipY;
} RunData[]{
{"", {64, 64}, {}, false, false},
{"flipped on X", {64, 64}, {}, true, false},
{"flipped on Y", {64, 64}, {}, false, true},
{"with offset", {128, 96}, {64, 32}, false, false},
{"texture output",
false, {64, 64}, {}, false, false},
{"texture output, flipped on X",
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() {
@ -97,8 +109,7 @@ DistanceFieldGLTest::DistanceFieldGLTest() {
&DistanceFieldGLTest::constructCopy,
&DistanceFieldGLTest::constructMove});
addInstancedTests({&DistanceFieldGLTest::runTexture,
&DistanceFieldGLTest::runFramebuffer},
addInstancedTests({&DistanceFieldGLTest::run},
Containers::arraySize(RunData));
addTests({&DistanceFieldGLTest::formatNotDrawable,
@ -156,7 +167,7 @@ void DistanceFieldGLTest::constructMove() {
CORRADE_VERIFY(std::is_nothrow_move_assignable<DistanceFieldGL>::value);
}
void DistanceFieldGLTest::runTexture() {
void DistanceFieldGLTest::run() {
auto&& data = RunData[testCaseInstanceId()];
setTestCaseDescription(data.name);
@ -223,183 +234,47 @@ void DistanceFieldGLTest::runTexture() {
#endif
const GL::PixelType outputPixelType = GL::PixelType::UnsignedByte;
GL::Texture2D output;
output.setMinificationFilter(GL::SamplerFilter::Nearest, GL::SamplerMipmap::Base)
GL::Texture2D outputTexture;
outputTexture.setMinificationFilter(GL::SamplerFilter::Nearest, GL::SamplerMipmap::Base)
.setMagnificationFilter(GL::SamplerFilter::Nearest)
.setStorage(1, outputTextureFormat, data.size);
/* Fill the texture with some data to verify they don't affect the output
and aren't accidentally overwritten when running on just a
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'}});
DistanceFieldGL distanceField{32};
CORRADE_COMPARE(distanceField.radius(), 32);
MAGNUM_VERIFY_NO_GL_ERROR();
distanceField(input, output, Range2Di::fromSize(data.offset, Vector2i{64})
#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 */
GL::Framebuffer outputFramebuffer{NoCreate};
if(data.framebuffer) {
/* Deliberately making the viewport the whole framebuffer -- the tool
should adjust it as appropriate and then revert back */
outputFramebuffer = GL::Framebuffer{{{}, data.size}};
outputFramebuffer.attachTexture(GL::Framebuffer::ColorAttachment(0), outputTexture, 0);
}
#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};
CORRADE_COMPARE(distanceField.radius(), 32);
MAGNUM_VERIFY_NO_GL_ERROR();
distanceField(input, output, Range2Di::fromSize(data.offset, Vector2i{64})
#ifdef MAGNUM_TARGET_GLES
, inputImage->size()
#endif
);
if(data.framebuffer) {
distanceField(input, outputFramebuffer, Range2Di::fromSize(data.offset, Vector2i{64})
#ifdef MAGNUM_TARGET_GLES
, 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 */
CORRADE_COMPARE(output.viewport(), (Range2Di{{}, data.size}));
if(data.framebuffer)
CORRADE_COMPARE(outputFramebuffer.viewport(), (Range2Di{{}, data.size}));
Containers::Optional<Image2D> actualOutputImage;
#ifndef MAGNUM_TARGET_GLES2

Loading…
Cancel
Save