[v4,04/21] test: libipa: Provide FixedPoint Quantized tests
diff mbox series

Message ID 20251114005428.90024-5-kieran.bingham@ideasonboard.com
State New
Headers show
Series
  • libipa: Introduce a Quantized type
Related show

Commit Message

Kieran Bingham Nov. 14, 2025, 12:54 a.m. UTC
Validate the new fixed-point Quantized types with tests covering Q1.7,
UQ1.7, Q12.4 and UQ12.4 types.

Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

---
v3:
- Rename quantized_type to QuantizedType

 test/ipa/libipa/fixedpoint.cpp | 120 +++++++++++++++++++++++++++++++--
 1 file changed, 116 insertions(+), 4 deletions(-)

Comments

Barnabás Pőcze Nov. 14, 2025, 6:08 p.m. UTC | #1
2025. 11. 14. 1:54 keltezéssel, Kieran Bingham írta:
> Validate the new fixed-point Quantized types with tests covering Q1.7,
> UQ1.7, Q12.4 and UQ12.4 types.
> 
> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> 
> ---
> v3:
> - Rename quantized_type to QuantizedType
> 
>   test/ipa/libipa/fixedpoint.cpp | 120 +++++++++++++++++++++++++++++++--
>   1 file changed, 116 insertions(+), 4 deletions(-)
> 
> diff --git a/test/ipa/libipa/fixedpoint.cpp b/test/ipa/libipa/fixedpoint.cpp
> index 99eb662ddf4e..935412771851 100644
> --- a/test/ipa/libipa/fixedpoint.cpp
> +++ b/test/ipa/libipa/fixedpoint.cpp
> @@ -5,12 +5,14 @@
>    * Fixed / Floating point utility tests
>    */
>   
> +#include "../src/ipa/libipa/fixedpoint.h"
> +
>   #include <cmath>
>   #include <iostream>
>   #include <map>
>   #include <stdint.h>
>   
> -#include "../src/ipa/libipa/fixedpoint.h"
> +#include <libcamera/base/utils.h>
>   
>   #include "test.h"
>   
> @@ -95,14 +97,124 @@ protected:
>   		return TestPass;
>   	}
>   
> -	int run()
> +	template<typename Q>
> +	int quantizedCheck(float input, typename Q::QuantizedType expected, float value)
>   	{
> -		/* fixed point conversion test */
> -		if (testFixedPoint() != TestPass)
> +		Q q(input);
> +		using T = typename Q::QuantizedType;
> +
> +		cerr << "  Checking " << input << " == " << q.toString() << std::endl;
> +
> +		T quantized = q.quantized();
> +		if (quantized != expected) {
> +			cerr << "    ** Q Expected " << input
> +			     << " to quantize to " << utils::hex(expected)
> +			     << ", got " << utils::hex(quantized)
> +			     << " - (" << q.toString() << ")"
> +			     << std::endl;
> +			return 1;
> +		}
> +
> +		if ((std::abs(q.value() - value)) > 0.0001f) {
> +			cerr << "    ** V Expected " << input
> +			     << " to quantize to " << value
> +			     << ", got " << q.value()
> +			     << " - (" << q.toString() << ")"
> +			     << std::endl;
> +			return 1;
> +		}
> +
> +		return 0;
> +	}
> +
> +	template<typename Q>
> +	int introduce(std::string type)

I'd use `const char *` or `std::string_view`.


