From 4d565a8f73aa816cd14bc3e26b798f42206d4806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 26 Apr 2018 11:52:53 +0200 Subject: [PATCH] DebugTools: CompareImage now supports only generic pixel formats. --- doc/changelog.dox | 4 + doc/snippets/debugtools-compareimage.cpp | 4 +- src/Magnum/DebugTools/CMakeLists.txt | 64 ++- src/Magnum/DebugTools/CompareImage.cpp | 413 +++++++++--------- src/Magnum/DebugTools/CompareImage.h | 23 +- src/Magnum/DebugTools/Test/CMakeLists.txt | 2 +- .../DebugTools/Test/CompareImageTest.cpp | 131 +++--- src/Magnum/DebugTools/visibility.h | 2 +- 8 files changed, 348 insertions(+), 295 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index c6642fd1a..4cd3bdb31 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -128,6 +128,8 @@ See also: - @ref DebugTools::textureSubImage() now accepts both GL-specific @ref GL::PixelFormat / @ref GL::PixelType combination and the generic @ref PixelFormat enum +- @ref DebugTools::CompareImage now accepts generic @ref PixelFormat on input + instead of GL-specific @ref GL::PixelFormat / @ref GL::PixelType @subsubsection changelog-latest-changes-gl GL library @@ -328,6 +330,8 @@ See also: - Configuration value reader/writers are now for only @ref Magnum::MeshPrimitive and @ref Magnum::MeshIndexType, not for @ref GL::MeshPrimitive or @ref GL::MeshIndexType +- @ref DebugTools::CompareImage no longer accepts GL-specific pixel formats, + only the non-deprecated values from the generic @ref PixelFormat enum - The @ref Trade::TgaImageConverter "TgaImageConverter" plugin no longer accepts GL-specific pixel formats, only the non-deprecated values from the generic @ref PixelFormat enum diff --git a/doc/snippets/debugtools-compareimage.cpp b/doc/snippets/debugtools-compareimage.cpp index 449d93832..8bf44dfae 100644 --- a/doc/snippets/debugtools-compareimage.cpp +++ b/doc/snippets/debugtools-compareimage.cpp @@ -44,7 +44,7 @@ Image2D doProcessing() { importer->openFile(Utility::Directory::join(SNIPPETS_DIR, "image2.tga")); auto image = importer->image2D(0); CORRADE_INTERNAL_ASSERT(image); - return Image2D{image->storage(), image->format(), image->type(), image->size(), image->release()}; + return Image2D{image->storage(), image->format(), image->size(), image->release()}; } Image2D loadExpectedImage() { @@ -53,7 +53,7 @@ Image2D loadExpectedImage() { importer->openFile(Utility::Directory::join(SNIPPETS_DIR, "image1.tga")); auto image = importer->image2D(0); CORRADE_INTERNAL_ASSERT(image); - return Image2D{image->storage(), image->format(), image->type(), image->size(), image->release()}; + return Image2D{image->storage(), image->format(), image->size(), image->release()}; } } diff --git a/src/Magnum/DebugTools/CMakeLists.txt b/src/Magnum/DebugTools/CMakeLists.txt index 50587589b..69a9cc35d 100644 --- a/src/Magnum/DebugTools/CMakeLists.txt +++ b/src/Magnum/DebugTools/CMakeLists.txt @@ -26,6 +26,8 @@ set(MagnumDebugTools_SRCS Profiler.cpp) +set(MagnumDebugTools_GracefulAssert_SRCS ) + set(MagnumDebugTools_HEADERS DebugTools.h Profiler.h) @@ -105,18 +107,34 @@ endif() # Build the TestSuite-related functionality only if it is present find_package(Corrade COMPONENTS TestSuite) if(Corrade_TestSuite_FOUND) - list(APPEND MagnumDebugTools_SRCS + list(APPEND MagnumDebugTools_GracefulAssert_SRCS CompareImage.cpp) list(APPEND MagnumDebugTools_HEADERS CompareImage.h) endif() -# DebugTools library -add_library(MagnumDebugTools ${SHARED_OR_STATIC} +# Objects shared between main and test library +add_library(MagnumDebugToolsObjects OBJECT ${MagnumDebugTools_SRCS} ${MagnumDebugTools_HEADERS} ${MagnumDebugTools_PRIVATE_HEADERS}) +target_include_directories(MagnumDebugToolsObjects PUBLIC $) +if(NOT BUILD_STATIC) + target_compile_definitions(MagnumDebugToolsObjects PRIVATE "MagnumDebugToolsObjects_EXPORTS") +endif() +if(NOT BUILD_STATIC OR BUILD_STATIC_PIC) + set_target_properties(MagnumDebugToolsObjects PROPERTIES POSITION_INDEPENDENT_CODE ON) +endif() +set_target_properties(MagnumDebugToolsObjects PROPERTIES FOLDER "Magnum/DebugTools") +if(TARGET_GL) + target_include_directories(MagnumDebugToolsObjects PUBLIC $) +endif() + +# DebugTools library +add_library(MagnumDebugTools ${SHARED_OR_STATIC} + $ + ${MagnumDebugTools_GracefulAssert_SRCS}) set_target_properties(MagnumDebugTools PROPERTIES DEBUG_POSTFIX "-d" FOLDER "Magnum/DebugTools") @@ -151,6 +169,46 @@ install(TARGETS MagnumDebugTools install(FILES ${MagnumDebugTools_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/DebugTools) if(BUILD_TESTS) + # Library with graceful assert for testing + add_library(MagnumDebugToolsTestLib ${SHARED_OR_STATIC} + $ + ${MagnumDebugTools_GracefulAssert_SRCS}) + set_target_properties(MagnumDebugToolsTestLib PROPERTIES + DEBUG_POSTFIX "-d" + FOLDER "Magnum/DebugTools") + target_compile_definitions(MagnumDebugToolsTestLib PRIVATE + "CORRADE_GRACEFUL_ASSERT" "MagnumDebugTools_EXPORTS") + if(BUILD_STATIC_PIC) + set_target_properties(MagnumDebugToolsTestLib PROPERTIES POSITION_INDEPENDENT_CODE ON) + endif() + target_link_libraries(MagnumDebugToolsTestLib PUBLIC Magnum) + if(Corrade_TestSuite_FOUND) + target_link_libraries(MagnumDebugToolsTestLib PUBLIC Corrade::TestSuite) + endif() + if(TARGET_GL) + target_link_libraries(MagnumDebugToolsTestLib PUBLIC MagnumGL) + if(WITH_SCENEGRAPH) + target_link_libraries(MagnumDebugToolsTestLib PUBLIC MagnumSceneGraph) + endif() + if(WITH_SHAPES) + target_link_libraries(MagnumDebugToolsTestLib PUBLIC MagnumShapes MagnumPrimitives) + endif() + if(WITH_SCENEGRAPH OR WITH_SHAPES) + target_link_libraries(MagnumDebugToolsTestLib PUBLIC + MagnumMeshTools + MagnumShaders) + endif() + endif() + + # On Windows we need to install first and then run the tests to avoid "DLL + # not found" hell, thus we need to install this too + if(CORRADE_TARGET_WINDOWS AND NOT CMAKE_CROSSCOMPILING AND NOT BUILD_STATIC) + install(TARGETS MagnumDebugToolsTestLib + RUNTIME DESTINATION ${MAGNUM_BINARY_INSTALL_DIR} + LIBRARY DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR} + ARCHIVE DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) + endif() + add_subdirectory(Test) endif() diff --git a/src/Magnum/DebugTools/CompareImage.cpp b/src/Magnum/DebugTools/CompareImage.cpp index 482a4e4a9..f0a31fb4e 100644 --- a/src/Magnum/DebugTools/CompareImage.cpp +++ b/src/Magnum/DebugTools/CompareImage.cpp @@ -73,108 +73,122 @@ template Float calculateImageDelta(const ImageView2D& return max; } -template Float calculateIntegerImageDelta(const ImageView2D& actual, const ImageView2D& expected, std::vector& output) { - if( +} + +std::tuple, Float, Float> calculateImageDelta(const ImageView2D& actual, const ImageView2D& expected) { + /* Calculate a delta image */ + std::vector delta(expected.size().product()); + + CORRADE_ASSERT(!isPixelFormatImplementationSpecific(expected.format()), + "DebugTools::CompareImage: can't compare implementation-specific pixel formats", {}); + + Float max{Constants::nan()}; + switch(expected.format()) { + #define _c(format, size, T) \ + case PixelFormat::format: \ + max = calculateImageDelta(actual, expected, delta); \ + break; + #define _d(first, second, size, T) \ + case PixelFormat::first: \ + case PixelFormat::second: \ + max = calculateImageDelta(actual, expected, delta); \ + break; + _d(R8Unorm, R8UI, 1, UnsignedByte) + _d(RG8Unorm, RG8UI, 2, UnsignedByte) + _d(RGB8Unorm, RGB8UI, 3, UnsignedByte) + _d(RGBA8Unorm, RGBA8UI, 4, UnsignedByte) + _d(R8Snorm, R8I, 1, Byte) + _d(RG8Snorm, RG8I, 2, Byte) + _d(RGB8Snorm, RGB8I, 3, Byte) + _d(RGBA8Snorm, RGBA8I, 4, Byte) + _d(R16Unorm, R16UI, 1, UnsignedShort) + _d(RG16Unorm, RG16UI, 2, UnsignedShort) + _d(RGB16Unorm, RGB16UI, 3, UnsignedShort) + _d(RGBA16Unorm, RGBA16UI, 4, UnsignedShort) + _d(R16Snorm, R16I, 1, Short) + _d(RG16Snorm, RG16I, 2, Short) + _d(RGB16Snorm, RGB16I, 3, Short) + _d(RGBA16Snorm, RGBA16I, 4, Short) + _c(R32UI, 1, UnsignedInt) + _c(RG32UI, 2, UnsignedInt) + _c(RGB32UI, 3, UnsignedInt) + _c(RGBA32UI, 4, UnsignedInt) + _c(R32I, 1, Int) + _c(RG32I, 2, Int) + _c(RGB32I, 3, Int) + _c(RGBA32I, 4, Int) + _c(R32F, 1, Float) + _c(RG32F, 2, Float) + _c(RGB32F, 3, Float) + _c(RGBA32F, 4, Float) + #undef _d + #undef _c + + case PixelFormat::R16F: + case PixelFormat::RG16F: + case PixelFormat::RGB16F: + case PixelFormat::RGBA16F: + CORRADE_ASSERT(false, + "DebugTools::CompareImage: half-float formats are not supported yet", {}); + + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + CORRADE_IGNORE_DEPRECATED_PUSH #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) - expected.format() == PixelFormat::Red + case PixelFormat::Red: #endif - #ifndef MAGNUM_TARGET_GLES2 - || expected.format() == PixelFormat::RedInteger - #else - #ifndef MAGNUM_TARGET_WEBGL - || + #ifndef MAGNUM_TARGET_GLES + case PixelFormat::Green: + case PixelFormat::Blue: #endif - expected.format() == PixelFormat::Luminance + #ifdef MAGNUM_TARGET_GLES2 + case PixelFormat::Luminance: #endif - ) - return calculateImageDelta<1, T>(actual, expected, output); - else if( #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) - expected.format() == PixelFormat::RG - #endif - #ifndef MAGNUM_TARGET_GLES2 - || expected.format() == PixelFormat::RGInteger - #else - #ifndef MAGNUM_TARGET_WEBGL - || + case PixelFormat::RG: #endif - expected.format() == PixelFormat::LuminanceAlpha + #ifdef MAGNUM_TARGET_GLES2 + case PixelFormat::LuminanceAlpha: #endif - ) - return calculateImageDelta<2, T>(actual, expected, output); - else if(expected.format() == PixelFormat::RGB - #ifndef MAGNUM_TARGET_GLES2 - || expected.format() == PixelFormat::RGBInteger + case PixelFormat::RGB: + case PixelFormat::RGBA: + #ifndef MAGNUM_TARGET_GLES + case PixelFormat::BGR: #endif - ) - return calculateImageDelta<3, T>(actual, expected, output); - else if(expected.format() == PixelFormat::RGBA - #ifndef MAGNUM_TARGET_GLES2 - || expected.format() == PixelFormat::RGBAInteger - #endif - ) - return calculateImageDelta<4, T>(actual, expected, output); - - CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ -} - -template Float calculateImageDelta(const ImageView2D& actual, const ImageView2D& expected, std::vector& output) { - if( - #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) - expected.format() == PixelFormat::Red + #ifndef MAGNUM_TARGET_WEBGL + case PixelFormat::BGRA: #endif #ifdef MAGNUM_TARGET_GLES2 - #ifndef MAGNUM_TARGET_WEBGL - || + case PixelFormat::SRGB: + case PixelFormat::SRGBAlpha: #endif - expected.format() == PixelFormat::Luminance + #ifndef MAGNUM_TARGET_GLES2 + case PixelFormat::RedInteger: + #ifndef MAGNUM_TARGET_GLES + case PixelFormat::GreenInteger: + case PixelFormat::BlueInteger: #endif - ) - return calculateImageDelta<1, T>(actual, expected, output); - else if( - #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) - expected.format() == PixelFormat::RG + case PixelFormat::RGInteger: + case PixelFormat::RGBInteger: + case PixelFormat::RGBAInteger: + #ifndef MAGNUM_TARGET_GLES + case PixelFormat::BGRInteger: + case PixelFormat::BGRAInteger: #endif - #ifdef MAGNUM_TARGET_GLES2 + #endif + case PixelFormat::DepthComponent: #ifndef MAGNUM_TARGET_WEBGL - || + case PixelFormat::StencilIndex: #endif - expected.format() == PixelFormat::LuminanceAlpha + case PixelFormat::DepthStencil: + /** @todo CORRADE_ASSERT_UNREACHABLE() with message here */ + CORRADE_ASSERT(false, + "DebugTools::CompareImage: deprecated GL-specific formats are not supported", {}); + CORRADE_IGNORE_DEPRECATED_POP #endif - ) - return calculateImageDelta<2, T>(actual, expected, output); - else if(expected.format() == PixelFormat::RGB) - return calculateImageDelta<3, T>(actual, expected, output); - else if(expected.format() == PixelFormat::RGBA) - return calculateImageDelta<4, T>(actual, expected, output); - - CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ -} - -} - -std::tuple, Float, Float> calculateImageDelta(const ImageView2D& actual, const ImageView2D& expected) { - /* Calculate a delta image */ - std::vector delta(expected.size().product()); + } - Float max; - if(expected.type() == PixelType::UnsignedByte) - max = calculateIntegerImageDelta(actual, expected, delta); - else if(expected.type() == PixelType::UnsignedShort) - max = calculateIntegerImageDelta(actual, expected, delta); - else if(expected.type() == PixelType::UnsignedInt) - max = calculateIntegerImageDelta(actual, expected, delta); - #ifndef MAGNUM_TARGET_GLES2 - else if(expected.type() == PixelType::Byte) - max = calculateIntegerImageDelta(actual, expected, delta); - else if(expected.type() == PixelType::Short) - max = calculateIntegerImageDelta(actual, expected, delta); - else if(expected.type() == PixelType::Int) - max = calculateIntegerImageDelta(actual, expected, delta); - #endif - else if(expected.type() == PixelType::Float) - max = calculateImageDelta(actual, expected, delta); - else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ + CORRADE_ASSERT(max == max, + "DebugTools::CompareImage: unknown format" << expected.format(), {}); /* Calculate mean delta. Do it the special way so we don't lose precision -- that would result in having false negatives! */ @@ -225,101 +239,115 @@ void printDeltaImage(Debug& out, const std::vector& deltas, const Vector2 namespace { -template void printIntegerPixelAt(Debug& out, const char* const pixels, const std::size_t stride, const Vector2i& pos, const PixelFormat format) { - if( +void printPixelAt(Debug& out, const char* const pixels, const std::size_t stride, const Vector2i& pos, const PixelFormat format) { + switch(format) { + #define _c(format, size, T) \ + case PixelFormat::format: \ + out << pixelAt(pixels, stride, pos); \ + break; + #define _d(first, second, size, T) \ + case PixelFormat::first: \ + case PixelFormat::second: \ + out << pixelAt(pixels, stride, pos); \ + break; + _d(R8Unorm, R8UI, 1, UnsignedByte) + _d(RG8Unorm, RG8UI, 2, UnsignedByte) + _c(RGB8UI, 3, UnsignedByte) + _c(RGBA8UI, 4, UnsignedByte) + /* RGB8Unorm, RGBA8Unorm handled below */ + _d(R8Snorm, R8I, 1, Byte) + _d(RG8Snorm, RG8I, 2, Byte) + _d(RGB8Snorm, RGB8I, 3, Byte) + _d(RGBA8Snorm, RGBA8I, 4, Byte) + _d(R16Unorm, R16UI, 1, UnsignedShort) + _d(RG16Unorm, RG16UI, 2, UnsignedShort) + _d(RGB16Unorm, RGB16UI, 3, UnsignedShort) + _d(RGBA16Unorm, RGBA16UI, 4, UnsignedShort) + _d(R16Snorm, R16I, 1, Short) + _d(RG16Snorm, RG16I, 2, Short) + _d(RGB16Snorm, RGB16I, 3, Short) + _d(RGBA16Snorm, RGBA16I, 4, Short) + _c(R32UI, 1, UnsignedInt) + _c(RG32UI, 2, UnsignedInt) + _c(RGB32UI, 3, UnsignedInt) + _c(RGBA32UI, 4, UnsignedInt) + _c(R32I, 1, Int) + _c(RG32I, 2, Int) + _c(RGB32I, 3, Int) + _c(RGBA32I, 4, Int) + _c(R32F, 1, Float) + _c(RG32F, 2, Float) + _c(RGB32F, 3, Float) + _c(RGBA32F, 4, Float) + #undef _d + #undef _c + + /* Take the opportunity and print 8-bit colors in hex */ + case PixelFormat::RGB8Unorm: + out << Color3ub{pixelAt<3, UnsignedByte>(pixels, stride, pos)}; + break; + case PixelFormat::RGBA8Unorm: + out << Color4ub{pixelAt<4, UnsignedByte>(pixels, stride, pos)}; + break; + + case PixelFormat::R16F: + case PixelFormat::RG16F: + case PixelFormat::RGB16F: + case PixelFormat::RGBA16F: + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + CORRADE_IGNORE_DEPRECATED_PUSH #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) - format == PixelFormat::Red + case PixelFormat::Red: #endif - #ifndef MAGNUM_TARGET_GLES2 - || format == PixelFormat::RedInteger - #else - #ifndef MAGNUM_TARGET_WEBGL - || + #ifndef MAGNUM_TARGET_GLES + case PixelFormat::Green: + case PixelFormat::Blue: #endif - format == PixelFormat::Luminance + #ifdef MAGNUM_TARGET_GLES2 + case PixelFormat::Luminance: #endif - ) - out << pixelAt<1, T>(pixels, stride, pos); - else if( #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) - format == PixelFormat::RG - #endif - #ifndef MAGNUM_TARGET_GLES2 - || format == PixelFormat::RGInteger - #else - #ifndef MAGNUM_TARGET_WEBGL - || + case PixelFormat::RG: #endif - format == PixelFormat::LuminanceAlpha - #endif - ) - out << pixelAt<2, T>(pixels, stride, pos); - /* Take the opportunity and print 8-bit colors in hex */ - else if(format == PixelFormat::RGB - #ifndef MAGNUM_TARGET_GLES2 - || format == PixelFormat::RGBInteger + #ifdef MAGNUM_TARGET_GLES2 + case PixelFormat::LuminanceAlpha: #endif - ) - out << Math::Color3{pixelAt<3, T>(pixels, stride, pos)}; - else if(format == PixelFormat::RGBA - #ifndef MAGNUM_TARGET_GLES2 - || format == PixelFormat::RGBAInteger + case PixelFormat::RGB: + case PixelFormat::RGBA: + #ifndef MAGNUM_TARGET_GLES + case PixelFormat::BGR: #endif - ) - out << Math::Color4{pixelAt<4, T>(pixels, stride, pos)}; - else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ -} - -template void printPixelAt(Debug& out, const char* const pixels, const std::size_t stride, const Vector2i& pos, const PixelFormat format) { - if( - #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) - format == PixelFormat::Red + #ifndef MAGNUM_TARGET_WEBGL + case PixelFormat::BGRA: #endif #ifdef MAGNUM_TARGET_GLES2 - #ifndef MAGNUM_TARGET_WEBGL - || + case PixelFormat::SRGB: + case PixelFormat::SRGBAlpha: + #endif + #ifndef MAGNUM_TARGET_GLES2 + case PixelFormat::RedInteger: + #ifndef MAGNUM_TARGET_GLES + case PixelFormat::GreenInteger: + case PixelFormat::BlueInteger: #endif - format == PixelFormat::Luminance + case PixelFormat::RGInteger: + case PixelFormat::RGBInteger: + case PixelFormat::RGBAInteger: + #ifndef MAGNUM_TARGET_GLES + case PixelFormat::BGRInteger: + case PixelFormat::BGRAInteger: #endif - ) - out << pixelAt<1, T>(pixels, stride, pos); - else if( - #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) - format == PixelFormat::RG #endif - #ifdef MAGNUM_TARGET_GLES2 + case PixelFormat::DepthComponent: #ifndef MAGNUM_TARGET_WEBGL - || + case PixelFormat::StencilIndex: #endif - format == PixelFormat::LuminanceAlpha + case PixelFormat::DepthStencil: + CORRADE_IGNORE_DEPRECATED_POP #endif - ) - out << pixelAt<2, T>(pixels, stride, pos); - else if(format == PixelFormat::RGB) - out << pixelAt<3, T>(pixels, stride, pos); - else if(format == PixelFormat::RGBA) - out << pixelAt<4, T>(pixels, stride, pos); - else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ -} - -void printPixelAt(Debug& out, const char* const pixels, const std::size_t stride, const Vector2i& pos, const PixelFormat format, const PixelType type) { - if(type == PixelType::UnsignedByte) - printIntegerPixelAt(out, pixels, stride, pos, format); - else if(type == PixelType::UnsignedShort) - printIntegerPixelAt(out, pixels, stride, pos, format); - else if(type == PixelType::UnsignedInt) - printIntegerPixelAt(out, pixels, stride, pos, format); - #ifndef MAGNUM_TARGET_GLES2 - else if(type == PixelType::Byte) - printIntegerPixelAt(out, pixels, stride, pos, format); - else if(type == PixelType::Short) - printIntegerPixelAt(out, pixels, stride, pos, format); - else if(type == PixelType::Int) - printIntegerPixelAt(out, pixels, stride, pos, format); - #endif - else if(type == PixelType::Float) - printPixelAt(out, pixels, stride, pos, format); - else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ + /* Already handled by a printing assert before */ + CORRADE_ASSERT_UNREACHABLE(); + } } } @@ -363,11 +391,11 @@ void printPixelDeltas(Debug& out, const std::vector& delta, const ImageVi << Debug::nospace << "," << Debug::nospace << pos.y() << Debug::nospace << "]"; - printPixelAt(out, actualPixels, actualStride, pos, expected.format(), expected.type()); + printPixelAt(out, actualPixels, actualStride, pos, expected.format()); out << Debug::nospace << ", expected"; - printPixelAt(out, expectedPixels, expectedStride, pos, expected.format(), expected.type()); + printPixelAt(out, expectedPixels, expectedStride, pos, expected.format()); out << "(Δ =" << Debug::boldColor(delta[it->second] > maxThreshold ? Debug::Color::Red : Debug::Color::Yellow) << delta[it->second] @@ -398,56 +426,11 @@ bool Comparator::operator()(const ImageView2D& actual, _state = State::DifferentSize; return false; } - if(actual.format() != expected.format() || actual.type() != expected.type()) { + if(actual.format() != expected.format()) { _state = State::DifferentFormat; return false; } - /* Assert on unsupported format/storage */ - #ifndef CORRADE_NO_DEBUG - const bool formatSupported = ( - ( - #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) - expected.format() == PixelFormat::Red || - expected.format() == PixelFormat::RG || - #endif - #ifndef MAGNUM_TARGET_GLES2 - expected.format() == PixelFormat::RedInteger || - expected.format() == PixelFormat::RGInteger || - expected.format() == PixelFormat::RGBInteger || - expected.format() == PixelFormat::RGBAInteger || - #else - expected.format() == PixelFormat::Luminance || - expected.format() == PixelFormat::LuminanceAlpha || - #endif - expected.format() == PixelFormat::RGB || - expected.format() == PixelFormat::RGBA - ) && ( - #ifndef MAGNUM_TARGET_GLES2 - expected.type() == PixelType::Byte || - expected.type() == PixelType::Short || - expected.type() == PixelType::Int || - #endif - expected.type() == PixelType::UnsignedByte || - expected.type() == PixelType::UnsignedShort || - expected.type() == PixelType::UnsignedInt - )) || (( - #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) - expected.format() == PixelFormat::Red || - expected.format() == PixelFormat::RG || - #endif - #ifdef MAGNUM_TARGET_GLES2 - expected.format() == PixelFormat::Luminance || - expected.format() == PixelFormat::LuminanceAlpha || - #endif - expected.format() == PixelFormat::RGB || - expected.format() == PixelFormat::RGBA - ) && expected.type() == PixelType::Float); - CORRADE_ASSERT( - formatSupported, - "DebugTools::CompareImage: format" << expected.format() << Debug::nospace << "/" << expected.type() << "is not supported", {}); - #endif - std::vector delta; std::tie(delta, _max, _mean) = DebugTools::Implementation::calculateImageDelta(actual, expected); @@ -471,10 +454,8 @@ void Comparator::printErrorMessage(Debug& out, const s out << "different size, actual" << _actualImage->size() << "but" << _expectedImage->size() << "expected."; else if(_state == State::DifferentFormat) - out << "different format, actual" << _actualImage->format() - << Debug::nospace << "/" << Debug::nospace << _actualImage->type() - << "but" << _expectedImage->format() << Debug::nospace << "/" - << Debug::nospace << _expectedImage->type() << "expected."; + out << "different format, actual" << _actualImage->format() << "but" + << _expectedImage->format() << "expected."; else { if(_state == State::AboveThresholds) out << "both max and mean delta above threshold, actual" diff --git a/src/Magnum/DebugTools/CompareImage.h b/src/Magnum/DebugTools/CompareImage.h index 3254bcdc4..9236070d8 100644 --- a/src/Magnum/DebugTools/CompareImage.h +++ b/src/Magnum/DebugTools/CompareImage.h @@ -102,17 +102,18 @@ give for example the following result: Supports the following formats: -- @ref PixelFormat::Red, @ref PixelFormat::RedInteger, @ref PixelFormat::RG, - @ref PixelFormat::RGInteger, @ref PixelFormat::RGB, @ref PixelFormat::RGBInteger, - @ref PixelFormat::RGBA and @ref PixelFormat::RGBAInteger with - @ref PixelType::UnsignedByte, @ref PixelType::Byte, @ref PixelType::UnsignedShort, - @ref PixelType::Short, @ref PixelType::UnsignedInt and @ref PixelType::Int -- @ref PixelFormat::Red, @ref PixelFormat::RG, @ref PixelFormat::RGB and - @ref PixelFormat::RGBA with @ref PixelType::Float - -In OpenGL ES 2.0 and WebGL 1.0, @ref PixelFormat::Luminance and -@ref PixelFormat::LuminanceAlpha are also accepted in place of -@ref PixelFormat::Red and @ref PixelFormat::RG. +- @ref PixelFormat::RGBA8Unorm, @ref PixelFormat::RGBA16Unorm and their + one-/two-/three-component versions +- @ref PixelFormat::RGBA8Snorm, @ref PixelFormat::RGBA16Snorm and their + one-/two-/three-component versions +- @ref PixelFormat::RGBA8UI, @ref PixelFormat::RGBA16UI, + @ref PixelFormat::RGBA32UI and their one-/two-/three-component versions +- @ref PixelFormat::RGBA8I, @ref PixelFormat::RGBA16I, + @ref PixelFormat::RGBA32I and their one-/two-/three-component versions +- @ref PixelFormat::RGBA32F and its one-/two-/three-component versions + +@ref PixelFormat::RGBA16F and other half-float formats are not supported at the +moment. Implementation-specific pixel formats can't be supported. Supports all @ref PixelStorage parameters. The images don't need to have the same pixel storage parameters, meaning you are able to compare different diff --git a/src/Magnum/DebugTools/Test/CMakeLists.txt b/src/Magnum/DebugTools/Test/CMakeLists.txt index 6299c862d..60576e315 100644 --- a/src/Magnum/DebugTools/Test/CMakeLists.txt +++ b/src/Magnum/DebugTools/Test/CMakeLists.txt @@ -24,7 +24,7 @@ # if(Corrade_TestSuite_FOUND) - corrade_add_test(DebugToolsCompareImageTest CompareImageTest.cpp LIBRARIES MagnumDebugTools) + corrade_add_test(DebugToolsCompareImageTest CompareImageTest.cpp LIBRARIES MagnumDebugToolsTestLib) set_target_properties(DebugToolsCompareImageTest PROPERTIES FOLDER "Magnum/DebugTools/Test") endif() diff --git a/src/Magnum/DebugTools/Test/CompareImageTest.cpp b/src/Magnum/DebugTools/Test/CompareImageTest.cpp index fafa604f7..eae0e7fed 100644 --- a/src/Magnum/DebugTools/Test/CompareImageTest.cpp +++ b/src/Magnum/DebugTools/Test/CompareImageTest.cpp @@ -29,8 +29,8 @@ #include #include "Magnum/ImageView.h" +#include "Magnum/PixelFormat.h" #include "Magnum/DebugTools/CompareImage.h" -#include "Magnum/GL/PixelFormat.h" #include "Magnum/Math/Functions.h" #include "Magnum/Math/Color.h" @@ -39,6 +39,13 @@ namespace Magnum { namespace DebugTools { namespace Test { struct CompareImageTest: TestSuite::Tester { explicit CompareImageTest(); + void formatUnknown(); + void formatHalf(); + void formatImplementationSpecific(); + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + void formatDeprecated(); + #endif + void calculateDelta(); void calculateDeltaStorage(); @@ -51,7 +58,6 @@ struct CompareImageTest: TestSuite::Tester { void compareDifferentSize(); void compareDifferentFormat(); - void compareDifferentType(); void compareSameZeroThreshold(); void compareAboveThresholds(); void compareAboveMaxThreshold(); @@ -59,7 +65,14 @@ struct CompareImageTest: TestSuite::Tester { }; CompareImageTest::CompareImageTest() { - addTests({&CompareImageTest::calculateDelta, + addTests({&CompareImageTest::formatUnknown, + &CompareImageTest::formatHalf, + &CompareImageTest::formatImplementationSpecific, + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + &CompareImageTest::formatDeprecated, + #endif + + &CompareImageTest::calculateDelta, &CompareImageTest::calculateDeltaStorage, &CompareImageTest::deltaImage, @@ -71,7 +84,6 @@ CompareImageTest::CompareImageTest() { &CompareImageTest::compareDifferentSize, &CompareImageTest::compareDifferentFormat, - &CompareImageTest::compareDifferentType, &CompareImageTest::compareSameZeroThreshold, &CompareImageTest::compareAboveThresholds, &CompareImageTest::compareAboveMaxThreshold, @@ -96,22 +108,54 @@ namespace { 0.01f, 0.0f, 0.1f, 0.12f, 1.0f, 0.0f}; - const ImageView2D ActualRed{ - #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) - PixelFormat::Red - #else - PixelFormat::Luminance - #endif - , PixelType::Float, {3, 3}, ActualRedData}; - const ImageView2D ExpectedRed{ - #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) - PixelFormat::Red - #else - PixelFormat::Luminance - #endif - , PixelType::Float, {3, 3}, ExpectedRedData}; + const ImageView2D ActualRed{PixelFormat::R32F, {3, 3}, ActualRedData}; + const ImageView2D ExpectedRed{PixelFormat::R32F, {3, 3}, ExpectedRedData}; } +void CompareImageTest::formatUnknown() { + std::ostringstream out; + Error redirectError{&out}; + + ImageView2D image{PixelStorage{}, PixelFormat(0xdead), 0, 0, {}}; + Implementation::calculateImageDelta(image, image); + + CORRADE_COMPARE(out.str(), "DebugTools::CompareImage: unknown format PixelFormat(0xdead)\n"); +} + +void CompareImageTest::formatHalf() { + std::ostringstream out; + Error redirectError{&out}; + + ImageView2D image{PixelFormat::RG16F, {}}; + Implementation::calculateImageDelta(image, image); + + CORRADE_COMPARE(out.str(), "DebugTools::CompareImage: half-float formats are not supported yet\n"); +} + +void CompareImageTest::formatImplementationSpecific() { + std::ostringstream out; + Error redirectError{&out}; + + ImageView2D image{PixelStorage{}, pixelFormatWrap(0xdead), 0, 0, {}}; + Implementation::calculateImageDelta(image, image); + + CORRADE_COMPARE(out.str(), "DebugTools::CompareImage: can't compare implementation-specific pixel formats\n"); +} + +#if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) +void CompareImageTest::formatDeprecated() { + std::ostringstream out; + Error redirectError{&out}; + + CORRADE_IGNORE_DEPRECATED_PUSH + ImageView2D image{PixelFormat::RGB, PixelType::UnsignedByte, {}}; + CORRADE_IGNORE_DEPRECATED_POP + Implementation::calculateImageDelta(image, image); + + CORRADE_COMPARE(out.str(), "DebugTools::CompareImage: deprecated GL-specific formats are not supported\n"); +} +#endif + void CompareImageTest::calculateDelta() { std::vector delta; Float max, mean; @@ -131,22 +175,15 @@ namespace { }; const UnsignedByte ExpectedRgbData[] = { - #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) 0, 0, 0, 0x55, 0xf8, 0x3a, 0x56, 0x10, 0xed, 0, 0, 0, 0, 0, 0, 0x23, 0x27, 0x10, 0xab, 0xcd, 0xfa, 0, 0, 0 - #else - 0x55, 0xf8, 0x3a, 0x56, 0x10, 0xed, 0, 0, - 0x23, 0x27, 0x10, 0xab, 0xcd, 0xfa, 0, 0, - #endif }; const ImageView2D ActualRgb{PixelStorage{}.setSkip({0, 1, 0}), - PixelFormat::RGB, PixelType::UnsignedByte, {2, 2}, ActualRgbData}; + PixelFormat::RGB8Unorm, {2, 2}, ActualRgbData}; const ImageView2D ExpectedRgb{ - #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) PixelStorage{}.setSkip({1, 0, 0}).setRowLength(3), - #endif - PixelFormat::RGB, PixelType::UnsignedByte, {2, 2}, ExpectedRgbData}; + PixelFormat::RGB8Unorm, {2, 2}, ExpectedRgbData}; } void CompareImageTest::calculateDeltaStorage() { @@ -267,20 +304,8 @@ void CompareImageTest::pixelDeltaOverflow() { void CompareImageTest::compareDifferentSize() { std::stringstream out; - ImageView2D a{ - #ifndef MAGNUM_TARGET_GLES2 - PixelFormat::RGInteger, - #else - PixelFormat::LuminanceAlpha, - #endif - PixelType::UnsignedByte, {3, 4}, nullptr}; - ImageView2D b{ - #ifndef MAGNUM_TARGET_GLES2 - PixelFormat::RGInteger, - #else - PixelFormat::LuminanceAlpha, - #endif - PixelType::UnsignedByte, {3, 5}, nullptr}; + ImageView2D a{PixelFormat::RG8UI, {3, 4}, nullptr}; + ImageView2D b{PixelFormat::RG8UI, {3, 5}, nullptr}; { Error e(&out); @@ -295,24 +320,8 @@ void CompareImageTest::compareDifferentSize() { void CompareImageTest::compareDifferentFormat() { std::stringstream out; - ImageView2D a{PixelFormat::RGBA, PixelType::Float, {3, 4}, nullptr}; - ImageView2D b{PixelFormat::RGB, PixelType::Float, {3, 4}, nullptr}; - - { - Error e(&out); - TestSuite::Comparator compare; - CORRADE_VERIFY(!compare(a, b)); - compare.printErrorMessage(e, "a", "b"); - } - - CORRADE_COMPARE(out.str(), "Images a and b have different format, actual GL::PixelFormat::RGBA/GL::PixelType::Float but GL::PixelFormat::RGB/GL::PixelType::Float expected.\n"); -} - -void CompareImageTest::compareDifferentType() { - std::stringstream out; - - ImageView2D a{PixelFormat::RGB, PixelType::UnsignedByte, {3, 4}, nullptr}; - ImageView2D b{PixelFormat::RGB, PixelType::UnsignedShort, {3, 4}, nullptr}; + ImageView2D a{PixelFormat::RGBA32F, {3, 4}, nullptr}; + ImageView2D b{PixelFormat::RGB32F, {3, 4}, nullptr}; { Error e(&out); @@ -321,7 +330,7 @@ void CompareImageTest::compareDifferentType() { compare.printErrorMessage(e, "a", "b"); } - CORRADE_COMPARE(out.str(), "Images a and b have different format, actual GL::PixelFormat::RGB/GL::PixelType::UnsignedByte but GL::PixelFormat::RGB/GL::PixelType::UnsignedShort expected.\n"); + CORRADE_COMPARE(out.str(), "Images a and b have different format, actual PixelFormat::RGBA32F but PixelFormat::RGB32F expected.\n"); } void CompareImageTest::compareSameZeroThreshold() { @@ -332,7 +341,7 @@ void CompareImageTest::compareSameZeroThreshold() { 0xbadc0d_rgbf, 0xbeefe0_rgbf }; - const ImageView2D image{PixelFormat::RGB, PixelType::Float, {2, 2}, data}; + const ImageView2D image{PixelFormat::RGB32F, {2, 2}, data}; CORRADE_VERIFY((TestSuite::Comparator{0.0f, 0.0f}(image, image))); } diff --git a/src/Magnum/DebugTools/visibility.h b/src/Magnum/DebugTools/visibility.h index 93793d216..66595cbc3 100644 --- a/src/Magnum/DebugTools/visibility.h +++ b/src/Magnum/DebugTools/visibility.h @@ -31,7 +31,7 @@ #ifndef DOXYGEN_GENERATING_OUTPUT #ifndef MAGNUM_BUILD_STATIC - #ifdef MagnumDebugTools_EXPORTS + #if defined(MagnumDebugTools_EXPORTS) || defined(MagnumDebugToolsObjects_EXPORTS) #define MAGNUM_DEBUGTOOLS_EXPORT CORRADE_VISIBILITY_EXPORT #else #define MAGNUM_DEBUGTOOLS_EXPORT CORRADE_VISIBILITY_IMPORT