From e4b2fecf46f0a168c9500cf5ed76714d9bb4269d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 1 Jul 2025 17:33:35 +0200 Subject: [PATCH] TextureTools: split DistanceFieldGL benchmark into a separate test. So I can exclude it along with other *GLBenchmark executables on the CI but still run the CPU benchmarks. --- src/Magnum/TextureTools/Test/CMakeLists.txt | 33 ++- .../Test/DistanceFieldGLBenchmark.cpp | 205 ++++++++++++++++++ .../TextureTools/Test/DistanceFieldGLTest.cpp | 108 --------- 3 files changed, 236 insertions(+), 110 deletions(-) create mode 100644 src/Magnum/TextureTools/Test/DistanceFieldGLBenchmark.cpp diff --git a/src/Magnum/TextureTools/Test/CMakeLists.txt b/src/Magnum/TextureTools/Test/CMakeLists.txt index cfc8969da..6a926d3c7 100644 --- a/src/Magnum/TextureTools/Test/CMakeLists.txt +++ b/src/Magnum/TextureTools/Test/CMakeLists.txt @@ -95,11 +95,15 @@ if(MAGNUM_TARGET_GL) # Otherwise CMake complains that Corrade::PluginManager is not found, wtf find_package(Corrade REQUIRED PluginManager) - set(TextureToolsDistanceFieldGLTest_SRCS DistanceFieldGLTest.cpp) + # Shared by DistanceFieldGLTest and DistanceFieldGLBenchmark if(CORRADE_TARGET_IOS) - # TODO: do this in a generic way in corrade_add_test() set_source_files_properties(DistanceFieldGLTestFiles PROPERTIES MACOSX_PACKAGE_LOCATION Resources) + endif() + + set(TextureToolsDistanceFieldGLTest_SRCS DistanceFieldGLTest.cpp) + if(CORRADE_TARGET_IOS) + # TODO: do this in a generic way in corrade_add_test() list(APPEND TextureToolsDistanceFieldGLTest_SRCS DistanceFieldGLTestFiles) endif() corrade_add_test(TextureToolsDistanceFieldGLTest ${TextureToolsDistanceFieldGLTest_SRCS} @@ -129,5 +133,30 @@ if(MAGNUM_TARGET_GL) add_dependencies(TextureToolsDistanceFieldGLTest TgaImporter) endif() endif() + + set(TextureToolsDistanceFieldGLBenchmark_SRCS DistanceFieldGLBenchmark.cpp) + if(CORRADE_TARGET_IOS) + # TODO: do this in a generic way in corrade_add_test() + list(APPEND TextureToolsDistanceFieldGLBenchmark_SRCS DistanceFieldGLTestFiles) + endif() + corrade_add_test(TextureToolsDistanceFieldGLBenchmark ${TextureToolsDistanceFieldGLBenchmark_SRCS} + LIBRARIES + MagnumGL + MagnumOpenGLTester + MagnumTextureTools + MagnumTrade + FILES + DistanceFieldGLTestFiles/input.tga) + target_include_directories(TextureToolsDistanceFieldGLBenchmark PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/$) + if(MAGNUM_BUILD_PLUGINS_STATIC) + if(MAGNUM_WITH_TGAIMPORTER) + target_link_libraries(TextureToolsDistanceFieldGLBenchmark PRIVATE TgaImporter) + endif() + else() + # So the plugins get properly built when building the test + if(MAGNUM_WITH_TGAIMPORTER) + add_dependencies(TextureToolsDistanceFieldGLBenchmark TgaImporter) + endif() + endif() endif() endif() diff --git a/src/Magnum/TextureTools/Test/DistanceFieldGLBenchmark.cpp b/src/Magnum/TextureTools/Test/DistanceFieldGLBenchmark.cpp new file mode 100644 index 000000000..d9f035db7 --- /dev/null +++ b/src/Magnum/TextureTools/Test/DistanceFieldGLBenchmark.cpp @@ -0,0 +1,205 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021, 2022, 2023, 2024, 2025 + Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include + +#ifdef CORRADE_TARGET_APPLE +#include /* isSandboxed() */ +#endif + +#include "Magnum/ImageView.h" +#include "Magnum/PixelFormat.h" +#ifdef MAGNUM_TARGET_GLES +#include "Magnum/GL/Context.h" +#include "Magnum/GL/Extensions.h" +#endif +#include "Magnum/GL/Framebuffer.h" +#include "Magnum/GL/OpenGLTester.h" +#ifdef MAGNUM_TARGET_GLES2 +#include "Magnum/GL/PixelFormat.h" +#endif +#include "Magnum/GL/Texture.h" +#include "Magnum/GL/TextureFormat.h" +#include "Magnum/TextureTools/DistanceFieldGL.h" +#include "Magnum/Trade/AbstractImporter.h" +#include "Magnum/Trade/ImageData.h" + +#include "configure.h" + +namespace Magnum { namespace TextureTools { namespace Test { namespace { + +struct DistanceFieldGLBenchmark: GL::OpenGLTester { + explicit DistanceFieldGLBenchmark(); + + void benchmark(); + + private: + PluginManager::Manager _manager{"nonexistent"}; + Containers::String _testDir; +}; + +using namespace Math::Literals; + +const struct { + const char* name; + GL::TextureFormat format; +} BenchmarkData[]{ + /* On ES2 the format selection is too annoying, just skip the variants + altogether and pick *some* format in the function itself */ + #ifdef MAGNUM_TARGET_GLES2 + {"", GL::TextureFormat{}}, + #else + {"R8 output", GL::TextureFormat::R8}, + {"RGB8 output", GL::TextureFormat::RGB8}, + {"RGBA8 output", GL::TextureFormat::RGBA8}, + {"R16 output", GL::TextureFormat::R16}, + #endif +}; + +DistanceFieldGLBenchmark::DistanceFieldGLBenchmark() { + addInstancedBenchmarks({&DistanceFieldGLBenchmark::benchmark}, 10, + Containers::arraySize(BenchmarkData), + BenchmarkType::GpuTime); + + /* Load the plugin directly from the build tree. Otherwise it's either + static and already loaded or not present in the build tree */ + #ifdef ANYIMAGEIMPORTER_PLUGIN_FILENAME + CORRADE_INTERNAL_ASSERT_OUTPUT(_manager.load(ANYIMAGEIMPORTER_PLUGIN_FILENAME) & PluginManager::LoadState::Loaded); + #endif + #ifdef TGAIMPORTER_PLUGIN_FILENAME + CORRADE_INTERNAL_ASSERT_OUTPUT(_manager.load(TGAIMPORTER_PLUGIN_FILENAME) & PluginManager::LoadState::Loaded); + #endif + + #ifdef CORRADE_TARGET_APPLE + if(Utility::System::isSandboxed() + #if defined(CORRADE_TARGET_IOS) && defined(CORRADE_TESTSUITE_TARGET_XCTEST) + /** @todo Fix this once I persuade CMake to run XCTest tests properly */ + && std::getenv("SIMULATOR_UDID") + #endif + ) { + _testDir = Utility::Path::join(Utility::Path::path(*Utility::Path::executableLocation()), "DistanceFieldGLTestFiles"); + } else + #endif + { + _testDir = Utility::Path::join(TEXTURETOOLS_TEST_DIR, "DistanceFieldGLTestFiles"); + } +} + +void DistanceFieldGLBenchmark::benchmark() { + auto&& data = BenchmarkData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + + #ifdef MAGNUM_TARGET_GLES + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::EXT::disjoint_timer_query::string() << "is not supported, can't benchmark"); + #endif + + 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); + + #ifndef MAGNUM_TARGET_GLES2 + const GL::TextureFormat inputFormat = GL::TextureFormat::R8; + #else + GL::TextureFormat inputFormat; + #ifndef MAGNUM_TARGET_WEBGL + if(GL::Context::current().isExtensionSupported()) { + inputFormat = GL::TextureFormat::R8; + } else + #endif + { + inputFormat = GL::TextureFormat::Luminance; /** @todo Luminance8 */ + } + #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 + #ifndef MAGNUM_TARGET_WEBGL + if(GL::Context::current().isExtensionSupported()) { + input.setSubImage(0, {}, ImageView2D{inputImage->storage(), GL::PixelFormat::Red, GL::PixelType::UnsignedByte, inputImage->size(), inputImage->data()}); + } else + #endif + { + input.setSubImage(0, {}, *inputImage); + } + #endif + + /* On ES2 the format selection is too annoying, just skip the variants + altogether and pick *some* format in the function itself */ + #ifndef MAGNUM_TARGET_GLES2 + const GL::TextureFormat outputFormat = data.format; + #else + GL::TextureFormat outputFormat; + #ifndef MAGNUM_TARGET_WEBGL + if(GL::Context::current().isExtensionSupported()) { + outputFormat = GL::TextureFormat::R8; + } else + #endif + { + outputFormat = GL::TextureFormat::Luminance; /** @todo Luminance8 */ + } + #endif + + GL::Texture2D output; + output.setMinificationFilter(GL::SamplerFilter::Nearest, GL::SamplerMipmap::Base) + .setMagnificationFilter(GL::SamplerFilter::Nearest) + .setStorage(1, outputFormat, Vector2i{64}); + + GL::Framebuffer framebuffer{{{}, Vector2i{64}}}; + framebuffer.attachTexture(GL::Framebuffer::ColorAttachment(0), output, 0); + + MAGNUM_VERIFY_NO_GL_ERROR(); + + DistanceFieldGL distanceField{32}; + + CORRADE_BENCHMARK(50) { + distanceField(input, framebuffer, {{}, Vector2i{64}} + #ifdef MAGNUM_TARGET_GLES + , inputImage->size() + #endif + ); + } + + MAGNUM_VERIFY_NO_GL_ERROR(); +} + +}}}} + +CORRADE_TEST_MAIN(Magnum::TextureTools::Test::DistanceFieldGLBenchmark) diff --git a/src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp b/src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp index 8394dd346..1f1f8131a 100644 --- a/src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp +++ b/src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp @@ -71,10 +71,6 @@ struct DistanceFieldGLTest: GL::OpenGLTester { void formatNotDrawable(); void sizeRatioNotMultipleOfTwo(); - #ifndef MAGNUM_TARGET_WEBGL - void benchmark(); - #endif - private: PluginManager::Manager _manager{"nonexistent"}; Containers::String _testDir; @@ -126,24 +122,6 @@ const struct { #endif }; -#ifndef MAGNUM_TARGET_WEBGL -const struct { - const char* name; - GL::TextureFormat format; -} BenchmarkData[]{ - /* On ES2 the format selection is too annoying, just skip the variants - altogether and pick *some* format in the function itself */ - #ifdef MAGNUM_TARGET_GLES2 - {"", GL::TextureFormat{}}, - #else - {"R8 output", GL::TextureFormat::R8}, - {"RGB8 output", GL::TextureFormat::RGB8}, - {"RGBA8 output", GL::TextureFormat::RGBA8}, - {"R16 output", GL::TextureFormat::R16}, - #endif -}; -#endif - DistanceFieldGLTest::DistanceFieldGLTest() { addTests({&DistanceFieldGLTest::construct, &DistanceFieldGLTest::constructCopy, @@ -155,12 +133,6 @@ DistanceFieldGLTest::DistanceFieldGLTest() { addTests({&DistanceFieldGLTest::formatNotDrawable, &DistanceFieldGLTest::sizeRatioNotMultipleOfTwo}); - #ifndef MAGNUM_TARGET_WEBGL - addInstancedBenchmarks({&DistanceFieldGLTest::benchmark}, 10, - Containers::arraySize(BenchmarkData), - BenchmarkType::GpuTime); - #endif - /* Load the plugin directly from the build tree. Otherwise it's either static and already loaded or not present in the build tree */ #ifdef ANYIMAGEIMPORTER_PLUGIN_FILENAME @@ -562,86 +534,6 @@ void DistanceFieldGLTest::sizeRatioNotMultipleOfTwo() { "TextureTools::DistanceFieldGL: expected input and output size ratio to be a multiple of 2, got {322, 322} and {23, 22}\n"); } -#ifndef MAGNUM_TARGET_WEBGL -void DistanceFieldGLTest::benchmark() { - auto&& data = BenchmarkData[testCaseInstanceId()]; - setTestCaseDescription(data.name); - - #ifdef MAGNUM_TARGET_GLES - if(!GL::Context::current().isExtensionSupported()) - CORRADE_SKIP(GL::Extensions::EXT::disjoint_timer_query::string() << "is not supported, can't benchmark"); - #endif - - 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); - - #ifndef MAGNUM_TARGET_GLES2 - const GL::TextureFormat inputFormat = GL::TextureFormat::R8; - #else - GL::TextureFormat inputFormat; - if(GL::Context::current().isExtensionSupported()) - inputFormat = GL::TextureFormat::R8; - else - inputFormat = GL::TextureFormat::Luminance; /** @todo Luminance8 */ - #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 - - /* On ES2 the format selection is too annoying, just skip the variants - altogether and pick *some* format in the function itself */ - #ifndef MAGNUM_TARGET_GLES2 - const GL::TextureFormat outputFormat = data.format; - #else - GL::TextureFormat outputFormat; - if(GL::Context::current().isExtensionSupported()) - outputFormat = GL::TextureFormat::R8; - else - outputFormat = GL::TextureFormat::Luminance; /** @todo Luminance8 */ - #endif - - GL::Texture2D output; - output.setMinificationFilter(GL::SamplerFilter::Nearest, GL::SamplerMipmap::Base) - .setMagnificationFilter(GL::SamplerFilter::Nearest) - .setStorage(1, outputFormat, Vector2i{64}); - - GL::Framebuffer framebuffer{{{}, Vector2i{64}}}; - framebuffer.attachTexture(GL::Framebuffer::ColorAttachment(0), output, 0); - - MAGNUM_VERIFY_NO_GL_ERROR(); - - DistanceFieldGL distanceField{32}; - - CORRADE_BENCHMARK(50) { - distanceField(input, framebuffer, {{}, Vector2i{64}} - #ifdef MAGNUM_TARGET_GLES - , inputImage->size() - #endif - ); - } - - MAGNUM_VERIFY_NO_GL_ERROR(); -} -#endif - }}}} CORRADE_TEST_MAIN(Magnum::TextureTools::Test::DistanceFieldGLTest)