diff --git a/src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp b/src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp index 4026de0df..acd6068c8 100644 --- a/src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp +++ b/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::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{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 actualOutputImage; - #ifndef MAGNUM_TARGET_GLES2 - actualOutputImage = Image2D{PixelFormat::R8Unorm}; - #elif !defined(MAGNUM_TARGET_WEBGL) - if(GL::Context::current().isExtensionSupported()) - 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 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 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 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 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()) { - 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()) - 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()) - 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 actualOutputImage; #ifndef MAGNUM_TARGET_GLES2