| Message ID | 20260121173737.376113-3-kieran.bingham@ideasonboard.com |
|---|---|
| State | New |
| Headers | show |
| Series |
|
| Related | show |
Hi Kiearan, Quoting Kieran Bingham (2026-01-21 18:37:21) > Provide use case tests for the Quantized types to ensure construction > and usages are consistent and work as expected. > > Reviewed-by: Isaac Scott <isaac.scott@ideasonboard.com> > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > > --- > v3: > - Rename quantized_type to QuantizedType > > v5: > - use static asserts for constructible failure tests > - Remove constexpr from lround users (only possible in C++23) > - Remove move tests > - Fix up inequality test > > v6: > - Remove static casts on fromFloat conversions > - Use int8_t(64) instead of (int8_t)64 > - Add new test from different floats to the same quantized value > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Double signed off? Will be cut anyways... Looks good to me. Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com> Regards, Stefan > --- > test/ipa/libipa/meson.build | 1 + > test/ipa/libipa/quantized.cpp | 148 ++++++++++++++++++++++++++++++++++ > 2 files changed, 149 insertions(+) > create mode 100644 test/ipa/libipa/quantized.cpp > > diff --git a/test/ipa/libipa/meson.build b/test/ipa/libipa/meson.build > index 2070bed70222..c3e255871f4f 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 000000000000..860d54d2dd18 > --- /dev/null > +++ b/test/ipa/libipa/quantized.cpp > @@ -0,0 +1,148 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +/* > + * Copyright (C) 2025, Ideas on Board > + * > + * Dual Type and Quantizer tests > + */ > + > +#include "../src/ipa/libipa/quantized.h" > + > +#include <algorithm> > +#include <cmath> > +#include <iostream> > +#include <map> > +#include <stdint.h> > + > +#include "test.h" > + > +using namespace std; > +using namespace libcamera; > +using namespace ipa; > + > +struct BrightnessHueTraits { > + using QuantizedType = int8_t; > + static QuantizedType fromFloat(float v) > + { > + int quantized = std::lround(v * 128.0f); > + return std::clamp<int>(quantized, -128, 127); > + } > + static float toFloat(QuantizedType v) > + { > + return static_cast<float>(v) / 128.0f; > + } > +}; > + > +using BrightnessHueQuantizer = Quantized<BrightnessHueTraits>; > + > +struct ContrastSaturationTraits { > + using QuantizedType = uint8_t; > + static QuantizedType fromFloat(float v) > + { > + int quantized = std::lround(v * 128.0f); > + return std::clamp<int>(quantized, 0, 255); > + } > + static float toFloat(QuantizedType v) > + { > + return static_cast<float>(v) / 128.0f; > + } > +}; > + > +using ContrastSaturationQuantizer = Quantized<ContrastSaturationTraits>; > + > +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<BrightnessQ, unsigned int>); > + static_assert(!std::is_constructible_v<BrightnessQ, uint8_t>); > + static_assert(!std::is_constructible_v<BrightnessQ, double>); > + static_assert(!std::is_constructible_v<ContrastQ, int>); > + static_assert(!std::is_constructible_v<ContrastQ, int8_t>); > + static_assert(!std::is_constructible_v<ContrastQ, unsigned int>); > + > + /* Test equality */ > + { > + BrightnessQ b1(0.5f), b2(int8_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; > + } > + > + std::cout << "Quantised tests passed successfully." << std::endl; > + > + return TestPass; > + } > +}; > + > +TEST_REGISTER(QuantizedTest) > -- > 2.52.0 >
diff --git a/test/ipa/libipa/meson.build b/test/ipa/libipa/meson.build index 2070bed70222..c3e255871f4f 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 000000000000..860d54d2dd18 --- /dev/null +++ b/test/ipa/libipa/quantized.cpp @@ -0,0 +1,148 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2025, Ideas on Board + * + * Dual Type and Quantizer tests + */ + +#include "../src/ipa/libipa/quantized.h" + +#include <algorithm> +#include <cmath> +#include <iostream> +#include <map> +#include <stdint.h> + +#include "test.h" + +using namespace std; +using namespace libcamera; +using namespace ipa; + +struct BrightnessHueTraits { + using QuantizedType = int8_t; + static QuantizedType fromFloat(float v) + { + int quantized = std::lround(v * 128.0f); + return std::clamp<int>(quantized, -128, 127); + } + static float toFloat(QuantizedType v) + { + return static_cast<float>(v) / 128.0f; + } +}; + +using BrightnessHueQuantizer = Quantized<BrightnessHueTraits>; + +struct ContrastSaturationTraits { + using QuantizedType = uint8_t; + static QuantizedType fromFloat(float v) + { + int quantized = std::lround(v * 128.0f); + return std::clamp<int>(quantized, 0, 255); + } + static float toFloat(QuantizedType v) + { + return static_cast<float>(v) / 128.0f; + } +}; + +using ContrastSaturationQuantizer = Quantized<ContrastSaturationTraits>; + +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<BrightnessQ, unsigned int>); + static_assert(!std::is_constructible_v<BrightnessQ, uint8_t>); + static_assert(!std::is_constructible_v<BrightnessQ, double>); + static_assert(!std::is_constructible_v<ContrastQ, int>); + static_assert(!std::is_constructible_v<ContrastQ, int8_t>); + static_assert(!std::is_constructible_v<ContrastQ, unsigned int>); + + /* Test equality */ + { + BrightnessQ b1(0.5f), b2(int8_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; + } + + std::cout << "Quantised tests passed successfully." << std::endl; + + return TestPass; + } +}; + +TEST_REGISTER(QuantizedTest)