{"id":24824,"url":"https://patchwork.libcamera.org/api/patches/24824/?format=json","web_url":"https://patchwork.libcamera.org/patch/24824/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20251026233048.175689-2-kieran.bingham@ideasonboard.com>","date":"2025-10-26T23:30:38","name":"[1/6] libipa: Provide a Quantized type and Quantizer support","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"9f6ba8cadee5c18470ee0299aa5b7a1f00682034","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/?format=json","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/24824/mbox/","series":[{"id":5532,"url":"https://patchwork.libcamera.org/api/series/5532/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=5532","date":"2025-10-26T23:30:37","name":"libipa: Introduce a Quantized type","version":1,"mbox":"https://patchwork.libcamera.org/series/5532/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/24824/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/24824/checks/","tags":{},"headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id D6068BE080\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSun, 26 Oct 2025 23:30:59 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 5AEE4606F8;\n\tMon, 27 Oct 2025 00:30:57 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id EAE8D606E0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 27 Oct 2025 00:30:53 +0100 (CET)","from charm.hippo-penny.ts.net (unknown [209.38.108.23])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 38CE4E77;\n\tMon, 27 Oct 2025 00:29:06 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"gN822ZId\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1761521346;\n\tbh=1FcaQEB87OPnpDmcTCZcyq3suw1t0sx0KOfWaRXpDsw=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=gN822ZId2NSBWy5bEOP1F2N8efdTHaLGqDTpOEWZgz8N4Ho8tiyNWocAPGAt7XYK/\n\tCS0NqUlVKFifCNglucxdUQAnlX7PjM6qAnxmRQYJ1kIREiXzq64gRe7iVwFdmZN08t\n\tk+dAte/yEeZng0x3JNpFFIaDL9XzP4wLlZuw+iZg=","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","To":"libcamera devel <libcamera-devel@lists.libcamera.org>","Cc":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Subject":"[PATCH 1/6] libipa: Provide a Quantized type and Quantizer support","Date":"Sun, 26 Oct 2025 23:30:38 +0000","Message-ID":"<20251026233048.175689-2-kieran.bingham@ideasonboard.com>","X-Mailer":"git-send-email 2.51.0","In-Reply-To":"<20251026233048.175689-1-kieran.bingham@ideasonboard.com>","References":"<20251026233048.175689-1-kieran.bingham@ideasonboard.com>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"},"content":"Frequently when handling data in IPA components we must convert and\nstore user interface values which may be floating point values, and\nperform a specific operation or conversion to quantize this to a\nhardware value.\n\nThis value may be to a fixed point type, or more custom code mappings,\nbut in either case it is important to contain both the required hardware\nvalue, with it's effective quantized value.\n\nProvide a new storage type 'Quantized' which can be read publicly but\nmust only be written through a controller class known as a Quantizer.\n\nQuantizers can be customised and specified by the owner of the data\nobject and must implement conversion between floats and the underlying\nhardware type.\n\nSigned-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n---\n src/ipa/libipa/meson.build   |   2 +\n src/ipa/libipa/quantized.cpp | 167 +++++++++++++++++++++++++++++++++++\n src/ipa/libipa/quantized.h   |  90 +++++++++++++++++++\n 3 files changed, 259 insertions(+)\n create mode 100644 src/ipa/libipa/quantized.cpp\n create mode 100644 src/ipa/libipa/quantized.h","diff":"diff --git a/src/ipa/libipa/meson.build b/src/ipa/libipa/meson.build\nindex 660be94054fa..804289778f72 100644\n--- a/src/ipa/libipa/meson.build\n+++ b/src/ipa/libipa/meson.build\n@@ -17,6 +17,7 @@ libipa_headers = files([\n     'lux.h',\n     'module.h',\n     'pwl.h',\n+    'quantized.h',\n ])\n \n libipa_sources = files([\n@@ -36,6 +37,7 @@ libipa_sources = files([\n     'lux.cpp',\n     'module.cpp',\n     'pwl.cpp',\n+    'quantized.cpp',\n ])\n \n libipa_includes = include_directories('..')\ndiff --git a/src/ipa/libipa/quantized.cpp b/src/ipa/libipa/quantized.cpp\nnew file mode 100644\nindex 000000000000..0078c6f740a9\n--- /dev/null\n+++ b/src/ipa/libipa/quantized.cpp\n@@ -0,0 +1,167 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2025, Ideas On Board.\n+ *\n+ * Helper class to manage conversions between floating point types and quantized\n+ * storage and representation of those values.\n+ */\n+\n+#include \"quantized.h\"\n+\n+/**\n+ * \\file quantized.h\n+ * \\brief Quantized storage and Quantizer representations\n+ */\n+\n+namespace libcamera {\n+\n+namespace ipa {\n+\n+/**\n+ * \\struct Quantized\n+ * \\brief Quantized stores both an internal and quantized representation of a value\n+ * \\tparam T The quantized type (e.g., uint16_t, int16_t).\n+ *\n+ * This struct provides read-only access to both representations of the value.\n+ * It does not perform any conversions or quantization logic itself. This must\n+ * be handled externally by a quantizer that knows the appropriate behaviour.\n+ *\n+ * This type can be used to store values that need to be represented in both\n+ * fixed-point or integer (for hardware interfaces) and floating-point (for user\n+ * facing interfaces)\n+ *\n+ * It is intended to be used in shared context structures where both\n+ * hardware-level and software-level representations of a value are required.\n+ */\n+\n+/**\n+ * \\fn float Quantized::value() const noexcept\n+ * \\brief Get the floating-point representation of the quantized value\n+ *\n+ * This function returns the floating-point form that was either directly assigned\n+ * or computed from the quantized value.\n+ *\n+ * \\return The floating-point value\n+ */\n+\n+/**\n+ * \\fn T Quantized::quantized() const noexcept\n+ * \\brief Get the raw quantized representation of the value\n+ *\n+ * This function returns the internal quantized value (e.g. \\c uint8_t or \\c int16_t),\n+ * which is typically used for hardware-level programming or serialization.\n+ *\n+ * \\return The quantized value of type \\c T\n+ */\n+\n+/**\n+ * \\fn std::string Quantized::toString() const\n+ * \\brief Generate a string representation of the quantized and float values\n+ *\n+ * Produces a human-readable string including both the quantized and floating-point\n+ * values, typically in the format: \"Q:0xXX F:float\".\n+ *\n+ * \\return A formatted string representing the internal state\n+ */\n+\n+/**\n+ * \\fn bool Quantized::operator==(const Quantized<T> &other) const noexcept\n+ * \\brief Compare two quantized values for equality\n+ *\n+ * Two \\c Quantized<T> objects are equal if their quantized values are equal.\n+ *\n+ * \\param other The \\c Quantized<T> to compare with\n+ * \\return \\c true if equal, \\c false otherwise\n+ */\n+\n+/**\n+ * \\fn bool Quantized::operator!=(const Quantized<T> &other) const noexcept\n+ * \\brief Compare two quantized values for inequality\n+ *\n+ * Two \\c Quantized<T> objects are not equal if their quantized values differ.\n+ *\n+ * \\param other The \\c Quantized<T> to compare with\n+ * \\return \\c true if not equal, \\c false otherwise\n+ */\n+\n+/**\n+ * \\var Quantized::quantized_\n+ * \\brief The raw quantized value\n+ *\n+ * This member stores the fixed-point or integer representation of the value, typically\n+ * used for interfacing with hardware or protocols that require compact formats.\n+ *\n+ * It must only be updated or accessed through a Quantizer in conjunction with\n+ * corresponding updates to \\c Quantized::value_.\n+ */\n+\n+/**\n+ * \\var Quantized::value_\n+ * \\brief The floating-point representation of the quantized value\n+ *\n+ * This member holds the floating-point equivalent of the quantized value, usually\n+ * for use in calculations or presentation to higher-level software components.\n+ *\n+ * It must only be updated or accessed through a Quantizer in conjunction with\n+ * corresponding updates to \\c Quantized::quantized_.\n+ */\n+\n+/**\n+ * \\class Quantizer\n+ * \\brief Interface for converting between floating-point and quantized types\n+ * \\tparam T The quantized type (e.g., uint16_t, int16_t).\n+ *\n+ * This abstract class defines the interface for quantizers that handle\n+ * conversions between floating-point values and their quantized representations.\n+ * Specific quantization handlers should implement this interface and provide\n+ * the toFloat and fromFloat methods specifically for their types.\n+ */\n+\n+/**\n+ * \\typedef Quantizer::qType\n+ * \\brief The underlying quantized type used by the quantizer\n+ *\n+ * This alias exposes the quantized type (e.g. \\c uint8_t or \\c int16_t) used internally\n+ * by the \\c Quantizer, which is helpful in template and debug contexts.\n+ */\n+\n+/**\n+ * \\fn Quantizer::fromFloat(T val)\n+ * \\brief Convert a floating-point value to its quantized representation\n+ *\n+ * \\param val The floating-point value\n+ * \\return The quantized equivalent\n+ */\n+\n+/**\n+ * \\fn Quantizer::toFloat(T val)\n+ * \\brief Convert a quantized value to its floating-point representation\n+ *\n+ * \\param val The quantized value\n+ * \\return The floating-point equivalent\n+ */\n+\n+/**\n+ * \\fn Quantizer::set(float val)\n+ * \\brief Set the value of a Quantized<T> using a floating-point input\n+ *\n+ * This function updates both the quantized and floating-point\n+ * representations stored in the Quantized<T>, storing the quantized\n+ * version of the float input.\n+ *\n+ * \\param val The floating-point value to set\n+ */\n+\n+/**\n+ * \\fn Quantizer::set(T val)\n+ * \\brief Set the value of a Quantized<T> using a quantized input\n+ *\n+ * This function updates both the quantized and floating-point\n+ * representations stored in the Quantized<T>.\n+ *\n+ * \\param val The quantized value to set\n+ */\n+\n+} /* namespace ipa */\n+\n+} /* namespace libcamera */\ndiff --git a/src/ipa/libipa/quantized.h b/src/ipa/libipa/quantized.h\nnew file mode 100644\nindex 000000000000..1c1963cf0848\n--- /dev/null\n+++ b/src/ipa/libipa/quantized.h\n@@ -0,0 +1,90 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2025, Ideas On Board.\n+ *\n+ * Helper class to manage conversions between floating point types and quantized\n+ * storage and representation of those values.\n+ */\n+\n+#pragma once\n+\n+#include <iomanip>\n+#include <sstream>\n+#include <stdint.h>\n+#include <type_traits>\n+\n+namespace libcamera {\n+\n+namespace ipa {\n+\n+template<typename Q>\n+class Quantizer;\n+\n+template<typename T>\n+struct Quantized {\n+\tstatic_assert(std::is_arithmetic_v<T>, \"Quantized: T must be an arithmetic type\");\n+\n+\tfloat value() const noexcept { return value_; }\n+\tT quantized() const noexcept { return quantized_; }\n+\n+\tstd::string toString() const\n+\t{\n+\t\tusing UT = std::make_unsigned_t<T>;\n+\t\tstd::ostringstream oss;\n+\n+\t\toss << \"Q:0x\" << std::hex << std::uppercase << std::setw(sizeof(T) * 2)\n+\t\t    << std::setfill('0');\n+\n+\t\tif constexpr (std::is_unsigned_v<T>) {\n+\t\t\toss << static_cast<unsigned>(quantized_);\n+\t\t} else {\n+\t\t\toss << static_cast<unsigned>(static_cast<UT>(quantized_));\n+\t\t}\n+\n+\t\toss << \" F:\" << value_;\n+\n+\t\treturn oss.str();\n+\t}\n+\n+\tbool operator==(const Quantized<T> &other) const noexcept\n+\t{\n+\t\treturn quantized_ == other.quantized_ && value_ == other.value_;\n+\t}\n+\n+\tbool operator!=(const Quantized<T> &other) const noexcept\n+\t{\n+\t\treturn !(*this == other);\n+\t}\n+\n+protected:\n+\tT quantized_{};\n+\tfloat value_{};\n+};\n+\n+template<typename T>\n+class Quantizer : public Quantized<T>\n+{\n+public:\n+\tusing qType = T;\n+\n+\tvirtual ~Quantizer() = default;\n+\n+\tvirtual T fromFloat(float val) const = 0;\n+\tvirtual float toFloat(T val) const = 0;\n+\n+\tvoid set(float val)\n+\t{\n+\t\tthis->quantized_ = fromFloat(val);\n+\t\tthis->value_ = toFloat(this->quantized_);\n+\t}\n+\n+\tvoid set(T val)\n+\t{\n+\t\tthis->quantized_ = val;\n+\t\tthis->value_ = toFloat(val);\n+\t}\n+};\n+\n+} /* namespace ipa */\n+\n+} /* namespace libcamera */\n","prefixes":["1/6"]}