| Message ID | 20251114005428.90024-3-kieran.bingham@ideasonboard.com |
|---|---|
| State | New |
| Headers | show |
| Series |
|
| Related | show |
Hi 2025. 11. 14. 1:54 keltezéssel, Kieran Bingham írta: > Provide use case tests for the Quantized types to ensure construction > and usages are consistent and work as expected. > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > > --- > v3: > - Rename quantized_type to QuantizedType > > test/ipa/libipa/meson.build | 1 + > test/ipa/libipa/quantized.cpp | 130 ++++++++++++++++++++++++++++++++++ > 2 files changed, 131 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..3bbd6dd48c14 > --- /dev/null > +++ b/test/ipa/libipa/quantized.cpp > @@ -0,0 +1,130 @@ > +/* 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 constexpr QuantizedType fromFloat(float v) std::lround() is only constexpr since C++23; and `Quantized<>` itself does not call the conversion functions in constexpr contexts, so I would drop it. > + { > + int quantized = std::lround(v * 128.0f); > + return static_cast<int8_t>(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 constexpr QuantizedType fromFloat(float v) > + { > + int quantized = std::lround(v * 128.0f); > + return static_cast<uint8_t>(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; > + } > + > + /* > + * Test construction from non-float/non-T type (Expected Fail) > + * These should be a compile-time error if uncommented: > + */ > + // BrightnessQ bad1(15); // overloaded ‘Quantized(int)’ is ambiguous > + // BrightnessQ bad2(0xff); // overloaded ‘Quantized(int)’ is ambiguous > + // ContrastQ bad3(0x33); // overloaded ‘Quantized(int)’ is ambiguous > + // ContrastQ bad4(55U); // overloaded ‘Quantized(unsigned int)’ is ambiguous I think you should be able to do something e.g. static_assert(!std::is_constructible_v<BrightnessQ, unsigned int>); static_assert(!std::is_constructible_v<BrightnessQ, double>); // etc. if you want to test this. > + > + /* 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) I would do if (!(b1 != b2)) > + return TestFail; > + } > + > + /* Test copying */ > + { > + BrightnessQ b1(0.25f); > + BrightnessQ b2 = b1; > + if (!(b1 == b2)) > + return TestFail; > + } > + > + /* Test moving */ > + { > + BrightnessQ b1(0.25f); > + BrightnessQ b2 = std::move(b1); // Allow move semantics > + if (b2.value() != 0.25f) > + return TestFail; > + } > + > + /* Test assignment */ > + { > + ContrastQ c1(1.5f); > + ContrastQ c2(0.0f); > + c2 = c1; > + if (!(c1 == c2)) > + return TestFail; > + } > + > + std::cout << "Quantised tests passed successfully." << std::endl; > + > + return TestPass; > + } > +}; > + > +TEST_REGISTER(QuantizedTest)
Quoting Barnabás Pőcze (2025-11-14 18:08:06) > Hi > > 2025. 11. 14. 1:54 keltezéssel, Kieran Bingham írta: > > Provide use case tests for the Quantized types to ensure construction > > and usages are consistent and work as expected. > > > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > > > > --- > > v3: > > - Rename quantized_type to QuantizedType > > > > test/ipa/libipa/meson.build | 1 + > > test/ipa/libipa/quantized.cpp | 130 ++++++++++++++++++++++++++++++++++ > > 2 files changed, 131 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..3bbd6dd48c14 > > --- /dev/null > > +++ b/test/ipa/libipa/quantized.cpp > > @@ -0,0 +1,130 @@ > > +/* 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 constexpr QuantizedType fromFloat(float v) > > std::lround() is only constexpr since C++23; and `Quantized<>` itself does not > call the conversion functions in constexpr contexts, so I would drop it. > Ack. > > > + { > > + int quantized = std::lround(v * 128.0f); > > + return static_cast<int8_t>(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 constexpr QuantizedType fromFloat(float v) > > + { > > + int quantized = std::lround(v * 128.0f); > > + return static_cast<uint8_t>(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; > > + } > > + > > + /* > > + * Test construction from non-float/non-T type (Expected Fail) > > + * These should be a compile-time error if uncommented: > > + */ > > + // BrightnessQ bad1(15); // overloaded ‘Quantized(int)’ is ambiguous > > + // BrightnessQ bad2(0xff); // overloaded ‘Quantized(int)’ is ambiguous > > + // ContrastQ bad3(0x33); // overloaded ‘Quantized(int)’ is ambiguous > > + // ContrastQ bad4(55U); // overloaded ‘Quantized(unsigned int)’ is ambiguous > > I think you should be able to do something e.g. > > static_assert(!std::is_constructible_v<BrightnessQ, unsigned int>); > static_assert(!std::is_constructible_v<BrightnessQ, double>); > // etc. > > if you want to test this. Interesting, I didn't know I could do something like that - I'll give it a go. > > > > + > > + /* 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) > > I would do > > if (!(b1 != b2)) > ack > > > + return TestFail; > > + } > > + > > + /* Test copying */ > > + { > > + BrightnessQ b1(0.25f); > > + BrightnessQ b2 = b1; > > + if (!(b1 == b2)) > > + return TestFail; > > + } > > + > > + /* Test moving */ > > + { > > + BrightnessQ b1(0.25f); > > + BrightnessQ b2 = std::move(b1); // Allow move semantics > > + if (b2.value() != 0.25f) > > + return TestFail; > > + } > > + > > + /* Test assignment */ > > + { > > + ContrastQ c1(1.5f); > > + ContrastQ c2(0.0f); > > + c2 = c1; > > + if (!(c1 == c2)) > > + return TestFail; > > + } > > + > > + std::cout << "Quantised tests passed successfully." << std::endl; > > + > > + return TestPass; > > + } > > +}; > > + > > +TEST_REGISTER(QuantizedTest) >
Hi Kieran, Thank you for the patch! Reviewed-by: Isaac Scott <isaac.scott@ideasonboard.com> Quoting Kieran Bingham (2025-11-14 00:54:06) > Provide use case tests for the Quantized types to ensure construction > and usages are consistent and work as expected. > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > > --- > v3: > - Rename quantized_type to QuantizedType > > test/ipa/libipa/meson.build | 1 + > test/ipa/libipa/quantized.cpp | 130 ++++++++++++++++++++++++++++++++++ > 2 files changed, 131 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..3bbd6dd48c14 > --- /dev/null > +++ b/test/ipa/libipa/quantized.cpp > @@ -0,0 +1,130 @@ > +/* 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 constexpr QuantizedType fromFloat(float v) > + { > + int quantized = std::lround(v * 128.0f); > + return static_cast<int8_t>(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 constexpr QuantizedType fromFloat(float v) > + { > + int quantized = std::lround(v * 128.0f); > + return static_cast<uint8_t>(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; > + } > + > + /* > + * Test construction from non-float/non-T type (Expected Fail) > + * These should be a compile-time error if uncommented: > + */ > + // BrightnessQ bad1(15); // overloaded ‘Quantized(int)’ is ambiguous > + // BrightnessQ bad2(0xff); // overloaded ‘Quantized(int)’ is ambiguous > + // ContrastQ bad3(0x33); // overloaded ‘Quantized(int)’ is ambiguous > + // ContrastQ bad4(55U); // overloaded ‘Quantized(unsigned int)’ is ambiguous > + > + /* 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 moving */ > + { > + BrightnessQ b1(0.25f); > + BrightnessQ b2 = std::move(b1); // Allow move semantics > + if (b2.value() != 0.25f) > + return TestFail; > + } > + > + /* Test assignment */ > + { > + ContrastQ c1(1.5f); > + ContrastQ c2(0.0f); > + c2 = c1; > + if (!(c1 == c2)) > + return TestFail; > + } > + > + std::cout << "Quantised tests passed successfully." << std::endl; > + > + return TestPass; > + } > +}; > + > +TEST_REGISTER(QuantizedTest) > -- > 2.51.1 >
On Fri, Nov 14, 2025 at 12:54:06AM +0000, Kieran Bingham wrote: > Provide use case tests for the Quantized types to ensure construction > and usages are consistent and work as expected. > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > > --- > v3: > - Rename quantized_type to QuantizedType > > test/ipa/libipa/meson.build | 1 + > test/ipa/libipa/quantized.cpp | 130 ++++++++++++++++++++++++++++++++++ > 2 files changed, 131 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..3bbd6dd48c14 > --- /dev/null > +++ b/test/ipa/libipa/quantized.cpp > @@ -0,0 +1,130 @@ > +/* 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 constexpr QuantizedType fromFloat(float v) > + { > + int quantized = std::lround(v * 128.0f); > + return static_cast<int8_t>(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 constexpr QuantizedType fromFloat(float v) > + { > + int quantized = std::lround(v * 128.0f); > + return static_cast<uint8_t>(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; > + } > + > + /* > + * Test construction from non-float/non-T type (Expected Fail) > + * These should be a compile-time error if uncommented: > + */ > + // BrightnessQ bad1(15); // overloaded ‘Quantized(int)’ is ambiguous > + // BrightnessQ bad2(0xff); // overloaded ‘Quantized(int)’ is ambiguous > + // ContrastQ bad3(0x33); // overloaded ‘Quantized(int)’ is ambiguous > + // ContrastQ bad4(55U); // overloaded ‘Quantized(unsigned int)’ is ambiguous C-style comments. > + > + /* 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 moving */ > + { > + BrightnessQ b1(0.25f); > + BrightnessQ b2 = std::move(b1); // Allow move semantics C-style comments. > + if (b2.value() != 0.25f) > + return TestFail; > + } There are no move constructors or assignment operators in the class, I'd drop this. > + > + /* Test assignment */ > + { > + ContrastQ c1(1.5f); > + ContrastQ c2(0.0f); > + c2 = c1; > + if (!(c1 == c2)) > + return TestFail; > + } > + > + std::cout << "Quantised tests passed successfully." << std::endl; > + > + return TestPass; > + } > +}; > + > +TEST_REGISTER(QuantizedTest)
Quoting Laurent Pinchart (2025-11-19 04:23:35) > On Fri, Nov 14, 2025 at 12:54:06AM +0000, Kieran Bingham wrote: > > Provide use case tests for the Quantized types to ensure construction > > and usages are consistent and work as expected. > > > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > > > > --- > > v3: > > - Rename quantized_type to QuantizedType > > > > test/ipa/libipa/meson.build | 1 + > > test/ipa/libipa/quantized.cpp | 130 ++++++++++++++++++++++++++++++++++ > > 2 files changed, 131 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..3bbd6dd48c14 > > --- /dev/null > > +++ b/test/ipa/libipa/quantized.cpp > > @@ -0,0 +1,130 @@ > > +/* 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 constexpr QuantizedType fromFloat(float v) > > + { > > + int quantized = std::lround(v * 128.0f); > > + return static_cast<int8_t>(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 constexpr QuantizedType fromFloat(float v) > > + { > > + int quantized = std::lround(v * 128.0f); > > + return static_cast<uint8_t>(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; > > + } > > + > > + /* > > + * Test construction from non-float/non-T type (Expected Fail) > > + * These should be a compile-time error if uncommented: > > + */ > > + // BrightnessQ bad1(15); // overloaded ‘Quantized(int)’ is ambiguous > > + // BrightnessQ bad2(0xff); // overloaded ‘Quantized(int)’ is ambiguous > > + // ContrastQ bad3(0x33); // overloaded ‘Quantized(int)’ is ambiguous > > + // ContrastQ bad4(55U); // overloaded ‘Quantized(unsigned int)’ is ambiguous > > C-style comments. This was intentional to allow easy 'uncommenting for test'. Of course that doesn't apply to the text after which is the actual comment. But anyway, thanks to Barnabas' proposal these are removed so there's no issue here anymore. > > > + > > + /* 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 moving */ > > + { > > + BrightnessQ b1(0.25f); > > + BrightnessQ b2 = std::move(b1); // Allow move semantics > > C-style comments. > > > + if (b2.value() != 0.25f) > > + return TestFail; > > + } > > There are no move constructors or assignment operators in the class, I'd > drop this. Ok. > > + > > + /* Test assignment */ > > + { > > + ContrastQ c1(1.5f); > > + ContrastQ c2(0.0f); > > + c2 = c1; > > + if (!(c1 == c2)) > > + return TestFail; > > + } > > + > > + std::cout << "Quantised tests passed successfully." << std::endl; > > + > > + return TestPass; > > + } > > +}; > > + > > +TEST_REGISTER(QuantizedTest) > > -- > Regards, > > Laurent Pinchart
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..3bbd6dd48c14 --- /dev/null +++ b/test/ipa/libipa/quantized.cpp @@ -0,0 +1,130 @@ +/* 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 constexpr QuantizedType fromFloat(float v) + { + int quantized = std::lround(v * 128.0f); + return static_cast<int8_t>(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 constexpr QuantizedType fromFloat(float v) + { + int quantized = std::lround(v * 128.0f); + return static_cast<uint8_t>(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; + } + + /* + * Test construction from non-float/non-T type (Expected Fail) + * These should be a compile-time error if uncommented: + */ + // BrightnessQ bad1(15); // overloaded ‘Quantized(int)’ is ambiguous + // BrightnessQ bad2(0xff); // overloaded ‘Quantized(int)’ is ambiguous + // ContrastQ bad3(0x33); // overloaded ‘Quantized(int)’ is ambiguous + // ContrastQ bad4(55U); // overloaded ‘Quantized(unsigned int)’ is ambiguous + + /* 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 moving */ + { + BrightnessQ b1(0.25f); + BrightnessQ b2 = std::move(b1); // Allow move semantics + if (b2.value() != 0.25f) + return TestFail; + } + + /* Test assignment */ + { + ContrastQ c1(1.5f); + ContrastQ c2(0.0f); + c2 = c1; + if (!(c1 == c2)) + return TestFail; + } + + std::cout << "Quantised tests passed successfully." << std::endl; + + return TestPass; + } +}; + +TEST_REGISTER(QuantizedTest)
Provide use case tests for the Quantized types to ensure construction and usages are consistent and work as expected. Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> --- v3: - Rename quantized_type to QuantizedType test/ipa/libipa/meson.build | 1 + test/ipa/libipa/quantized.cpp | 130 ++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 test/ipa/libipa/quantized.cpp