> +	{
> +		using T = typename Q::QuantizedType;
> +
> +		std::cerr << std::endl;
> +
> +		cerr << type << "(" << Q::TraitsType::min << " .. " << Q::TraitsType::max << ") "
> +		     << " Min: " << Q(Q::TraitsType::min).toString()
> +		     << " -- Max: " << Q(Q::TraitsType::max).toString()
> +		     << " Step:" << Q(T(1)).value()
> +		     << std::endl;
> +
> +		if (Q::TraitsType::min > Q::TraitsType::max) {
> +			cerr << "    *** " << type
> +			     << " Min (" << Q::TraitsType::min
> +			     << ") must be less than max ("
> +			     << Q::TraitsType::max << ")" << std::endl;
> +			return 1;

Is the return value checked anywhere? I think this check is something that
could belong to a static_assert somewhere, possibly in `Quantized`.


> +		}
> +
> +		return 0;
> +	}
> +
> +	int testFixedPointQuantizers()
> +	{
> +		unsigned int fails = 0;
> +
> +		/* clang-format off */
> +
> +		/* Q1_7(-1 .. 0.992188)  Min: [0x80:-1] -- Max: [0x7f:0.992188] Step:0.0078125*/
> +		fails += introduce<Q1_7>("Q1_7");
> +		fails += quantizedCheck<Q1_7>(-1.000f, 0b1'0000000, -1.0f);		/* Min */
> +		fails += quantizedCheck<Q1_7>(-0.992f, 0b1'0000001, -0.992188f);	/* Min + 1 step */
> +		fails += quantizedCheck<Q1_7>(-0.006f, 0b1'1111111, -0.0078125f);	/* -1 step */
> +		fails += quantizedCheck<Q1_7>( 0.000f, 0b0'0000000,  0.0f);		/* Zero */
> +		fails += quantizedCheck<Q1_7>( 0.008f, 0b0'0000001,  0.0078125f);	/* +1 step */
> +		fails += quantizedCheck<Q1_7>( 0.992f, 0b0'1111111,  0.992188f);	/* Max */
> +
> +		/* UQ1_7(0 .. 1.99219)  Min: [0x00:0] -- Max: [0xff:1.99219] Step:0.0078125 */
> +		fails += introduce<UQ1_7>("UQ1_7");
> +		fails += quantizedCheck<UQ1_7>(0.0f,   0b0'0000000, 0.0f);		/* Min / Zero */
> +		fails += quantizedCheck<UQ1_7>(1.0f,   0b1'0000000, 1.0f);		/* Mid */
> +		fails += quantizedCheck<UQ1_7>(1.992f, 0b1'1111111, 1.99219f);		/* Max */
> +
> +		/* Q12.4(-2048 .. 2047.94)  Min: [0x8000:-2048] -- Max: [0x7fff:2047.94] Step:0.0625 */
> +		introduce<Q12_4>("Q12_4");
> +		fails += quantizedCheck<Q12_4>(0.0f, 0b000000000000'0000, 0.0f);
> +		fails += quantizedCheck<Q12_4>(7.5f, 0b000000000111'1000, 7.5f);
> +
> +		/* UQ12_4(0 .. 4095.94)  Min: [0x0000:0] -- Max: [0xffff:4095.94] Step:0.0625 */
> +		introduce<UQ12_4>("UQ12_4");
> +		fails += quantizedCheck<UQ12_4>(0.0f, 0b000000000000'0000, 0.0f);
> +		fails += quantizedCheck<UQ12_4>(7.5f, 0b000000000111'1000, 7.5f);
> +
> +		/* Validate that exceeding limits clamps to type range */
> +		cerr << std::endl << "Range validation:" << std::endl;
> +		fails += quantizedCheck<Q1_7>(-100.0f, 0b1'0000000, -1.0f);
> +		fails += quantizedCheck<Q1_7>(+100.0f, 0b0'1111111, 0.992188f);
> +		fails += quantizedCheck<UQ1_7>(-100.0f, 0b0'0000000, 0.0f);
> +		fails += quantizedCheck<UQ1_7>(+100.0f, 0b1'1111111, 1.99219f);
> +
> +		/* clang-format on */
> +
> +		std::cerr << std::endl;
> +
> +		if (fails > 0) {
> +			cerr << "Fixed point quantizer tests failed: "
> +			     << std::dec << fails << " failures." << std::endl;
>   			return TestFail;
> +		}
>   
>   		return TestPass;
>   	}
> +
> +	int run()
> +	{
> +		unsigned int fails = 0;
> +
> +		/* fixed point conversion test */
> +		if (testFixedPoint() != TestPass)
> +			fails++;
> +
> +		if (testFixedPointQuantizers() != TestPass)
> +			fails++;
> +
> +		return fails ? TestFail : TestPass;
> +	}
>   };
>   
>   TEST_REGISTER(FixedPointUtilsTest)
Isaac Scott Nov. 18, 2025, 12:37 p.m. UTC | #2
Hi Kieran,

Thank you for the patch!

Reviewed-by: Isaac Scott <isaac.scott@ideasonboard.com>

Quoting Kieran Bingham (2025-11-14 00:54:08)
> Validate the new fixed-point Quantized types with tests covering Q1.7,
> UQ1.7, Q12.4 and UQ12.4 types.
> 
> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> 
> ---
> v3:
> - Rename quantized_type to QuantizedType
> 
>  test/ipa/libipa/fixedpoint.cpp | 120 +++++++++++++++++++++++++++++++--
>  1 file changed, 116 insertions(+), 4 deletions(-)
> 
> diff --git a/test/ipa/libipa/fixedpoint.cpp b/test/ipa/libipa/fixedpoint.cpp
> index 99eb662ddf4e..935412771851 100644
> --- a/test/ipa/libipa/fixedpoint.cpp
> +++ b/test/ipa/libipa/fixedpoint.cpp
> @@ -5,12 +5,14 @@
>   * Fixed / Floating point utility tests
>   */
>  
> +#include "../src/ipa/libipa/fixedpoint.h"
> +
>  #include <cmath>
>  #include <iostream>
>  #include <map>
>  #include <stdint.h>
>  
> -#include "../src/ipa/libipa/fixedpoint.h"
> +#include <libcamera/base/utils.h>
>  
>  #include "test.h"
>  
> @@ -95,14 +97,124 @@ protected:
>                 return TestPass;
>         }
>  
> -       int run()
> +       template<typename Q>
> +       int quantizedCheck(float input, typename Q::QuantizedType expected, float value)
>         {
> -               /* fixed point conversion test */
> -               if (testFixedPoint() != TestPass)
> +               Q q(input);
> +               using T = typename Q::QuantizedType;
> +
> +               cerr << "  Checking " << input << " == " << q.toString() << std::endl;
> +
> +               T quantized = q.quantized();
> +               if (quantized != expected) {
> +                       cerr << "    ** Q Expected " << input
> +                            << " to quantize to " << utils::hex(expected)
> +                            << ", got " << utils::hex(quantized)
> +                            << " - (" << q.toString() << ")"
> +                            << std::endl;
> +                       return 1;
> +               }
> +
> +               if ((std::abs(q.value() - value)) > 0.0001f) {
> +                       cerr << "    ** V Expected " << input
> +                            << " to quantize to " << value
> +                            << ", got " << q.value()
> +                            << " - (" << q.toString() << ")"
> +                            << std::endl;
> +                       return 1;
> +               }
> +
> +               return 0;
> +       }
> +
> +       template<typename Q>
> +       int introduce(std::string type)
> +       {
> +               using T = typename Q::QuantizedType;
> +
> +               std::cerr << std::endl;
> +
> +               cerr << type << "(" << Q::TraitsType::min << " .. " << Q::TraitsType::max << ") "
> +                    << " Min: " << Q(Q::TraitsType::min).toString()
> +                    << " -- Max: " << Q(Q::TraitsType::max).toString()
> +                    << " Step:" << Q(T(1)).value()
> +                    << std::endl;
> +
> +               if (Q::TraitsType::min > Q::TraitsType::max) {
> +                       cerr << "    *** " << type
> +                            << " Min (" << Q::TraitsType::min
> +                            << ") must be less than max ("
> +                            << Q::TraitsType::max << ")" << std::endl;
> +                       return 1;
> +               }
> +
> +               return 0;
> +       }
> +
> +       int testFixedPointQuantizers()
> +       {
> +               unsigned int fails = 0;
> +
> +               /* clang-format off */
> +
> +               /* Q1_7(-1 .. 0.992188)  Min: [0x80:-1] -- Max: [0x7f:0.992188] Step:0.0078125*/
> +               fails += introduce<Q1_7>("Q1_7");
> +               fails += quantizedCheck<Q1_7>(-1.000f, 0b1'0000000, -1.0f);             /* Min */
> +               fails += quantizedCheck<Q1_7>(-0.992f, 0b1'0000001, -0.992188f);        /* Min + 1 step */
> +               fails += quantizedCheck<Q1_7>(-0.006f, 0b1'1111111, -0.0078125f);       /* -1 step */
> +               fails += quantizedCheck<Q1_7>( 0.000f, 0b0'0000000,  0.0f);             /* Zero */
> +               fails += quantizedCheck<Q1_7>( 0.008f, 0b0'0000001,  0.0078125f);       /* +1 step */
> +               fails += quantizedCheck<Q1_7>( 0.992f, 0b0'1111111,  0.992188f);        /* Max */
> +
> +               /* UQ1_7(0 .. 1.99219)  Min: [0x00:0] -- Max: [0xff:1.99219] Step:0.0078125 */
> +               fails += introduce<UQ1_7>("UQ1_7");
> +               fails += quantizedCheck<UQ1_7>(0.0f,   0b0'0000000, 0.0f);              /* Min / Zero */
> +               fails += quantizedCheck<UQ1_7>(1.0f,   0b1'0000000, 1.0f);              /* Mid */
> +               fails += quantizedCheck<UQ1_7>(1.992f, 0b1'1111111, 1.99219f);          /* Max */
> +
> +               /* Q12.4(-2048 .. 2047.94)  Min: [0x8000:-2048] -- Max: [0x7fff:2047.94] Step:0.0625 */
> +               introduce<Q12_4>("Q12_4");
> +               fails += quantizedCheck<Q12_4>(0.0f, 0b000000000000'0000, 0.0f);
> +               fails += quantizedCheck<Q12_4>(7.5f, 0b000000000111'1000, 7.5f);
> +
> +               /* UQ12_4(0 .. 4095.94)  Min: [0x0000:0] -- Max: [0xffff:4095.94] Step:0.0625 */
> +               introduce<UQ12_4>("UQ12_4");
> +               fails += quantizedCheck<UQ12_4>(0.0f, 0b000000000000'0000, 0.0f);
> +               fails += quantizedCheck<UQ12_4>(7.5f, 0b000000000111'1000, 7.5f);
> +
> +               /* Validate that exceeding limits clamps to type range */
> +               cerr << std::endl << "Range validation:" << std::endl;
> +               fails += quantizedCheck<Q1_7>(-100.0f, 0b1'0000000, -1.0f);
> +               fails += quantizedCheck<Q1_7>(+100.0f, 0b0'1111111, 0.992188f);
> +               fails += quantizedCheck<UQ1_7>(-100.0f, 0b0'0000000, 0.0f);
> +               fails += quantizedCheck<UQ1_7>(+100.0f, 0b1'1111111, 1.99219f);
> +
> +               /* clang-format on */
> +
> +               std::cerr << std::endl;
> +
> +               if (fails > 0) {
> +                       cerr << "Fixed point quantizer tests failed: "
> +                            << std::dec << fails << " failures." << std::endl;
>                         return TestFail;
> +               }
>  
>                 return TestPass;
>         }
> +
> +       int run()
> +       {
> +               unsigned int fails = 0;
> +
> +               /* fixed point conversion test */
> +               if (testFixedPoint() != TestPass)
> +                       fails++;
> +
> +               if (testFixedPointQuantizers() != TestPass)
> +                       fails++;
> +
> +               return fails ? TestFail : TestPass;
> +       }
>  };
>  
>  TEST_REGISTER(FixedPointUtilsTest)
> -- 
> 2.51.1
>
Kieran Bingham Nov. 18, 2025, 11:38 p.m. UTC | #3
Quoting Barnabás Pőcze (2025-11-14 18:08:13)
> 2025. 11. 14. 1:54 keltezéssel, Kieran Bingham írta:
> > Validate the new fixed-point Quantized types with tests covering Q1.7,
> > UQ1.7, Q12.4 and UQ12.4 types.
> > 
> > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > 
> > ---
> > v3:
> > - Rename quantized_type to QuantizedType
> > 
> >   test/ipa/libipa/fixedpoint.cpp | 120 +++++++++++++++++++++++++++++++--
> >   1 file changed, 116 insertions(+), 4 deletions(-)
> > 
> > diff --git a/test/ipa/libipa/fixedpoint.cpp b/test/ipa/libipa/fixedpoint.cpp
> > index 99eb662ddf4e..935412771851 100644
> > --- a/test/ipa/libipa/fixedpoint.cpp
> > +++ b/test/ipa/libipa/fixedpoint.cpp
> > @@ -5,12 +5,14 @@
> >    * Fixed / Floating point utility tests
> >    */
> >   
> > +#include "../src/ipa/libipa/fixedpoint.h"
> > +
> >   #include <cmath>
> >   #include <iostream>
> >   #include <map>
> >   #include <stdint.h>
> >   
> > -#include "../src/ipa/libipa/fixedpoint.h"
> > +#include <libcamera/base/utils.h>
> >   
> >   #include "test.h"
> >   
> > @@ -95,14 +97,124 @@ protected:
> >               return TestPass;
> >       }
> >   
> > -     int run()
> > +     template<typename Q>
> > +     int quantizedCheck(float input, typename Q::QuantizedType expected, float value)
> >       {
> > -             /* fixed point conversion test */
> > -             if (testFixedPoint() != TestPass)
> > +             Q q(input);
> > +             using T = typename Q::QuantizedType;
> > +
> > +             cerr << "  Checking " << input << " == " << q.toString() << std::endl;
> > +
> > +             T quantized = q.quantized();
> > +             if (quantized != expected) {
> > +                     cerr << "    ** Q Expected " << input
> > +                          << " to quantize to " << utils::hex(expected)
> > +                          << ", got " << utils::hex(quantized)
> > +                          << " - (" << q.toString() << ")"
> > +                          << std::endl;
> > +                     return 1;
> > +             }
> > +
> > +             if ((std::abs(q.value() - value)) > 0.0001f) {
> > +                     cerr << "    ** V Expected " << input
> > +                          << " to quantize to " << value
> > +                          << ", got " << q.value()
> > +                          << " - (" << q.toString() << ")"
> > +                          << std::endl;
> > +                     return 1;
> > +             }
> > +
> > +             return 0;
> > +     }
> > +
> > +     template<typename Q>
> > +     int introduce(std::string type)
> 
> I'd use `const char *` or `std::string_view`.
> 

Ack,

> > +     {
> > +             using T = typename Q::QuantizedType;
> > +
> > +             std::cerr << std::endl;
> > +
> > +             cerr << type << "(" << Q::TraitsType::min << " .. " << Q::TraitsType::max << ") "
> > +                  << " Min: " << Q(Q::TraitsType::min).toString()
> > +                  << " -- Max: " << Q(Q::TraitsType::max).toString()
> > +                  << " Step:" << Q(T(1)).value()
> > +                  << std::endl;
> > +
> > +             if (Q::TraitsType::min > Q::TraitsType::max) {
> > +                     cerr << "    *** " << type
> > +                          << " Min (" << Q::TraitsType::min
> > +                          << ") must be less than max ("
> > +                          << Q::TraitsType::max << ")" << std::endl;
> > +                     return 1;
> 
> Is the return value checked anywhere? I think this check is something that
> could belong to a static_assert somewhere, possibly in `Quantized`.

I think this caught issues when I was developing and got the
signed/unsigned types wrong - but I don't expect it to come up again now
it's all sorted. A static assert is reasonable though.

> 
> > +             }
> > +
> > +             return 0;
> > +     }
> > +
> > +     int testFixedPointQuantizers()
> > +     {
> > +             unsigned int fails = 0;
> > +
> > +             /* clang-format off */
> > +
> > +             /* Q1_7(-1 .. 0.992188)  Min: [0x80:-1] -- Max: [0x7f:0.992188] Step:0.0078125*/
> > +             fails += introduce<Q1_7>("Q1_7");

Like here I think - but I'll make introduce return void.

> > +             fails += quantizedCheck<Q1_7>(-1.000f, 0b1'0000000, -1.0f);             /* Min */
> > +             fails += quantizedCheck<Q1_7>(-0.992f, 0b1'0000001, -0.992188f);        /* Min + 1 step */
> > +             fails += quantizedCheck<Q1_7>(-0.006f, 0b1'1111111, -0.0078125f);       /* -1 step */
> > +             fails += quantizedCheck<Q1_7>( 0.000f, 0b0'0000000,  0.0f);             /* Zero */
> > +             fails += quantizedCheck<Q1_7>( 0.008f, 0b0'0000001,  0.0078125f);       /* +1 step */
> > +             fails += quantizedCheck<Q1_7>( 0.992f, 0b0'1111111,  0.992188f);        /* Max */
> > +
> > +             /* UQ1_7(0 .. 1.99219)  Min: [0x00:0] -- Max: [0xff:1.99219] Step:0.0078125 */
> > +             fails += introduce<UQ1_7>("UQ1_7");
> > +             fails += quantizedCheck<UQ1_7>(0.0f,   0b0'0000000, 0.0f);              /* Min / Zero */
> > +             fails += quantizedCheck<UQ1_7>(1.0f,   0b1'0000000, 1.0f);              /* Mid */
> > +             fails += quantizedCheck<UQ1_7>(1.992f, 0b1'1111111, 1.99219f);          /* Max */
> > +
> > +             /* Q12.4(-2048 .. 2047.94)  Min: [0x8000:-2048] -- Max: [0x7fff:2047.94] Step:0.0625 */
> > +             introduce<Q12_4>("Q12_4");
> > +             fails += quantizedCheck<Q12_4>(0.0f, 0b000000000000'0000, 0.0f);
> > +             fails += quantizedCheck<Q12_4>(7.5f, 0b000000000111'1000, 7.5f);
> > +
> > +             /* UQ12_4(0 .. 4095.94)  Min: [0x0000:0] -- Max: [0xffff:4095.94] Step:0.0625 */
> > +             introduce<UQ12_4>("UQ12_4");
> > +             fails += quantizedCheck<UQ12_4>(0.0f, 0b000000000000'0000, 0.0f);
> > +             fails += quantizedCheck<UQ12_4>(7.5f, 0b000000000111'1000, 7.5f);
> > +
> > +             /* Validate that exceeding limits clamps to type range */
> > +             cerr << std::endl << "Range validation:" << std::endl;
> > +             fails += quantizedCheck<Q1_7>(-100.0f, 0b1'0000000, -1.0f);
> > +             fails += quantizedCheck<Q1_7>(+100.0f, 0b0'1111111, 0.992188f);
> > +             fails += quantizedCheck<UQ1_7>(-100.0f, 0b0'0000000, 0.0f);
> > +             fails += quantizedCheck<UQ1_7>(+100.0f, 0b1'1111111, 1.99219f);
> > +
> > +             /* clang-format on */
> > +
> > +             std::cerr << std::endl;
> > +
> > +             if (fails > 0) {
> > +                     cerr << "Fixed point quantizer tests failed: "
> > +                          << std::dec << fails << " failures." << std::endl;
> >                       return TestFail;
> > +             }
> >   
> >               return TestPass;
> >       }
> > +
> > +     int run()
> > +     {
> > +             unsigned int fails = 0;
> > +
> > +             /* fixed point conversion test */
> > +             if (testFixedPoint() != TestPass)
> > +                     fails++;
> > +
> > +             if (testFixedPointQuantizers() != TestPass)
> > +                     fails++;
> > +
> > +             return fails ? TestFail : TestPass;
> > +     }
> >   };
> >   
> >   TEST_REGISTER(FixedPointUtilsTest)
>
Laurent Pinchart Nov. 19, 2025, 4:31 a.m. UTC | #4
On Fri, Nov 14, 2025 at 12:54:08AM +0000, Kieran Bingham wrote:
> Validate the new fixed-point Quantized types with tests covering Q1.7,
> UQ1.7, Q12.4 and UQ12.4 types.
> 
> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> 
> ---
> v3:
> - Rename quantized_type to QuantizedType
> 
>  test/ipa/libipa/fixedpoint.cpp | 120 +++++++++++++++++++++++++++++++--
>  1 file changed, 116 insertions(+), 4 deletions(-)
> 
> diff --git a/test/ipa/libipa/fixedpoint.cpp b/test/ipa/libipa/fixedpoint.cpp
> index 99eb662ddf4e..935412771851 100644
> --- a/test/ipa/libipa/fixedpoint.cpp
> +++ b/test/ipa/libipa/fixedpoint.cpp
> @@ -5,12 +5,14 @@
>   * Fixed / Floating point utility tests
>   */
>  
> +#include "../src/ipa/libipa/fixedpoint.h"
> +
>  #include <cmath>
>  #include <iostream>
>  #include <map>
>  #include <stdint.h>
>  
> -#include "../src/ipa/libipa/fixedpoint.h"
> +#include <libcamera/base/utils.h>
>  
>  #include "test.h"
>  
> @@ -95,14 +97,124 @@ protected:
>  		return TestPass;
>  	}
>  
> -	int run()
> +	template<typename Q>
> +	int quantizedCheck(float input, typename Q::QuantizedType expected, float value)
>  	{
> -		/* fixed point conversion test */
> -		if (testFixedPoint() != TestPass)
> +		Q q(input);
> +		using T = typename Q::QuantizedType;
> +
> +		cerr << "  Checking " << input << " == " << q.toString() << std::endl;

You mix qualified and unqualified cout/cerr through the file. Let's
qualify them all.

> +
> +		T quantized = q.quantized();
> +		if (quantized != expected) {
> +			cerr << "    ** Q Expected " << input
> +			     << " to quantize to " << utils::hex(expected)
> +			     << ", got " << utils::hex(quantized)
> +			     << " - (" << q.toString() << ")"
> +			     << std::endl;
> +			return 1;
> +		}
> +
> +		if ((std::abs(q.value() - value)) > 0.0001f) {
> +			cerr << "    ** V Expected " << input
> +			     << " to quantize to " << value
> +			     << ", got " << q.value()
> +			     << " - (" << q.toString() << ")"
> +			     << std::endl;
> +			return 1;
> +		}
> +
> +		return 0;
> +	}
> +
> +	template<typename Q>
> +	int introduce(std::string type)
> +	{
> +		using T = typename Q::QuantizedType;
> +
> +		std::cerr << std::endl;
> +
> +		cerr << type << "(" << Q::TraitsType::min << " .. " << Q::TraitsType::max << ") "
> +		     << " Min: " << Q(Q::TraitsType::min).toString()
> +		     << " -- Max: " << Q(Q::TraitsType::max).toString()
> +		     << " Step:" << Q(T(1)).value()
> +		     << std::endl;

This seems more suitable for std::cout than cerr.

> +
> +		if (Q::TraitsType::min > Q::TraitsType::max) {
> +			cerr << "    *** " << type
> +			     << " Min (" << Q::TraitsType::min
> +			     << ") must be less than max ("
> +			     << Q::TraitsType::max << ")" << std::endl;
> +			return 1;
> +		}
> +
> +		return 0;
> +	}
> +
> +	int testFixedPointQuantizers()
> +	{
> +		unsigned int fails = 0;
> +
> +		/* clang-format off */
> +
> +		/* Q1_7(-1 .. 0.992188)  Min: [0x80:-1] -- Max: [0x7f:0.992188] Step:0.0078125*/
> +		fails += introduce<Q1_7>("Q1_7");
> +		fails += quantizedCheck<Q1_7>(-1.000f, 0b1'0000000, -1.0f);		/* Min */
> +		fails += quantizedCheck<Q1_7>(-0.992f, 0b1'0000001, -0.992188f);	/* Min + 1 step */
> +		fails += quantizedCheck<Q1_7>(-0.006f, 0b1'1111111, -0.0078125f);	/* -1 step */
> +		fails += quantizedCheck<Q1_7>( 0.000f, 0b0'0000000,  0.0f);		/* Zero */
> +		fails += quantizedCheck<Q1_7>( 0.008f, 0b0'0000001,  0.0078125f);	/* +1 step */
> +		fails += quantizedCheck<Q1_7>( 0.992f, 0b0'1111111,  0.992188f);	/* Max */
> +
> +		/* UQ1_7(0 .. 1.99219)  Min: [0x00:0] -- Max: [0xff:1.99219] Step:0.0078125 */
> +		fails += introduce<UQ1_7>("UQ1_7");
> +		fails += quantizedCheck<UQ1_7>(0.0f,   0b0'0000000, 0.0f);		/* Min / Zero */
> +		fails += quantizedCheck<UQ1_7>(1.0f,   0b1'0000000, 1.0f);		/* Mid */
> +		fails += quantizedCheck<UQ1_7>(1.992f, 0b1'1111111, 1.99219f);		/* Max */
> +
> +		/* Q12.4(-2048 .. 2047.94)  Min: [0x8000:-2048] -- Max: [0x7fff:2047.94] Step:0.0625 */
> +		introduce<Q12_4>("Q12_4");
> +		fails += quantizedCheck<Q12_4>(0.0f, 0b000000000000'0000, 0.0f);
> +		fails += quantizedCheck<Q12_4>(7.5f, 0b000000000111'1000, 7.5f);
> +
> +		/* UQ12_4(0 .. 4095.94)  Min: [0x0000:0] -- Max: [0xffff:4095.94] Step:0.0625 */
> +		introduce<UQ12_4>("UQ12_4");
> +		fails += quantizedCheck<UQ12_4>(0.0f, 0b000000000000'0000, 0.0f);
> +		fails += quantizedCheck<UQ12_4>(7.5f, 0b000000000111'1000, 7.5f);
> +
> +		/* Validate that exceeding limits clamps to type range */
> +		cerr << std::endl << "Range validation:" << std::endl;
> +		fails += quantizedCheck<Q1_7>(-100.0f, 0b1'0000000, -1.0f);
> +		fails += quantizedCheck<Q1_7>(+100.0f, 0b0'1111111, 0.992188f);
> +		fails += quantizedCheck<UQ1_7>(-100.0f, 0b0'0000000, 0.0f);
> +		fails += quantizedCheck<UQ1_7>(+100.0f, 0b1'1111111, 1.99219f);
> +
> +		/* clang-format on */
> +
> +		std::cerr << std::endl;

std::cout here too.

> +
> +		if (fails > 0) {
> +			cerr << "Fixed point quantizer tests failed: "
> +			     << std::dec << fails << " failures." << std::endl;
>  			return TestFail;
> +		}
>  
>  		return TestPass;
>  	}
> +
> +	int run()
> +	{
> +		unsigned int fails = 0;
> +
> +		/* fixed point conversion test */
> +		if (testFixedPoint() != TestPass)
> +			fails++;
> +
> +		if (testFixedPointQuantizers() != TestPass)
> +			fails++;
> +
> +		return fails ? TestFail : TestPass;
> +	}
>  };
>  
>  TEST_REGISTER(FixedPointUtilsTest)

Patch
diff mbox series

diff --git a/test/ipa/libipa/fixedpoint.cpp b/test/ipa/libipa/fixedpoint.cpp
index 99eb662ddf4e..935412771851 100644
--- a/test/ipa/libipa/fixedpoint.cpp
+++ b/test/ipa/libipa/fixedpoint.cpp
@@ -5,12 +5,14 @@ 
  * Fixed / Floating point utility tests
  */
 
+#include "../src/ipa/libipa/fixedpoint.h"
+
 #include <cmath>
 #include <iostream>
 #include <map>
 #include <stdint.h>
 
-#include "../src/ipa/libipa/fixedpoint.h"
+#include <libcamera/base/utils.h>
 
 #include "test.h"
 
@@ -95,14 +97,124 @@  protected:
 		return TestPass;
 	}
 
-	int run()
+	template<typename Q>
+	int quantizedCheck(float input, typename Q::QuantizedType expected, float value)
 	{
-		/* fixed point conversion test */
-		if (testFixedPoint() != TestPass)
+		Q q(input);
+		using T = typename Q::QuantizedType;
+
+		cerr << "  Checking " << input << " == " << q.toString() << std::endl;
+
+		T quantized = q.quantized();
+		if (quantized != expected) {
+			cerr << "    ** Q Expected " << input
+			     << " to quantize to " << utils::hex(expected)
+			     << ", got " << utils::hex(quantized)
+			     << " - (" << q.toString() << ")"
+			     << std::endl;
+			return 1;
+		}
+
+		if ((std::abs(q.value() - value)) > 0.0001f) {
+			cerr << "    ** V Expected " << input
+			     << " to quantize to " << value
+			     << ", got " << q.value()
+			     << " - (" << q.toString() << ")"
+			     << std::endl;
+			return 1;
+		}
+
+		return 0;
+	}
+
+	template<typename Q>
+	int introduce(std::string type)
+	{
+		using T = typename Q::QuantizedType;
+
+		std::cerr << std::endl;
+
+		cerr << type << "(" << Q::TraitsType::min << " .. " << Q::TraitsType::max << ") "
+		     << " Min: " << Q(Q::TraitsType::min).toString()
+		     << " -- Max: " << Q(Q::TraitsType::max).toString()
+		     << " Step:" << Q(T(1)).value()
+		     << std::endl;
+
+		if (Q::TraitsType::min > Q::TraitsType::max) {
+			cerr << "    *** " << type
+			     << " Min (" << Q::TraitsType::min
+			     << ") must be less than max ("
+			     << Q::TraitsType::max << ")" << std::endl;
+			return 1;
+		}
+
+		return 0;
+	}
+
+	int testFixedPointQuantizers()
+	{
+		unsigned int fails = 0;
+
+		/* clang-format off */
+
+		/* Q1_7(-1 .. 0.992188)  Min: [0x80:-1] -- Max: [0x7f:0.992188] Step:0.0078125*/
+		fails += introduce<Q1_7>("Q1_7");
+		fails += quantizedCheck<Q1_7>(-1.000f, 0b1'0000000, -1.0f);		/* Min */
+		fails += quantizedCheck<Q1_7>(-0.992f, 0b1'0000001, -0.992188f);	/* Min + 1 step */
+		fails += quantizedCheck<Q1_7>(-0.006f, 0b1'1111111, -0.0078125f);	/* -1 step */
+		fails += quantizedCheck<Q1_7>( 0.000f, 0b0'0000000,  0.0f);		/* Zero */
+		fails += quantizedCheck<Q1_7>( 0.008f, 0b0'0000001,  0.0078125f);	/* +1 step */
+		fails += quantizedCheck<Q1_7>( 0.992f, 0b0'1111111,  0.992188f);	/* Max */
+
+		/* UQ1_7(0 .. 1.99219)  Min: [0x00:0] -- Max: [0xff:1.99219] Step:0.0078125 */
+		fails += introduce<UQ1_7>("UQ1_7");
+		fails += quantizedCheck<UQ1_7>(0.0f,   0b0'0000000, 0.0f);		/* Min / Zero */
+		fails += quantizedCheck<UQ1_7>(1.0f,   0b1'0000000, 1.0f);		/* Mid */
+		fails += quantizedCheck<UQ1_7>(1.992f, 0b1'1111111, 1.99219f);		/* Max */
+
+		/* Q12.4(-2048 .. 2047.94)  Min: [0x8000:-2048] -- Max: [0x7fff:2047.94] Step:0.0625 */
+		introduce<Q12_4>("Q12_4");
+		fails += quantizedCheck<Q12_4>(0.0f, 0b000000000000'0000, 0.0f);
+		fails += quantizedCheck<Q12_4>(7.5f, 0b000000000111'1000, 7.5f);
+
+		/* UQ12_4(0 .. 4095.94)  Min: [0x0000:0] -- Max: [0xffff:4095.94] Step:0.0625 */
+		introduce<UQ12_4>("UQ12_4");
+		fails += quantizedCheck<UQ12_4>(0.0f, 0b000000000000'0000, 0.0f);
+		fails += quantizedCheck<UQ12_4>(7.5f, 0b000000000111'1000, 7.5f);
+
+		/* Validate that exceeding limits clamps to type range */
+		cerr << std::endl << "Range validation:" << std::endl;
+		fails += quantizedCheck<Q1_7>(-100.0f, 0b1'0000000, -1.0f);
+		fails += quantizedCheck<Q1_7>(+100.0f, 0b0'1111111, 0.992188f);
+		fails += quantizedCheck<UQ1_7>(-100.0f, 0b0'0000000, 0.0f);
+		fails += quantizedCheck<UQ1_7>(+100.0f, 0b1'1111111, 1.99219f);
+
+		/* clang-format on */
+
+		std::cerr << std::endl;
+
+		if (fails > 0) {
+			cerr << "Fixed point quantizer tests failed: "
+			     << std::dec << fails << " failures." << std::endl;
 			return TestFail;
+		}
 
 		return TestPass;
 	}
+
+	int run()
+	{
+		unsigned int fails = 0;
+
+		/* fixed point conversion test */
+		if (testFixedPoint() != TestPass)
+			fails++;
+
+		if (testFixedPointQuantizers() != TestPass)
+			fails++;
+
+		return fails ? TestFail : TestPass;
+	}
 };
 
 TEST_REGISTER(FixedPointUtilsTest)