From patchwork Fri Nov 14 00:54:05 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 25031 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 54DA7C3263 for ; Fri, 14 Nov 2025 00:54:55 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 9C6ED60AA6; Fri, 14 Nov 2025 01:54:50 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="BTtBngs8"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A43D86069A for ; Fri, 14 Nov 2025 01:54:48 +0100 (CET) Received: from charm.hippo-penny.ts.net (cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id EFD8A1306; Fri, 14 Nov 2025 01:52:47 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1763081568; bh=ud1HOG88tPSwa2Pk7AE0XFPHaQoaHTjsGpR3GRO/EWk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=BTtBngs8fhpF8LQ7EvsFaUtdAdPEB6EwK4b+Z/SLWXrvmB+/dckGvy3aWJXo4ddVo 5l+32vtaVaaYQC9vSay6Lw3I9E3kZB6ck1X7Gq5hy06iCWMAERiuF6Dqp5hbLYN1zx 52F9lWWs/+a5dYRv0ijybh5Zb9RfrRiLhZEXGcJI= From: Kieran Bingham To: libcamera devel Cc: Kieran Bingham Subject: [PATCH v4 01/21] ipa: libipa: Provide a Quantized data type support Date: Fri, 14 Nov 2025 00:54:05 +0000 Message-ID: <20251114005428.90024-2-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251114005428.90024-1-kieran.bingham@ideasonboard.com> References: <20251114005428.90024-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 its effective quantized value. Provide a new storage type 'Quantized' which can be defined based on a set of type specific Traits to perform the conversions between floats and the underlying hardware type. Signed-off-by: Kieran Bingham --- v3: - adapt string format to [0xff:1.99] style instead of Q:0xff V:1.99 - Clean up comments and copyright - Remove private initialisers - already handled by constructors - Change quantized_type to QuantizedType src/ipa/libipa/meson.build | 2 + src/ipa/libipa/quantized.cpp | 134 +++++++++++++++++++++++++++++++++++ src/ipa/libipa/quantized.h | 78 ++++++++++++++++++++ 3 files changed, 214 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..ef3ae21e9a3b --- /dev/null +++ b/src/ipa/libipa/quantized.cpp @@ -0,0 +1,134 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2025, Ideas On Board Oy + * + * 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 libcamera::ipa::Quantized + * \brief Wrapper that stores a value in both quantized and floating-point form + * \tparam Traits The traits class defining the quantization behaviour + * + * The Quantized struct template provides a thin wrapper around a quantized + * representation of a floating-point value. It uses a traits type \a Traits + * to define the conversion policy between the floating-point domain and the + * quantized integer domain. + * + * Each Quantized instance maintains two synchronized members: + * - the quantized integer representation, and + * - the corresponding floating-point value. + * + * The traits type defines: + * - the integer storage type used for quantization, + * - the static conversion functions \c fromFloat() and \c toFloat(), and + * - optional metadata such as value ranges. + * + * Quantized provides convenient constructors and assignment operators from + * either representation, as well as comparison and string formatting utilities. + */ + +/** + * \typedef Quantized::TraitsType + * \brief The traits policy type defining the quantization behaviour + * + * Exposes the associated traits type used by this Quantized instance. + * This allows external code to refer to constants or metadata defined in + * the traits, such as \c TraitsType::min or \c TraitsType::max. + */ + +/** + * \typedef Quantized::QuantizedType + * \brief The integer type used for the quantized representation + * + * This alias corresponds to \c TraitsType::QuantizedType, as defined by + * the traits class. + */ + +/** + * \fn Quantized::Quantized(float x) + * \brief Construct a Quantized value from a floating-point number + * \param[in] x The floating-point value to be quantized + * + * Converts the floating-point input \a x to its quantized integer + * representation using the associated traits policy, and initializes + * both the quantized and floating-point members. + */ + +/** + * \fn Quantized::Quantized(QuantizedType x) + * \brief Construct a Quantized value from an existing quantized integer + * \param[in] x The quantized integer value + * + * Converts the quantized integer \a x to its corresponding floating-point + * value using the traits policy, and initializes both internal members. + */ + +/** + * \fn Quantized::operator=(float x) + * \brief Assign a floating-point value to the Quantized object + * \param[in] x The floating-point value to assign + * \return A reference to the updated Quantized object + * + * Converts the floating-point value \a x to its quantized integer + * representation using the traits policy and updates both members. + */ + +/** + * \fn Quantized::operator=(QuantizedType x) + * \brief Assign a quantized integer value to the Quantized object + * \param[in] x The quantized integer value to assign + * \return A reference to the updated Quantized object + * + * Converts the quantized integer \a x to its corresponding floating-point + * value using the traits policy and updates both members. + */ + +/** + * \fn Quantized::value() const noexcept + * \brief Retrieve the floating-point representation + * \return The floating-point value corresponding to the quantized value + */ + +/** + * \fn Quantized::quantized() const noexcept + * \brief Retrieve the quantized integer representation + * \return The quantized integer value + */ + +/** + * \fn Quantized::toString() const + * \brief Format the quantized and floating-point values as a string + * \return A string containing the hexadecimal quantized value and its + * floating-point equivalent. + */ + +/** + * \fn Quantized::operator==(const Quantized &other) const noexcept + * \brief Compare two Quantized objects for equality + * \param[in] other The other Quantized object to compare against + * \return True if both objects have the same quantized integer value + */ + +/** + * \fn Quantized::operator!=(const Quantized &other) const noexcept + * \brief Compare two Quantized objects for inequality + * \param[in] other The other Quantized object to compare against + * \return True if the quantized integer values differ + */ + +} /* namespace ipa */ + +} /* namespace libcamera */ diff --git a/src/ipa/libipa/quantized.h b/src/ipa/libipa/quantized.h new file mode 100644 index 000000000000..db1c0d72db86 --- /dev/null +++ b/src/ipa/libipa/quantized.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2025, Ideas On Board Oy + * + * Helper class to manage conversions between floating point types and quantized + * storage and representation of those values. + */ + +#pragma once + +#include +#include +#include +#include + +#include + +namespace libcamera { + +namespace ipa { + +template +struct Quantized { + using TraitsType = Traits; + using QuantizedType = typename Traits::QuantizedType; + static_assert(std::is_arithmetic_v, + "Quantized: QuantizedType must be arithmetic"); + + Quantized() + : Quantized(0.0f) {} + Quantized(float x) { *this = x; } + Quantized(QuantizedType x) { *this = x; } + + Quantized &operator=(float x) + { + quantized_ = Traits::fromFloat(x); + value_ = Traits::toFloat(quantized_); + return *this; + } + + Quantized &operator=(QuantizedType x) + { + value_ = Traits::toFloat(x); + quantized_ = x; + return *this; + } + + float value() const noexcept { return value_; } + QuantizedType quantized() const noexcept { return quantized_; } + + std::string toString() const + { + std::ostringstream oss; + + oss << "[" << utils::hex(quantized_) + << ":" << value_ << "]"; + + return oss.str(); + } + + bool operator==(const Quantized &other) const noexcept + { + return quantized_ == other.quantized_; + } + + bool operator!=(const Quantized &other) const noexcept + { + return !(*this == other); + } + +private: + QuantizedType quantized_; + float value_; +}; + +} /* namespace ipa */ + +} /* namespace libcamera */ From patchwork Fri Nov 14 00:54:06 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 25032 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 E1E47C3263 for ; Fri, 14 Nov 2025 00:54:56 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B196E60AAC; Fri, 14 Nov 2025 01:54:51 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="eYICAGAj"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id DAE43609E0 for ; Fri, 14 Nov 2025 01:54:48 +0100 (CET) Received: from charm.hippo-penny.ts.net (cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 498FD16A8; Fri, 14 Nov 2025 01:52:48 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1763081568; bh=vOK2o8m9OcySiFDcfiv+GDPC5ehrYxHyJ5q47/SHuog=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=eYICAGAjZmzsYQagFQd4Sim9VZuQpMYblnSLiTgv0HvoD06uRS60yJUC+OJxI0Z55 J//eHnpnS+NHQYBs8Jo2TP27bCd80k/Yq7+QuHU4HSDynQO9lc4iWUm4f/meDCDxM6 JbPrJC/OQoGujDkazJjEoENRKCE/Na8XVPrFYb4M= From: Kieran Bingham To: libcamera devel Cc: Kieran Bingham Subject: [PATCH v4 02/21] test: libipa: Add tests for Quantized types Date: Fri, 14 Nov 2025 00:54:06 +0000 Message-ID: <20251114005428.90024-3-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251114005428.90024-1-kieran.bingham@ideasonboard.com> References: <20251114005428.90024-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" Provide use case tests for the Quantized types to ensure construction and usages are consistent and work as expected. Signed-off-by: Kieran Bingham --- 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 +#include +#include +#include +#include + +#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(std::clamp(quantized, -128, 127)); + } + static float toFloat(QuantizedType v) + { + return static_cast(v) / 128.0f; + } +}; + +using BrightnessHueQuantizer = Quantized; + +struct ContrastSaturationTraits { + using QuantizedType = uint8_t; + static constexpr QuantizedType fromFloat(float v) + { + int quantized = std::lround(v * 128.0f); + return static_cast(std::clamp(quantized, 0, 255)); + } + static float toFloat(QuantizedType v) + { + return static_cast(v) / 128.0f; + } +}; + +using ContrastSaturationQuantizer = Quantized; + +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) From patchwork Fri Nov 14 00:54:07 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 25033 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 81673C3263 for ; Fri, 14 Nov 2025 00:54:58 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id EFEA960A8A; Fri, 14 Nov 2025 01:54:52 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="sQKqjYXF"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2B62B6069A for ; Fri, 14 Nov 2025 01:54:49 +0100 (CET) Received: from charm.hippo-penny.ts.net (cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 9774819AD; Fri, 14 Nov 2025 01:52:48 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1763081568; bh=iI4pJjXoTff8rWtLHaq/vvewmwwoZYk8584XcCi+8GU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=sQKqjYXFCjV/Nn+rvGyGy0gW6H1CErkNKkaYbmINaTKrhtJaCqBq+4Ki/wDfy6Irl C40K1hM6G1sV4clMwzaBm5PZJcI45KXwXEmWhpWH2BfsDFwXtJ8KyYOn533Kvcd5VX JKL7GBGjP90F9/qmcX8KaG7+Bd1rJplun0r5fIek= From: Kieran Bingham To: libcamera devel Cc: Kieran Bingham Subject: [PATCH v4 03/21] ipa: libipa: Provide fixed point quantized traits Date: Fri, 14 Nov 2025 00:54:07 +0000 Message-ID: <20251114005428.90024-4-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251114005428.90024-1-kieran.bingham@ideasonboard.com> References: <20251114005428.90024-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" 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. Signed-off-by: Kieran Bingham --- v4: - Assert that the given type has enough bits for the usage - Use unsigned types for calculating qmin/qmax - Reorder toFloat/fromFloat and min/max for future inlining - Make toFloat and fromFloat constexpr src/ipa/libipa/fixedpoint.cpp | 121 ++++++++++++++++++++++++++++++++++ src/ipa/libipa/fixedpoint.h | 45 +++++++++++++ 2 files changed, 166 insertions(+) diff --git a/src/ipa/libipa/fixedpoint.cpp b/src/ipa/libipa/fixedpoint.cpp index 6b698fc5d680..4c3ea33497bf 100644 --- a/src/ipa/libipa/fixedpoint.cpp +++ b/src/ipa/libipa/fixedpoint.cpp @@ -37,6 +37,127 @@ namespace ipa { * \return The converted value */ +/** + * \struct libcamera::ipa::FixedPointQTraits + * \brief Traits type implementing fixed-point quantisation conversions + * + * The FixedPointQTraits structure defines a policy for mapping floating-point + * values to and from fixed-point 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 + * quantised type that stores both the fixed-point representation and the + * corresponding floating-point value. + * + * 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 quantised value + */ + +/** + * \typedef FixedPointQTraits::QuantizedType + * \brief The integral storage type used for the fixed-point representation + */ + +/** + * \typedef FixedPointQTraits::UT + * \brief The unsigned representation of the integral storage + * + * This type definition is to support internal usage only. + */ + +/** + * \var FixedPointQTraits::Bits + * \brief Total number of bits used in the fixed-point format (I + F) + */ + +/** + * \var FixedPointQTraits::BitMask + * \brief Bit mask selecting all valid bits in the fixed-point representation + */ + +/** + * \var FixedPointQTraits::qmin + * \brief Minimum representable quantised integer value + * + * This corresponds to the most negative value for signed formats or zero for + * unsigned formats. + */ + +/** + * \var FixedPointQTraits::qmax + * \brief Maximum representable quantised 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 quantised fixed-point integer representation + * + * The conversion rounds the floating-point input \a v to the nearest integer + * 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 Q1_7 + * \brief 1.7 signed fixed-point quantizer + * + * A Quantized type using 1 bit for the integer part and 7 bits for the + * fractional part, stored in a signed 8-bit integer (\c int8_t). Represents + * values approximately in the range [-1.0, 0.992] with a resolution of 1/128. + */ + +/** + * \typedef UQ1_7 + * \brief 1.7 unsigned fixed-point quantizer + * + * A Quantized type using 1 bit for the integer part and 7 bits for the + * fractional part, stored in an unsigned 8-bit integer (\c uint8_t). Represents + * values in the range [0.0, 1.992] with a resolution of 1/128. + */ + +/** + * \typedef Q12_4 + * \brief 12.4 signed fixed-point quantizer + * + * A Quantized type using 12 bits for the integer part and 4 bits for the + * fractional part, stored in a signed 16-bit integer (\c int16_t). Represents + * values in the range approximately [-2048.0, 2047.9375] with a resolution of + * 1/16. + */ + +/** + * \typedef UQ12_4 + * \brief 12.4 unsigned fixed-point quantizer + * + * A Quantized type using 12 bits for the integer part and 4 bits for the + * fractional part, stored in an unsigned 16-bit integer (\c uint16_t). + * Represents values in the range [0.0, 4095.9375] with a resolution of 1/16. + */ + } /* namespace ipa */ } /* namespace libcamera */ diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h index 709cf50f0fcd..17db8a026502 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 { @@ -60,6 +62,49 @@ constexpr R fixedToFloatingPoint(T number) return static_cast(t) / static_cast(1 << F); } +template +struct FixedPointQTraits { + static_assert(std::is_integral_v, "FixedPointQTraits: T must be integral"); + using QuantizedType = T; + using UT = std::make_unsigned_t; + + static constexpr unsigned int Bits = I + F; + static_assert(Bits <= sizeof(T) * 8, "FixedPointQTraits: too many bits for type T"); + + static constexpr T BitMask = (Bits < sizeof(T) * 8) + ? static_cast((UT{1} << Bits) - 1) + : static_cast(~UT{0}); + + static constexpr T qmin = std::is_signed_v + ? static_cast(-(UT{1} << (Bits - 1))) + : static_cast(0); + + static constexpr T qmax = std::is_signed_v + ? static_cast((UT{1} << (Bits - 1)) - 1) + : static_cast((UT{1} << Bits) - 1); + + static constexpr float toFloat(QuantizedType q) + { + return fixedToFloatingPoint(q); + } + + static constexpr float min = fixedToFloatingPoint(qmin); + static constexpr float max = fixedToFloatingPoint(qmax); + + /* Conversion functions required by Quantized */ + static constexpr QuantizedType fromFloat(float v) + { + v = std::clamp(v, min, max); + return floatingToFixedPoint(v); + } +}; + +using Q1_7 = Quantized>; +using UQ1_7 = Quantized>; + +using Q12_4 = Quantized>; +using UQ12_4 = Quantized>; + } /* namespace ipa */ } /* namespace libcamera */ From patchwork Fri Nov 14 00:54:08 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 25034 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 A64A3C32DB for ; Fri, 14 Nov 2025 00:54:59 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B1A8960AB1; Fri, 14 Nov 2025 01:54:53 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="PXVI2SSY"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6DB79609E0 for ; Fri, 14 Nov 2025 01:54:49 +0100 (CET) Received: from charm.hippo-penny.ts.net (cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E331E19B5; Fri, 14 Nov 2025 01:52:48 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1763081569; bh=n3/3tFyiHOCWPNZM8/CpMp27FgZ2l3bqMyskBwyknmk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=PXVI2SSYPXGiIbSQMyt9LkzulfV1R08+bH/BCSRFQ9GWNwU0jIjIo94Hsfw2/MZOV Rh2fTU1ri7pQNICSSKxVoUzGNfvxS5ojK5d4TnmTMKqWenEMbdO21BkP9Yss/T5Vf5 AX9O76WCc71hnzEZzY2GDRTdtJzoCJgGYb8DBDUA= From: Kieran Bingham To: libcamera devel Cc: Kieran Bingham Subject: [PATCH v4 04/21] test: libipa: Provide FixedPoint Quantized tests Date: Fri, 14 Nov 2025 00:54:08 +0000 Message-ID: <20251114005428.90024-5-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251114005428.90024-1-kieran.bingham@ideasonboard.com> References: <20251114005428.90024-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" 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 --- 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 #include #include #include -#include "../src/ipa/libipa/fixedpoint.h" +#include #include "test.h" @@ -95,14 +97,124 @@ protected: return TestPass; } - int run() + template + 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 + 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"); + fails += quantizedCheck(-1.000f, 0b1'0000000, -1.0f); /* Min */ + fails += quantizedCheck(-0.992f, 0b1'0000001, -0.992188f); /* Min + 1 step */ + fails += quantizedCheck(-0.006f, 0b1'1111111, -0.0078125f); /* -1 step */ + fails += quantizedCheck( 0.000f, 0b0'0000000, 0.0f); /* Zero */ + fails += quantizedCheck( 0.008f, 0b0'0000001, 0.0078125f); /* +1 step */ + fails += quantizedCheck( 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"); + fails += quantizedCheck(0.0f, 0b0'0000000, 0.0f); /* Min / Zero */ + fails += quantizedCheck(1.0f, 0b1'0000000, 1.0f); /* Mid */ + fails += quantizedCheck(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"); + fails += quantizedCheck(0.0f, 0b000000000000'0000, 0.0f); + fails += quantizedCheck(7.5f, 0b000000000111'1000, 7.5f); + + /* UQ12_4(0 .. 4095.94) Min: [0x0000:0] -- Max: [0xffff:4095.94] Step:0.0625 */ + introduce("UQ12_4"); + fails += quantizedCheck(0.0f, 0b000000000000'0000, 0.0f); + fails += quantizedCheck(7.5f, 0b000000000111'1000, 7.5f); + + /* Validate that exceeding limits clamps to type range */ + cerr << std::endl << "Range validation:" << std::endl; + fails += quantizedCheck(-100.0f, 0b1'0000000, -1.0f); + fails += quantizedCheck(+100.0f, 0b0'1111111, 0.992188f); + fails += quantizedCheck(-100.0f, 0b0'0000000, 0.0f); + fails += quantizedCheck(+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) From patchwork Fri Nov 14 00:54:09 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 25035 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 B7366C3263 for ; Fri, 14 Nov 2025 00:55:00 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 9670560AA4; Fri, 14 Nov 2025 01:54:54 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="cPstbPrg"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BCD926069A for ; Fri, 14 Nov 2025 01:54:49 +0100 (CET) Received: from charm.hippo-penny.ts.net (cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 3A9F71A8F; Fri, 14 Nov 2025 01:52:49 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1763081569; bh=1IPDkgGCsPGcPqiWv72Qvyih6Y9GiVwJ1uyjPYY8mSo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=cPstbPrg9CJUaOxr4TJWgMwBM+9l6OjXDg8UTSBmc0RvZ4WNoEXQygvK5DLrqPpuh GuLgu/s2ZTvwnbF6ehl8o4WD7eotM9XEXhzIPhcLqoI4bSFsH3Ss/mMMYOsaZTnZ9C 57cFWB38M73L1AcD7TJr998k6hnhJJmt8MPSp4dQ= From: Kieran Bingham To: libcamera devel Cc: Kieran Bingham Subject: [PATCH v4 05/21] ipa: libipa: fixedpoint: Fix unsigned usage Date: Fri, 14 Nov 2025 00:54:09 +0000 Message-ID: <20251114005428.90024-6-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251114005428.90024-1-kieran.bingham@ideasonboard.com> References: <20251114005428.90024-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" The fixedToFloatingPoint does not support unsigned Q types, and incorrectly sign-extends all values which have the top most bit set in the quantized values. Fix this by ensuring that only signed types perform sign extension, and simplify the calcuation for unsigned types. Convert the storage of the test cases to signed types to correctly represent their intended purpose, to prevent test failures. Signed-off-by: Kieran Bingham --- src/ipa/libipa/fixedpoint.h | 3 +++ test/ipa/libipa/fixedpoint.cpp | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h index 17db8a026502..d97e6d6135ad 100644 --- a/src/ipa/libipa/fixedpoint.h +++ b/src/ipa/libipa/fixedpoint.h @@ -51,6 +51,9 @@ constexpr R fixedToFloatingPoint(T number) static_assert(sizeof(int) >= sizeof(T)); static_assert(I + F <= sizeof(T) * 8); + if constexpr (std::is_unsigned_v) + return static_cast(number) / static_cast(1 << F); + /* * Recreate the upper bits in case of a negative number by shifting the sign * bit from the fixed point to the first bit of the unsigned and then right shifting diff --git a/test/ipa/libipa/fixedpoint.cpp b/test/ipa/libipa/fixedpoint.cpp index 935412771851..3f2d9ac97fe5 100644 --- a/test/ipa/libipa/fixedpoint.cpp +++ b/test/ipa/libipa/fixedpoint.cpp @@ -70,7 +70,7 @@ protected: * The second 7.992 test is to test that unused bits don't * affect the result. */ - std::map testCases = { + std::map testCases = { { 7.992, 0x3ff }, { 0.2, 0x01a }, { -0.2, 0x7e6 }, @@ -83,14 +83,14 @@ protected: int ret; for (const auto &testCase : testCases) { - ret = testSingleFixedPoint<4, 7, uint16_t>(testCase.first, + ret = testSingleFixedPoint<4, 7, int16_t>(testCase.first, testCase.second); if (ret != TestPass) return ret; } /* Special case with a superfluous one in the unused bits */ - ret = testFixedToFloat<4, 7, uint16_t, double>(0xbff, 7.992); + ret = testFixedToFloat<4, 7, int16_t, double>(0xbff, 7.992); if (ret != TestPass) return ret; From patchwork Fri Nov 14 00:54:10 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 25036 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 C4FDBC32DC for ; Fri, 14 Nov 2025 00:55:01 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 598BF60B0B; Fri, 14 Nov 2025 01:54:57 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="rsCgRSrH"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1C33160A9D for ; Fri, 14 Nov 2025 01:54:50 +0100 (CET) Received: from charm.hippo-penny.ts.net (cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 886A51ADF; Fri, 14 Nov 2025 01:52:49 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1763081569; bh=S7W+F4U77Cj+CteLPKx3s8t6Hevdo98NcKTO5qf8Ql8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=rsCgRSrH4l1zNa51u6dmve+8UMohJ9VN7mOFFJhSm6YnZ8xRDwR8FqB/GLk2+Ikuo 22Bq7s+bNMNq3peqzSWATW8emj4MX/292t1ftq19hpmwAVeOdRXaao2ZbVp2UPPRzQ GEkVLu4s7H6LcDLsdSpbzjxVyTv4/1bJrFqLcGcY= From: Kieran Bingham To: libcamera devel Cc: Kieran Bingham Subject: [PATCH v4 06/21] test: libipa: Add Q4.7 type and tests to match existing use case tests Date: Fri, 14 Nov 2025 00:54:10 +0000 Message-ID: <20251114005428.90024-7-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251114005428.90024-1-kieran.bingham@ideasonboard.com> References: <20251114005428.90024-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" The existing fixed point test cases utilise a signed Q4.7 format. Add matching tests covering the same values and extend to validate the full type. Signed-off-by: Kieran Bingham --- v4: - Remove redundant "No Sign Extension" comment test/ipa/libipa/fixedpoint.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/ipa/libipa/fixedpoint.cpp b/test/ipa/libipa/fixedpoint.cpp index 3f2d9ac97fe5..338571e38f68 100644 --- a/test/ipa/libipa/fixedpoint.cpp +++ b/test/ipa/libipa/fixedpoint.cpp @@ -20,6 +20,9 @@ using namespace std; using namespace libcamera; using namespace ipa; +/* Q4_7(-8 .. 7.99219) Min: [0x0400:-8] -- Max: [0x03ff:7.99219] Step:0.0078125 */ +using Q4_7 = Quantized>; + class FixedPointUtilsTest : public Test { protected: @@ -172,6 +175,21 @@ protected: fails += quantizedCheck(1.0f, 0b1'0000000, 1.0f); /* Mid */ fails += quantizedCheck(1.992f, 0b1'1111111, 1.99219f); /* Max */ + /* Q4_7(-8 .. 7.99219) Min: [0x0400:-8] -- Max: [0x03ff:7.99219] Step:0.0078125 */ + introduce("Q4_7"); + fails += quantizedCheck(-8.0f, 0b1000'0000000, -8.0f); /* Min */ + fails += quantizedCheck(-0.008f, 0b1111'1111111, -0.0078125); /* -1 step */ + fails += quantizedCheck( 0.0f, 0b0000'0000000, 0.0f); /* Zero */ + fails += quantizedCheck( 0.008f, 0b0000'0000001, 0.0078125f); /* +1 step */ + fails += quantizedCheck( 7.992f, 0b0111'1111111, 7.99219f); /* Max */ + + /* Retain additional tests from original testFixedPoint() */ + fails += quantizedCheck( 0.2f, 0b0000'0011010, 0.203125f); /* 0x01a */ + fails += quantizedCheck(-0.2f, 0b1111'1100110, -0.203125f); /* 0x7e6 */ + fails += quantizedCheck(-0.8f, 0b1111'0011010, -0.796875f); /* 0x79a */ + fails += quantizedCheck(-0.4f, 0b1111'1001101, -0.398438f); /* 0x7cd */ + fails += quantizedCheck(-1.4f, 0b1110'1001101, -1.39844f); /* 0x74d */ + /* Q12.4(-2048 .. 2047.94) Min: [0x8000:-2048] -- Max: [0x7fff:2047.94] Step:0.0625 */ introduce("Q12_4"); fails += quantizedCheck(0.0f, 0b000000000000'0000, 0.0f); From patchwork Fri Nov 14 00:54:11 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 25037 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 AF4B1C32DB for ; Fri, 14 Nov 2025 00:55:02 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id AC58760AA3; Fri, 14 Nov 2025 01:54:58 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Sl4pNZCQ"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6710960A9E for ; Fri, 14 Nov 2025 01:54:50 +0100 (CET) Received: from charm.hippo-penny.ts.net (cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id D812C1306; Fri, 14 Nov 2025 01:52:49 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1763081570; bh=WkCHl7q7EkW2IT3c4qk5dJwd7TPeEcVjNIGVOdput9w=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Sl4pNZCQIyHzVOdJctHiSZD7nAMJ5I7udhqDIiYN9ss+TxwwvxmEAqJZsfd6/xHeK C3HwSPahD60YcrbGTXHAjCcC0SDUXI+vZftoyNfceXHqOc5nTmnGkgv9nEGy50zfUU xtYTWkfEQ31hhRMwJx7IWzSOUmHgaaR581Je+aks= From: Kieran Bingham To: libcamera devel Cc: Kieran Bingham Subject: [PATCH v4 07/21] ipa: libipa: Provide Q5.4 FixedPoint support Date: Fri, 14 Nov 2025 00:54:11 +0000 Message-ID: <20251114005428.90024-8-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251114005428.90024-1-kieran.bingham@ideasonboard.com> References: <20251114005428.90024-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" Provide a FixedPoint Quantized type to support the Q5.4 format representing values in the range [-16.0, 15.9375] with a resolution of 1/16. Signed-off-by: Kieran Bingham --- This format is used by the RKISP1 for Chromatic Abberation Correction handling v4: - Fix grammar in type documentation src/ipa/libipa/fixedpoint.cpp | 9 +++++++++ src/ipa/libipa/fixedpoint.h | 2 ++ test/ipa/libipa/fixedpoint.cpp | 5 +++++ 3 files changed, 16 insertions(+) diff --git a/src/ipa/libipa/fixedpoint.cpp b/src/ipa/libipa/fixedpoint.cpp index 4c3ea33497bf..967b00bcd7c2 100644 --- a/src/ipa/libipa/fixedpoint.cpp +++ b/src/ipa/libipa/fixedpoint.cpp @@ -139,6 +139,15 @@ namespace ipa { * values in the range [0.0, 1.992] with a resolution of 1/128. */ +/** + * \typedef Q5_4 + * \brief 5.4 signed fixed-point quantizer + * + * A Quantized type using 5 bits for the integer part and 4 bits for the + * fractional part, stored in a signed 16-bit integer (\c int16_t). Represents + * values in the range [-16.0, 15.9375] with a resolution of 1/16. + */ + /** * \typedef Q12_4 * \brief 12.4 signed fixed-point quantizer diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h index d97e6d6135ad..ce621cb01a5a 100644 --- a/src/ipa/libipa/fixedpoint.h +++ b/src/ipa/libipa/fixedpoint.h @@ -105,6 +105,8 @@ struct FixedPointQTraits { using Q1_7 = Quantized>; using UQ1_7 = Quantized>; +using Q5_4 = Quantized>; + using Q12_4 = Quantized>; using UQ12_4 = Quantized>; diff --git a/test/ipa/libipa/fixedpoint.cpp b/test/ipa/libipa/fixedpoint.cpp index 338571e38f68..1d018c0128df 100644 --- a/test/ipa/libipa/fixedpoint.cpp +++ b/test/ipa/libipa/fixedpoint.cpp @@ -190,6 +190,11 @@ protected: fails += quantizedCheck(-0.4f, 0b1111'1001101, -0.398438f); /* 0x7cd */ fails += quantizedCheck(-1.4f, 0b1110'1001101, -1.39844f); /* 0x74d */ + /* Q5_4(-16 .. 15.9375) Min: [0x0100:-16] -- Max: [0x00ff:15.9375] Step:0.0625 */ + introduce("Q5_4"); + fails += quantizedCheck(-16.00f, 0b10000'0000, -16.00f); + fails += quantizedCheck( 15.94f, 0b01111'1111, 15.9375f); + /* Q12.4(-2048 .. 2047.94) Min: [0x8000:-2048] -- Max: [0x7fff:2047.94] Step:0.0625 */ introduce("Q12_4"); fails += quantizedCheck(0.0f, 0b000000000000'0000, 0.0f); From patchwork Fri Nov 14 00:54:12 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 25038 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 BDA62C3317 for ; Fri, 14 Nov 2025 00:55:03 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7860B60AA8; Fri, 14 Nov 2025 01:54:59 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="plz86knk"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B5D3F60AA7 for ; Fri, 14 Nov 2025 01:54:50 +0100 (CET) Received: from charm.hippo-penny.ts.net (cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 369218FA; Fri, 14 Nov 2025 01:52:50 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1763081570; bh=6G2ZcQHiEZLvQTYgB1pu+nA9XQdJ0oX8jEE+U0kKygw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=plz86knkwgkbusvEZlxhOYWOiRqFQNiW4Vf1w0gly/8WYEpojQJuPJFWxOF6TksKT M36gXSqvG8NKRROZVeytjNKgAzwz5zkEwClI2WikTqqDRYr+8/O6woLVs3PVJ9Gbos zShopYWrAeaeJmK7s/EjOFLro2QgHJL4hYa+7xwQ= From: Kieran Bingham To: libcamera devel Cc: Kieran Bingham Subject: [PATCH v4 08/21] ipa: libipa: Provide Q5.8 FixedPoint support Date: Fri, 14 Nov 2025 00:54:12 +0000 Message-ID: <20251114005428.90024-9-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251114005428.90024-1-kieran.bingham@ideasonboard.com> References: <20251114005428.90024-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" Provide a FixedPoint Quantized type to support the Q5.8 format representing values in the range [0 .. 31.9961] with a resolution of 1/256. Signed-off-by: Kieran Bingham --- This type is used by the Mali-C55 Digital Gain component. src/ipa/libipa/fixedpoint.cpp | 9 +++++++++ src/ipa/libipa/fixedpoint.h | 1 + test/ipa/libipa/fixedpoint.cpp | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/src/ipa/libipa/fixedpoint.cpp b/src/ipa/libipa/fixedpoint.cpp index 967b00bcd7c2..a6f8ef351c32 100644 --- a/src/ipa/libipa/fixedpoint.cpp +++ b/src/ipa/libipa/fixedpoint.cpp @@ -148,6 +148,15 @@ namespace ipa { * values in the range [-16.0, 15.9375] with a resolution of 1/16. */ +/** + * \typedef UQ5_8 + * \brief 5.8 unsigned fixed-point quantizer + * + * A Quantized type using 5 bits for the integer part and 8 bits for the + * fractional part, stored in an unsigned 16-bit integer (\c uint16_t). Represents + * values in the range [0.0, 31.9961] with a resolution of 1/256. + */ + /** * \typedef Q12_4 * \brief 12.4 signed fixed-point quantizer diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h index ce621cb01a5a..8f095210a918 100644 --- a/src/ipa/libipa/fixedpoint.h +++ b/src/ipa/libipa/fixedpoint.h @@ -106,6 +106,7 @@ using Q1_7 = Quantized>; using UQ1_7 = Quantized>; using Q5_4 = Quantized>; +using UQ5_8 = Quantized>; using Q12_4 = Quantized>; using UQ12_4 = Quantized>; diff --git a/test/ipa/libipa/fixedpoint.cpp b/test/ipa/libipa/fixedpoint.cpp index 1d018c0128df..c830b5f05a19 100644 --- a/test/ipa/libipa/fixedpoint.cpp +++ b/test/ipa/libipa/fixedpoint.cpp @@ -195,6 +195,11 @@ protected: fails += quantizedCheck(-16.00f, 0b10000'0000, -16.00f); fails += quantizedCheck( 15.94f, 0b01111'1111, 15.9375f); + /* UQ5_8(0 .. 31.9961) Min: [0x0000:0] -- Max: [0x1fff:31.9961] Step:0.00390625 */ + introduce("UQ5_8"); + fails += quantizedCheck( 0.00f, 0b00000'00000000, 0.00f); + fails += quantizedCheck(32.00f, 0b11111'11111111, 31.9961f); + /* Q12.4(-2048 .. 2047.94) Min: [0x8000:-2048] -- Max: [0x7fff:2047.94] Step:0.0625 */ introduce("Q12_4"); fails += quantizedCheck(0.0f, 0b000000000000'0000, 0.0f); From patchwork Fri Nov 14 00:54:13 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 25039 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 C455AC3263 for ; Fri, 14 Nov 2025 00:55:04 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 3087E60A9D; Fri, 14 Nov 2025 01:55:00 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="o/vHTcWa"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1026560AAD for ; Fri, 14 Nov 2025 01:54:51 +0100 (CET) Received: from charm.hippo-penny.ts.net (cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 827C61AED; Fri, 14 Nov 2025 01:52:50 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1763081570; bh=N9XX3MGD8XPi40ZBAJ/UtIUyiZ3FR/uTa+qPdmjcRvw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=o/vHTcWa4a5+62OQHOVeCC6/nulVJCI+8yWbjXQ/9zcE3Gl6f4pP6I9Ta6D7fWUfh RWBS3ZakmWPLHPv0keYvNLyCf9l8lOcAAoNQ749OJAoVn1wAHcOl6fiO/BgZZM+ugs pd/k1cLzC8jE04l96R4qsnlt4gbHkm3zfCClX7Ps= From: Kieran Bingham To: libcamera devel Cc: Kieran Bingham Subject: [PATCH v4 09/21] ipa: libipa: Provide Q4.8 FixedPoint support Date: Fri, 14 Nov 2025 00:54:13 +0000 Message-ID: <20251114005428.90024-10-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251114005428.90024-1-kieran.bingham@ideasonboard.com> References: <20251114005428.90024-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" Provide a FixedPoint Quantized type to support the Q4.8 format representing values in the range [0 .. 15.9961] with a resolution of 1/256. Signed-off-by: Kieran Bingham --- This type is used by the Mali-C55 AWB Gains src/ipa/libipa/fixedpoint.cpp | 9 +++++++++ src/ipa/libipa/fixedpoint.h | 2 ++ test/ipa/libipa/fixedpoint.cpp | 5 +++++ 3 files changed, 16 insertions(+) diff --git a/src/ipa/libipa/fixedpoint.cpp b/src/ipa/libipa/fixedpoint.cpp index a6f8ef351c32..03053668ed79 100644 --- a/src/ipa/libipa/fixedpoint.cpp +++ b/src/ipa/libipa/fixedpoint.cpp @@ -139,6 +139,15 @@ namespace ipa { * values in the range [0.0, 1.992] with a resolution of 1/128. */ +/** + * \typedef UQ4_8 + * \brief 4.8 unsigned fixed-point quantizer + * + * A Quantized type using 4 bits for the integer part and 8 bits for the + * fractional part, stored in an unsigned 16-bit integer (\c uint16_t). Represents + * values in the range [0.0, 15.9961] with a resolution of 1/256. + */ + /** * \typedef Q5_4 * \brief 5.4 signed fixed-point quantizer diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h index 8f095210a918..05dd97e64f40 100644 --- a/src/ipa/libipa/fixedpoint.h +++ b/src/ipa/libipa/fixedpoint.h @@ -105,6 +105,8 @@ struct FixedPointQTraits { using Q1_7 = Quantized>; using UQ1_7 = Quantized>; +using UQ4_8 = Quantized>; + using Q5_4 = Quantized>; using UQ5_8 = Quantized>; diff --git a/test/ipa/libipa/fixedpoint.cpp b/test/ipa/libipa/fixedpoint.cpp index c830b5f05a19..f3773dfe6ad4 100644 --- a/test/ipa/libipa/fixedpoint.cpp +++ b/test/ipa/libipa/fixedpoint.cpp @@ -190,6 +190,11 @@ protected: fails += quantizedCheck(-0.4f, 0b1111'1001101, -0.398438f); /* 0x7cd */ fails += quantizedCheck(-1.4f, 0b1110'1001101, -1.39844f); /* 0x74d */ + /* UQ4_8(0 .. 15.9961) Min: [0x0000:0] -- Max: [0x0fff:15.9961] Step:0.00390625 */ + introduce("UQ4_8"); + fails += quantizedCheck( 0.0f, 0b0000'00000000, 0.00f); + fails += quantizedCheck(16.0f, 0b1111'11111111, 15.9961f); + /* Q5_4(-16 .. 15.9375) Min: [0x0100:-16] -- Max: [0x00ff:15.9375] Step:0.0625 */ introduce("Q5_4"); fails += quantizedCheck(-16.00f, 0b10000'0000, -16.00f); From patchwork Fri Nov 14 00:54:14 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 25040 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 A7318C3331 for ; Fri, 14 Nov 2025 00:55:05 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 45C9A60B33; Fri, 14 Nov 2025 01:55:01 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="tRemIF5s"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 61AA860AAF for ; Fri, 14 Nov 2025 01:54:51 +0100 (CET) Received: from charm.hippo-penny.ts.net (cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id D22031D1C; Fri, 14 Nov 2025 01:52:50 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1763081571; bh=DUlrlB6Trv3GWQH/Kyuo8tA9uj00B6YqWBYvIM2LaE4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=tRemIF5sfHlhePWHVJr41J0kZYUZJCU3z+D5+udrkvfWet325JjmE/ZxwS4kDkDw5 wo6OjrFCd6oWqbsl8Hk6ojWcYWLsaNHv3AbnGmVVIKQuji5cDWKKor6BmWJ4Izt4p+ clBQmS+g5YANd4ProMUZGMlnf9fdC+jsacoV1NrY= From: Kieran Bingham To: libcamera devel Cc: Kieran Bingham Subject: [PATCH v4 10/21] ipa: libipa: fixedpoint: Provide a ScaledFixedPoint type Date: Fri, 14 Nov 2025 00:54:14 +0000 Message-ID: <20251114005428.90024-11-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251114005428.90024-1-kieran.bingham@ideasonboard.com> References: <20251114005428.90024-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" Extend the new Quantized FixedPoint capabilities with a ScaledFixedPointQTraits which takes an existing Quantized type and scales the conversion by the given Scale template parameter. This can be useful to represent fixed point values which represent a linear range with a different scale to the underlying float or integral type. Signed-off-by: Kieran Bingham --- v3: - Rename quantized_type to QuantizedType v4: - Fix copydoc for ScaledFixedPointQTraits::toFloat src/ipa/libipa/fixedpoint.cpp | 59 +++++++++++++++++++++++++++++++++++ src/ipa/libipa/fixedpoint.h | 24 ++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/src/ipa/libipa/fixedpoint.cpp b/src/ipa/libipa/fixedpoint.cpp index 03053668ed79..97cdd9b3f7aa 100644 --- a/src/ipa/libipa/fixedpoint.cpp +++ b/src/ipa/libipa/fixedpoint.cpp @@ -185,6 +185,65 @@ namespace ipa { * Represents values in the range [0.0, 4095.9375] with a resolution of 1/16. */ +/** + * \struct ScaledFixedPointQTraits + * \brief Wrap a FixedPointQTraits with a linear scaling factor + * + * This trait extends an existing fixed-point quantisation policy + * by applying an additional multiplicative scale between the + * floating-point and quantised domains. + * + * \tparam Q The base fixed-point traits type + * \tparam Scale The scale factor applied to the floating-point domain + */ + +/** + * \typedef ScaledFixedPointQTraits::QuantizedType + * \copydoc FixedPointQTraits::QuantizedType + */ + +/** + * \var ScaledFixedPointQTraits::scale + * \brief The constant scaling factor applied to the floating-point domain + * + * Floating-point inputs are divided by this factor before quantisation, + * and multiplied by it after dequantisation. + */ + +/** + * \var ScaledFixedPointQTraits::qmin + * \copydoc FixedPointQTraits::qmin + */ + +/** + * \var ScaledFixedPointQTraits::qmax + * \copydoc FixedPointQTraits::qmax + */ + +/** + * \var ScaledFixedPointQTraits::min + * \copydoc FixedPointQTraits::min + */ + +/** + * \var ScaledFixedPointQTraits::max + * \copydoc FixedPointQTraits::max + */ + +/** + * \fn ScaledFixedPointQTraits::fromFloat(float v) + * \copydoc FixedPointQTraits::fromFloat(float v) + * + * The input value \a v is divided by the scaling factor before conversion. + */ + +/** + * \fn ScaledFixedPointQTraits::toFloat(QuantizedType q) + * \copydoc FixedPointQTraits::toFloat() + * + * The output value is multiplied by the scaling factor after conversion. + */ + } /* namespace ipa */ } /* namespace libcamera */ diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h index 05dd97e64f40..1e984350111c 100644 --- a/src/ipa/libipa/fixedpoint.h +++ b/src/ipa/libipa/fixedpoint.h @@ -113,6 +113,30 @@ using UQ5_8 = Quantized>; using Q12_4 = Quantized>; using UQ12_4 = Quantized>; +template +struct ScaledFixedPointQTraits { + using QuantizedType = typename Q::QuantizedType; + + static constexpr float scale = static_cast(Scale); + + /* Re-expose base limits, adjusted by the scaling factor */ + static constexpr QuantizedType qmin = Q::qmin; + static constexpr QuantizedType qmax = Q::qmax; + static constexpr float min = Q::min * scale; + static constexpr float max = Q::max * scale; + + static QuantizedType fromFloat(float v) + { + v = std::clamp(v, min, max); + return Q::fromFloat(v / scale); + } + + static float toFloat(QuantizedType q) + { + return Q::toFloat(q) * scale; + } +}; + } /* namespace ipa */ } /* namespace libcamera */ From patchwork Fri Nov 14 00:54:15 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 25041 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 628CCC32DC for ; Fri, 14 Nov 2025 00:55:06 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id AB72460ABA; Fri, 14 Nov 2025 01:55:03 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="dpKB1Se9"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 011BC60AAB for ; Fri, 14 Nov 2025 01:54:52 +0100 (CET) Received: from charm.hippo-penny.ts.net (cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 7290A16A8; Fri, 14 Nov 2025 01:52:51 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1763081571; bh=ToNsUOzmKiNF1icAMM5rna9vu6glhImwFOUKNWeZZt0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dpKB1Se9+gJpOjSGCHXH1ENrPUHZ9wpR/Bj/UwdQVW9X1w+QAS694qwVJDexm2Ezy /Q0eok36JdrImckmuMEQ7Rzuzkhr69rzkINTEEXAjKsZ70OhvZ7t/BUaXzAYIPpQg4 Cw2nPkfoh2VWMmX3UFostX9nFMMxzOB68rhQzRbc= From: Kieran Bingham To: libcamera devel Cc: Kieran Bingham Subject: [PATCH v4 11/21] test: libipa: Provide ScaledFixedPoint tests Date: Fri, 14 Nov 2025 00:54:15 +0000 Message-ID: <20251114005428.90024-12-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251114005428.90024-1-kieran.bingham@ideasonboard.com> References: <20251114005428.90024-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" Use the new ScaledFixedPointQTraits to create a HueQ representing the equivalent scale used by the RKISP1 Hue control to validate the scaling capabilities of the new quantized type. Signed-off-by: Kieran Bingham --- test/ipa/libipa/fixedpoint.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test/ipa/libipa/fixedpoint.cpp b/test/ipa/libipa/fixedpoint.cpp index f3773dfe6ad4..e3428272fae5 100644 --- a/test/ipa/libipa/fixedpoint.cpp +++ b/test/ipa/libipa/fixedpoint.cpp @@ -235,6 +235,33 @@ protected: return TestPass; } + int testScaledFixedPointQuantizers() + { + unsigned int fails = 0; + cerr << std::endl + << "Scaled Fixed-Point Quantizer tests:" << std::endl; + + using HueQ = Quantized>; + + /* HueQ (Scaled Q1_7 * 90) (-90 .. 89.2969) Min: [0x80:-90] -- Max: [0x7f:89.2969] Step:0.703125 */ + fails += introduce("HueQ (Scaled Q1_7 * 90) "); + + /* clang-format off */ + + fails += quantizedCheck(-90.0f, -128, -90.0f); /* Min */ + fails += quantizedCheck(-45.0f, -64, -45.0f); /* Mid negative */ + fails += quantizedCheck( 0.0f, 0, 0.0f); /* Zero */ + fails += quantizedCheck( 45.0f, 64, 45.0f); /* Mid positive */ + fails += quantizedCheck( 90.0f, 127, 89.2969f); /* Max */ + + fails += quantizedCheck(-99.0f, -128, -90.0f); /* Clamp low */ + fails += quantizedCheck( 99.0f, 127, 89.2969f); /* Clamp high */ + + /* clang-format on */ + + return fails ? TestFail : TestPass; + } + int run() { unsigned int fails = 0; @@ -246,6 +273,9 @@ protected: if (testFixedPointQuantizers() != TestPass) fails++; + if (testScaledFixedPointQuantizers() != TestPass) + fails++; + return fails ? TestFail : TestPass; } }; From patchwork Fri Nov 14 00:54:16 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 25042 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 44821C3332 for ; Fri, 14 Nov 2025 00:55:07 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C0D9160ABB; Fri, 14 Nov 2025 01:55:04 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="VhqcxJW+"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 52630609D8 for ; Fri, 14 Nov 2025 01:54:52 +0100 (CET) Received: from charm.hippo-penny.ts.net (cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id C06FE19AD; Fri, 14 Nov 2025 01:52:51 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1763081571; bh=coUU5VZUTYRXENFZLUupRUhAIG5OB9eKicUgwYzbizE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=VhqcxJW+Y8GcpSYenooR8vONR+hk+LFu+9fCVye57JO+cdAax9KNcICFSjiwWgALA BEAQUMYviBxTjNJ2Nabdfj2dTQYW1klAAw/WFi+NQCX4rLpFLpnJViba2lidzsTrA4 MCQLtBoSKGI3E4EXrbvSeOUcii8pdStnd1hImI+Q= From: Kieran Bingham To: libcamera devel Cc: Kieran Bingham Subject: [PATCH v4 12/21] ipa: rkisp1: cproc: Convert to use Quantized types Date: Fri, 14 Nov 2025 00:54:16 +0000 Message-ID: <20251114005428.90024-13-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251114005428.90024-1-kieran.bingham@ideasonboard.com> References: <20251114005428.90024-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" Convert the Contrast and Saturuation helper functions to a Quantizer type to support maintaining the data. Signed-off-by: Kieran Bingham --- v3: - Don't add into ipa_context.h anymore src/ipa/rkisp1/algorithms/cproc.cpp | 36 +++++++++++------------------ src/ipa/rkisp1/ipa_context.h | 19 ++++++++++----- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/cproc.cpp b/src/ipa/rkisp1/algorithms/cproc.cpp index d1fff6990d37..4637a824af03 100644 --- a/src/ipa/rkisp1/algorithms/cproc.cpp +++ b/src/ipa/rkisp1/algorithms/cproc.cpp @@ -14,6 +14,8 @@ #include +#include "libipa/quantized.h" + /** * \file cproc.h */ @@ -39,16 +41,6 @@ constexpr float kDefaultBrightness = 0.0f; constexpr float kDefaultContrast = 1.0f; constexpr float kDefaultSaturation = 1.0f; -int convertBrightness(const float v) -{ - return std::clamp(std::lround(v * 128), -128, 127); -} - -int convertContrastOrSaturation(const float v) -{ - return std::clamp(std::lround(v * 128), 0, 255); -} - } /* namespace */ /** @@ -74,9 +66,9 @@ int ColorProcessing::configure(IPAContext &context, { auto &cproc = context.activeState.cproc; - cproc.brightness = convertBrightness(kDefaultBrightness); - cproc.contrast = convertContrastOrSaturation(kDefaultContrast); - cproc.saturation = convertContrastOrSaturation(kDefaultSaturation); + cproc.brightness = BrightnessQ(kDefaultBrightness); + cproc.contrast = ContrastQ(kDefaultContrast); + cproc.saturation = SaturationQ(kDefaultSaturation); return 0; } @@ -97,35 +89,35 @@ void ColorProcessing::queueRequest(IPAContext &context, const auto &brightness = controls.get(controls::Brightness); if (brightness) { - int value = convertBrightness(*brightness); + BrightnessQ value = *brightness; if (cproc.brightness != value) { cproc.brightness = value; update = true; } - LOG(RkISP1CProc, Debug) << "Set brightness to " << value; + LOG(RkISP1CProc, Debug) << "Set brightness to " << value.value(); } const auto &contrast = controls.get(controls::Contrast); if (contrast) { - int value = convertContrastOrSaturation(*contrast); + ContrastQ value = *contrast; if (cproc.contrast != value) { cproc.contrast = value; update = true; } - LOG(RkISP1CProc, Debug) << "Set contrast to " << value; + LOG(RkISP1CProc, Debug) << "Set contrast to " << value.value(); } const auto saturation = controls.get(controls::Saturation); if (saturation) { - int value = convertContrastOrSaturation(*saturation); + SaturationQ value = *saturation; if (cproc.saturation != value) { cproc.saturation = value; update = true; } - LOG(RkISP1CProc, Debug) << "Set saturation to " << value; + LOG(RkISP1CProc, Debug) << "Set saturation to " << value.value(); } frameContext.cproc.brightness = cproc.brightness; @@ -148,9 +140,9 @@ void ColorProcessing::prepare([[maybe_unused]] IPAContext &context, auto config = params->block(); config.setEnabled(true); - config->brightness = frameContext.cproc.brightness; - config->contrast = frameContext.cproc.contrast; - config->sat = frameContext.cproc.saturation; + config->brightness = frameContext.cproc.brightness.quantized(); + config->contrast = frameContext.cproc.contrast.quantized(); + config->sat = frameContext.cproc.saturation.quantized(); } REGISTER_IPA_ALGORITHM(ColorProcessing, "ColorProcessing") diff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h index f85a130d9c23..651558bdf42d 100644 --- a/src/ipa/rkisp1/ipa_context.h +++ b/src/ipa/rkisp1/ipa_context.h @@ -27,11 +27,17 @@ #include #include #include "libipa/agc_mean_luminance.h" +#include "libipa/fixedpoint.h" namespace libcamera { namespace ipa::rkisp1 { +/* Fixed point types used by CPROC */ +using BrightnessQ = Q1_7; +using ContrastQ = UQ1_7; +using SaturationQ = UQ1_7; + struct IPAHwSettings { unsigned int numAeCells; unsigned int numHistogramBins; @@ -115,9 +121,9 @@ struct IPAActiveState { } ccm; struct { - int8_t brightness; - uint8_t contrast; - uint8_t saturation; + BrightnessQ brightness; + ContrastQ contrast; + SaturationQ saturation; } cproc; struct { @@ -169,9 +175,10 @@ struct IPAFrameContext : public FrameContext { } awb; struct { - int8_t brightness; - uint8_t contrast; - uint8_t saturation; + BrightnessQ brightness; + ContrastQ contrast; + SaturationQ saturation; + bool update; } cproc; From patchwork Fri Nov 14 00:54:17 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 25043 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 BDC15C32DB for ; Fri, 14 Nov 2025 00:55:07 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6719960AC4; Fri, 14 Nov 2025 01:55:06 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="WmZ0Hlva"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A081660AB0 for ; Fri, 14 Nov 2025 01:54:52 +0100 (CET) Received: from charm.hippo-penny.ts.net (cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 1FB5E1E3E; Fri, 14 Nov 2025 01:52:52 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1763081572; bh=T70AeJymcH6fgdT/wFjigBew8V6NxzsWhQ+URP0en44=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WmZ0HlvaC6bguC/W/dbmRezDatfCEmRJwhd0vyhje5ibJ/B/rnz+wfaeH6UC7SrCi JU/1fUO66NH4uWlE4jMgGDBfzIMBNix4JCUEwXZofX4DvnHmr4FAN1KcJsEt5YKTSH gbsMho1c5XJ6izZdZ5xw/uw5IrGliFuKjNr1atg0= From: Kieran Bingham To: libcamera devel Cc: Kieran Bingham Subject: [PATCH v4 13/21] ipa: rkisp1: cproc: Report metadata Date: Fri, 14 Nov 2025 00:54:17 +0000 Message-ID: <20251114005428.90024-14-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251114005428.90024-1-kieran.bingham@ideasonboard.com> References: <20251114005428.90024-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" Presently the colour processing component exposes controls for brightness, saturation, and contrast to the applications which are handled and processed accordingly on the ISP. The implementation lacks reporting the values that are set back to the application. Utilise the new Quantised types to provide the values that were applied to the hardware and report them in the completed request metadata. Signed-off-by: Kieran Bingham --- src/ipa/rkisp1/algorithms/cproc.cpp | 12 ++++++++++++ src/ipa/rkisp1/algorithms/cproc.h | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/src/ipa/rkisp1/algorithms/cproc.cpp b/src/ipa/rkisp1/algorithms/cproc.cpp index 4637a824af03..7475e6c1b609 100644 --- a/src/ipa/rkisp1/algorithms/cproc.cpp +++ b/src/ipa/rkisp1/algorithms/cproc.cpp @@ -145,6 +145,18 @@ void ColorProcessing::prepare([[maybe_unused]] IPAContext &context, config->sat = frameContext.cproc.saturation.quantized(); } +/** + * \copydoc libcamera::ipa::Algorithm::process + */ +void ColorProcessing::process([[maybe_unused]] IPAContext &context, [[maybe_unused]] const uint32_t frame, + IPAFrameContext &frameContext, [[maybe_unused]] const rkisp1_stat_buffer *stats, + ControlList &metadata) +{ + metadata.set(controls::Brightness, frameContext.cproc.brightness.value()); + metadata.set(controls::Contrast, frameContext.cproc.contrast.value()); + metadata.set(controls::Saturation, frameContext.cproc.saturation.value()); +} + REGISTER_IPA_ALGORITHM(ColorProcessing, "ColorProcessing") } /* namespace ipa::rkisp1::algorithms */ diff --git a/src/ipa/rkisp1/algorithms/cproc.h b/src/ipa/rkisp1/algorithms/cproc.h index fd38fd17e8bb..9b589ebd4ad7 100644 --- a/src/ipa/rkisp1/algorithms/cproc.h +++ b/src/ipa/rkisp1/algorithms/cproc.h @@ -30,6 +30,10 @@ public: void prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, RkISP1Params *params) override; + void process(IPAContext &context, const uint32_t frame, + IPAFrameContext &frameContext, + const rkisp1_stat_buffer *stats, + ControlList &metadata) override; }; } /* namespace ipa::rkisp1::algorithms */ From patchwork Fri Nov 14 00:54:18 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 25044 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 5B16FC3333 for ; Fri, 14 Nov 2025 00:55:08 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id AC29C60AB6; Fri, 14 Nov 2025 01:55:07 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="JVyhs/f3"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id F310160AA0 for ; Fri, 14 Nov 2025 01:54:52 +0100 (CET) Received: from charm.hippo-penny.ts.net (cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 6C4C11FDD; Fri, 14 Nov 2025 01:52:52 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1763081572; bh=YLvgUXyg3F8wyijZB37FRgiAh8OyoKDVnefYZwHIDxg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=JVyhs/f3ju8CjPg3sEHgWAJlVDH3DTc+90DNEXts+XTrY3BATrvndqMzf6qZ1MJaI /pdge5MTba2B6UoPCPfHL+WKEap3OJNoxPC17Ghp7Rmii90T9MoVctBm52fGLmQGUn KPnnKwT5UPai2nbrVtEfoo2G7DmviRZv0Q1hGBV0= From: Kieran Bingham To: libcamera devel Cc: "van Veen, Stephan" , Kieran Bingham Subject: [PATCH v4 14/21] libcamera: controls: Define a new core Hue control Date: Fri, 14 Nov 2025 00:54:18 +0000 Message-ID: <20251114005428.90024-15-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251114005428.90024-1-kieran.bingham@ideasonboard.com> References: <20251114005428.90024-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" From: "van Veen, Stephan" Define a new control to support configuration of Hue adjustments when supported by the available platform. Signed-off-by: van Veen, Stephan [Kieran: Rework to define as a rotation in degrees] Signed-off-by: Kieran Bingham --- src/libcamera/control_ids_core.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/libcamera/control_ids_core.yaml b/src/libcamera/control_ids_core.yaml index f781865859ac..4993da14b3f6 100644 --- a/src/libcamera/control_ids_core.yaml +++ b/src/libcamera/control_ids_core.yaml @@ -1346,4 +1346,17 @@ controls: reduces the WdrExposureValue until the amount of pixels that are close to saturation is lower than this value. + - Hue: + type: float + direction: inout + description: | + Adjusts the image hue (colour rotation) in degrees. + + The value specifies a rotation around the colour wheel: + positive values rotate hues counter-clockwise (for example a +60 degree + rotation turns Red hues to Magenta hues), and negative values rotate + clockwise (a -60 degree rotation turns Red hues to Yellow hues). + + A value of 0 leaves the hue unchanged. + ... From patchwork Fri Nov 14 00:54:19 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 25045 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 4CBC1C3317 for ; Fri, 14 Nov 2025 00:55:09 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D850960B2C; Fri, 14 Nov 2025 01:55:08 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="mTZL0kbE"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 520D460A85 for ; Fri, 14 Nov 2025 01:54:53 +0100 (CET) Received: from charm.hippo-penny.ts.net (cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id C17C41A8F; Fri, 14 Nov 2025 01:52:52 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1763081572; bh=h7NHzB/HMBOlhMPGaDcUma5G7xptruhyDj1qNA5ufbE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mTZL0kbEk3LzG+yIN3N34LfBGHJf1NEpVtUQdBOb2kKJLoO3lF35bKVUnNZ2gV2VR n+An/5c6HrbRKg+fUnnRtJ6p8qIrLJN+6+pJJ5Pm9S3CKIaE+OLT62Sl3tpwgfjhER 4710wNqmGGL17vS+cYy4HeiG3UsNwx8924gCYKrU= From: Kieran Bingham To: libcamera devel Cc: Kieran Bingham Subject: [PATCH v4 15/21] ipa: rkisp1: cproc: Provide a Hue control Date: Fri, 14 Nov 2025 00:54:19 +0000 Message-ID: <20251114005428.90024-16-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251114005428.90024-1-kieran.bingham@ideasonboard.com> References: <20251114005428.90024-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" The RKISP1 supports a configurable Hue as part of the colour processing unit (cproc). This is implemented as a phase shift of the chrominance values between -90 and +87.188 degrees according to the datasheet however the type itself would imply that this is a range between -90 and 89.2969. Implement the new control converting to the hardware scale accordingly and report the applied control in the completed request metadata. Signed-off-by: Kieran Bingham --- src/ipa/rkisp1/algorithms/cproc.cpp | 18 ++++++++++++++++++ src/ipa/rkisp1/ipa_context.h | 3 +++ 2 files changed, 21 insertions(+) diff --git a/src/ipa/rkisp1/algorithms/cproc.cpp b/src/ipa/rkisp1/algorithms/cproc.cpp index 7475e6c1b609..5389882c1685 100644 --- a/src/ipa/rkisp1/algorithms/cproc.cpp +++ b/src/ipa/rkisp1/algorithms/cproc.cpp @@ -39,6 +39,7 @@ namespace { constexpr float kDefaultBrightness = 0.0f; constexpr float kDefaultContrast = 1.0f; +constexpr float kDefaultHue = 0.0f; constexpr float kDefaultSaturation = 1.0f; } /* namespace */ @@ -53,6 +54,8 @@ int ColorProcessing::init(IPAContext &context, cmap[&controls::Brightness] = ControlInfo(-1.0f, 0.993f, kDefaultBrightness); cmap[&controls::Contrast] = ControlInfo(0.0f, 1.993f, kDefaultContrast); + cmap[&controls::Hue] = ControlInfo(HueQ::TraitsType::min, + HueQ::TraitsType::max, kDefaultHue); cmap[&controls::Saturation] = ControlInfo(0.0f, 1.993f, kDefaultSaturation); return 0; @@ -68,6 +71,7 @@ int ColorProcessing::configure(IPAContext &context, cproc.brightness = BrightnessQ(kDefaultBrightness); cproc.contrast = ContrastQ(kDefaultContrast); + cproc.hue = HueQ(kDefaultHue); cproc.saturation = SaturationQ(kDefaultSaturation); return 0; @@ -109,6 +113,17 @@ void ColorProcessing::queueRequest(IPAContext &context, LOG(RkISP1CProc, Debug) << "Set contrast to " << value.value(); } + const auto &hue = controls.get(controls::Hue); + if (hue) { + HueQ value = *hue; + if (cproc.hue != value) { + cproc.hue = value; + update = true; + } + + LOG(RkISP1CProc, Debug) << "Set hue to " << value.value(); + } + const auto saturation = controls.get(controls::Saturation); if (saturation) { SaturationQ value = *saturation; @@ -122,6 +137,7 @@ void ColorProcessing::queueRequest(IPAContext &context, frameContext.cproc.brightness = cproc.brightness; frameContext.cproc.contrast = cproc.contrast; + frameContext.cproc.hue = cproc.hue; frameContext.cproc.saturation = cproc.saturation; frameContext.cproc.update = update; } @@ -142,6 +158,7 @@ void ColorProcessing::prepare([[maybe_unused]] IPAContext &context, config.setEnabled(true); config->brightness = frameContext.cproc.brightness.quantized(); config->contrast = frameContext.cproc.contrast.quantized(); + config->hue = frameContext.cproc.hue.quantized(); config->sat = frameContext.cproc.saturation.quantized(); } @@ -154,6 +171,7 @@ void ColorProcessing::process([[maybe_unused]] IPAContext &context, [[maybe_unus { metadata.set(controls::Brightness, frameContext.cproc.brightness.value()); metadata.set(controls::Contrast, frameContext.cproc.contrast.value()); + metadata.set(controls::Hue, frameContext.cproc.hue.value()); metadata.set(controls::Saturation, frameContext.cproc.saturation.value()); } diff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h index 651558bdf42d..52d458a90cc3 100644 --- a/src/ipa/rkisp1/ipa_context.h +++ b/src/ipa/rkisp1/ipa_context.h @@ -36,6 +36,7 @@ namespace ipa::rkisp1 { /* Fixed point types used by CPROC */ using BrightnessQ = Q1_7; using ContrastQ = UQ1_7; +using HueQ = Quantized>; using SaturationQ = UQ1_7; struct IPAHwSettings { @@ -123,6 +124,7 @@ struct IPAActiveState { struct { BrightnessQ brightness; ContrastQ contrast; + HueQ hue; SaturationQ saturation; } cproc; @@ -177,6 +179,7 @@ struct IPAFrameContext : public FrameContext { struct { BrightnessQ brightness; ContrastQ contrast; + HueQ hue; SaturationQ saturation; bool update; From patchwork Fri Nov 14 00:54:20 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 25046 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 2C5AFC3334 for ; Fri, 14 Nov 2025 00:55:10 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C0C9E60AA4; Fri, 14 Nov 2025 01:55:09 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="oPj9lYFA"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9FE1960A81 for ; Fri, 14 Nov 2025 01:54:53 +0100 (CET) Received: from charm.hippo-penny.ts.net (cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 204B719B5; Fri, 14 Nov 2025 01:52:53 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1763081573; bh=r1ZXJQShnSWr/dg4t9QvGQ2E3oU88IEwg8g8aeTsFfk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=oPj9lYFAThzrzll5jxaJ0aVSLIgOtGFoiYXy0MSu3OXHg45TJ2DhdjpBO0lGxywTI 4aZ4ygwvKY2CqWw35QRgVMLRQnuEF9RkTlNtJdZSnizsTyZEg3Y4ZI/0yiAhlFhtUI 6IKdIwDSNCX/kjp1cOKhi94C1uF+zqvSub4hlOX8= From: Kieran Bingham To: libcamera devel Cc: Kieran Bingham Subject: [PATCH v4 16/21] ipa: rkisp1: ccm: Use Q4_7 format directly Date: Fri, 14 Nov 2025 00:54:20 +0000 Message-ID: <20251114005428.90024-17-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251114005428.90024-1-kieran.bingham@ideasonboard.com> References: <20251114005428.90024-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" Replace the legacy call to floatingToFixedPoint with the new FixedPoint quantizer to explicitly describe the type used by the RKISP1 Colour Correction Matrix. Signed-off-by: Kieran Bingham --- src/ipa/rkisp1/algorithms/ccm.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/ccm.cpp b/src/ipa/rkisp1/algorithms/ccm.cpp index de2b6fe775aa..a99336c478b1 100644 --- a/src/ipa/rkisp1/algorithms/ccm.cpp +++ b/src/ipa/rkisp1/algorithms/ccm.cpp @@ -115,10 +115,11 @@ void Ccm::setParameters(struct rkisp1_cif_isp_ctk_config &config, * 4 bit integer and 7 bit fractional, ranging from -8 (0x400) to * +7.9921875 (0x3ff) */ + using Q4_7 = Quantized>; + for (unsigned int i = 0; i < 3; i++) { for (unsigned int j = 0; j < 3; j++) - config.coeff[i][j] = - floatingToFixedPoint<4, 7, uint16_t, double>(matrix[i][j]); + config.coeff[i][j] = Q4_7(matrix[i][j]).quantized(); } for (unsigned int i = 0; i < 3; i++) From patchwork Fri Nov 14 00:54:21 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 25047 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 D2E6DC3263 for ; Fri, 14 Nov 2025 00:55:10 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7DFB760A81; Fri, 14 Nov 2025 01:55:10 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="A838l/BU"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id F388160AB8 for ; Fri, 14 Nov 2025 01:54:53 +0100 (CET) Received: from charm.hippo-penny.ts.net (cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 6ED77201D; Fri, 14 Nov 2025 01:52:53 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1763081573; bh=pmpqXM/gTIccr4acD4Uf74aey0kdK+gtY1dkgp7O7dk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=A838l/BUsRjE9Tf7yUa8pdfodfAjguPJPNFb72IdXAiK5UB0RYGTLE6o9boGYpcjr ONFJw2kNcNKxc9CsSKPVmw5TuuIWeGYEHH24/5j89Vb6bgQzFQU4dXPxU7De2+OWAi TE6amGZFB9A7rYxm6Xg7WQshVVAUVtzC9kyi8nxs= From: Kieran Bingham To: libcamera devel Cc: Kieran Bingham Subject: [PATCH v4 17/21] ipa: mali-c55: Convert AWB to UQ4_8 usage Date: Fri, 14 Nov 2025 00:54:21 +0000 Message-ID: <20251114005428.90024-18-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251114005428.90024-1-kieran.bingham@ideasonboard.com> References: <20251114005428.90024-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" Utilise the new FixedPoint type to explicitly calculate gains for AWB in Q4.8 format. This ensures that reporting of gains in metadata reflect the true AWB gains applied. Signed-off-by: Kieran Bingham --- src/ipa/mali-c55/algorithms/awb.cpp | 44 ++++++++++++++--------------- src/ipa/mali-c55/ipa_context.h | 10 ++++--- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/src/ipa/mali-c55/algorithms/awb.cpp b/src/ipa/mali-c55/algorithms/awb.cpp index 3d546e5a854b..6e213f43e762 100644 --- a/src/ipa/mali-c55/algorithms/awb.cpp +++ b/src/ipa/mali-c55/algorithms/awb.cpp @@ -37,8 +37,8 @@ int Awb::configure([[maybe_unused]] IPAContext &context, * for the first frame we will make no assumptions and leave the R/B * channels unmodified. */ - context.activeState.awb.rGain = 1.0; - context.activeState.awb.bGain = 1.0; + context.activeState.awb.rGain = 1.0f; + context.activeState.awb.bGain = 1.0f; return 0; } @@ -50,8 +50,8 @@ size_t Awb::fillGainsParamBlock(mali_c55_params_block block, IPAContext &context block.header->flags = MALI_C55_PARAM_BLOCK_FL_NONE; block.header->size = sizeof(struct mali_c55_params_awb_gains); - double rGain = context.activeState.awb.rGain; - double bGain = context.activeState.awb.bGain; + UQ4_8 rGain = context.activeState.awb.rGain; + UQ4_8 bGain = context.activeState.awb.bGain; /* * The gains here map as follows: @@ -63,10 +63,10 @@ size_t Awb::fillGainsParamBlock(mali_c55_params_block block, IPAContext &context * This holds true regardless of the bayer order of the input data, as * the mapping is done internally in the ISP. */ - block.awb_gains->gain00 = floatingToFixedPoint<4, 8, uint16_t, double>(rGain); - block.awb_gains->gain01 = floatingToFixedPoint<4, 8, uint16_t, double>(1.0); - block.awb_gains->gain10 = floatingToFixedPoint<4, 8, uint16_t, double>(1.0); - block.awb_gains->gain11 = floatingToFixedPoint<4, 8, uint16_t, double>(bGain); + block.awb_gains->gain00 = rGain.quantized(); + block.awb_gains->gain01 = UQ4_8(1.0f).quantized(); + block.awb_gains->gain10 = UQ4_8(1.0f).quantized(); + block.awb_gains->gain11 = bGain.quantized(); frameContext.awb.rGain = rGain; frameContext.awb.bGain = bGain; @@ -162,8 +162,8 @@ void Awb::process(IPAContext &context, const uint32_t frame, * The statistics are in Q4.8 format, so we convert to double * here. */ - rgSum += fixedToFloatingPoint<4, 8, double, uint16_t>(awb_ratios[i].avg_rg_gr); - bgSum += fixedToFloatingPoint<4, 8, double, uint16_t>(awb_ratios[i].avg_bg_br); + rgSum += UQ4_8(awb_ratios[i].avg_rg_gr).value(); + bgSum += UQ4_8(awb_ratios[i].avg_bg_br).value(); counted_zones++; } @@ -186,8 +186,8 @@ void Awb::process(IPAContext &context, const uint32_t frame, * figure by the gains that were applied when the statistics for this * frame were generated. */ - double rRatio = rgAvg / frameContext.awb.rGain; - double bRatio = bgAvg / frameContext.awb.bGain; + double rRatio = rgAvg / frameContext.awb.rGain.value(); + double bRatio = bgAvg / frameContext.awb.bGain.value(); /* * And then we can simply invert the ratio to find the gain we should @@ -203,24 +203,24 @@ void Awb::process(IPAContext &context, const uint32_t frame, * want to fix the miscolouring as quickly as possible. */ double speed = frame < kNumStartupFrames ? 1.0 : 0.2; - rGain = speed * rGain + context.activeState.awb.rGain * (1.0 - speed); - bGain = speed * bGain + context.activeState.awb.bGain * (1.0 - speed); + rGain = speed * rGain + context.activeState.awb.rGain.value() * (1.0 - speed); + bGain = speed * bGain + context.activeState.awb.bGain.value() * (1.0 - speed); - context.activeState.awb.rGain = rGain; - context.activeState.awb.bGain = bGain; + context.activeState.awb.rGain = static_cast(rGain); + context.activeState.awb.bGain = static_cast(bGain); metadata.set(controls::ColourGains, { - static_cast(frameContext.awb.rGain), - static_cast(frameContext.awb.bGain), + frameContext.awb.rGain.value(), + frameContext.awb.bGain.value(), }); LOG(MaliC55Awb, Debug) << "For frame number " << frame << ": " << "Average R/G Ratio: " << rgAvg << ", Average B/G Ratio: " << bgAvg - << "\nrGain applied to this frame: " << frameContext.awb.rGain - << ", bGain applied to this frame: " << frameContext.awb.bGain - << "\nrGain to apply: " << context.activeState.awb.rGain - << ", bGain to apply: " << context.activeState.awb.bGain; + << "\nrGain applied to this frame: " << frameContext.awb.rGain.value() + << ", bGain applied to this frame: " << frameContext.awb.bGain.value() + << "\nrGain to apply: " << context.activeState.awb.rGain.value() + << ", bGain to apply: " << context.activeState.awb.bGain.value(); } REGISTER_IPA_ALGORITHM(Awb, "Awb") diff --git a/src/ipa/mali-c55/ipa_context.h b/src/ipa/mali-c55/ipa_context.h index 13885eb83b5c..86d060a731cb 100644 --- a/src/ipa/mali-c55/ipa_context.h +++ b/src/ipa/mali-c55/ipa_context.h @@ -14,6 +14,8 @@ #include +#include "libipa/fixedpoint.h" + namespace libcamera { namespace ipa::mali_c55 { @@ -53,8 +55,8 @@ struct IPAActiveState { } agc; struct { - double rGain; - double bGain; + UQ4_8 rGain; + UQ4_8 bGain; } awb; }; @@ -66,8 +68,8 @@ struct IPAFrameContext : public FrameContext { } agc; struct { - double rGain; - double bGain; + UQ4_8 rGain; + UQ4_8 bGain; } awb; }; From patchwork Fri Nov 14 00:54:22 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 25048 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 75126C3241 for ; Fri, 14 Nov 2025 00:55:11 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 28B4760AAD; Fri, 14 Nov 2025 01:55:11 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="XOvCWz02"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 47E9C6069A for ; Fri, 14 Nov 2025 01:54:54 +0100 (CET) Received: from charm.hippo-penny.ts.net (cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id BC94420A4; Fri, 14 Nov 2025 01:52:53 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1763081573; bh=58vba508uZ769PzpojQWpViY+uYaqEr0rRQ22PkPNSA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XOvCWz02E5t5BDWWeXGI0tAdc+Q0wJrEVSkj0BNwRotHiSxdN/Wkt7RuiRISRonDd XiNM92ru55tQEhbxDT5SUiELiGu/OKE3kz2FJM7q0gVA+EQmtoqsReA1JouXANts6/ 3PWr/048xedSFnqSq2YNM394/rQ25oX+fpYemmV8= From: Kieran Bingham To: libcamera devel Cc: Kieran Bingham Subject: [PATCH v4 18/21] ipa: mali-c55: agc: Quantise the ISP Digital Gain Date: Fri, 14 Nov 2025 00:54:22 +0000 Message-ID: <20251114005428.90024-19-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251114005428.90024-1-kieran.bingham@ideasonboard.com> References: <20251114005428.90024-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" The Mali-C55 ISP has a digital gain block which allows setting gain in Q5.8 format, a range of 0.0 to (very nearly) 32.0. Convert usage to the new UQ5_8 FixedPoint Quantised type which will support the conversion, clamping and quantisation so that the metadata and debug prints can now report the effective gain applied instead of the potentially inaccurate float. As the UQ5_8 type already clamps values, remove the explicit clamping. This removes the clamping to a minimum of 1.0 gain, so we rely on calculateNewEv to provide a valid gain. Signed-off-by: Kieran Bingham --- src/ipa/mali-c55/algorithms/agc.cpp | 20 ++++++++++---------- src/ipa/mali-c55/ipa_context.h | 6 +++--- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/ipa/mali-c55/algorithms/agc.cpp b/src/ipa/mali-c55/algorithms/agc.cpp index f60fddac3f04..3f10b237f581 100644 --- a/src/ipa/mali-c55/algorithms/agc.cpp +++ b/src/ipa/mali-c55/algorithms/agc.cpp @@ -38,8 +38,8 @@ static constexpr unsigned int kNumHistogramBins = 256; * format, a range of 0.0 to (very nearly) 32.0. We clamp from 1.0 to the actual * max value which is 8191 * 2^-8. */ -static constexpr double kMinDigitalGain = 1.0; -static constexpr double kMaxDigitalGain = 31.99609375; +static constexpr float kMinDigitalGain = 1.0; +static constexpr float kMaxDigitalGain = UQ5_8::TraitsType::max; uint32_t AgcStatistics::decodeBinValue(uint16_t binVal) { @@ -236,7 +236,7 @@ void Agc::queueRequest(IPAContext &context, const uint32_t frame, agc.manual.ispGain = *digitalGain; LOG(MaliC55Agc, Debug) - << "Digital gain set to " << agc.manual.ispGain + << "Digital gain set to " << agc.manual.ispGain.value() << " on request sequence " << frame; } } @@ -245,7 +245,7 @@ size_t Agc::fillGainParamBlock(IPAContext &context, IPAFrameContext &frameContex mali_c55_params_block block) { IPAActiveState &activeState = context.activeState; - double gain; + UQ5_8 gain; if (activeState.agc.autoEnabled) gain = activeState.agc.automatic.ispGain; @@ -256,7 +256,7 @@ size_t Agc::fillGainParamBlock(IPAContext &context, IPAFrameContext &frameContex block.header->flags = MALI_C55_PARAM_BLOCK_FL_NONE; block.header->size = sizeof(struct mali_c55_params_digital_gain); - block.digital_gain->gain = floatingToFixedPoint<5, 8, uint16_t, double>(gain); + block.digital_gain->gain = gain.quantized(); frameContext.agc.ispGain = gain; return block.header->size; @@ -376,7 +376,7 @@ void Agc::process(IPAContext &context, */ uint32_t exposure = frameContext.agc.exposure; double analogueGain = frameContext.agc.sensorGain; - double digitalGain = frameContext.agc.ispGain; + double digitalGain = frameContext.agc.ispGain.value(); double totalGain = analogueGain * digitalGain; utils::Duration currentShutter = exposure * configuration.sensor.lineDuration; utils::Duration effectiveExposureValue = currentShutter * totalGain; @@ -388,19 +388,19 @@ void Agc::process(IPAContext &context, activeState.agc.exposureMode, statistics_.yHist, effectiveExposureValue); - dGain = std::clamp(dGain, kMinDigitalGain, kMaxDigitalGain); + UQ5_8 dGainQ = static_cast(dGain); LOG(MaliC55Agc, Debug) << "Divided up shutter, analogue gain and digital gain are " - << shutterTime << ", " << aGain << " and " << dGain; + << shutterTime << ", " << aGain << " and " << dGainQ.value(); activeState.agc.automatic.exposure = shutterTime / configuration.sensor.lineDuration; activeState.agc.automatic.sensorGain = aGain; - activeState.agc.automatic.ispGain = dGain; + activeState.agc.automatic.ispGain = dGainQ; metadata.set(controls::ExposureTime, currentShutter.get()); metadata.set(controls::AnalogueGain, frameContext.agc.sensorGain); - metadata.set(controls::DigitalGain, frameContext.agc.ispGain); + metadata.set(controls::DigitalGain, frameContext.agc.ispGain.value()); metadata.set(controls::ColourTemperature, context.activeState.agc.temperatureK); } diff --git a/src/ipa/mali-c55/ipa_context.h b/src/ipa/mali-c55/ipa_context.h index 86d060a731cb..2db3fdf9e5cf 100644 --- a/src/ipa/mali-c55/ipa_context.h +++ b/src/ipa/mali-c55/ipa_context.h @@ -41,12 +41,12 @@ struct IPAActiveState { struct { uint32_t exposure; double sensorGain; - double ispGain; + UQ5_8 ispGain; } automatic; struct { uint32_t exposure; double sensorGain; - double ispGain; + UQ5_8 ispGain; } manual; bool autoEnabled; uint32_t constraintMode; @@ -64,7 +64,7 @@ struct IPAFrameContext : public FrameContext { struct { uint32_t exposure; double sensorGain; - double ispGain; + UQ5_8 ispGain; } agc; struct { From patchwork Fri Nov 14 00:54:23 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 25049 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 29534C3331 for ; Fri, 14 Nov 2025 00:55:12 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C802260AB4; Fri, 14 Nov 2025 01:55:11 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Bi/TBMv1"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9971A60AB2 for ; Fri, 14 Nov 2025 01:54:54 +0100 (CET) Received: from charm.hippo-penny.ts.net (cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 181382147; Fri, 14 Nov 2025 01:52:54 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1763081574; bh=vDMGWjYjPnIFctv9HNPlYxUJ7HArB6476qXCi/sFhPM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Bi/TBMv1Q6ZOyTtxV2TX84VtGIe7GbH3FD9/aaXbbOY9HAVCCDmvE1hySxHutaICr 5mwPQsT+ZR7CFZDl/0QTzVjHIBqpnX5Vhkikr+LB9p4GCawRhRfPDd6xsBIfiAwNsY KdmLgSO/DiRswL2kx2VeioR0KDdsf6iW0oZgs+Xk= From: Kieran Bingham To: libcamera devel Cc: Kieran Bingham Subject: [PATCH v4 19/21] test: libipa: Remove legacy fixed point conversion test Date: Fri, 14 Nov 2025 00:54:23 +0000 Message-ID: <20251114005428.90024-20-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251114005428.90024-1-kieran.bingham@ideasonboard.com> References: <20251114005428.90024-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" Now that the fixed point conversions are equally covered by the new Q types, the legacy tests for fixedToFloatingPoint and floatingToFixedPoint are redundant. Remove them. Signed-off-by: Kieran Bingham --- test/ipa/libipa/fixedpoint.cpp | 78 ---------------------------------- 1 file changed, 78 deletions(-) diff --git a/test/ipa/libipa/fixedpoint.cpp b/test/ipa/libipa/fixedpoint.cpp index e3428272fae5..357af6afa75e 100644 --- a/test/ipa/libipa/fixedpoint.cpp +++ b/test/ipa/libipa/fixedpoint.cpp @@ -26,80 +26,6 @@ using Q4_7 = Quantized>; class FixedPointUtilsTest : public Test { protected: - /* R for real, I for integer */ - template - int testFixedToFloat(I input, R expected) - { - R out = fixedToFloatingPoint(input); - R prec = 1.0 / (1 << FracPrec); - if (std::abs(out - expected) > prec) { - cerr << "Reverse conversion expected " << input - << " to convert to " << expected - << ", got " << out << std::endl; - return TestFail; - } - - return TestPass; - } - - template - int testSingleFixedPoint(double input, T expected) - { - T ret = floatingToFixedPoint(input); - if (ret != expected) { - cerr << "Expected " << input << " to convert to " - << expected << ", got " << ret << std::endl; - return TestFail; - } - - /* - * The precision check is fairly arbitrary but is based on what - * the rkisp1 is capable of in the crosstalk module. - */ - double f = fixedToFloatingPoint(ret); - if (std::abs(f - input) > 0.005) { - cerr << "Reverse conversion expected " << ret - << " to convert to " << input - << ", got " << f << std::endl; - return TestFail; - } - - return TestPass; - } - - int testFixedPoint() - { - /* - * The second 7.992 test is to test that unused bits don't - * affect the result. - */ - std::map testCases = { - { 7.992, 0x3ff }, - { 0.2, 0x01a }, - { -0.2, 0x7e6 }, - { -0.8, 0x79a }, - { -0.4, 0x7cd }, - { -1.4, 0x74d }, - { -8, 0x400 }, - { 0, 0 }, - }; - - int ret; - for (const auto &testCase : testCases) { - ret = testSingleFixedPoint<4, 7, int16_t>(testCase.first, - testCase.second); - if (ret != TestPass) - return ret; - } - - /* Special case with a superfluous one in the unused bits */ - ret = testFixedToFloat<4, 7, int16_t, double>(0xbff, 7.992); - if (ret != TestPass) - return ret; - - return TestPass; - } - template int quantizedCheck(float input, typename Q::QuantizedType expected, float value) { @@ -266,10 +192,6 @@ protected: { unsigned int fails = 0; - /* fixed point conversion test */ - if (testFixedPoint() != TestPass) - fails++; - if (testFixedPointQuantizers() != TestPass) fails++; From patchwork Fri Nov 14 00:54:24 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 25050 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 D60C6C3336 for ; Fri, 14 Nov 2025 00:55:12 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7F63860AD0; Fri, 14 Nov 2025 01:55:12 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="PvcP5dsJ"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E139560AB4 for ; Fri, 14 Nov 2025 01:54:54 +0100 (CET) Received: from charm.hippo-penny.ts.net (cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 65A8021B1; Fri, 14 Nov 2025 01:52:54 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1763081574; bh=r+jmSGgwKOxgTlQD1/jrIVqqf02bCo3w3gFv/O7Otl4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=PvcP5dsJOXYDQWj1LgqGcFM0DMf1lj9Dnk3xFtuxyLZke+coBSyTG/HPdtZ6vOM1O yy9XO7wO9J98ZHsBJEKwD7EsTrxkjI2xWWPrVC+hH30UPfm65VDnn4wEdFcYrDiXLU 82cF2wKrZUzhUdVLXkoLHS/BHN3fugjO2VEkhYmQ= From: Kieran Bingham To: libcamera devel Cc: Kieran Bingham Subject: [PATCH v4 20/21] ipa: libipa: fixedpoint: Move float conversion inline Date: Fri, 14 Nov 2025 00:54:24 +0000 Message-ID: <20251114005428.90024-21-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251114005428.90024-1-kieran.bingham@ideasonboard.com> References: <20251114005428.90024-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" With all users of the floatingToFixedPoint and fixedToFloatingPoint calls converted to use the FixedPoint Quantized types, remove the calls and documentation and move the implementation inline in the FixedPointTraits implementation. Signed-off-by: Kieran Bingham --- src/ipa/libipa/fixedpoint.cpp | 22 ---------- src/ipa/libipa/fixedpoint.h | 76 +++++++++++------------------------ 2 files changed, 23 insertions(+), 75 deletions(-) diff --git a/src/ipa/libipa/fixedpoint.cpp b/src/ipa/libipa/fixedpoint.cpp index 97cdd9b3f7aa..f2c93b1cf706 100644 --- a/src/ipa/libipa/fixedpoint.cpp +++ b/src/ipa/libipa/fixedpoint.cpp @@ -15,28 +15,6 @@ namespace libcamera { namespace ipa { -/** - * \fn R floatingToFixedPoint(T number) - * \brief Convert a floating point number to a fixed-point representation - * \tparam I Bit width of the integer part of the fixed-point - * \tparam F Bit width of the fractional part of the fixed-point - * \tparam R Return type of the fixed-point representation - * \tparam T Input type of the floating point representation - * \param number The floating point number to convert to fixed point - * \return The converted value - */ - -/** - * \fn R fixedToFloatingPoint(T number) - * \brief Convert a fixed-point number to a floating point representation - * \tparam I Bit width of the integer part of the fixed-point - * \tparam F Bit width of the fractional part of the fixed-point - * \tparam R Return type of the floating point representation - * \tparam T Input type of the fixed-point representation - * \param number The fixed point number to convert to floating point - * \return The converted value - */ - /** * \struct libcamera::ipa::FixedPointQTraits * \brief Traits type implementing fixed-point quantisation conversions diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h index 1e984350111c..fe75af16bb54 100644 --- a/src/ipa/libipa/fixedpoint.h +++ b/src/ipa/libipa/fixedpoint.h @@ -16,55 +16,6 @@ namespace libcamera { namespace ipa { -#ifndef __DOXYGEN__ -template && - std::is_floating_point_v> * = nullptr> -#else -template -#endif -constexpr R floatingToFixedPoint(T number) -{ - static_assert(sizeof(int) >= sizeof(R)); - static_assert(I + F <= sizeof(R) * 8); - - /* - * The intermediate cast to int is needed on arm platforms to properly - * cast negative values. See - * https://embeddeduse.com/2013/08/25/casting-a-negative-float-to-an-unsigned-int/ - */ - R mask = (1 << (F + I)) - 1; - R frac = static_cast(static_cast(std::round(number * (1 << F)))) & mask; - - return frac; -} - -#ifndef __DOXYGEN__ -template && - std::is_integral_v> * = nullptr> -#else -template -#endif -constexpr R fixedToFloatingPoint(T number) -{ - static_assert(sizeof(int) >= sizeof(T)); - static_assert(I + F <= sizeof(T) * 8); - - if constexpr (std::is_unsigned_v) - return static_cast(number) / static_cast(1 << F); - - /* - * Recreate the upper bits in case of a negative number by shifting the sign - * bit from the fixed point to the first bit of the unsigned and then right shifting - * by the same amount which keeps the sign bit in place. - * This can be optimized by the compiler quite well. - */ - int remaining_bits = sizeof(int) * 8 - (I + F); - int t = static_cast(static_cast(number) << remaining_bits) >> remaining_bits; - return static_cast(t) / static_cast(1 << F); -} - template struct FixedPointQTraits { static_assert(std::is_integral_v, "FixedPointQTraits: T must be integral"); @@ -88,17 +39,36 @@ struct FixedPointQTraits { static constexpr float toFloat(QuantizedType q) { - return fixedToFloatingPoint(q); + if constexpr (std::is_unsigned_v) + return static_cast(q) / static_cast(1 << F); + + /* + * Recreate the upper bits in case of a negative number by shifting the sign + * bit from the fixed point to the first bit of the unsigned and then right shifting + * by the same amount which keeps the sign bit in place. + * This can be optimized by the compiler quite well. + */ + static_assert(sizeof(int) >= sizeof(T)); + + int remaining_bits = sizeof(int) * 8 - (I + F); + int t = static_cast(static_cast(q) << remaining_bits) >> remaining_bits; + return static_cast(t) / static_cast(1 << F); } - static constexpr float min = fixedToFloatingPoint(qmin); - static constexpr float max = fixedToFloatingPoint(qmax); + static constexpr float min = toFloat(qmin); + static constexpr float max = toFloat(qmax); /* Conversion functions required by Quantized */ static constexpr QuantizedType fromFloat(float v) { v = std::clamp(v, min, max); - return floatingToFixedPoint(v); + + /* + * The intermediate cast to int is needed on arm platforms to properly + * cast negative values. See + * https://embeddeduse.com/2013/08/25/casting-a-negative-float-to-an-unsigned-int/ + */ + return static_cast(static_cast(std::round(v * (1 << F)))) & BitMask; } }; From patchwork Fri Nov 14 00:54:25 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 25051 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 92507C3337 for ; Fri, 14 Nov 2025 00:55:13 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 397F260AAB; Fri, 14 Nov 2025 01:55:13 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="kizGMTfY"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3C74760AB6 for ; Fri, 14 Nov 2025 01:54:55 +0100 (CET) Received: from charm.hippo-penny.ts.net (cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B0C9C21D0; Fri, 14 Nov 2025 01:52:54 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1763081574; bh=uth9B+Igoo2je6o6stn0vFxruvyE8aKvrJFiExHl6BI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=kizGMTfYWU4Rj5YZ6njEzoaAZCIVuVek4naIOuhryvhWCUAAqTLR3n4EYRlRka9oq 4CrEEIKlopwM/I36aETOkv4IsFHvG/Wm74mgW/FQzNk80ier326nGGjXFbCDAXi9CG nWUk361wTSuzXC3SYw7z/8qO0sjd5JJ4GBmDyfaU= From: Kieran Bingham To: libcamera devel Cc: Kieran Bingham Subject: [PATCH v4 21/21] ipa: libipa: fixedpoint: Remove unsigned workaround Date: Fri, 14 Nov 2025 00:54:25 +0000 Message-ID: <20251114005428.90024-22-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251114005428.90024-1-kieran.bingham@ideasonboard.com> References: <20251114005428.90024-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" Now that we no longer attempt or allow storing signed negative floats as an unsigned integer representation, remove the workaround which required an intermediate cast when converting floats to fixed point values. Signed-off-by: Kieran Bingham --- src/ipa/libipa/fixedpoint.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h index fe75af16bb54..fd57826d0ac0 100644 --- a/src/ipa/libipa/fixedpoint.h +++ b/src/ipa/libipa/fixedpoint.h @@ -63,12 +63,7 @@ struct FixedPointQTraits { { v = std::clamp(v, min, max); - /* - * The intermediate cast to int is needed on arm platforms to properly - * cast negative values. See - * https://embeddeduse.com/2013/08/25/casting-a-negative-float-to-an-unsigned-int/ - */ - return static_cast(static_cast(std::round(v * (1 << F)))) & BitMask; + return static_cast(std::round(v * (1 << F))) & BitMask; } };