diff --git a/test/ipa/libipa/meson.build b/test/ipa/libipa/meson.build index 2070bed7..c3e25587 100644 --- a/test/ipa/libipa/meson.build +++ b/test/ipa/libipa/meson.build @@ -5,6 +5,7 @@ libipa_test = [ {'name': 'histogram', 'sources': ['histogram.cpp']}, {'name': 'interpolator', 'sources': ['interpolator.cpp']}, {'name': 'pwl', 'sources': ['pwl.cpp'] }, + {'name': 'quantized', 'sources': ['quantized.cpp']}, ] foreach test : libipa_test diff --git a/test/ipa/libipa/quantized.cpp b/test/ipa/libipa/quantized.cpp new file mode 100644 index 00000000..f138597f --- /dev/null +++ b/test/ipa/libipa/quantized.cpp @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2026, Ideas on Board + * + * Dual Type and Quantizer tests + */ + +#include "../src/ipa/libipa/quantized.h" + +#include +#include +#include +#include + +#include "test.h" + +using namespace std; +using namespace libcamera; +using namespace ipa; + +struct BrightnessHueTraits { + using QuantizedType = uint8_t; + static QuantizedType fromFloat(float v) + { + int quantized = std::lround(v * 128.0f); + return std::clamp(quantized, -128, 127); + } + static float toFloat(QuantizedType v) + { + return static_cast(v) / 128.0f; + } +}; + +using BrightnessHueQuantizer = Quantized; + +struct ContrastSaturationTraits { + using QuantizedType = uint8_t; + static QuantizedType fromFloat(float v) + { + int quantized = std::lround(v * 128.0f); + return std::clamp(quantized, 0, 255); + } + static float toFloat(QuantizedType v) + { + return static_cast(v) / 128.0f; + } +}; + +using ContrastSaturationQuantizer = Quantized; + +using BrightnessQ = BrightnessHueQuantizer; +using HueQ = BrightnessHueQuantizer; +using ContrastQ = ContrastSaturationQuantizer; +using SaturationQ = ContrastSaturationQuantizer; + +class QuantizedTest : public Test +{ +protected: + int run() + { + /* Test construction from float */ + { + BrightnessQ b(0.5f); + if (b.quantized() != 64 || std::abs(b.value() - 0.5f) > 0.01f) + return TestFail; + } + + /* Test construction from T */ + { + ContrastQ c(uint8_t(128)); + if (c.quantized() != 128 || std::abs(c.value() - 1.0f) > 0.01f) + return TestFail; + } + + /* + * Only construction from the exact storage type or a float + * is permitted. + */ + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + + /* Test equality */ + { + BrightnessQ b1(0.5f), b2(uint8_t(64)); + if (!(b1 == b2)) + return TestFail; + } + + /* Test inequality */ + { + BrightnessQ b1(0.5f), b2(-0.5f); + if (!(b1 != b2)) + return TestFail; + } + + /* Test copying */ + { + BrightnessQ b1(0.25f); + BrightnessQ b2 = b1; + if (!(b1 == b2)) + return TestFail; + } + + /* Test assignment */ + { + ContrastQ c1(1.5f); + ContrastQ c2(0.0f); + c2 = c1; + if (!(c1 == c2)) + return TestFail; + } + + /* + * Test construction from different floats mapping to same + * quantized value + */ + { + /* Two floats that have the same quantized value. */ + const float f1 = 1.007f; + const float f2 = 1.008f; + + ContrastQ c1(f1); + ContrastQ c2(f2); + + /* Quantized values must match */ + if (!(c1.quantized() == c2.quantized())) + return TestFail; + + /* Float values must now match */ + if (!(c1.value() == c2.value())) + return TestFail; + + if (!(c1 == c2)) + return TestFail; + } + + return TestPass; + } +}; + +TEST_REGISTER(QuantizedTest)