{"id":21957,"url":"https://patchwork.libcamera.org/api/patches/21957/?format=json","web_url":"https://patchwork.libcamera.org/patch/21957/","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":"<20241118150528.1856797-3-stefan.klug@ideasonboard.com>","date":"2024-11-18T15:05:05","name":"[2/4] libcamera: Enable and use matrix implementation from libcamera/internal","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"a17fb90ecb7323bc8d84a16c9b883b6441789b93","submitter":{"id":184,"url":"https://patchwork.libcamera.org/api/people/184/?format=json","name":"Stefan Klug","email":"stefan.klug@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/21957/mbox/","series":[{"id":4797,"url":"https://patchwork.libcamera.org/api/series/4797/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=4797","date":"2024-11-18T15:05:03","name":"Move Matrix class from libipa to libcamera","version":1,"mbox":"https://patchwork.libcamera.org/series/4797/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/21957/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/21957/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 BA70CC32EF\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 18 Nov 2024 15:05:51 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 54EB2658EC;\n\tMon, 18 Nov 2024 16:05:50 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 0793C658E0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 18 Nov 2024 16:05:48 +0100 (CET)","from ideasonboard.com (unknown\n\t[IPv6:2a00:6020:448c:6c00:4424:4869:bb88:5c61])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 4B0CDB2B;\n\tMon, 18 Nov 2024 16:05:31 +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=\"DgxcKIju\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1731942331;\n\tbh=kUh+Xri+YK7SjkWjEl6eR6u0Duu3KJuPqlPpiC1M0Sg=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=DgxcKIjuDy2OZL/CI5BysACFr1DYzW19W0mkJpbacoPmONneIIqn5ohFggBgZPNTa\n\t41GWmme8RqC7eGVgwJN8WfBtR8S5XN5L0YyVuyeMU6ZDzPI6dGttwiA5I/qmjY3E+N\n\tl14CgmEHH7gv+v7YlLf3aVZ7kDOZskihSNPbjNt4=","From":"Stefan Klug <stefan.klug@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Cc":"Stefan Klug <stefan.klug@ideasonboard.com>","Subject":"[PATCH 2/4] libcamera: Enable and use matrix implementation from\n\tlibcamera/internal","Date":"Mon, 18 Nov 2024 16:05:05 +0100","Message-ID":"<20241118150528.1856797-3-stefan.klug@ideasonboard.com>","X-Mailer":"git-send-email 2.43.0","In-Reply-To":"<20241118150528.1856797-1-stefan.klug@ideasonboard.com>","References":"<20241118150528.1856797-1-stefan.klug@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":"The matrix code copied from libipa needs to be adapted to compile and\nwork from the new location. To keep the project buildable at all times,\nthese changes are not split into multiple commits but kept as a single\none.\n\nThe changes are:\n- Add matrix class to meson.build\n- Move matrix class from libipa namespace into libcamera\n- Add std::initializer_list based constructor to be able to replace the\n  Matrix implementation contained in the rpi pipeline\n- Replace Matrix class in rpi pipeline with the new one to prevent name\n  clashes\n\nSigned-off-by: Stefan Klug <stefan.klug@ideasonboard.com>\n---\n include/libcamera/internal/matrix.h    | 20 ++++-----\n include/libcamera/internal/meson.build |  1 +\n src/ipa/rpi/controller/rpi/ccm.cpp     | 56 +++++++-------------------\n src/ipa/rpi/controller/rpi/ccm.h       | 35 +---------------\n src/libcamera/matrix.cpp               |  8 +---\n src/libcamera/meson.build              |  1 +\n 6 files changed, 32 insertions(+), 89 deletions(-)","diff":"diff --git a/include/libcamera/internal/matrix.h b/include/libcamera/internal/matrix.h\nindex 5471e6975b74..b82d33f98658 100644\n--- a/include/libcamera/internal/matrix.h\n+++ b/include/libcamera/internal/matrix.h\n@@ -19,8 +19,6 @@ namespace libcamera {\n \n LOG_DECLARE_CATEGORY(Matrix)\n \n-namespace ipa {\n-\n #ifndef __DOXYGEN__\n template<typename T, unsigned int Rows, unsigned int Cols,\n \t std::enable_if_t<std::is_arithmetic_v<T>> * = nullptr>\n@@ -35,6 +33,12 @@ public:\n \t\tdata_.fill(static_cast<T>(0));\n \t}\n \n+\tMatrix(std::initializer_list<T> data)\n+\t{\n+\t\tASSERT(data.size() == Rows * Cols);\n+\t\tstd::copy(data.begin(), data.end(), data_.begin());\n+\t}\n+\n \tMatrix(const std::vector<T> &data)\n \t{\n \t\tstd::copy(data.begin(), data.end(), data_.begin());\n@@ -166,24 +170,22 @@ Matrix<T, Rows, Cols> operator+(const Matrix<T, Rows, Cols> &m1, const Matrix<T,\n bool matrixValidateYaml(const YamlObject &obj, unsigned int size);\n #endif /* __DOXYGEN__ */\n \n-} /* namespace ipa */\n-\n #ifndef __DOXYGEN__\n template<typename T, unsigned int Rows, unsigned int Cols>\n-std::ostream &operator<<(std::ostream &out, const ipa::Matrix<T, Rows, Cols> &m)\n+std::ostream &operator<<(std::ostream &out, const Matrix<T, Rows, Cols> &m)\n {\n \tout << m.toString();\n \treturn out;\n }\n \n template<typename T, unsigned int Rows, unsigned int Cols>\n-struct YamlObject::Getter<ipa::Matrix<T, Rows, Cols>> {\n-\tstd::optional<ipa::Matrix<T, Rows, Cols>> get(const YamlObject &obj) const\n+struct YamlObject::Getter<Matrix<T, Rows, Cols>> {\n+\tstd::optional<Matrix<T, Rows, Cols>> get(const YamlObject &obj) const\n \t{\n-\t\tif (!ipa::matrixValidateYaml(obj, Rows * Cols))\n+\t\tif (!matrixValidateYaml(obj, Rows * Cols))\n \t\t\treturn std::nullopt;\n \n-\t\tipa::Matrix<T, Rows, Cols> matrix;\n+\t\tMatrix<T, Rows, Cols> matrix;\n \t\tT *data = &matrix[0][0];\n \n \t\tunsigned int i = 0;\ndiff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build\nindex 1dddcd50c90b..7d6aa8b72bd7 100644\n--- a/include/libcamera/internal/meson.build\n+++ b/include/libcamera/internal/meson.build\n@@ -29,6 +29,7 @@ libcamera_internal_headers = files([\n     'ipc_pipe.h',\n     'ipc_unixsocket.h',\n     'mapped_framebuffer.h',\n+    'matrix.h',\n     'media_device.h',\n     'media_object.h',\n     'pipeline_handler.h',\ndiff --git a/src/ipa/rpi/controller/rpi/ccm.cpp b/src/ipa/rpi/controller/rpi/ccm.cpp\nindex aefa580c9a4b..418bead56ecd 100644\n--- a/src/ipa/rpi/controller/rpi/ccm.cpp\n+++ b/src/ipa/rpi/controller/rpi/ccm.cpp\n@@ -29,34 +29,7 @@ LOG_DEFINE_CATEGORY(RPiCcm)\n \n #define NAME \"rpi.ccm\"\n \n-Matrix::Matrix()\n-{\n-\tmemset(m, 0, sizeof(m));\n-}\n-Matrix::Matrix(double m0, double m1, double m2, double m3, double m4, double m5,\n-\t       double m6, double m7, double m8)\n-{\n-\tm[0][0] = m0, m[0][1] = m1, m[0][2] = m2, m[1][0] = m3, m[1][1] = m4,\n-\tm[1][2] = m5, m[2][0] = m6, m[2][1] = m7, m[2][2] = m8;\n-}\n-int Matrix::read(const libcamera::YamlObject &params)\n-{\n-\tdouble *ptr = (double *)m;\n-\n-\tif (params.size() != 9) {\n-\t\tLOG(RPiCcm, Error) << \"Wrong number of values in CCM\";\n-\t\treturn -EINVAL;\n-\t}\n-\n-\tfor (const auto &param : params.asList()) {\n-\t\tauto value = param.get<double>();\n-\t\tif (!value)\n-\t\t\treturn -EINVAL;\n-\t\t*ptr++ = *value;\n-\t}\n-\n-\treturn 0;\n-}\n+using Matrix3x3 = Matrix<double, 3, 3>;\n \n Ccm::Ccm(Controller *controller)\n \t: CcmAlgorithm(controller), saturation_(1.0) {}\n@@ -68,8 +41,6 @@ char const *Ccm::name() const\n \n int Ccm::read(const libcamera::YamlObject &params)\n {\n-\tint ret;\n-\n \tif (params.contains(\"saturation\")) {\n \t\tconfig_.saturation = params[\"saturation\"].get<ipa::Pwl>(ipa::Pwl{});\n \t\tif (config_.saturation.empty())\n@@ -83,9 +54,12 @@ int Ccm::read(const libcamera::YamlObject &params)\n \n \t\tCtCcm ctCcm;\n \t\tctCcm.ct = *value;\n-\t\tret = ctCcm.ccm.read(p[\"ccm\"]);\n-\t\tif (ret)\n-\t\t\treturn ret;\n+\n+\t\tauto ccm = p[\"ccm\"].get<Matrix3x3>();\n+\t\tif (!ccm)\n+\t\t\treturn -EINVAL;\n+\n+\t\tctCcm.ccm = *ccm;\n \n \t\tif (!config_.ccms.empty() && ctCcm.ct <= config_.ccms.back().ct) {\n \t\t\tLOG(RPiCcm, Error)\n@@ -125,7 +99,7 @@ bool getLocked(Metadata *metadata, std::string const &tag, T &value)\n \treturn true;\n }\n \n-Matrix calculateCcm(std::vector<CtCcm> const &ccms, double ct)\n+Matrix3x3 calculateCcm(std::vector<CtCcm> const &ccms, double ct)\n {\n \tif (ct <= ccms.front().ct)\n \t\treturn ccms.front().ccm;\n@@ -141,13 +115,13 @@ Matrix calculateCcm(std::vector<CtCcm> const &ccms, double ct)\n \t}\n }\n \n-Matrix applySaturation(Matrix const &ccm, double saturation)\n+Matrix3x3 applySaturation(Matrix3x3 const &ccm, double saturation)\n {\n-\tMatrix RGB2Y(0.299, 0.587, 0.114, -0.169, -0.331, 0.500, 0.500, -0.419,\n-\t\t     -0.081);\n-\tMatrix Y2RGB(1.000, 0.000, 1.402, 1.000, -0.345, -0.714, 1.000, 1.771,\n-\t\t     0.000);\n-\tMatrix S(1, 0, 0, 0, saturation, 0, 0, 0, saturation);\n+\tMatrix3x3 RGB2Y({ 0.299, 0.587, 0.114, -0.169, -0.331, 0.500, 0.500,\n+\t\t\t  -0.419, -0.081 });\n+\tMatrix3x3 Y2RGB({ 1.000, 0.000, 1.402, 1.000, -0.345, -0.714, 1.000,\n+\t\t\t  1.771, 0.000 });\n+\tMatrix3x3 S({ 1, 0, 0, 0, saturation, 0, 0, 0, saturation });\n \treturn Y2RGB * S * RGB2Y * ccm;\n }\n \n@@ -181,7 +155,7 @@ void Ccm::prepare(Metadata *imageMetadata)\n \tfor (int j = 0; j < 3; j++)\n \t\tfor (int i = 0; i < 3; i++)\n \t\t\tccmStatus.matrix[j * 3 + i] =\n-\t\t\t\tstd::max(-8.0, std::min(7.9999, ccm.m[j][i]));\n+\t\t\t\tstd::max(-8.0, std::min(7.9999, ccm[j][i]));\n \tLOG(RPiCcm, Debug)\n \t\t<< \"colour temperature \" << awb.temperatureK << \"K\";\n \tLOG(RPiCcm, Debug)\ndiff --git a/src/ipa/rpi/controller/rpi/ccm.h b/src/ipa/rpi/controller/rpi/ccm.h\nindex 4e5b33fefa4e..c05dbb17a264 100644\n--- a/src/ipa/rpi/controller/rpi/ccm.h\n+++ b/src/ipa/rpi/controller/rpi/ccm.h\n@@ -8,6 +8,7 @@\n \n #include <vector>\n \n+#include \"libcamera/internal/matrix.h\"\n #include <libipa/pwl.h>\n \n #include \"../ccm_algorithm.h\"\n@@ -16,41 +17,9 @@ namespace RPiController {\n \n /* Algorithm to calculate colour matrix. Should be placed after AWB. */\n \n-struct Matrix {\n-\tMatrix(double m0, double m1, double m2, double m3, double m4, double m5,\n-\t       double m6, double m7, double m8);\n-\tMatrix();\n-\tdouble m[3][3];\n-\tint read(const libcamera::YamlObject &params);\n-};\n-static inline Matrix operator*(double d, Matrix const &m)\n-{\n-\treturn Matrix(m.m[0][0] * d, m.m[0][1] * d, m.m[0][2] * d,\n-\t\t      m.m[1][0] * d, m.m[1][1] * d, m.m[1][2] * d,\n-\t\t      m.m[2][0] * d, m.m[2][1] * d, m.m[2][2] * d);\n-}\n-static inline Matrix operator*(Matrix const &m1, Matrix const &m2)\n-{\n-\tMatrix m;\n-\tfor (int i = 0; i < 3; i++)\n-\t\tfor (int j = 0; j < 3; j++)\n-\t\t\tm.m[i][j] = m1.m[i][0] * m2.m[0][j] +\n-\t\t\t\t    m1.m[i][1] * m2.m[1][j] +\n-\t\t\t\t    m1.m[i][2] * m2.m[2][j];\n-\treturn m;\n-}\n-static inline Matrix operator+(Matrix const &m1, Matrix const &m2)\n-{\n-\tMatrix m;\n-\tfor (int i = 0; i < 3; i++)\n-\t\tfor (int j = 0; j < 3; j++)\n-\t\t\tm.m[i][j] = m1.m[i][j] + m2.m[i][j];\n-\treturn m;\n-}\n-\n struct CtCcm {\n \tdouble ct;\n-\tMatrix ccm;\n+\tlibcamera::Matrix<double, 3, 3> ccm;\n };\n \n struct CcmConfig {\ndiff --git a/src/libcamera/matrix.cpp b/src/libcamera/matrix.cpp\nindex 8346f0d34160..c3ed54895b22 100644\n--- a/src/libcamera/matrix.cpp\n+++ b/src/libcamera/matrix.cpp\n@@ -5,7 +5,7 @@\n  * Matrix and related operations\n  */\n \n-#include \"matrix.h\"\n+#include \"libcamera/internal/matrix.h\"\n \n #include <libcamera/base/log.h>\n \n@@ -18,8 +18,6 @@ namespace libcamera {\n \n LOG_DEFINE_CATEGORY(Matrix)\n \n-namespace ipa {\n-\n /**\n  * \\class Matrix\n  * \\brief Matrix class\n@@ -34,7 +32,7 @@ namespace ipa {\n  */\n \n /**\n- * \\fn Matrix::Matrix(const std::vector<T> &data)\n+ * \\fn Matrix::Matrix(const Span<T> &data)\n  * \\brief Construct a matrix from supplied data\n  * \\param[in] data Data from which to construct a matrix\n  *\n@@ -144,6 +142,4 @@ bool matrixValidateYaml(const YamlObject &obj, unsigned int size)\n }\n #endif /* __DOXYGEN__ */\n \n-} /* namespace ipa */\n-\n } /* namespace libcamera */\ndiff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\nindex 21cae11756d6..57fde8a8fab0 100644\n--- a/src/libcamera/meson.build\n+++ b/src/libcamera/meson.build\n@@ -40,6 +40,7 @@ libcamera_internal_sources = files([\n     'ipc_pipe_unixsocket.cpp',\n     'ipc_unixsocket.cpp',\n     'mapped_framebuffer.cpp',\n+    'matrix.cpp',\n     'media_device.cpp',\n     'media_object.cpp',\n     'pipeline_handler.cpp',\n","prefixes":["2/4"]}