From patchwork Fri Sep 26 14:39:36 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 24476 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 A50B2C328C for ; Fri, 26 Sep 2025 14:40:05 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 9A7A16B60E; Fri, 26 Sep 2025 16:40:01 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="AU/SdOtN"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5618A6B60E for ; Fri, 26 Sep 2025 16:39:57 +0200 (CEST) Received: from [192.168.1.100] (93-61-96-190.ip145.fastwebnet.it [93.61.96.190]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 2FAE914B0; Fri, 26 Sep 2025 16:38:30 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1758897510; bh=7Ee0rX17/WUpoPHK1wgIT+gfWlEw7zHRDHPoo9rNdi8=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=AU/SdOtNoUHWqcfrDIGiqo0Z+3vJRaAt0/6Zzx+kQlCeltFfhSsxwUIe2+yoY8Oj6 D3O7B73aP8DGREbH38pG5dGqVKkEyxRLXEDUd+Fpp3nhp3yKqA66VrRg4QsTvCSAK6 YTEycJgiaP2wBx0w+QcAcEO6Tn5um18U8yPG5YCo= From: Jacopo Mondi Date: Fri, 26 Sep 2025 16:39:36 +0200 Subject: [PATCH v3 4/5] ipa: libipa: Introduce V4L2Params MIME-Version: 1.0 Message-Id: <20250926-v4l2-params-v3-4-ee114782c1be@ideasonboard.com> References: <20250926-v4l2-params-v3-0-ee114782c1be@ideasonboard.com> In-Reply-To: <20250926-v4l2-params-v3-0-ee114782c1be@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Jacopo Mondi , Antoine Bouyer X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=25777; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=7Ee0rX17/WUpoPHK1wgIT+gfWlEw7zHRDHPoo9rNdi8=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBo1qW29QcGyykjFYS9qNnDk7OpmYYHO0/iHQ9Vw +G9whR9KW2JAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCaNaltgAKCRByNAaPFqFW PPwiD/9gzZq6DW8gcGF4wYuYLhSBnjAzD9D2aS2pz5Cl42oI6qrHJc69NEBYvJDXsFh1mrQspcG kHo0f9nUIjXO8AWD/jvzZh7HbLerjsQtUzXaWDPOpEJLQUi7XZMu2t5OqdvDinjYY0lbXQ/rsTn zIqnUroM0yCKV2LHZXeZKC4nf1Z4KpVkQwcpiugRpFuPm+NDnAjjtqDmQqp55KgW9V5zo6g4jta C1//T3FWUXCjS//Rxsk/UDacU9wQrU6LNbcGlHJzcRhb/MrOTY1xUGVeufYVpUQwdIEP5MtJ6ku InLu333BSQ+l3tAP49HawIiKR/my4WYX3ekNgePvmqI+4qgaqN8wLa8VbJKbN4LouHFmw/+IKu3 m42jLuyQZqh5DbkYjnsDnk8wFqhWoC0/J07PRUOI4FU5aJKt7Go139+UFsC0Krr98UJQmAUzJ8k 782nQEugNdKDfzmNYlFSjUqSskW5p6cXvA3pF3/KGhLx4ExcDsS1o52B2YzgU0QUFVRjn/NTVv8 DkYDjGKWupwYtUNjQkrOh/tnnViQgnPuLNLtHMbDxjmb28rhBOzEJuoDECH2fBPzYEKa8SHKfnV jV8qDCVQNnmM6nVEdAuLefF/vRfXzH6uYNAEZmmEv7b5dT7onTUeA5Nku8xHHlvk787cJt9EiQk 8tIgvW7iCAtXe6g== X-Developer-Key: i=jacopo.mondi@ideasonboard.com; a=openpgp; fpr=72392EDC88144A65C701EA9BA5826A2587AD026B 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 RkISP1Params helper classes allows the RkISP1 to handle V4L2 extensible parameters format and the legacy RkIPS1-specific fixed-size parameters format. With the introduction of v4l2-isp.h in the Linux kernel the part of the RkISP1Params helper class that handles extensible parameters can be generalized so that other IPA modules can use the same helpers to populate a v4l2-params compatible buffer. Generalize the RkISP1Params class to a new libipa component named V4L2Params and derive the existing RkISP1Params from it, leaving in the RkISP1-specific implementation the handling of the legacy format. Deriving RkISP1Params from V4L2Params requires changing the size associated to each block to include the size of v4l2_params_block_header in the ipa:rkisp1::kBlockTypeInfo map as the V4L2Params::block() implementation doesn't account for that as RkIS1Params::block() implementation did. Signed-off-by: Jacopo Mondi Tested-By: Antoine Bouyer --- src/ipa/libipa/meson.build | 2 + src/ipa/libipa/v4l2_params.cpp | 262 +++++++++++++++++++++++++++++++++++++++++ src/ipa/libipa/v4l2_params.h | 142 ++++++++++++++++++++++ src/ipa/rkisp1/params.cpp | 93 +-------------- src/ipa/rkisp1/params.h | 175 +++++++++++++++------------ 5 files changed, 509 insertions(+), 165 deletions(-) diff --git a/src/ipa/libipa/meson.build b/src/ipa/libipa/meson.build index 660be94054fa98b714b6bc586039081e45a6b4bc..4010739e710eb38aa6108eb8258c574a616bf3c0 100644 --- a/src/ipa/libipa/meson.build +++ b/src/ipa/libipa/meson.build @@ -16,6 +16,7 @@ libipa_headers = files([ 'lsc_polynomial.h', 'lux.h', 'module.h', + 'v4l2_params.h', 'pwl.h', ]) @@ -35,6 +36,7 @@ libipa_sources = files([ 'lsc_polynomial.cpp', 'lux.cpp', 'module.cpp', + 'v4l2_params.cpp', 'pwl.cpp', ]) diff --git a/src/ipa/libipa/v4l2_params.cpp b/src/ipa/libipa/v4l2_params.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b116d0a2f79da8ab9cf695195b317f4038202262 --- /dev/null +++ b/src/ipa/libipa/v4l2_params.cpp @@ -0,0 +1,262 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2025, Ideas On Board + * + * V4L2 Parameters + */ + +#include "v4l2_params.h" + +namespace libcamera { + +namespace ipa { + +/** + * \file v4l2_params.cpp + * \brief Helper class to populate an ISP configuration buffer compatible with + * the generic V4L2 ISP extensible format + * + * The Linux kernel defines a generic buffer format for configuring ISP devices + * through a set of parameters in the form of V4L2 extensible parameters. The + * V4L2 extensible parameters define a serialization format for ISP parameters + * that allows userspace to populate a buffer of configuration data by appending + * them one after the other in a binary buffer. + * + * Each ISP driver compatible with the v4l2-isp format will define its own + * meta-output format identifier and defines the types of the configuration data + * of each ISP block that usually match the registers layout. + * + * The V4L2Params class represent the V4L2 extensible parameters buffer and + * allows users to populate the ISP configuration blocks, represented by the + * V4L2ParamBlock class instances. + * + * IPA implementations using this helpers should define an enumeration of ISP + * blocks the IPA module supports and use a set of common abstraction to help + * their derived implementation of V4L2Params translate the enumerated ISP block + * identifier to the actual type of the configuration data as defined by the + * kernel interface. + * + * As an example of this see the RkISP1 and Mali-C55 implementations. + */ + +/** + * \class V4L2ParamsBlock + * \brief Helper class that represents a ISP configuration block + * + * Each ISP function is associated with a set of configuration parameters + * defined by the kernel interface. + * + * This class represents an ISP block configuration entry. It is constructed + * with a reference to the memory area where the block configuration will be + * stored in the parameters buffer. The template parameter represents + * the underlying kernel-defined ISP block configuration type and allow its + * user to easily cast it to said type to populate and read the configuration + * parameters. + * + * \sa V4L2Params::block() + */ + +/** + * \fn V4L2ParamsBlock::V4L2ParamsBlock() + * \brief Construct a V4L2ParamsBlock with memory represented by \a data + * \param[in] data A view on the memory area where the ISP block is located + */ + +/** + * \fn V4L2ParamsBlock::setEnabled() + * \brief Enable/disable an ISP configuration block + * \param[in] enabled The enable flag + */ + +/** + * \fn V4L2ParamsBlock::operator->() + * \brief Access the ISP configuration block casting it to the kernel-defined + * ISP configuration type + * + * The V4L2ParamsBlock is templated with the kernel defined ISP configuration + * block type. This function allows users to easily cast a V4L2ParamsBlock to + * the underlying kernel-defined type in order to easily populate or read + * the ISP configuration data. + * + * \code{.cpp} + * + * // The kernel header defines the ISP configuration types, in example + * // struct my_isp_awb_config_data { + * // u16 gain_ch00; + * // u16 gain_ch01; + * // u16 gain_ch10; + * // u16 gain_ch11; + * // + * // } + * + * template<> V4L2ParamsBlock awbBlock + * + * awbBlock->gain_ch00 = ...; + * awbBlock->gain_ch01 = ...; + * awbBlock->gain_ch10 = ...; + * awbBlock->gain_ch11 = ...; + * + * \endcode + * + * Users of this class are not expected to create a V4L2ParamsBlock manually but + * should rather use V4L2Params::block() to retrieve a reference to the memory + * area used to construct a V4L2ParamsBlock in their overloaded + * implementation of V4L2Params::block(). + */ + +/** + * \fn V4L2ParamsBlock::operator->() const + * \copydoc V4L2ParamsBlock::operator->() + */ + +/** + * \fn V4L2ParamsBlock::operator*() const + * \copydoc V4L2ParamsBlock::operator->() + */ + +/** + * \fn V4L2ParamsBlock::operator*() + * \copydoc V4L2ParamsBlock::operator->() + */ + +/** + * \var V4L2ParamsBlock::data_ + * \brief Memory area reserved for the ISP configuration block + */ + + /** + * \class V4L2Params + * \brief Helper class that represent an ISP configuration buffer + * + * ISP implementation compatible with v4l2-isp define their ISP configuration + * buffer types compatible with the struct v4l2_params_buffer type. + * + * This class represents an ISP configuration buffer. It is constructed + * with a reference to the memory mapped buffer that will be queued to the ISP. + * + * This class is templated with the type of the enumeration of ISP blocks that + * each IPA module is expected to support. IPA modules are expected to derive + * this class by providing a 'param_traits' type the helps the class associate + * a block type with the actual memory area that represents the ISP + * configuration block. + * + * \code{.cpp} + * + * // Define the supported ISP blocks + * enum class myISPBlocks { + * Agc, + * Awb, + * ... + * }; + * + * // Associated to the ISP blocks the kernel types + * template + * struct block_type { + * }; + * + * template<> + * struct block_type { + * using type = struct my_isp_kernel_config_type_agc; + * static constextpr struct my_isp_kernel_block_type MY_ISP_TYPE_AGC; + * }; + * + * template<> + * struct block_type { + * using type = struct my_isp_kernel_config_type_awb; + * static constextpr struct my_isp_kernel_block_type MY_ISP_TYPE_AWB; + * }; + * + * + * // Convenience type to associated a block id to the 'block_type' overload + * struct params_traits { + * using id_type = myISPBlocks; + * template using id_to_details = block_type; + * }; + * + * ... + * + * // Derive the V4L2Params class by providing params_traits + * class MyISPParams : public V4L2Params + * { + * public: + * MyISPParams::MyISPParams(Span data) + * : V4L2Params(data, kVersion) + * { + * } + * }; + * + * \endcode + * + * Users of this class can then easily access an ISP configuration block as a + * V4L2ParamsBlock instance. + * + * \code{.cpp} + * + * MyISPParams params(data); + * + * auto awb = params.block(); + * awb->gain00 = ...; + * awb->gain01 = ...; + * awb->gain10 = ...; + * awb->gain11 = ...; + * \endcode + */ + +/** + * \fn V4L2Params::V4L2Params() + * \brief Construct a V4L2Params + * \param[in] data Reference to the v4l2-buffer memory mapped area + * \param[in] version The ISP parameters version the implementation supports + */ + +/** + * \fn V4L2Params::size() + * \brief Retrieve the used size of the parameters buffer (in bytes) + * + * The parameters buffer size is mostly used to populate the v4l2_buffer + * bytesused field before queueing the buffer to the ISP. + * + * \return The number of bytes occupied by the ISP configuration parameters + */ + +/** + * \fn V4L2Params::block() + * \brief Retrieve the location of an ISP configuration block a returns it + * \return A V4L2ParamsBlock instance that points to the ISP configuration block + */ + +/** + * \fn V4L2Params::block(typename Traits::id_type type, unsigned int blockType, size_t blockSize) + * \brief Populate an ISP configuration block a returns a reference to its + * memory + * \param[in] type The ISP block identifier enumerated by the IPA module + * \param[in] blockType The kernel-defined ISP block identifier, used to + * populate the block header + * \param[in] blockSize The ISP block size, used to populate the block header + * + * Initialize the block header with \a blockType and \a blockSize and + * returns a reference to the memory used to store an ISP configuration block. + * + * IPA modules that derive the V4L2Params class shall use this function to + * retrieve the memory area that will be used to construct a V4L2ParamsBlock + * before returning it to the caller. + */ + +/** + * \var V4L2Params::data_ + * \brief The ISP parameters buffer memory + */ + +/** + * \var V4L2Params::used_ + * \brief The number of bytes used in the parameters buffer + */ + +/** + * \var V4L2Params::blocks_ + * \brief Cache of ISP configuration blocks + */ + +} /* namespace ipa */ + +} /* namespace libcamera */ diff --git a/src/ipa/libipa/v4l2_params.h b/src/ipa/libipa/v4l2_params.h new file mode 100644 index 0000000000000000000000000000000000000000..c85552ec50ae6f3a1bd8a0fede3c793df2f6da4d --- /dev/null +++ b/src/ipa/libipa/v4l2_params.h @@ -0,0 +1,142 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2025, Ideas On Board + * + * V4L2 Parameters + */ + +#pragma once + +#include +#include +#include + +#include + +#include + +namespace libcamera { + +namespace ipa { + +template +class V4L2ParamsBlock +{ +public: + V4L2ParamsBlock(const Span data) + : data_(data) + { + } + + virtual ~V4L2ParamsBlock() {} + + virtual void setEnabled(bool enabled) + { + struct v4l2_params_block_header *header = + reinterpret_cast(data_.data()); + + header->flags &= ~(V4L2_PARAMS_FL_BLOCK_ENABLE | + V4L2_PARAMS_FL_BLOCK_DISABLE); + header->flags |= enabled ? V4L2_PARAMS_FL_BLOCK_ENABLE + : V4L2_PARAMS_FL_BLOCK_DISABLE; + } + + virtual const T *operator->() const + { + return reinterpret_cast(data_.data()); + } + + virtual T *operator->() + { + return reinterpret_cast(data_.data()); + } + + virtual const T &operator*() const + { + return *reinterpret_cast(data_.data()); + } + + virtual T &operator*() + { + return *reinterpret_cast(data_.data()); + } + +protected: + Span data_; +}; + +template +class V4L2Params +{ +public: + V4L2Params(Span data, unsigned int version) + : data_(data) + { + struct v4l2_params_buffer *cfg = + reinterpret_cast(data_.data()); + cfg->data_size = 0; + cfg->version = version; + used_ = offsetof(struct v4l2_params_buffer, data); + } + + size_t size() const { return used_; } + + template + auto block() + { + using Details = typename Traits::template id_to_details; + + using Type = typename Details::type; + constexpr auto kernelId = Details::blockType; + + auto data = block(Id, kernelId, sizeof(Type)); + return V4L2ParamsBlock(data); + } + +protected: + Span block(typename Traits::id_type type, + unsigned int blockType, size_t blockSize) + { + /* + * Look up the block in the cache first. If an algorithm + * requests the same block type twice, it should get the same + * block. + */ + auto cacheIt = blocks_.find(type); + if (cacheIt != blocks_.end()) + return cacheIt->second; + + /* Make sure we don't run out of space. */ + if (blockSize > data_.size() - used_) + return {}; + + /* Allocate a new block, clear its memory, and initialize its header. */ + Span block = data_.subspan(used_, blockSize); + used_ += blockSize; + + struct v4l2_params_buffer *cfg = + reinterpret_cast(data_.data()); + cfg->data_size += blockSize; + + memset(block.data(), 0, block.size()); + + struct v4l2_params_block_header *header = + reinterpret_cast(block.data()); + header->type = blockType; + header->size = block.size(); + + /* Update the cache. */ + blocks_[type] = block; + + return block; + } + + Span data_; + size_t used_; + + std::map> blocks_; +}; + +} /* namespace ipa */ + +} /* namespace libcamera */ diff --git a/src/ipa/rkisp1/params.cpp b/src/ipa/rkisp1/params.cpp index 5edb36c91b87859d02c0a8b41efe977ff048def5..7040207c26557aa278050a1f7232cc6c380505b1 100644 --- a/src/ipa/rkisp1/params.cpp +++ b/src/ipa/rkisp1/params.cpp @@ -35,7 +35,7 @@ struct BlockTypeInfo { #define RKISP1_BLOCK_TYPE_ENTRY(block, id, type, category, bit) \ { BlockType::block, { \ RKISP1_EXT_PARAMS_BLOCK_TYPE_##id, \ - sizeof(struct rkisp1_cif_isp_##type##_config), \ + sizeof(struct rkisp1_ext_params_##type##_config), \ offsetof(struct rkisp1_params_cfg, category.type##_config), \ RKISP1_CIF_ISP_MODULE_##bit, \ } } @@ -49,7 +49,7 @@ struct BlockTypeInfo { #define RKISP1_BLOCK_TYPE_ENTRY_EXT(block, id, type) \ { BlockType::block, { \ RKISP1_EXT_PARAMS_BLOCK_TYPE_##id, \ - sizeof(struct rkisp1_cif_isp_##type##_config), \ + sizeof(struct rkisp1_ext_params_##type##_config), \ 0, 0, \ } } @@ -79,56 +79,6 @@ const std::map kBlockTypeInfo = { } /* namespace */ -RkISP1ParamsBlockBase::RkISP1ParamsBlockBase(RkISP1Params *params, BlockType type, - const Span &data) - : params_(params), type_(type) -{ - if (params_->format() == V4L2_META_FMT_RK_ISP1_EXT_PARAMS) { - header_ = data.subspan(0, sizeof(rkisp1_ext_params_block_header)); - data_ = data.subspan(sizeof(rkisp1_ext_params_block_header)); - } else { - data_ = data; - } -} - -void RkISP1ParamsBlockBase::setEnabled(bool enabled) -{ - /* - * For the legacy fixed format, blocks are enabled in the top-level - * header. Delegate to the RkISP1Params class. - */ - if (params_->format() == V4L2_META_FMT_RK_ISP1_PARAMS) - return params_->setBlockEnabled(type_, enabled); - - /* - * For the extensible format, set the enable and disable flags in the - * block header directly. - */ - struct rkisp1_ext_params_block_header *header = - reinterpret_cast(header_.data()); - header->flags &= ~(RKISP1_EXT_PARAMS_FL_BLOCK_ENABLE | - RKISP1_EXT_PARAMS_FL_BLOCK_DISABLE); - header->flags |= enabled ? RKISP1_EXT_PARAMS_FL_BLOCK_ENABLE - : RKISP1_EXT_PARAMS_FL_BLOCK_DISABLE; -} - -RkISP1Params::RkISP1Params(uint32_t format, Span data) - : format_(format), data_(data), used_(0) -{ - if (format_ == V4L2_META_FMT_RK_ISP1_EXT_PARAMS) { - struct rkisp1_ext_params_cfg *cfg = - reinterpret_cast(data.data()); - - cfg->version = RKISP1_EXT_PARAM_BUFFER_V1; - cfg->data_size = 0; - - used_ += offsetof(struct rkisp1_ext_params_cfg, data); - } else { - memset(data.data(), 0, data.size()); - used_ = sizeof(struct rkisp1_params_cfg); - } -} - void RkISP1Params::setBlockEnabled(BlockType type, bool enabled) { const BlockTypeInfo &info = kBlockTypeInfo.at(type); @@ -178,44 +128,7 @@ Span RkISP1Params::block(BlockType type) return data_.subspan(info.offset, info.size); } - /* - * For the extensible format, allocate memory for the block, including - * the header. Look up the block in the cache first. If an algorithm - * requests the same block type twice, it should get the same block. - */ - auto cacheIt = blocks_.find(type); - if (cacheIt != blocks_.end()) - return cacheIt->second; - - /* Make sure we don't run out of space. */ - size_t size = sizeof(struct rkisp1_ext_params_block_header) - + ((info.size + 7) & ~7); - if (size > data_.size() - used_) { - LOG(RkISP1Params, Error) - << "Out of memory to allocate block type " - << utils::to_underlying(type); - return {}; - } - - /* Allocate a new block, clear its memory, and initialize its header. */ - Span block = data_.subspan(used_, size); - used_ += size; - - struct rkisp1_ext_params_cfg *cfg = - reinterpret_cast(data_.data()); - cfg->data_size += size; - - memset(block.data(), 0, block.size()); - - struct rkisp1_ext_params_block_header *header = - reinterpret_cast(block.data()); - header->type = info.type; - header->size = block.size(); - - /* Update the cache. */ - blocks_[type] = block; - - return block; + return V4L2Params::block(type, info.type, info.size); } } /* namespace ipa::rkisp1 */ diff --git a/src/ipa/rkisp1/params.h b/src/ipa/rkisp1/params.h index 2e60528d102ec44a31417d4b146e74cace363efa..a7fbbc581c6df8a92dcc4fcfe1e620da6c469915 100644 --- a/src/ipa/rkisp1/params.h +++ b/src/ipa/rkisp1/params.h @@ -7,13 +7,10 @@ #pragma once -#include -#include - #include +#include -#include -#include +#include namespace libcamera { @@ -49,115 +46,143 @@ template struct block_type { }; -#define RKISP1_DEFINE_BLOCK_TYPE(blockType, blockStruct) \ +#define RKISP1_DEFINE_BLOCK_TYPE(blockType, blockStruct, id) \ template<> \ struct block_type { \ using type = struct rkisp1_cif_isp_##blockStruct##_config; \ + static constexpr rkisp1_ext_params_block_type blockType = \ + RKISP1_EXT_PARAMS_BLOCK_TYPE_##id; \ }; -RKISP1_DEFINE_BLOCK_TYPE(Bls, bls) -RKISP1_DEFINE_BLOCK_TYPE(Dpcc, dpcc) -RKISP1_DEFINE_BLOCK_TYPE(Sdg, sdg) -RKISP1_DEFINE_BLOCK_TYPE(AwbGain, awb_gain) -RKISP1_DEFINE_BLOCK_TYPE(Flt, flt) -RKISP1_DEFINE_BLOCK_TYPE(Bdm, bdm) -RKISP1_DEFINE_BLOCK_TYPE(Ctk, ctk) -RKISP1_DEFINE_BLOCK_TYPE(Goc, goc) -RKISP1_DEFINE_BLOCK_TYPE(Dpf, dpf) -RKISP1_DEFINE_BLOCK_TYPE(DpfStrength, dpf_strength) -RKISP1_DEFINE_BLOCK_TYPE(Cproc, cproc) -RKISP1_DEFINE_BLOCK_TYPE(Ie, ie) -RKISP1_DEFINE_BLOCK_TYPE(Lsc, lsc) -RKISP1_DEFINE_BLOCK_TYPE(Awb, awb_meas) -RKISP1_DEFINE_BLOCK_TYPE(Hst, hst) -RKISP1_DEFINE_BLOCK_TYPE(Aec, aec) -RKISP1_DEFINE_BLOCK_TYPE(Afc, afc) -RKISP1_DEFINE_BLOCK_TYPE(CompandBls, compand_bls) -RKISP1_DEFINE_BLOCK_TYPE(CompandExpand, compand_curve) -RKISP1_DEFINE_BLOCK_TYPE(CompandCompress, compand_curve) -RKISP1_DEFINE_BLOCK_TYPE(Wdr, wdr) +RKISP1_DEFINE_BLOCK_TYPE(Bls, bls, BLS) +RKISP1_DEFINE_BLOCK_TYPE(Dpcc, dpcc, DPCC) +RKISP1_DEFINE_BLOCK_TYPE(Sdg, sdg, SDG) +RKISP1_DEFINE_BLOCK_TYPE(AwbGain, awb_gain, AWB_GAIN) +RKISP1_DEFINE_BLOCK_TYPE(Flt, flt, FLT) +RKISP1_DEFINE_BLOCK_TYPE(Bdm, bdm, BDM) +RKISP1_DEFINE_BLOCK_TYPE(Ctk, ctk, CTK) +RKISP1_DEFINE_BLOCK_TYPE(Goc, goc, GOC) +RKISP1_DEFINE_BLOCK_TYPE(Dpf, dpf, DPF) +RKISP1_DEFINE_BLOCK_TYPE(DpfStrength, dpf_strength, DPF_STRENGTH) +RKISP1_DEFINE_BLOCK_TYPE(Cproc, cproc, CPROC) +RKISP1_DEFINE_BLOCK_TYPE(Ie, ie, IE) +RKISP1_DEFINE_BLOCK_TYPE(Lsc, lsc, LSC) +RKISP1_DEFINE_BLOCK_TYPE(Awb, awb_meas, AWB_MEAS) +RKISP1_DEFINE_BLOCK_TYPE(Hst, hst, HST_MEAS) +RKISP1_DEFINE_BLOCK_TYPE(Aec, aec, AEC_MEAS) +RKISP1_DEFINE_BLOCK_TYPE(Afc, afc, AFC_MEAS) +RKISP1_DEFINE_BLOCK_TYPE(CompandBls, compand_bls, COMPAND_BLS) +RKISP1_DEFINE_BLOCK_TYPE(CompandExpand, compand_curve, COMPAND_EXPAND) +RKISP1_DEFINE_BLOCK_TYPE(CompandCompress, compand_curve, COMPAND_COMPRESS) +RKISP1_DEFINE_BLOCK_TYPE(Wdr, wdr, WDR) + +struct params_traits { + using id_type = BlockType; + + template + using id_to_details = block_type; +}; } /* namespace details */ -class RkISP1Params; +template +class RkISP1ParamsBlock; -class RkISP1ParamsBlockBase +class RkISP1Params : public V4L2Params { public: - RkISP1ParamsBlockBase(RkISP1Params *params, BlockType type, - const Span &data); + static constexpr unsigned int kVersion = RKISP1_EXT_PARAM_BUFFER_V1; + + RkISP1Params(uint32_t format, Span data) + : V4L2Params(data, kVersion), format_(format) + { + if (format_ == V4L2_META_FMT_RK_ISP1_PARAMS) { + memset(data.data(), 0, data.size()); + used_ = sizeof(struct rkisp1_params_cfg); + } + } + + template + auto block() + { + using Type = typename details::block_type::type; - Span data() const { return data_; } + return RkISP1ParamsBlock(this, id, block(id)); + } - void setEnabled(bool enabled); + uint32_t format() const { return format_; } + void setBlockEnabled(BlockType type, bool enabled); private: - LIBCAMERA_DISABLE_COPY(RkISP1ParamsBlockBase) + Span block(BlockType type); - RkISP1Params *params_; - BlockType type_; - Span header_; - Span data_; + uint32_t format_; }; -template -class RkISP1ParamsBlock : public RkISP1ParamsBlockBase +template +class RkISP1ParamsBlock : public V4L2ParamsBlock { public: - using Type = typename details::block_type::type; - - RkISP1ParamsBlock(RkISP1Params *params, const Span &data) - : RkISP1ParamsBlockBase(params, B, data) + RkISP1ParamsBlock(RkISP1Params *params, BlockType type, + const Span data) + : V4L2ParamsBlock(data) { + params_ = params; + type_ = type; + + /* + * cifData_ points to the actual configuration data + * (struct rkisp1_cif_isp_*) which is not prefixed by any header, + * for the legacy fixed format. + */ + if (params_->format() == V4L2_META_FMT_RK_ISP1_PARAMS) + cifData_ = data; + else + cifData_ = data.subspan(sizeof(v4l2_params_block_header)); } - const Type *operator->() const + void setEnabled(bool enabled) override { - return reinterpret_cast(data().data()); + /* + * For the legacy fixed format, blocks are enabled in the + * top-level header. Delegate to the RkISP1Params class. + */ + if (params_->format() == V4L2_META_FMT_RK_ISP1_PARAMS) + return params_->setBlockEnabled(type_, enabled); + + return V4L2ParamsBlock::setEnabled(enabled); } - Type *operator->() + /* + * Override the dereference operators to return a reference to the + * actual configuration data (struct rkisp1_cif_isp_*) skipping the + * 'v4l2_params_block_header' header. + */ + + virtual const T *operator->() const override { - return reinterpret_cast(data().data()); + return reinterpret_cast(cifData_.data()); } - const Type &operator*() const & + virtual T *operator->() override { - return *reinterpret_cast(data().data()); + return reinterpret_cast(cifData_.data()); } - Type &operator*() & + virtual const T &operator*() const override { - return *reinterpret_cast(data().data()); + return *reinterpret_cast(cifData_.data()); } -}; - -class RkISP1Params -{ -public: - RkISP1Params(uint32_t format, Span data); - template - RkISP1ParamsBlock block() + virtual T &operator*() override { - return RkISP1ParamsBlock(this, block(B)); + return *reinterpret_cast(cifData_.data()); } - uint32_t format() const { return format_; } - size_t size() const { return used_; } - private: - friend class RkISP1ParamsBlockBase; - - Span block(BlockType type); - void setBlockEnabled(BlockType type, bool enabled); - - uint32_t format_; - - Span data_; - size_t used_; - - std::map> blocks_; + RkISP1Params *params_; + BlockType type_; + Span cifData_; }; } /* namespace ipa::rkisp1 */