Browse Source

DebugTools: CompareImage now supports only generic pixel formats.

pull/233/head
Vladimír Vondruš 8 years ago
parent
commit
4d565a8f73
  1. 4
      doc/changelog.dox
  2. 4
      doc/snippets/debugtools-compareimage.cpp
  3. 64
      src/Magnum/DebugTools/CMakeLists.txt
  4. 413
      src/Magnum/DebugTools/CompareImage.cpp
  5. 23
      src/Magnum/DebugTools/CompareImage.h
  6. 2
      src/Magnum/DebugTools/Test/CMakeLists.txt
  7. 131
      src/Magnum/DebugTools/Test/CompareImageTest.cpp
  8. 2
      src/Magnum/DebugTools/visibility.h

4
doc/changelog.dox

@ -128,6 +128,8 @@ See also:
- @ref DebugTools::textureSubImage() now accepts both GL-specific - @ref DebugTools::textureSubImage() now accepts both GL-specific
@ref GL::PixelFormat / @ref GL::PixelType combination and the generic @ref GL::PixelFormat / @ref GL::PixelType combination and the generic
@ref PixelFormat enum @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 @subsubsection changelog-latest-changes-gl GL library
@ -328,6 +330,8 @@ See also:
- Configuration value reader/writers are now for only - Configuration value reader/writers are now for only
@ref Magnum::MeshPrimitive and @ref Magnum::MeshIndexType, not for @ref Magnum::MeshPrimitive and @ref Magnum::MeshIndexType, not for
@ref GL::MeshPrimitive or @ref GL::MeshIndexType @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 - The @ref Trade::TgaImageConverter "TgaImageConverter" plugin no longer
accepts GL-specific pixel formats, only the non-deprecated values from the accepts GL-specific pixel formats, only the non-deprecated values from the
generic @ref PixelFormat enum generic @ref PixelFormat enum

4
doc/snippets/debugtools-compareimage.cpp

@ -44,7 +44,7 @@ Image2D doProcessing() {
importer->openFile(Utility::Directory::join(SNIPPETS_DIR, "image2.tga")); importer->openFile(Utility::Directory::join(SNIPPETS_DIR, "image2.tga"));
auto image = importer->image2D(0); auto image = importer->image2D(0);
CORRADE_INTERNAL_ASSERT(image); 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() { Image2D loadExpectedImage() {
@ -53,7 +53,7 @@ Image2D loadExpectedImage() {
importer->openFile(Utility::Directory::join(SNIPPETS_DIR, "image1.tga")); importer->openFile(Utility::Directory::join(SNIPPETS_DIR, "image1.tga"));
auto image = importer->image2D(0); auto image = importer->image2D(0);
CORRADE_INTERNAL_ASSERT(image); 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()};
} }
} }

64
src/Magnum/DebugTools/CMakeLists.txt

