Browse Source

DebugTools: special-case CompareImage delta calculation for integer types.

Integer / packed formats are the majority of uses for this utility, and
for them the additional complexity with NaN and infinity handling isn't
needed at all.

Running ShadersMeshVisualizerGLTest with this change in a Debug build
led to its runtime being reduced by about 35%, the total test time
excluding benchmarks went from 14.5 seconds to 11. Not bad.
pull/617/head
Vladimír Vondruš 3 years ago
parent
commit
79c42fee6e
  1. 31
      src/Magnum/DebugTools/CompareImage.cpp
  2. 34
      src/Magnum/DebugTools/Test/CompareImageTest.cpp

31
src/Magnum/DebugTools/CompareImage.cpp

@ -52,7 +52,11 @@ namespace Magnum { namespace DebugTools { namespace Implementation {
namespace {
template<std::size_t size, class T> Float calculateImageDelta(const Containers::StridedArrayView2D<const Math::Vector<size, T>>& actual, const Containers::StridedArrayView2D<const Math::Vector<size, T>>& expected, const Containers::StridedArrayView2D<Float>& output) {
/* There's a separate implementation for integral types, as those don't need
any additional logic for handling NaN and infinity values, allowing the
comparison to be much simpler & faster. */
template<std::size_t size, class T, typename std::enable_if<Math::IsFloatingPoint<T>::value, int>::type = 0> Float calculateImageDelta(const Containers::StridedArrayView2D<const Math::Vector<size, T>>& actual, const Containers::StridedArrayView2D<const Math::Vector<size, T>>& expected, const Containers::StridedArrayView2D<Float>& output) {
CORRADE_INTERNAL_ASSERT(actual.size() == output.size());
CORRADE_INTERNAL_ASSERT(output.size() == expected.size());
@ -93,6 +97,31 @@ template<std::size_t size, class T> Float calculateImageDelta(const Containers::
return max;
}
template<std::size_t size, class T, typename std::enable_if<Math::IsIntegral<T>::value, int>::type = 0> Float calculateImageDelta(const Containers::StridedArrayView2D<const Math::Vector<size, T>>& actual, const Containers::StridedArrayView2D<const Math::Vector<size, T>>& expected, const Containers::StridedArrayView2D<Float>& output) {
CORRADE_INTERNAL_ASSERT(actual.size() == output.size());
CORRADE_INTERNAL_ASSERT(output.size() == expected.size());
/* Calculate deltas and maximal value of them */
Float max{};
for(std::size_t i = 0, iMax = expected.size()[0]; i != iMax; ++i) {
Containers::StridedArrayView1D<const Math::Vector<size, T>> actualRow = actual[i];
Containers::StridedArrayView1D<const Math::Vector<size, T>> expectedRow = expected[i];
Containers::StridedArrayView1D<Float> outputRow = output[i];
for(std::size_t j = 0, jMax = expectedRow.size(); j != jMax; ++j) {
/* Explicitly convert from T to Float */
auto actualPixel = Math::Vector<size, Float>(actualRow[j]);
auto expectedPixel = Math::Vector<size, Float>(expectedRow[j]);
Math::Vector<size, Float> diff = Math::abs(actualPixel - expectedPixel);
outputRow[j] = diff.sum()/size;
max = Math::max(max, outputRow[j]);
}
}
return max;
}
}
Containers::Triple<Containers::Array<Float>, Float, Float> calculateImageDelta(const PixelFormat actualFormat, const Containers::StridedArrayView3D<const char>& actualPixels, const ImageView2D& expected) {

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

@ -60,6 +60,7 @@ struct CompareImageTest: TestSuite::Tester {
void formatImplementationSpecific();
void calculateDelta();
void calculateDeltaInteger();
void calculateDeltaStorage();
void calculateDeltaSpecials();
void calculateDeltaSpecials3();
@ -132,6 +133,7 @@ CompareImageTest::CompareImageTest() {
&CompareImageTest::formatImplementationSpecific,
&CompareImageTest::calculateDelta,
&CompareImageTest::calculateDeltaInteger,
&CompareImageTest::calculateDeltaStorage,
&CompareImageTest::calculateDeltaSpecials,
&CompareImageTest::calculateDeltaSpecials3,
@ -289,6 +291,38 @@ void CompareImageTest::calculateDelta() {
CORRADE_COMPARE(deltaMaxMean.third(), 0.208889f);
}
void CompareImageTest::calculateDeltaInteger() {
/* Like ActualRedData, ExpectedRedData and DeltaRed, just multiplied 100
times and saved into a Short */
const Short actualRedData[]{
30, 100, 90,
90, 60, 20,
-10, 100, 0
};
const Short expectedRedData[]{
65, 100, 60,
91, 60, 10,
2, 0, 0
};
const Float deltaRed[]{
35.0f, 0.0f, 30.0f,
1.0f, 0.0f, 10.0f,
12.0f, 100.0f, 0.0f
};
const ImageView2D actualRed{PixelStorage{}.setAlignment(2), PixelFormat::R16I, {3, 3}, actualRedData};
const ImageView2D expectedRed{PixelStorage{}.setAlignment(2), PixelFormat::R16I, {3, 3}, expectedRedData};
Containers::Triple<Containers::Array<Float>, Float, Float> deltaMaxMean = Implementation::calculateImageDelta(actualRed.format(), actualRed.pixels(), expectedRed);
CORRADE_COMPARE_AS(deltaMaxMean.first(),
Containers::arrayView(deltaRed),
TestSuite::Compare::Container);
CORRADE_COMPARE(deltaMaxMean.second(), 100.0f);
CORRADE_COMPARE(deltaMaxMean.third(), 20.8889f);
}
/* Different storage for each */
const UnsignedByte ActualRgbData[] = {
0, 0, 0, 0, 0, 0, 0, 0,

Loading…
Cancel
Save