From patchwork Sun Oct 26 23:30:38 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 24824 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id D6068BE080 for ; Sun, 26 Oct 2025 23:30:59 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5AEE4606F8; Mon, 27 Oct 2025 00:30:57 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="gN822ZId"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id EAE8D606E0 for ; Mon, 27 Oct 2025 00:30:53 +0100 (CET) Received: from charm.hippo-penny.ts.net (unknown [209.38.108.23]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 38CE4E77; Mon, 27 Oct 2025 00:29:06 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761521346; bh=1FcaQEB87OPnpDmcTCZcyq3suw1t0sx0KOfWaRXpDsw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gN822ZId2NSBWy5bEOP1F2N8efdTHaLGqDTpOEWZgz8N4Ho8tiyNWocAPGAt7XYK/ CS0NqUlVKFifCNglucxdUQAnlX7PjM6qAnxmRQYJ1kIREiXzq64gRe7iVwFdmZN08t k+dAte/yEeZng0x3JNpFFIaDL9XzP4wLlZuw+iZg= From: Kieran Bingham To: libcamera devel Cc: Kieran Bingham Subject: [PATCH 1/6] libipa: Provide a Quantized type and Quantizer support Date: Sun, 26 Oct 2025 23:30:38 +0000 Message-ID: <20251026233048.175689-2-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20251026233048.175689-1-kieran.bingham@ideasonboard.com> References: <20251026233048.175689-1-kieran.bingham@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" 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 --- 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 diff --git a/src/ipa/libipa/meson.build b/src/ipa/libipa/meson.build index 660be94054fa..804289778f72 100644 --- a/src/ipa/libipa/meson.build +++ b/src/ipa/libipa/meson.build @@ -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('..') diff --git a/src/ipa/libipa/quantized.cpp b/src/ipa/libipa/quantized.cpp new file mode 100644 index 000000000000..0078c6f740a9 --- /dev/null +++ b/src/ipa/libipa/quantized.cpp @@ -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 &other) const noexcept + * \brief Compare two quantized values for equality + * + * Two \c Quantized objects are equal if their quantized values are equal. + * + * \param other The \c Quantized to compare with + * \return \c true if equal, \c false otherwise + */ + +/** + * \fn bool Quantized::operator!=(const Quantized &other) const noexcept + * \brief Compare two quantized values for inequality + * + * Two \c Quantized objects are not equal if their quantized values differ. + * + * \param other The \c Quantized 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 using a floating-point input + * + * This function updates both the quantized and floating-point + * representations stored in the Quantized, 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 using a quantized input + * + * This function updates both the quantized and floating-point + * representations stored in the Quantized. + * + * \param val The quantized value to set + */ + +} /* namespace ipa */ + +} /* namespace libcamera */ diff --git a/src/ipa/libipa/quantized.h b/src/ipa/libipa/quantized.h new file mode 100644 index 000000000000..1c1963cf0848 --- /dev/null +++ b/src/ipa/libipa/quantized.h @@ -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 +#include +#include +#include + +namespace libcamera { + +namespace ipa { + +template +class Quantizer; + +template +struct Quantized { + static_assert(std::is_arithmetic_v, "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; + std::ostringstream oss; + + oss << "Q:0x" << std::hex << std::uppercase << std::setw(sizeof(T) * 2) + << std::setfill('0'); + + if constexpr (std::is_unsigned_v) { + oss << static_cast(quantized_); + } else { + oss << static_cast(static_cast(quantized_)); + } + + oss << " F:" << value_; + + return oss.str(); + } + + bool operator==(const Quantized &other) const noexcept + { + return quantized_ == other.quantized_ && value_ == other.value_; + } + + bool operator!=(const Quantized &other) const noexcept + { + return !(*this == other); + } + +protected: + T quantized_{}; + float value_{}; +}; + +template +class Quantizer : public Quantized +{ +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 */