@ -26,6 +26,8 @@
set(MagnumDebugTools_SRCS set(MagnumDebugTools_SRCS
Profiler.cpp) Profiler.cpp)
set(MagnumDebugTools_GracefulAssert_SRCS )
set(MagnumDebugTools_HEADERS set(MagnumDebugTools_HEADERS
DebugTools.h DebugTools.h
Profiler.h) Profiler.h)
@ -105,18 +107,34 @@ endif()
# Build the TestSuite-related functionality only if it is present # Build the TestSuite-related functionality only if it is present
find_package(Corrade COMPONENTS TestSuite) find_package(Corrade COMPONENTS TestSuite)
if(Corrade_TestSuite_FOUND) if(Corrade_TestSuite_FOUND)
list(APPEND MagnumDebugTools_SRCS list(APPEND MagnumDebugTools_GracefulAssert_SRCS
CompareImage.cpp) CompareImage.cpp)
list(APPEND MagnumDebugTools_HEADERS list(APPEND MagnumDebugTools_HEADERS
CompareImage.h) CompareImage.h)
endif() endif()
# DebugTools library # Objects shared between main and test library
add_library(MagnumDebugTools ${SHARED_OR_STATIC} add_library(MagnumDebugToolsObjects OBJECT
${MagnumDebugTools_SRCS} ${MagnumDebugTools_SRCS}
${MagnumDebugTools_HEADERS} ${MagnumDebugTools_HEADERS}
${MagnumDebugTools_PRIVATE_HEADERS}) ${MagnumDebugTools_PRIVATE_HEADERS})
target_include_directories(MagnumDebugToolsObjects PUBLIC $<TARGET_PROPERTY:Magnum,INTERFACE_INCLUDE_DIRECTORIES>)
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 $<TARGET_PROPERTY:MagnumGL,INTERFACE_INCLUDE_DIRECTORIES>)
endif()
# DebugTools library
add_library(MagnumDebugTools ${SHARED_OR_STATIC}
$<TARGET_OBJECTS:MagnumDebugToolsObjects>
${MagnumDebugTools_GracefulAssert_SRCS})
set_target_properties(MagnumDebugTools PROPERTIES set_target_properties(MagnumDebugTools PROPERTIES
DEBUG_POSTFIX "-d" DEBUG_POSTFIX "-d"
FOLDER "Magnum/DebugTools") FOLDER "Magnum/DebugTools")
@ -151,6 +169,46 @@ install(TARGETS MagnumDebugTools
install(FILES ${MagnumDebugTools_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/DebugTools) install(FILES ${MagnumDebugTools_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/DebugTools)
if(BUILD_TESTS) if(BUILD_TESTS)
# Library with graceful assert for testing
add_library(MagnumDebugToolsTestLib ${SHARED_OR_STATIC}
$<TARGET_OBJECTS:MagnumDebugToolsObjects>
${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) add_subdirectory(Test)
endif() endif()

413
src/Magnum/DebugTools/CompareImage.cpp

@ -73,108 +73,122 @@ template<std::size_t size, class T> Float calculateImageDelta(const ImageView2D&
return max; return max;
} }
template<class T> Float calculateIntegerImageDelta(const ImageView2D& actual, const ImageView2D& expected, std::vector<Float>& output) { }
if(
std::tuple<std::vector<Float>, Float, Float> calculateImageDelta(const ImageView2D& actual, const ImageView2D& expected) {
/* Calculate a delta image */
std::vector<Float> 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<size, T>(actual, expected, delta); \
break;
#define _d(first, second, size, T) \
case PixelFormat::first: \
case PixelFormat::second: \
max = calculateImageDelta<size, T>(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)) #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2))
expected.format() == PixelFormat::Red case PixelFormat::Red:
#endif #endif
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES
|| expected.format() == PixelFormat::RedInteger case PixelFormat::Green:
#else case PixelFormat::Blue:
#ifndef MAGNUM_TARGET_WEBGL
||
#endif #endif
expected.format() == PixelFormat::Luminance #ifdef MAGNUM_TARGET_GLES2
case PixelFormat::Luminance:
#endif #endif
)
return calculateImageDelta<1, T>(actual, expected, output);
else if(
#if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2))
expected.format() == PixelFormat::RG case PixelFormat::RG:
#endif
#ifndef MAGNUM_TARGET_GLES2
|| expected.format() == PixelFormat::RGInteger
#else
#ifndef MAGNUM_TARGET_WEBGL
||
#endif #endif
expected.format() == PixelFormat::LuminanceAlpha #ifdef MAGNUM_TARGET_GLES2
case PixelFormat::LuminanceAlpha:
#endif #endif
) case PixelFormat::RGB:
return calculateImageDelta<2, T>(actual, expected, output); case PixelFormat::RGBA:
else if(expected.format() == PixelFormat::RGB #ifndef MAGNUM_TARGET_GLES
#ifndef MAGNUM_TARGET_GLES2 case PixelFormat::BGR:
|| expected.format() == PixelFormat::RGBInteger
#endif #endif
) #ifndef MAGNUM_TARGET_WEBGL
return calculateImageDelta<3, T>(actual, expected, output); case PixelFormat::BGRA:
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<class T> Float calculateImageDelta(const ImageView2D& actual, const ImageView2D& expected, std::vector<Float>& output) {
if(
#if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2))
expected.format() == PixelFormat::Red
#endif #endif
#ifdef MAGNUM_TARGET_GLES2 #ifdef MAGNUM_TARGET_GLES2
#ifndef MAGNUM_TARGET_WEBGL case PixelFormat::SRGB:
|| case PixelFormat::SRGBAlpha:
#endif #endif
expected.format() == PixelFormat::Luminance #ifndef MAGNUM_TARGET_GLES2
case PixelFormat::RedInteger:
#ifndef MAGNUM_TARGET_GLES
case PixelFormat::GreenInteger:
case PixelFormat::BlueInteger:
#endif #endif
) case PixelFormat::RGInteger:
return calculateImageDelta<1, T>(actual, expected, output); case PixelFormat::RGBInteger:
else if( case PixelFormat::RGBAInteger:
#if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) #ifndef MAGNUM_TARGET_GLES
expected.format() == PixelFormat::RG case PixelFormat::BGRInteger:
case PixelFormat::BGRAInteger:
#endif #endif
#ifdef MAGNUM_TARGET_GLES2 #endif
case PixelFormat::DepthComponent:
#ifndef MAGNUM_TARGET_WEBGL #ifndef MAGNUM_TARGET_WEBGL
|| case PixelFormat::StencilIndex:
#endif #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 #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<std::vector<Float>, Float, Float> calculateImageDelta(const ImageView2D& actual, const ImageView2D& expected) {
/* Calculate a delta image */
std::vector<Float> delta(expected.size().product());
Float max; CORRADE_ASSERT(max == max,
if(expected.type() == PixelType::UnsignedByte) "DebugTools::CompareImage: unknown format" << expected.format(), {});
max = calculateIntegerImageDelta<UnsignedByte>(actual, expected, delta);
else if(expected.type() == PixelType::UnsignedShort)
max = calculateIntegerImageDelta<UnsignedShort>(actual, expected, delta);
else if(expected.type() == PixelType::UnsignedInt)
max = calculateIntegerImageDelta<UnsignedInt>(actual, expected, delta);
#ifndef MAGNUM_TARGET_GLES2
else if(expected.type() == PixelType::Byte)
max = calculateIntegerImageDelta<Byte>(actual, expected, delta);
else if(expected.type() == PixelType::Short)
max = calculateIntegerImageDelta<Short>(actual, expected, delta);
else if(expected.type() == PixelType::Int)
max = calculateIntegerImageDelta<Int>(actual, expected, delta);
#endif
else if(expected.type() == PixelType::Float)
max = calculateImageDelta<Float>(actual, expected, delta);
else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
/* Calculate mean delta. Do it the special way so we don't lose /* Calculate mean delta. Do it the special way so we don't lose
precision -- that would result in having false negatives! */ precision -- that would result in having false negatives! */
@ -225,101 +239,115 @@ void printDeltaImage(Debug& out, const std::vector<Float>& deltas, const Vector2
namespace { namespace {
template<class T> void printIntegerPixelAt(Debug& out, const char* const pixels, const std::size_t stride, const Vector2i& pos, const PixelFormat format) { void printPixelAt(Debug& out, const char* const pixels, const std::size_t stride, const Vector2i& pos, const PixelFormat format) {
if( switch(format) {
#define _c(format, size, T) \
case PixelFormat::format: \
out << pixelAt<size, T>(pixels, stride, pos); \
break;
#define _d(first, second, size, T) \
case PixelFormat::first: \
case PixelFormat::second: \
out << pixelAt<size, T>(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)) #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2))
format == PixelFormat::Red case PixelFormat::Red:
#endif #endif
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES
|| format == PixelFormat::RedInteger case PixelFormat::Green:
#else case PixelFormat::Blue:
#ifndef MAGNUM_TARGET_WEBGL
||
#endif #endif
format == PixelFormat::Luminance #ifdef MAGNUM_TARGET_GLES2
case PixelFormat::Luminance:
#endif #endif
)
out << pixelAt<1, T>(pixels, stride, pos);
else if(
#if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2))
format == PixelFormat::RG case PixelFormat::RG:
#endif
#ifndef MAGNUM_TARGET_GLES2
|| format == PixelFormat::RGInteger
#else
#ifndef MAGNUM_TARGET_WEBGL
||
#endif #endif
format == PixelFormat::LuminanceAlpha #ifdef MAGNUM_TARGET_GLES2
#endif case PixelFormat::LuminanceAlpha:
)
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
#endif #endif
) case PixelFormat::RGB:
out << Math::Color3<T>{pixelAt<3, T>(pixels, stride, pos)}; case PixelFormat::RGBA:
else if(format == PixelFormat::RGBA #ifndef MAGNUM_TARGET_GLES
#ifndef MAGNUM_TARGET_GLES2 case PixelFormat::BGR:
|| format == PixelFormat::RGBAInteger
#endif #endif
) #ifndef MAGNUM_TARGET_WEBGL
out << Math::Color4<T>{pixelAt<4, T>(pixels, stride, pos)}; case PixelFormat::BGRA:
else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
}
template<class T> 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
#endif #endif
#ifdef MAGNUM_TARGET_GLES2 #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 #endif
format == PixelFormat::Luminance case PixelFormat::RGInteger:
case PixelFormat::RGBInteger:
case PixelFormat::RGBAInteger:
#ifndef MAGNUM_TARGET_GLES
case PixelFormat::BGRInteger:
case PixelFormat::BGRAInteger:
#endif #endif
)
out << pixelAt<1, T>(pixels, stride, pos);
else if(
#if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2))
format == PixelFormat::RG
#endif #endif
#ifdef MAGNUM_TARGET_GLES2 case PixelFormat::DepthComponent:
#ifndef MAGNUM_TARGET_WEBGL #ifndef MAGNUM_TARGET_WEBGL
|| case PixelFormat::StencilIndex:
#endif #endif
format == PixelFormat::LuminanceAlpha case PixelFormat::DepthStencil:
CORRADE_IGNORE_DEPRECATED_POP
#endif #endif
) /* Already handled by a printing assert before */
out << pixelAt<2, T>(pixels, stride, pos); CORRADE_ASSERT_UNREACHABLE();
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<UnsignedByte>(out, pixels, stride, pos, format);
else if(type == PixelType::UnsignedShort)
printIntegerPixelAt<UnsignedShort>(out, pixels, stride, pos, format);
else if(type == PixelType::UnsignedInt)
printIntegerPixelAt<UnsignedInt>(out, pixels, stride, pos, format);
#ifndef MAGNUM_TARGET_GLES2
else if(type == PixelType::Byte)
printIntegerPixelAt<Byte>(out, pixels, stride, pos, format);
else if(type == PixelType::Short)
printIntegerPixelAt<Short>(out, pixels, stride, pos, format);
else if(type == PixelType::Int)
printIntegerPixelAt<Int>(out, pixels, stride, pos, format);
#endif
else if(type == PixelType::Float)
printPixelAt<Float>(out, pixels, stride, pos, format);
else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
} }
} }
@ -363,11 +391,11 @@ void printPixelDeltas(Debug& out, const std::vector<Float>& delta, const ImageVi
<< Debug::nospace << "," << Debug::nospace << pos.y() << Debug::nospace << "," << Debug::nospace << pos.y()
<< Debug::nospace << "]"; << Debug::nospace << "]";
printPixelAt(out, actualPixels, actualStride, pos, expected.format(), expected.type()); printPixelAt(out, actualPixels, actualStride, pos, expected.format());
out << Debug::nospace << ", expected"; 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 ? out << "(Δ =" << Debug::boldColor(delta[it->second] > maxThreshold ?
Debug::Color::Red : Debug::Color::Yellow) << delta[it->second] Debug::Color::Red : Debug::Color::Yellow) << delta[it->second]
@ -398,56 +426,11 @@ bool Comparator<DebugTools::CompareImage>::operator()(const ImageView2D& actual,
_state = State::DifferentSize; _state = State::DifferentSize;
return false; return false;
} }
if(actual.format() != expected.format() || actual.type() != expected.type()) { if(actual.format() != expected.format()) {
_state = State::DifferentFormat; _state = State::DifferentFormat;
return false; 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<Float> delta; std::vector<Float> delta;
std::tie(delta, _max, _mean) = DebugTools::Implementation::calculateImageDelta(actual, expected); std::tie(delta, _max, _mean) = DebugTools::Implementation::calculateImageDelta(actual, expected);
@ -471,10 +454,8 @@ void Comparator<DebugTools::CompareImage>::printErrorMessage(Debug& out, const s
out << "different size, actual" << _actualImage->size() << "but" out << "different size, actual" << _actualImage->size() << "but"
<< _expectedImage->size() << "expected."; << _expectedImage->size() << "expected.";
else if(_state == State::DifferentFormat) else if(_state == State::DifferentFormat)
out << "different format, actual" << _actualImage->format() out << "different format, actual" << _actualImage->format() << "but"
<< Debug::nospace << "/" << Debug::nospace << _actualImage->type() << _expectedImage->format() << "expected.";
<< "but" << _expectedImage->format() << Debug::nospace << "/"
<< Debug::nospace << _expectedImage->type() << "expected.";
else { else {
if(_state == State::AboveThresholds) if(_state == State::AboveThresholds)
out << "both max and mean delta above threshold, actual" out << "both max and mean delta above threshold, actual"

23
src/Magnum/DebugTools/CompareImage.h

@ -102,17 +102,18 @@ give for example the following result:
Supports the following formats: Supports the following formats:
- @ref PixelFormat::Red, @ref PixelFormat::RedInteger, @ref PixelFormat::RG, - @ref PixelFormat::RGBA8Unorm, @ref PixelFormat::RGBA16Unorm and their
@ref PixelFormat::RGInteger, @ref PixelFormat::RGB, @ref PixelFormat::RGBInteger, one-/two-/three-component versions
@ref PixelFormat::RGBA and @ref PixelFormat::RGBAInteger with - @ref PixelFormat::RGBA8Snorm, @ref PixelFormat::RGBA16Snorm and their
@ref PixelType::UnsignedByte, @ref PixelType::Byte, @ref PixelType::UnsignedShort, one-/two-/three-component versions
@ref PixelType::Short, @ref PixelType::UnsignedInt and @ref PixelType::Int - @ref PixelFormat::RGBA8UI, @ref PixelFormat::RGBA16UI,
- @ref PixelFormat::Red, @ref PixelFormat::RG, @ref PixelFormat::RGB and @ref PixelFormat::RGBA32UI and their one-/two-/three-component versions
@ref PixelFormat::RGBA with @ref PixelType::Float - @ref PixelFormat::RGBA8I, @ref PixelFormat::RGBA16I,
@ref PixelFormat::RGBA32I and their one-/two-/three-component versions
In OpenGL ES 2.0 and WebGL 1.0, @ref PixelFormat::Luminance and - @ref PixelFormat::RGBA32F and its one-/two-/three-component versions
@ref PixelFormat::LuminanceAlpha are also accepted in place of
@ref PixelFormat::Red and @ref PixelFormat::RG. @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 Supports all @ref PixelStorage parameters. The images don't need to have the
same pixel storage parameters, meaning you are able to compare different same pixel storage parameters, meaning you are able to compare different

2
src/Magnum/DebugTools/Test/CMakeLists.txt

@ -24,7 +24,7 @@
# #
if(Corrade_TestSuite_FOUND) 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") set_target_properties(DebugToolsCompareImageTest PROPERTIES FOLDER "Magnum/DebugTools/Test")
endif() endif()

131
src/Magnum/DebugTools/Test/CompareImageTest.cpp

@ -29,8 +29,8 @@
#include <Corrade/TestSuite/Compare/Container.h> #include <Corrade/TestSuite/Compare/Container.h>
#include "Magnum/ImageView.h" #include "Magnum/ImageView.h"
#include "Magnum/PixelFormat.h"
#include "Magnum/DebugTools/CompareImage.h" #include "Magnum/DebugTools/CompareImage.h"
#include "Magnum/GL/PixelFormat.h"
#include "Magnum/Math/Functions.h" #include "Magnum/Math/Functions.h"
#include "Magnum/Math/Color.h" #include "Magnum/Math/Color.h"
@ -39,6 +39,13 @@ namespace Magnum { namespace DebugTools { namespace Test {
struct CompareImageTest: TestSuite::Tester { struct CompareImageTest: TestSuite::Tester {
explicit CompareImageTest(); explicit CompareImageTest();
void formatUnknown();
void formatHalf();
void formatImplementationSpecific();
#if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL)
void formatDeprecated();
#endif
void calculateDelta(); void calculateDelta();
void calculateDeltaStorage(); void calculateDeltaStorage();
@ -51,7 +58,6 @@ struct CompareImageTest: TestSuite::Tester {
void compareDifferentSize(); void compareDifferentSize();
void compareDifferentFormat(); void compareDifferentFormat();
void compareDifferentType();
void compareSameZeroThreshold(); void compareSameZeroThreshold();
void compareAboveThresholds(); void compareAboveThresholds();
void compareAboveMaxThreshold(); void compareAboveMaxThreshold();
@ -59,7 +65,14 @@ struct CompareImageTest: TestSuite::Tester {
}; };
CompareImageTest::CompareImageTest() { 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::calculateDeltaStorage,
&CompareImageTest::deltaImage, &CompareImageTest::deltaImage,
@ -71,7 +84,6 @@ CompareImageTest::CompareImageTest() {
&CompareImageTest::compareDifferentSize, &CompareImageTest::compareDifferentSize,
&CompareImageTest::compareDifferentFormat, &CompareImageTest::compareDifferentFormat,
&CompareImageTest::compareDifferentType,
&CompareImageTest::compareSameZeroThreshold, &CompareImageTest::compareSameZeroThreshold,
&CompareImageTest::compareAboveThresholds, &CompareImageTest::compareAboveThresholds,
&CompareImageTest::compareAboveMaxThreshold, &CompareImageTest::compareAboveMaxThreshold,
@ -96,22 +108,54 @@ namespace {
0.01f, 0.0f, 0.1f, 0.01f, 0.0f, 0.1f,
0.12f, 1.0f, 0.0f}; 0.12f, 1.0f, 0.0f};
const ImageView2D ActualRed{ const ImageView2D ActualRed{PixelFormat::R32F, {3, 3}, ActualRedData};
#if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) const ImageView2D ExpectedRed{PixelFormat::R32F, {3, 3}, ExpectedRedData};
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};
} }
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() { void CompareImageTest::calculateDelta() {
std::vector<Float> delta; std::vector<Float> delta;
Float max, mean; Float max, mean;
@ -131,22 +175,15 @@ namespace {
}; };
const UnsignedByte ExpectedRgbData[] = { 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, 0x55, 0xf8, 0x3a, 0x56, 0x10, 0xed, 0, 0, 0,
0, 0, 0, 0x23, 0x27, 0x10, 0xab, 0xcd, 0xfa, 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}), const ImageView2D ActualRgb{PixelStorage{}.setSkip({0, 1, 0}),
PixelFormat::RGB, PixelType::UnsignedByte, {2, 2}, ActualRgbData}; PixelFormat::RGB8Unorm, {2, 2}, ActualRgbData};
const ImageView2D ExpectedRgb{ const ImageView2D ExpectedRgb{
#if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2))
PixelStorage{}.setSkip({1, 0, 0}).setRowLength(3), PixelStorage{}.setSkip({1, 0, 0}).setRowLength(3),
#endif PixelFormat::RGB8Unorm, {2, 2}, ExpectedRgbData};
PixelFormat::RGB, PixelType::UnsignedByte, {2, 2}, ExpectedRgbData};
} }
void CompareImageTest::calculateDeltaStorage() { void CompareImageTest::calculateDeltaStorage() {
@ -267,20 +304,8 @@ void CompareImageTest::pixelDeltaOverflow() {
void CompareImageTest::compareDifferentSize() { void CompareImageTest::compareDifferentSize() {
std::stringstream out; std::stringstream out;
ImageView2D a{ ImageView2D a{PixelFormat::RG8UI, {3, 4}, nullptr};
#ifndef MAGNUM_TARGET_GLES2 ImageView2D b{PixelFormat::RG8UI, {3, 5}, nullptr};
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};
{ {
Error e(&out); Error e(&out);
@ -295,24 +320,8 @@ void CompareImageTest::compareDifferentSize() {
void CompareImageTest::compareDifferentFormat() { void CompareImageTest::compareDifferentFormat() {
std::stringstream out; std::stringstream out;
ImageView2D a{PixelFormat::RGBA, PixelType::Float, {3, 4}, nullptr}; ImageView2D a{PixelFormat::RGBA32F, {3, 4}, nullptr};
ImageView2D b{PixelFormat::RGB, PixelType::Float, {3, 4}, nullptr}; ImageView2D b{PixelFormat::RGB32F, {3, 4}, nullptr};
{
Error e(&out);
TestSuite::Comparator<CompareImage> 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};
{ {
Error e(&out); Error e(&out);
@ -321,7 +330,7 @@ void CompareImageTest::compareDifferentType() {
compare.printErrorMessage(e, "a", "b"); 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() { void CompareImageTest::compareSameZeroThreshold() {
@ -332,7 +341,7 @@ void CompareImageTest::compareSameZeroThreshold() {
0xbadc0d_rgbf, 0xbeefe0_rgbf 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<CompareImage>{0.0f, 0.0f}(image, image))); CORRADE_VERIFY((TestSuite::Comparator<CompareImage>{0.0f, 0.0f}(image, image)));
} }

2
src/Magnum/DebugTools/visibility.h

@ -31,7 +31,7 @@
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
#ifndef MAGNUM_BUILD_STATIC #ifndef MAGNUM_BUILD_STATIC
#ifdef MagnumDebugTools_EXPORTS #if defined(MagnumDebugTools_EXPORTS) || defined(MagnumDebugToolsObjects_EXPORTS)
#define MAGNUM_DEBUGTOOLS_EXPORT CORRADE_VISIBILITY_EXPORT #define MAGNUM_DEBUGTOOLS_EXPORT CORRADE_VISIBILITY_EXPORT
#else #else
#define MAGNUM_DEBUGTOOLS_EXPORT CORRADE_VISIBILITY_IMPORT #define MAGNUM_DEBUGTOOLS_EXPORT CORRADE_VISIBILITY_IMPORT

Loading…
Cancel
Save