From patchwork Thu Feb 19 15:05:05 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 26201 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 AB882C0DA4 for ; Thu, 19 Feb 2026 15:05:22 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 26DF662268; Thu, 19 Feb 2026 16:05:16 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="syVmGh7b"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 84C8262255 for ; Thu, 19 Feb 2026 16:05:09 +0100 (CET) Received: from ping.linuxembedded.co.uk (cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 549F11023; Thu, 19 Feb 2026 16:04:16 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1771513456; bh=OLNJoiHLmmmIIuIvF7pWFX26DPsb+CGOkVU0InYRLUE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=syVmGh7bAO4VBh2bm9/ogXKXIymshZLCHYQ1KhzyJmeupy/zK3U+BCKFRZ8Uewxxr Jiv1J8VIMJTVsKsce/L/T3AdnThyhzCzG5H5Es3T/k7pSw3fr0cVPywOo1q39V32uA BHjOj751vh4b3XFYZuVjBEdAGKNjOoABF3o+3wuk= From: Kieran Bingham Date: Thu, 19 Feb 2026 15:05:05 +0000 Subject: [PATCH v8 04/15] ipa: libipa: Provide fixed point quantized traits MIME-Version: 1.0 Message-Id: <20260219-kbingham-quantizers-v8-4-2b6ff68ead26@ideasonboard.com> References: <20260219-kbingham-quantizers-v8-0-2b6ff68ead26@ideasonboard.com> In-Reply-To: <20260219-kbingham-quantizers-v8-0-2b6ff68ead26@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Kieran Bingham , Isaac Scott , Paul Elder , Stefan Klug X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1771513507; l=7570; i=kieran.bingham@ideasonboard.com; s=20260207; h=from:subject:message-id; bh=OLNJoiHLmmmIIuIvF7pWFX26DPsb+CGOkVU0InYRLUE=; b=a4oNA3kjlrp/bvUyt+hSgxgRYBddct6pV9AXOi37QMxp9Df6cHFC8QIJVNxy7RGM28XCbYkeS Bq1fOO3ViBxB/Hk3HfUOkkwrkZRcoiBnbbcOvd8m7jlL4ymZfIfGnfI X-Developer-Key: i=kieran.bingham@ideasonboard.com; a=ed25519; pk=FVXKN7YuwHc6UtbRUeTMAmranfsQomA+vnilfglWdaY= 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" Extend the new Quantized type infrastructure by providing a FixedPointQTraits template. This allows construction of fixed point types with a Quantized storage that allows easy reading of both the underlying quantized type value and a floating point representation of that same value. Reviewed-by: Isaac Scott Reviewed-by: Paul Elder Reviewed-by: Stefan Klug Signed-off-by: Kieran Bingham --- src/ipa/libipa/fixedpoint.cpp | 98 +++++++++++++++++++++++++++++++++++++++++++ src/ipa/libipa/fixedpoint.h | 74 ++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) diff --git a/src/ipa/libipa/fixedpoint.cpp b/src/ipa/libipa/fixedpoint.cpp index 6b698fc5d680..b581ca8453ef 100644 --- a/src/ipa/libipa/fixedpoint.cpp +++ b/src/ipa/libipa/fixedpoint.cpp @@ -37,6 +37,104 @@ namespace ipa { * \return The converted value */ +/** + * \struct libcamera::ipa::FixedPointQTraits + * \brief Traits type implementing fixed-point quantization conversions + * + * The FixedPointQTraits structure defines a policy for mapping floating-point + * values to and from fixed-point 2's complement integer representations. It is + * parameterised by the number of integer bits \a I, fractional bits \a F, and + * the integral storage type \a T. The traits are used with Quantized to + * create a quantized type that stores both the fixed-point representation and + * the corresponding floating-point value. + * + * The signedness of the type is determined by the signedness of \a T. For + * signed types, the number of integer bits in \a I includes the sign bit. + * + * Storage is determined by the total number of bits \a (I + F) and is + * automatically selected, but the internal storage type is always an unsigned + * integer to guarantee against sign extension when storing quantized values + * in registers. + * + * The trait exposes compile-time constants describing the bit layout, limits, + * and scaling factors used in the fixed-point representation. + * + * \tparam I Number of integer bits + * \tparam F Number of fractional bits + * \tparam T Integral type used to store the quantized value + */ + +/** + * \typedef FixedPointQTraits::QuantizedType + * \brief The integral storage type used for the fixed-point representation + */ + +/** + * \var FixedPointQTraits::qMin + * \brief Minimum representable quantized integer value + * + * This corresponds to the most negative value for signed formats or zero for + * unsigned formats. + */ + +/** + * \var FixedPointQTraits::qMax + * \brief Maximum representable quantized integer value + */ + +/** + * \var FixedPointQTraits::min + * \brief Minimum representable floating-point value corresponding to qMin + */ + +/** + * \var FixedPointQTraits::max + * \brief Maximum representable floating-point value corresponding to qMax + */ + +/** + * \fn FixedPointQTraits::fromFloat(float v) + * \brief Convert a floating-point value to a fixed-point integer + * \param[in] v The floating-point value to be converted + * \return The quantized fixed-point integer representation + * + * The conversion first clamps the floating-point input \a v to the range [min, + * max] and then rounds it to the nearest fixed-point value according to the + * scaling factor defined by the number of fractional bits F. + */ + +/** + * \fn FixedPointQTraits::toFloat(QuantizedType q) + * \brief Convert a fixed-point integer to a floating-point value + * \param[in] q The fixed-point integer value to be converted + * \return The corresponding floating-point value + * + * The conversion sign-extends the integer value if required and divides by the + * scaling factor defined by the number of fractional bits F. + */ + +/** + * \typedef Q + * \brief Define a signed fixed-point quantized type with automatic storage width + * \tparam I The number of integer bits + * \tparam F The number of fractional bits + * + * This alias defines a signed fixed-point quantized type using the + * \ref FixedPointQTraits trait and a suitable signed integer storage type + * automatically selected based on the total number of bits \a (I + F). + */ + +/** + * \typedef UQ + * \brief Define an unsigned fixed-point quantized type with automatic storage width + * \tparam I The number of integer bits + * \tparam F The number of fractional bits + * + * This alias defines an unsigned fixed-point quantized type using the + * \ref FixedPointQTraits trait and a suitable unsigned integer storage type + * automatically selected based on the total number of bits \a (I + F). + */ + } /* namespace ipa */ } /* namespace libcamera */ diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h index aeb9bce3269b..df685e852bff 100644 --- a/src/ipa/libipa/fixedpoint.h +++ b/src/ipa/libipa/fixedpoint.h @@ -10,6 +10,8 @@ #include #include +#include "quantized.h" + namespace libcamera { namespace ipa { @@ -63,6 +65,78 @@ constexpr R fixedToFloatingPoint(T number) return static_cast(t) / static_cast(1 << F); } +template +struct FixedPointQTraits { +private: + static_assert(std::is_integral_v, "FixedPointQTraits: T must be integral"); + using UT = std::make_unsigned_t; + + static constexpr unsigned int bits = I + F; + static_assert(bits <= sizeof(UT) * 8, "FixedPointQTraits: too many bits for type UT"); + + /* + * If fixed point storage is required with more than 24 bits, consider + * updating this implementation to use double-precision floating point. + */ + static_assert(bits <= 24, "Floating point precision may be insufficient for more than 24 bits"); + + static constexpr UT bitMask = bits < sizeof(UT) * 8 + ? (UT{ 1 } << bits) - 1 + : ~UT{ 0 }; + +public: + using QuantizedType = UT; + + static constexpr UT qMin = std::is_signed_v + ? -(UT{ 1 } << (bits - 1)) + : 0; + + static constexpr UT qMax = std::is_signed_v + ? (UT{ 1 } << (bits - 1)) - 1 + : bitMask; + + static constexpr float toFloat(QuantizedType q) + { + return fixedToFloatingPoint(q); + } + + static constexpr float min = fixedToFloatingPoint(static_cast(qMin)); + static constexpr float max = fixedToFloatingPoint(static_cast(qMax)); + + static_assert(min < max, "FixedPointQTraits: Minimum must be less than maximum"); + + /* Conversion functions required by Quantized */ + static QuantizedType fromFloat(float v) + { + v = std::clamp(v, min, max); + return floatingToFixedPoint(v); + } +}; + +namespace details { + +template +constexpr auto qtype() +{ + static_assert(Bits <= 32, + "Unsupported number of bits for quantized type"); + + if constexpr (Bits <= 8) + return int8_t(); + else if constexpr (Bits <= 16) + return int16_t(); + else if constexpr (Bits <= 32) + return int32_t(); +} + +} /* namespace details */ + +template +using Q = Quantized())>>; + +template +using UQ = Quantized())>>>; + } /* namespace ipa */ } /* namespace libcamera */