@@ -17,6 +17,7 @@ libipa_headers = files([
'lux.h',
'module.h',
'pwl.h',
+ 'quantized.h',
])
libipa_sources = files([
@@ -36,6 +37,7 @@ libipa_sources = files([
'lux.cpp',
'module.cpp',
'pwl.cpp',
+ 'quantized.cpp',
])
libipa_includes = include_directories('..')
new file mode 100644
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2025, Ideas On Board.
+ *
+ * Helper class to manage conversions between floating point types and quantized
+ * storage and representation of those values.
+ */
+
+#include "quantized.h"
+
+/**
+ * \file quantized.h
+ * \brief Quantized storage and Quantizer representations
+ */
+
+namespace libcamera {
+
+namespace ipa {
+
+/**
+ * \struct Quantized
+ * \brief Quantized stores both an internal and quantized representation of a value
+ * \tparam T The quantized type (e.g., uint16_t, int16_t).
+ *
+ * This struct provides read-only access to both representations of the value.
+ * It does not perform any conversions or quantization logic itself. This must
+ * be handled externally by a quantizer that knows the appropriate behaviour.
+ *
+ * This type can be used to store values that need to be represented in both
+ * fixed-point or integer (for hardware interfaces) and floating-point (for user
+ * facing interfaces)
+ *
+ * It is intended to be used in shared context structures where both
+ * hardware-level and software-level representations of a value are required.
+ */
+
+/**
+ * \fn float Quantized::value() const noexcept
+ * \brief Get the floating-point representation of the quantized value
+ *
+ * This function returns the floating-point form that was either directly assigned
+ * or computed from the quantized value.
+ *
+ * \return The floating-point value
+ */
+
+/**
+ * \fn T Quantized::quantized() const noexcept
+ * \brief Get the raw quantized representation of the value
+ *
+ * This function returns the internal quantized value (e.g. \c uint8_t or \c int16_t),
+ * which is typically used for hardware-level programming or serialization.
+ *
+ * \return The quantized value of type \c T
+ */
+
+/**
+ * \fn std::string Quantized::toString() const
+ * \brief Generate a string representation of the quantized and float values
+ *
+ * Produces a human-readable string including both the quantized and floating-point
+ * values, typically in the format: "Q:0xXX F:float".
+ *
+ * \return A formatted string representing the internal state
+ */
+
+/**
+ * \fn bool Quantized::operator==(const Quantized<T> &other) const noexcept
+ * \brief Compare two quantized values for equality
+ *
+ * Two \c Quantized<T> objects are equal if their quantized values are equal.
+ *
+ * \param other The \c Quantized<T> to compare with
+ * \return \c true if equal, \c false otherwise
+ */
+
+/**
+ * \fn bool Quantized::operator!=(const Quantized<T> &other) const noexcept
+ * \brief Compare two quantized values for inequality
+ *
+ * Two \c Quantized<T> objects are not equal if their quantized values differ.
+ *
+ * \param other The \c Quantized<T> to compare with
+ * \return \c true if not equal, \c false otherwise
+ */
+
+/**
+ * \var Quantized::quantized_
+ * \brief The raw quantized value
+ *
+ * This member stores the fixed-point or integer representation of the value, typically
+ * used for interfacing with hardware or protocols that require compact formats.
+ *
+ * It must only be updated or accessed through a Quantizer in conjunction with
+ * corresponding updates to \c Quantized::value_.
+ */
+
+/**
+ * \var Quantized::value_
+ * \brief The floating-point representation of the quantized value
+ *
+ * This member holds the floating-point equivalent of the quantized value, usually
+ * for use in calculations or presentation to higher-level software components.
+ *
+ * It must only be updated or accessed through a Quantizer in conjunction with
+ * corresponding updates to \c Quantized::quantized_.
+ */
+
+/**
+ * \class Quantizer
+ * \brief Interface for converting between floating-point and quantized types
+ * \tparam T The quantized type (e.g., uint16_t, int16_t).
+ *
+ * This abstract class defines the interface for quantizers that handle
+ * conversions between floating-point values and their quantized representations.
+ * Specific quantization handlers should implement this interface and provide
+ * the toFloat and fromFloat methods specifically for their types.
+ */
+
+/**
+ * \typedef Quantizer::qType
+ * \brief The underlying quantized type used by the quantizer
+ *
+ * This alias exposes the quantized type (e.g. \c uint8_t or \c int16_t) used internally
+ * by the \c Quantizer, which is helpful in template and debug contexts.
+ */
+
+/**
+ * \fn Quantizer::fromFloat(T val)
+ * \brief Convert a floating-point value to its quantized representation
+ *
+ * \param val The floating-point value
+ * \return The quantized equivalent
+ */
+
+/**
+ * \fn Quantizer::toFloat(T val)
+ * \brief Convert a quantized value to its floating-point representation
+ *
+ * \param val The quantized value
+ * \return The floating-point equivalent
+ */
+
+/**
+ * \fn Quantizer::set(float val)
+ * \brief Set the value of a Quantized<T> using a floating-point input
+ *
+ * This function updates both the quantized and floating-point
+ * representations stored in the Quantized<T>, storing the quantized
+ * version of the float input.
+ *
+ * \param val The floating-point value to set
+ */
+
+/**
+ * \fn Quantizer::set(T val)
+ * \brief Set the value of a Quantized<T> using a quantized input
+ *
+ * This function updates both the quantized and floating-point
+ * representations stored in the Quantized<T>.
+ *
+ * \param val The quantized value to set
+ */
+
+} /* namespace ipa */
+
+} /* namespace libcamera */
new file mode 100644
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2025, Ideas On Board.
+ *
+ * Helper class to manage conversions between floating point types and quantized
+ * storage and representation of those values.
+ */
+
+#pragma once
+
+#include <iomanip>
+#include <sstream>
+#include <stdint.h>
+#include <type_traits>
+
+namespace libcamera {
+
+namespace ipa {
+
+template<typename Q>
+class Quantizer;
+
+template<typename T>
+struct Quantized {
+ static_assert(std::is_arithmetic_v<T>, "Quantized: T must be an arithmetic type");
+
+ float value() const noexcept { return value_; }
+ T quantized() const noexcept { return quantized_; }
+
+ std::string toString() const
+ {
+ using UT = std::make_unsigned_t<T>;
+ std::ostringstream oss;
+
+ oss << "Q:0x" << std::hex << std::uppercase << std::setw(sizeof(T) * 2)
+ << std::setfill('0');
+
+ if constexpr (std::is_unsigned_v<T>) {
+ oss << static_cast<unsigned>(quantized_);
+ } else {
+ oss << static_cast<unsigned>(static_cast<UT>(quantized_));
+ }
+
+ oss << " F:" << value_;
+
+ return oss.str();
+ }
+
+ bool operator==(const Quantized<T> &other) const noexcept
+ {
+ return quantized_ == other.quantized_ && value_ == other.value_;
+ }
+
+ bool operator!=(const Quantized<T> &other) const noexcept
+ {
+ return !(*this == other);
+ }
+
+protected:
+ T quantized_{};
+ float value_{};
+};
+
+template<typename T>
+class Quantizer : public Quantized<T>
+{
+public:
+ using qType = T;
+
+ virtual ~Quantizer() = default;
+
+ virtual T fromFloat(float val) const = 0;
+ virtual float toFloat(T val) const = 0;
+
+ void set(float val)
+ {
+ this->quantized_ = fromFloat(val);
+ this->value_ = toFloat(this->quantized_);
+ }
+
+ void set(T val)
+ {
+ this->quantized_ = val;
+ this->value_ = toFloat(val);
+ }
+};
+
+} /* namespace ipa */
+
+} /* namespace libcamera */
Frequently when handling data in IPA components we must convert and store user interface values which may be floating point values, and perform a specific operation or conversion to quantize this to a hardware value. This value may be to a fixed point type, or more custom code mappings, but in either case it is important to contain both the required hardware value, with it's effective quantized value. Provide a new storage type 'Quantized' which can be read publicly but must only be written through a controller class known as a Quantizer. Quantizers can be customised and specified by the owner of the data object and must implement conversion between floats and the underlying hardware type. Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> --- src/ipa/libipa/meson.build | 2 + src/ipa/libipa/quantized.cpp | 167 +++++++++++++++++++++++++++++++++++ src/ipa/libipa/quantized.h | 90 +++++++++++++++++++ 3 files changed, 259 insertions(+) create mode 100644 src/ipa/libipa/quantized.cpp create mode 100644 src/ipa/libipa/quantized.h