From patchwork Tue Sep 16 12:28:22 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 24368 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 7CF85BE173 for ; Tue, 16 Sep 2025 12:28:41 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E500169371; Tue, 16 Sep 2025 14:28:40 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Gwj2Ci92"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 266A269371 for ; Tue, 16 Sep 2025 14:28:38 +0200 (CEST) Received: from [192.168.0.172] (mob-5-90-51-255.net.vodafone.it [5.90.51.255]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id BAD64DF3; Tue, 16 Sep 2025 14:27:18 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1758025639; bh=m6UKSto21lH4DyPU8izBwOOwuVC+d0tBZtGMWkTJvDE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Gwj2Ci92up1nRJnXpqbV51ALSH2LtrMJVUuq39Qo9ulECneOQGFuOX+Bk8h1s9ppv CYmwvc81TdLL1FS5d2nVxpNFsNnUbIi2OFSxPTzYdlfD+uzmEVQphZEWgj6x2lw16p 8eS2zBWIN4TvzcD8kHbqfkH0hS/zb82+ewuqgBm4= From: Jacopo Mondi Date: Tue, 16 Sep 2025 14:28:22 +0200 Subject: [PATCH v2 1/4] include: linux: Add v4l2-isp.h MIME-Version: 1.0 Message-Id: <20250916-v4l2-params-v2-1-764471ed6435@ideasonboard.com> References: <20250916-v4l2-params-v2-0-764471ed6435@ideasonboard.com> In-Reply-To: <20250916-v4l2-params-v2-0-764471ed6435@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=5197; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=m6UKSto21lH4DyPU8izBwOOwuVC+d0tBZtGMWkTJvDE=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBoyVfxSEwUApcymPTjAHbZd4mSbHxBl85OsOgtE SE5QnUfYdWJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCaMlX8QAKCRByNAaPFqFW PLQuEACnuswjJZj8jnhLhYh3Yh528F8KskvQd094JKdZl+SX6rIOMchdEX8no/9F/9uNEBrWypo r8X9vJsg569qynYSPixsJP8SfZ/zNJHvUVXxZuQw61f+oyOXs3ayyabWOBvX0kopPmdXxrIM3vM spq8F65sRfk66QoHmaklPdMeViWfCf7VfintAVjx502/FI3kDC/+HcbBCIZLrJ+Vak/h/QgwGV2 5ylaKAQL6JV7Th9DLJf6oJ0Yjijuvt11bZ9tJnefrXFOS0Ej00sRXf7+B97KwU959OvEzHPSlGj Tnr/UMScxrzhQm7oLwPWbjI/2Om6+8sOaezs/NT8DuhX0k6M6UxkCn9JYcwpkSwg4AND9QCAKVH WjdYEX7I0rFnmnQpPzVZDxCyJ0/8fV3052PSFj5/T3MLSNuvfg9RDrc/2qfXS6MlVC5zqWTvCtg prVxXniiKdgJsiPtX1a+j6N0NuaSjttlngwa0iJs3af49uZMSxqhRZ2cZZBf0PJ/2sTBxGBVnhX CPWq/+C7VeHk9rtXN/SO+euDgL+ZfNy3HhWkoGxSuaa3TUQ8cBdPNdvi9FPsPkde4ckRz46GcSx TmT/ddML3zwT+uYqzSjPUl1GYBujADGUS7kuJ/l4lVbPWzZ1Zn9cz70svuOdGuLy3ldTi+hQe6P bVQC8O1orO15N/Q== 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" Import the v4l2-isp.h header from the Linux kernel sources. The file has not been merged in mainline Linux yet but is available at: https://lore.kernel.org/all/20250915-extensible-parameters-validation-v5-0-e6db94468af3@ideasonboard.com/ Create the include/linux/media/ directory so that header files exported from the kernel which include this file do not need to be adjusted when imported in libcamera. Signed-off-by: Jacopo Mondi Tested-By: Antoine Bouyer --- include/linux/media/v4l2-isp.h | 100 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/include/linux/media/v4l2-isp.h b/include/linux/media/v4l2-isp.h new file mode 100644 index 0000000000000000000000000000000000000000..fed89b5678585a3565d33cf873d0313dc089524f --- /dev/null +++ b/include/linux/media/v4l2-isp.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Video4Linux2 generic ISP parameters and statistics support + * + * Copyright (C) 2025 Ideas On Board Oy + * Author: Jacopo Mondi + */ + +#ifndef _V4L2_ISP_H_ +#define _V4L2_ISP_H_ + +#include +#include + +#define V4L2_PARAMS_FL_BLOCK_DISABLE (1U << 0) +#define V4L2_PARAMS_FL_BLOCK_ENABLE (1U << 1) + +/* + * Reserve the first 8 bits for V4L2_PARAMS_FL_* flag. + * + * Driver-specific flags should be defined as: + * #define PLATFORM_SPECIFIC_FLAG0 ((1U << V4L2_PARAMS_FL_DRIVER_FLAGS(0)) + * #define PLATFORM_SPECIFIC_FLAG1 ((1U << V4L2_PARAMS_FL_DRIVER_FLAGS(1)) + */ +#define V4L2_PARAMS_FL_DRIVER_FLAGS(n) ((n) + 8) + +/** + * struct v4l2_params_block_header - V4L2 extensible parameters block header + * + * This structure represents the common part of all the ISP configuration + * blocks. Each parameters block shall embed an instance of this structure type + * as its first member, followed by the block-specific configuration data. The + * driver inspects this common header to discern the block type and its size and + * properly handle the block content. + * + * The @type field is an ISP driver-specific value that identifies the block + * type. The @size field specifies the size of the parameters block. + * + * The @flags field is a bitmask of per-block flags V4L2_PARAMS_FL_* and + * driver-specific flags specified by the driver header. + * + * @type: The parameters block type (driver-specific) + * @flags: A bitmask of block flags (driver-specific) + * @size: Size (in bytes) of the parameters block, including this header + */ +struct v4l2_params_block_header { + __u16 type; + __u16 flags; + __u32 size; +} __attribute__((aligned(8))); + +/** + * v4l2_params_buffer_size - Calculate size of v4l2_params_buffer for a platform + * + * Users of the v4l2 extensible parameters will have differing sized data arrays + * depending on their specific parameter buffers. Drivers and userspace will + * need to be able to calculate the appropriate size of the struct to + * accommodate all ISP configuration blocks provided by the platform. + * This macro provides a convenient tool for the calculation. + * + * @max_params_size: The total size of the ISP configuration blocks + */ +#define v4l2_params_buffer_size(max_params_size) \ + (offsetof(struct v4l2_params_buffer, data) + (max_params_size)) + +/** + * struct v4l2_params_buffer - V4L2 extensible parameters configuration + * + * This struct contains the configuration parameters of the ISP algorithms, + * serialized by userspace into a data buffer. Each configuration parameter + * block is represented by a block-specific structure which contains a + * :c:type:`v4l2_params_block_header` entry as first member. Userspace populates + * the @data buffer with configuration parameters for the blocks that it intends + * to configure. As a consequence, the data buffer effective size changes + * according to the number of ISP blocks that userspace intends to configure and + * is set by userspace in the @data_size field. + * + * The parameters buffer is versioned by the @version field to allow modifying + * and extending its definition. Userspace shall populate the @version field to + * inform the driver about the version it intends to use. The driver will parse + * and handle the @data buffer according to the data layout specific to the + * indicated version and return an error if the desired version is not + * supported. + * + * For each ISP block that userspace wants to configure, a block-specific + * structure is appended to the @data buffer, one after the other without gaps + * in between nor overlaps. Userspace shall populate the @data_size field with + * the effective size, in bytes, of the @data buffer. + * + * @version: The parameters buffer version (driver-specific) + * @data_size: The configuration data effective size, excluding this header + * @data: The configuration data + */ +struct v4l2_params_buffer { + __u32 version; + __u32 data_size; + __u8 data[] __counted_by(data_size); +}; + +#endif /* _V4L2_ISP_H_ */ From patchwork Tue Sep 16 12:28:23 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 24369 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 932FBBE173 for ; Tue, 16 Sep 2025 12:28:45 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 2C65D69379; Tue, 16 Sep 2025 14:28:45 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="SW/TyLcK"; 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 A053069377 for ; Tue, 16 Sep 2025 14:28:41 +0200 (CEST) Received: from [192.168.0.172] (mob-5-90-51-255.net.vodafone.it [5.90.51.255]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E9693C6F; Tue, 16 Sep 2025 14:27:20 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1758025643; bh=WLEQrRuf/BYMX0Z0xEaq9D9hy113lxygdvP4qq/1PE0=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=SW/TyLcKJanT5b/a17sczKVKN/VCqndM2cQDWdKTfDYgKM/NjJyuzWq/WkMzeEJAh 3p6wg0i5+4syq688zibi+J7xde2HMIAnVhmT0pam5BGAgb87PpTwBXo2WSWOcIin2O bjcaogx9k3/FQe+j625O5aMtHDt1RGTNcT6CErGQ= From: Jacopo Mondi Date: Tue, 16 Sep 2025 14:28:23 +0200 Subject: [PATCH v2 2/4] ipa: Update Mali C55 header file and adjust IPA MIME-Version: 1.0 Message-Id: <20250916-v4l2-params-v2-2-764471ed6435@ideasonboard.com> References: <20250916-v4l2-params-v2-0-764471ed6435@ideasonboard.com> In-Reply-To: <20250916-v4l2-params-v2-0-764471ed6435@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=26183; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=WLEQrRuf/BYMX0Z0xEaq9D9hy113lxygdvP4qq/1PE0=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBoyVfxdPo2JD3a4kR3tNLs2uS+BcttXykKF/uaa bfKXq12Au+JAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCaMlX8QAKCRByNAaPFqFW PC/8D/98OCRnlAsTz7RAcPoVfCnuwFn/i5W8BN6nSu7ZzC6Q5YjBQ+VLQPEVDmzauy5b8El7pVQ W+scF8xi60MPXtyt5fIWKUzbVkcGlisCP2Uhl8LOEqBtxYcbMoYQA82Eyyga5m0dzKbpJv+Orxo SZG90YNl0u0RvS5/beF6qHjR5AR3JeevtUEdRJB9IycUo64Wq7zXpAUxnfEcA+AChn+SBVOz+IQ a94bVbNMnpx2cfEFxHRIxSB0EwQEd/BrJF74zULnw2Y2nM0id3J5v6d6NaG1g3yV4GASKDKkSKv r8PE8bet00sJHXe4U8iHMWJ8Of+lJaxd9Kk29+d0E4oVpq0n6bwiX5ZweWbjHME8Ctc5Zqf9TLK 3uRkHk4iRovUQ3J+y73y2meXTprb6GqTBVQH33eKaQrXAvSzBatu6ucZpF1G8xUp1+xnjDFB0oq UIWBpd+bbmLt/F3ONhKnqmdk5pI3LUZEcIkxN19xleYc3u4YG1PEjtcq7nxpDEsasZn0l+HFCWd HoENdscgW9TpnNyOFwKVMhLXZboKm7ZZJhx0E6biaXvevC2L0LJY+S16pDL+IXJTaSY2m8t5mBp Naz3gyZZdYTr6De6QGDhGAnOtG9FO9TIC3BVF7IpXbfUCfmlAh9C2y+XaP0VAZYmQm3TtVTiQ2C 166uAqXdy44d53Q== 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" Update Mali C55 header file with the v11 version of the patch series, based on v4l2 extensible parameters, sent to the linux-media mailing list at: https://lore.kernel.org/all/20250714-c55-v11-0-bc20e460e42a@ideasonboard.com/ Adjust the IPA module to use the new v4l2-isp.h header file. Signed-off-by: Jacopo Mondi Tested-By: Antoine Bouyer --- include/linux/mali-c55-config.h | 162 +++++--------------------------- src/ipa/mali-c55/algorithms/agc.cpp | 28 +++--- src/ipa/mali-c55/algorithms/agc.h | 2 +- src/ipa/mali-c55/algorithms/algorithm.h | 2 +- src/ipa/mali-c55/algorithms/awb.cpp | 14 +-- src/ipa/mali-c55/algorithms/awb.h | 2 +- src/ipa/mali-c55/algorithms/blc.cpp | 8 +- src/ipa/mali-c55/algorithms/blc.h | 2 +- src/ipa/mali-c55/algorithms/lsc.cpp | 14 +-- src/ipa/mali-c55/algorithms/lsc.h | 2 +- src/ipa/mali-c55/mali-c55.cpp | 10 +- src/ipa/mali-c55/module.h | 2 +- 12 files changed, 67 insertions(+), 181 deletions(-) diff --git a/include/linux/mali-c55-config.h b/include/linux/mali-c55-config.h index b31415597e886496b65f8fb396c095618467f1ac..3e22a9e50dce85b69fc96f8e6cd03d199430eb8b 100644 --- a/include/linux/mali-c55-config.h +++ b/include/linux/mali-c55-config.h @@ -9,6 +9,22 @@ #define __UAPI_MALI_C55_CONFIG_H #include +#include + +#include + +#define V4L2_CID_MALI_C55_CAPABILITIES (V4L2_CID_USER_MALI_C55_BASE + 0x0) +#define MALI_C55_GPS_PONG (1U << 0) +#define MALI_C55_GPS_WDR (1U << 1) +#define MALI_C55_GPS_COMPRESSION (1U << 2) +#define MALI_C55_GPS_TEMPER (1U << 3) +#define MALI_C55_GPS_SINTER_LITE (1U << 4) +#define MALI_C55_GPS_SINTER (1U << 5) +#define MALI_C55_GPS_IRIDIX_LTM (1U << 6) +#define MALI_C55_GPS_IRIDIX_GTM (1U << 7) +#define MALI_C55_GPS_CNR (1U << 8) +#define MALI_C55_GPS_FRSCALER (1U << 9) +#define MALI_C55_GPS_DS_PIPE (1U << 10) /* * Frames are split into zones of almost equal width and height - a zone is a @@ -228,65 +244,6 @@ enum mali_c55_param_block_type { MALI_C55_PARAM_MESH_SHADING_SELECTION, }; -#define MALI_C55_PARAM_BLOCK_FL_NONE 0 -#define MALI_C55_PARAM_BLOCK_FL_DISABLED BIT(0) - -/** - * struct mali_c55_params_block_header - Mali-C55 parameter block header - * - * This structure represents the common part of all the ISP configuration - * blocks. Each parameters block embeds an instance of this structure type - * as its first member, followed by the block-specific configuration data. The - * driver inspects this common header to discern the block type and its size and - * properly handle the block content by casting it to the correct block-specific - * type. - * - * The @type field is one of the values enumerated by - * :c:type:`mali_c55_param_block_type` and specifies how the data should be - * interpreted by the driver. The @size field specifies the size of the - * parameters block and is used by the driver for validation purposes. The - * @flags field holds a bitmask of per-block flags MALI_C55_PARAM_BLOCK_FL_*. - * - * If userspace wants to disable an ISP block the - * MALI_C55_PARAM_BLOCK_FL_DISABLED bit should be set in the @flags field. In - * that case userspace may optionally omit the remainder of the configuration - * block, which will in any case be ignored by the driver. If a new - * configuration of an ISP block has to be applied userspace shall fully - * populate the ISP block and omit setting the MALI_C55_PARAM_BLOCK_FL_DISABLED - * bit in the @flags field. - * - * Userspace is responsible for correctly populating the parameters block header - * fields (@type, @flags and @size) and correctly populate the block-specific - * parameters. - * - * For example: - * - * .. code-block:: c - * - * void populate_sensor_offs(struct mali_c55_params_block_header *block) { - * block->type = MALI_C55_PARAM_BLOCK_SENSOR_OFFS; - * block->enabled = MALI_C55_PARAM_BLOCK_FL_NONE; - * block->size = sizeof(struct mali_c55_params_sensor_off_preshading); - * - * struct mali_c55_params_sensor_off_preshading *sensor_offs = - * (struct mali_c55_params_sensor_off_preshading *)block; - * - * sensor_offs->chan00 = offset00; - * sensor_offs->chan01 = offset01; - * sensor_offs->chan10 = offset10; - * sensor_offs->chan11 = offset11; - * } - * - * @type: The parameters block type from :c:type:`mali_c55_param_block_type` - * @flags: Bitmask of block flags - * @size: Size (in bytes) of the parameters block - */ -struct mali_c55_params_block_header { - __u16 type; - __u16 flags; - __u32 size; -} __attribute__((aligned(8))); - /** * struct mali_c55_params_sensor_off_preshading - offset subtraction for each * color channel @@ -305,7 +262,7 @@ struct mali_c55_params_block_header { * @chan11: Offset for color channel 11 (default: B) */ struct mali_c55_params_sensor_off_preshading { - struct mali_c55_params_block_header header; + struct v4l2_params_block_header header; __u32 chan00; __u32 chan01; __u32 chan10; @@ -470,7 +427,7 @@ enum mali_c55_aexp_hist_plane_mode { * This parameter is unused for the post-Iridix Histogram */ struct mali_c55_params_aexp_hist { - struct mali_c55_params_block_header header; + struct v4l2_params_block_header header; __u8 skip_x; __u8 offset_x; __u8 skip_y; @@ -502,7 +459,7 @@ struct mali_c55_params_aexp_hist { * @nodes_used_horiz */ struct mali_c55_params_aexp_weights { - struct mali_c55_params_block_header header; + struct v4l2_params_block_header header; __u8 nodes_used_horiz; __u8 nodes_used_vert; __u8 zone_weights[MALI_C55_MAX_ZONES]; @@ -520,7 +477,7 @@ struct mali_c55_params_aexp_weights { * @gain: The digital gain value to apply, in Q5.8 format. */ struct mali_c55_params_digital_gain { - struct mali_c55_params_block_header header; + struct v4l2_params_block_header header; __u16 gain; }; @@ -560,7 +517,7 @@ enum mali_c55_awb_stats_mode { * @gain11: Multiplier for colour channel 11 */ struct mali_c55_params_awb_gains { - struct mali_c55_params_block_header header; + struct v4l2_params_block_header header; __u16 gain00; __u16 gain01; __u16 gain10; @@ -635,7 +592,7 @@ enum mali_c55_params_awb_tap_points { * @cb_low: B/G ratio trim low (Q4.8 format) */ struct mali_c55_params_awb_config { - struct mali_c55_params_block_header header; + struct v4l2_params_block_header header; __u8 tap_point; __u8 stats_mode; __u16 white_level; @@ -745,7 +702,7 @@ struct mali_c55_params_awb_config { * @mesh: Mesh shading correction tables */ struct mali_c55_params_mesh_shading_config { - struct mali_c55_params_block_header header; + struct v4l2_params_block_header header; __u8 mesh_show; __u8 mesh_scale; __u8 mesh_page_r; @@ -800,7 +757,7 @@ enum mali_c55_params_mesh_alpha_bank { * @mesh_strength: Mesh strength in Q4.12 format [0..4096] */ struct mali_c55_params_mesh_shading_selection { - struct mali_c55_params_block_header header; + struct v4l2_params_block_header header; __u8 mesh_alpha_bank_r; __u8 mesh_alpha_bank_g; __u8 mesh_alpha_bank_b; @@ -835,75 +792,4 @@ struct mali_c55_params_mesh_shading_selection { sizeof(struct mali_c55_params_mesh_shading_config) + \ sizeof(struct mali_c55_params_mesh_shading_selection)) -/** - * struct mali_c55_params_buffer - 3A configuration parameters - * - * This struct contains the configuration parameters of the Mali-C55 ISP - * algorithms, serialized by userspace into a data buffer. Each configuration - * parameter block is represented by a block-specific structure which contains a - * :c:type:`mali_c55_params_block_header` entry as first member. Userspace - * populates the @data buffer with configuration parameters for the blocks that - * it intends to configure. As a consequence, the data buffer effective size - * changes according to the number of ISP blocks that userspace intends to - * configure. - * - * The parameters buffer is versioned by the @version field to allow modifying - * and extending its definition. Userspace shall populate the @version field to - * inform the driver about the version it intends to use. The driver will parse - * and handle the @data buffer according to the data layout specific to the - * indicated version and return an error if the desired version is not - * supported. - * - * For each ISP block that userspace wants to configure, a block-specific - * structure is appended to the @data buffer, one after the other without gaps - * in between nor overlaps. Userspace shall populate the @total_size field with - * the effective size, in bytes, of the @data buffer. - * - * The expected memory layout of the parameters buffer is:: - * - * +-------------------- struct mali_c55_params_buffer ------------------+ - * | version = MALI_C55_PARAM_BUFFER_V1; | - * | total_size = sizeof(struct mali_c55_params_sensor_off_preshading) | - * | sizeof(struct mali_c55_params_aexp_hist); | - * | +------------------------- data ---------------------------------+ | - * | | +--------- struct mali_c55_params_sensor_off_preshading ------+ | | - * | | | +-------- struct mali_c55_params_block_header header -----+ | | | - * | | | | type = MALI_C55_PARAM_BLOCK_SENSOR_OFFS; | | | | - * | | | | flags = MALI_C55_PARAM_BLOCK_FL_NONE; | | | | - * | | | | size = | | | | - * | | | | sizeof(struct mali_c55_params_sensor_off_preshading);| | | | - * | | | +---------------------------------------------------------+ | | | - * | | | chan00 = ...; | | | - * | | | chan01 = ...; | | | - * | | | chan10 = ...; | | | - * | | | chan11 = ...; | | | - * | | +------------ struct mali_c55_params_aexp_hist ---------------+ | | - * | | | +-------- struct mali_c55_params_block_header header -----+ | | | - * | | | | type = MALI_C55_PARAM_BLOCK_AEXP_HIST; | | | | - * | | | | flags = MALI_C55_PARAM_BLOCK_FL_NONE; | | | | - * | | | | size = sizeof(struct mali_c55_params_aexp_hist); | | | | - * | | | +---------------------------------------------------------+ | | | - * | | | skip_x = ...; | | | - * | | | offset_x = ...; | | | - * | | | skip_y = ...; | | | - * | | | offset_y = ...; | | | - * | | | scale_bottom = ...; | | | - * | | | scale_top = ...; | | | - * | | | plane_mode = ...; | | | - * | | | tap_point = ...; | | | - * | | +-------------------------------------------------------------+ | | - * | +-----------------------------------------------------------------+ | - * +---------------------------------------------------------------------+ - * - * @version: The version from :c:type:`mali_c55_param_buffer_version` - * @total_size: The Mali-C55 configuration data effective size, excluding this - * header - * @data: The Mali-C55 configuration blocks data - */ -struct mali_c55_params_buffer { - __u8 version; - __u32 total_size; - __u8 data[MALI_C55_PARAMS_MAX_SIZE]; -}; - #endif /* __UAPI_MALI_C55_CONFIG_H */ diff --git a/src/ipa/mali-c55/algorithms/agc.cpp b/src/ipa/mali-c55/algorithms/agc.cpp index 15963994b2d626485b33bac10e3eb38803f239dc..80d9d956d07d1665e61876b0429fb94a30c7cbe1 100644 --- a/src/ipa/mali-c55/algorithms/agc.cpp +++ b/src/ipa/mali-c55/algorithms/agc.cpp @@ -252,7 +252,7 @@ size_t Agc::fillGainParamBlock(IPAContext &context, IPAFrameContext &frameContex gain = activeState.agc.manual.ispGain; block.header->type = MALI_C55_PARAM_BLOCK_DIGITAL_GAIN; - block.header->flags = MALI_C55_PARAM_BLOCK_FL_NONE; + block.header->flags = 0; block.header->size = sizeof(struct mali_c55_params_digital_gain); block.digital_gain->gain = floatingToFixedPoint<5, 8, uint16_t, double>(gain); @@ -265,7 +265,7 @@ size_t Agc::fillParamsBuffer(mali_c55_params_block block, enum mali_c55_param_block_type type) { block.header->type = type; - block.header->flags = MALI_C55_PARAM_BLOCK_FL_NONE; + block.header->flags = 0; block.header->size = sizeof(struct mali_c55_params_aexp_hist); /* Collect every 3rd pixel horizontally */ @@ -291,7 +291,7 @@ size_t Agc::fillWeightsArrayBuffer(mali_c55_params_block block, enum mali_c55_param_block_type type) { block.header->type = type; - block.header->flags = MALI_C55_PARAM_BLOCK_FL_NONE; + block.header->flags = 0; block.header->size = sizeof(struct mali_c55_params_aexp_weights); /* We use every zone - a 15x15 grid */ @@ -313,30 +313,30 @@ size_t Agc::fillWeightsArrayBuffer(mali_c55_params_block block, } void Agc::prepare(IPAContext &context, const uint32_t frame, - IPAFrameContext &frameContext, mali_c55_params_buffer *params) + IPAFrameContext &frameContext, v4l2_params_buffer *params) { mali_c55_params_block block; - block.data = ¶ms->data[params->total_size]; - params->total_size += fillGainParamBlock(context, frameContext, block); + block.data = ¶ms->data[params->data_size]; + params->data_size += fillGainParamBlock(context, frameContext, block); if (frame > 0) return; - block.data = ¶ms->data[params->total_size]; - params->total_size += fillParamsBuffer(block, + block.data = ¶ms->data[params->data_size]; + params->data_size += fillParamsBuffer(block, MALI_C55_PARAM_BLOCK_AEXP_HIST); - block.data = ¶ms->data[params->total_size]; - params->total_size += fillWeightsArrayBuffer(block, + block.data = ¶ms->data[params->data_size]; + params->data_size += fillWeightsArrayBuffer(block, MALI_C55_PARAM_BLOCK_AEXP_HIST_WEIGHTS); - block.data = ¶ms->data[params->total_size]; - params->total_size += fillParamsBuffer(block, + block.data = ¶ms->data[params->data_size]; + params->data_size += fillParamsBuffer(block, MALI_C55_PARAM_BLOCK_AEXP_IHIST); - block.data = ¶ms->data[params->total_size]; - params->total_size += fillWeightsArrayBuffer(block, + block.data = ¶ms->data[params->data_size]; + params->data_size += fillWeightsArrayBuffer(block, MALI_C55_PARAM_BLOCK_AEXP_IHIST_WEIGHTS); } diff --git a/src/ipa/mali-c55/algorithms/agc.h b/src/ipa/mali-c55/algorithms/agc.h index 0b4bf7eda1c2a7c9894f6932452fea5f53699b30..64caf99350c1d1835832311a94a88a2bfde5721c 100644 --- a/src/ipa/mali-c55/algorithms/agc.h +++ b/src/ipa/mali-c55/algorithms/agc.h @@ -57,7 +57,7 @@ public: const ControlList &controls) override; void prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, - mali_c55_params_buffer *params) override; + v4l2_params_buffer *params) override; void process(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, const mali_c55_stats_buffer *stats, diff --git a/src/ipa/mali-c55/algorithms/algorithm.h b/src/ipa/mali-c55/algorithms/algorithm.h index ec8dd3973eaf2d804d8de8620840f716340e9cfd..c28789f6a619cf7fc05ffb705098ed8d1fac93b8 100644 --- a/src/ipa/mali-c55/algorithms/algorithm.h +++ b/src/ipa/mali-c55/algorithms/algorithm.h @@ -22,7 +22,7 @@ class Algorithm : public libcamera::ipa::Algorithm }; union mali_c55_params_block { - struct mali_c55_params_block_header *header; + struct v4l2_params_block_header *header; struct mali_c55_params_sensor_off_preshading *sensor_offs; struct mali_c55_params_aexp_hist *aexp_hist; struct mali_c55_params_aexp_weights *aexp_weights; diff --git a/src/ipa/mali-c55/algorithms/awb.cpp b/src/ipa/mali-c55/algorithms/awb.cpp index 3d546e5a854b8aa02987c44f57109a6171e3794b..6b2cbed9de1ebfe9a2466ebe999eceac44fe5deb 100644 --- a/src/ipa/mali-c55/algorithms/awb.cpp +++ b/src/ipa/mali-c55/algorithms/awb.cpp @@ -47,7 +47,7 @@ size_t Awb::fillGainsParamBlock(mali_c55_params_block block, IPAContext &context IPAFrameContext &frameContext) { block.header->type = MALI_C55_PARAM_BLOCK_AWB_GAINS; - block.header->flags = MALI_C55_PARAM_BLOCK_FL_NONE; + block.header->flags = 0; block.header->size = sizeof(struct mali_c55_params_awb_gains); double rGain = context.activeState.awb.rGain; @@ -77,7 +77,7 @@ size_t Awb::fillGainsParamBlock(mali_c55_params_block block, IPAContext &context size_t Awb::fillConfigParamBlock(mali_c55_params_block block) { block.header->type = MALI_C55_PARAM_BLOCK_AWB_CONFIG; - block.header->flags = MALI_C55_PARAM_BLOCK_FL_NONE; + block.header->flags = 0; block.header->size = sizeof(struct mali_c55_params_awb_config); /* Tap the stats after the purple fringe block */ @@ -126,18 +126,18 @@ size_t Awb::fillConfigParamBlock(mali_c55_params_block block) } void Awb::prepare(IPAContext &context, const uint32_t frame, - IPAFrameContext &frameContext, mali_c55_params_buffer *params) + IPAFrameContext &frameContext, v4l2_params_buffer *params) { mali_c55_params_block block; - block.data = ¶ms->data[params->total_size]; + block.data = ¶ms->data[params->data_size]; - params->total_size += fillGainsParamBlock(block, context, frameContext); + params->data_size += fillGainsParamBlock(block, context, frameContext); if (frame > 0) return; - block.data = ¶ms->data[params->total_size]; - params->total_size += fillConfigParamBlock(block); + block.data = ¶ms->data[params->data_size]; + params->data_size += fillConfigParamBlock(block); } void Awb::process(IPAContext &context, const uint32_t frame, diff --git a/src/ipa/mali-c55/algorithms/awb.h b/src/ipa/mali-c55/algorithms/awb.h index 2351d405553058dbff569e9e09e265a56baaa23f..b5ff121041d1a01e3a51d64b87a90fb2e1d8dd10 100644 --- a/src/ipa/mali-c55/algorithms/awb.h +++ b/src/ipa/mali-c55/algorithms/awb.h @@ -22,7 +22,7 @@ public: const IPACameraSensorInfo &configInfo) override; void prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, - mali_c55_params_buffer *params) override; + v4l2_params_buffer *params) override; void process(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, const mali_c55_stats_buffer *stats, diff --git a/src/ipa/mali-c55/algorithms/blc.cpp b/src/ipa/mali-c55/algorithms/blc.cpp index 2a54c86a91f83d24183cb7236fcd5181302eb622..8fd0f10c3082030a36a256830042d733ed4c8c78 100644 --- a/src/ipa/mali-c55/algorithms/blc.cpp +++ b/src/ipa/mali-c55/algorithms/blc.cpp @@ -85,10 +85,10 @@ int BlackLevelCorrection::configure(IPAContext &context, void BlackLevelCorrection::prepare([[maybe_unused]] IPAContext &context, const uint32_t frame, [[maybe_unused]] IPAFrameContext &frameContext, - mali_c55_params_buffer *params) + v4l2_params_buffer *params) { mali_c55_params_block block; - block.data = ¶ms->data[params->total_size]; + block.data = ¶ms->data[params->data_size]; if (frame > 0) return; @@ -97,7 +97,7 @@ void BlackLevelCorrection::prepare([[maybe_unused]] IPAContext &context, return; block.header->type = MALI_C55_PARAM_BLOCK_SENSOR_OFFS; - block.header->flags = MALI_C55_PARAM_BLOCK_FL_NONE; + block.header->flags = 0; block.header->size = sizeof(mali_c55_params_sensor_off_preshading); block.sensor_offs->chan00 = offset00; @@ -105,7 +105,7 @@ void BlackLevelCorrection::prepare([[maybe_unused]] IPAContext &context, block.sensor_offs->chan10 = offset10; block.sensor_offs->chan11 = offset11; - params->total_size += block.header->size; + params->data_size += block.header->size; } void BlackLevelCorrection::process([[maybe_unused]] IPAContext &context, diff --git a/src/ipa/mali-c55/algorithms/blc.h b/src/ipa/mali-c55/algorithms/blc.h index 9696e8e9f2aa8b9076a3a41fb8f5ea356e32be12..cf10505ce2908df0d5e658d3fdce663729c7ea76 100644 --- a/src/ipa/mali-c55/algorithms/blc.h +++ b/src/ipa/mali-c55/algorithms/blc.h @@ -22,7 +22,7 @@ public: const IPACameraSensorInfo &configInfo) override; void prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, - mali_c55_params_buffer *params) override; + v4l2_params_buffer *params) override; void process(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, const mali_c55_stats_buffer *stats, diff --git a/src/ipa/mali-c55/algorithms/lsc.cpp b/src/ipa/mali-c55/algorithms/lsc.cpp index c43d034a181edb7559706189f8d75edd67a2dc08..35f1d876e60db252a45cadb771e541735749d106 100644 --- a/src/ipa/mali-c55/algorithms/lsc.cpp +++ b/src/ipa/mali-c55/algorithms/lsc.cpp @@ -111,7 +111,7 @@ int Lsc::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData size_t Lsc::fillConfigParamsBlock(mali_c55_params_block block) const { block.header->type = MALI_C55_PARAM_MESH_SHADING_CONFIG; - block.header->flags = MALI_C55_PARAM_BLOCK_FL_NONE; + block.header->flags = 0; block.header->size = sizeof(struct mali_c55_params_mesh_shading_config); block.shading_config->mesh_show = false; @@ -131,7 +131,7 @@ size_t Lsc::fillSelectionParamsBlock(mali_c55_params_block block, uint8_t bank, uint8_t alpha) const { block.header->type = MALI_C55_PARAM_MESH_SHADING_SELECTION; - block.header->flags = MALI_C55_PARAM_BLOCK_FL_NONE; + block.header->flags = 0; block.header->size = sizeof(struct mali_c55_params_mesh_shading_selection); block.shading_selection->mesh_alpha_bank_r = bank; @@ -170,7 +170,7 @@ std::tuple Lsc::findBankAndAlpha(uint32_t ct) const void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, [[maybe_unused]] IPAFrameContext &frameContext, - mali_c55_params_buffer *params) + v4l2_params_buffer *params) { /* * For each frame we assess the colour temperature of the **last** frame @@ -194,9 +194,9 @@ void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, } mali_c55_params_block block; - block.data = ¶ms->data[params->total_size]; + block.data = ¶ms->data[params->data_size]; - params->total_size += fillSelectionParamsBlock(block, bank, alpha); + params->data_size += fillSelectionParamsBlock(block, bank, alpha); if (frame > 0) return; @@ -205,8 +205,8 @@ void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, * If this is the first frame, we need to load the parsed coefficient * tables from tuning data to the ISP. */ - block.data = ¶ms->data[params->total_size]; - params->total_size += fillConfigParamsBlock(block); + block.data = ¶ms->data[params->data_size]; + params->data_size += fillConfigParamsBlock(block); } REGISTER_IPA_ALGORITHM(Lsc, "Lsc") diff --git a/src/ipa/mali-c55/algorithms/lsc.h b/src/ipa/mali-c55/algorithms/lsc.h index d11e23bc7c34fa3e1f45ccf015b50f3d390d7159..9019a61aa547e41154615eba88547d3eee1634e2 100644 --- a/src/ipa/mali-c55/algorithms/lsc.h +++ b/src/ipa/mali-c55/algorithms/lsc.h @@ -23,7 +23,7 @@ public: int init(IPAContext &context, const YamlObject &tuningData) override; void prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, - mali_c55_params_buffer *params) override; + v4l2_params_buffer *params) override; private: static constexpr unsigned int kRedOffset = 0; static constexpr unsigned int kGreenOffset = 1024; diff --git a/src/ipa/mali-c55/mali-c55.cpp b/src/ipa/mali-c55/mali-c55.cpp index 7d45e7310aecdae0e47655e6d2e8830e776d74cd..a6d3e984a438c01509ed27469d9f20c25bc884cf 100644 --- a/src/ipa/mali-c55/mali-c55.cpp +++ b/src/ipa/mali-c55/mali-c55.cpp @@ -331,22 +331,22 @@ void IPAMaliC55::queueRequest(const uint32_t request, const ControlList &control void IPAMaliC55::fillParams(unsigned int request, [[maybe_unused]] uint32_t bufferId) { - struct mali_c55_params_buffer *params; + struct v4l2_params_buffer *params; IPAFrameContext &frameContext = context_.frameContexts.get(request); - params = reinterpret_cast( + params = reinterpret_cast( buffers_.at(bufferId).planes()[0].data()); - memset(params, 0, sizeof(mali_c55_params_buffer)); + memset(params, 0, sizeof(v4l2_params_buffer)); params->version = MALI_C55_PARAM_BUFFER_V1; for (auto const &algo : algorithms()) { algo->prepare(context_, request, frameContext, params); - ASSERT(params->total_size <= MALI_C55_PARAMS_MAX_SIZE); + ASSERT(params->data_size <= MALI_C55_PARAMS_MAX_SIZE); } - size_t bytesused = offsetof(struct mali_c55_params_buffer, data) + params->total_size; + size_t bytesused = offsetof(struct v4l2_params_buffer, data) + params->data_size; paramsComputed.emit(request, bytesused); } diff --git a/src/ipa/mali-c55/module.h b/src/ipa/mali-c55/module.h index 4f6a4f18bfaf83263ccb5b7eb1723da9b655cc3c..434d2c585d2f4eb03402c57e87302fc82e82a0f0 100644 --- a/src/ipa/mali-c55/module.h +++ b/src/ipa/mali-c55/module.h @@ -20,7 +20,7 @@ namespace libcamera { namespace ipa::mali_c55 { using Module = ipa::Module; + v4l2_params_buffer, mali_c55_stats_buffer>; } /* namespace ipa::mali_c55 */ From patchwork Tue Sep 16 12:28:24 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 24370 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 B8207BE173 for ; Tue, 16 Sep 2025 12:28:47 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 595986937C; Tue, 16 Sep 2025 14:28:47 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="mnRBAoXX"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C3F2569369 for ; Tue, 16 Sep 2025 14:28:43 +0200 (CEST) Received: from [192.168.0.172] (mob-5-90-51-255.net.vodafone.it [5.90.51.255]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 73D331989; Tue, 16 Sep 2025 14:27:24 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1758025645; bh=CC3WcDEQCARgdAWHwgQZLUwkcHpr26M6RSTRTE6y36E=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=mnRBAoXXkrDE+9jmFag5zk6XRG5BjujnHlvcpm/MTPnOg9CCZSv4o4l+aFRKOhN6j FkvFjyw30+PxKJ/1yOjHE4Dg9n0IvgB0lF7o+KKqOjFSUBSGv3ADqYZpwzRVjdBpTP dv00Tykp1Vr0a3HNa+td2GnXlLrDl/yPmTOGjKfw= From: Jacopo Mondi Date: Tue, 16 Sep 2025 14:28:24 +0200 Subject: [PATCH v2 3/4] ipa: libipa: Introduce V4L2Params MIME-Version: 1.0 Message-Id: <20250916-v4l2-params-v2-3-764471ed6435@ideasonboard.com> References: <20250916-v4l2-params-v2-0-764471ed6435@ideasonboard.com> In-Reply-To: <20250916-v4l2-params-v2-0-764471ed6435@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=25228; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=CC3WcDEQCARgdAWHwgQZLUwkcHpr26M6RSTRTE6y36E=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBoyVfxywB/y6rawK4ElAsucdr9eR1ILlC3yuh14 8eQZfEAnoWJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCaMlX8QAKCRByNAaPFqFW PGN0D/0QtMGTMXp811hL/q8GfYW5MXveJ3MAV0gsLdcfMFqVmvg6hWZaVi1dPSPYxYcmjqc+zHe s+Lu1EcvtensW7d5N43vXSMrg+PPg2OitRB8hAVXcH+AbVdwP+rV7UIgD/HIKB+Xqxh1j3c/AIV I65T1PljNi9qJTg9S1n4gXasabcQdkbrpJ+PfeQP4VdZfpwqQZVjlVdF36SjMPelds+teVMsHrv RyX7J9NzKxMX3jZdeURQi427aevcBKWF7a+TNqDLBUt8bIHDBhIgYdODEkhrGqFeqZ1qMeM7/nD 6A+P22MyWjwYqXqz51SpVN8dtdyP1yIuaYURTnyw9d4BWFVkRgD40veqiiEM+/aN1ZVJemZC5BI QkqKoWcm7q7ux765LX1Ccty5rsF/byEgjZkoQlWtAyw/hANFkYX940eFClCIEJbJpKVFebiLvP2 UtyTwVAK+DIExFoiBlF7UmcqUPKwSKxv9XqpVW45tUPWhUQVgqtHO6vut7sx1iWZZJibGui6dTl 5u71O8w8hMGlk68VN5kENMJDhOh5EYMa4ug4JSI11/9yPzeyckC4hQ3oleX7gLX+ipEK3mzMLMm SB+trLWCfanZsEJ2wmJjuLlEfpbL+XxP8gwQX2tJIcxTUxS4rDnSAX7cDo6onCHM+RTjBVaAP0P E9FtVa+r39wb/XA== 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 | 269 +++++++++++++++++++++++++++++++++++++++++ src/ipa/libipa/v4l2_params.h | 145 ++++++++++++++++++++++ src/ipa/rkisp1/params.cpp | 93 +------------- src/ipa/rkisp1/params.h | 159 ++++++++++++------------ 5 files changed, 495 insertions(+), 173 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..e098cfc21a4c6ad765bf37c738cfd2600d544132 --- /dev/null +++ b/src/ipa/libipa/v4l2_params.cpp @@ -0,0 +1,269 @@ +/* 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::header() + * \brief Retrieve a reference to the header (struct v4l2_params_block_header) + * \return The block header + */ + +/** + * \fn V4L2ParamsBlock::data() + * \brief Retrieve a reference to block configuration data memory area + * \return The block data + */ + +/** + * \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->() + */ + + /** + * \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..203972867bbb7b1d2c6dbdd449baff2fd5356a7b --- /dev/null +++ b/src/ipa/libipa/v4l2_params.h @@ -0,0 +1,145 @@ +/* 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) + : header_(data.subspan(0, sizeof(v4l2_params_block_header))), + data_(data.subspan(sizeof(v4l2_params_block_header))) + { + } + + void setEnabled(bool enabled) + { + struct v4l2_params_block_header *header = + reinterpret_cast(header_.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; + } + + Span header() const { return header_; } + Span data() const { return data_; } + + const T *operator->() const + { + return reinterpret_cast(data().data()); + } + + T *operator->() + { + return reinterpret_cast(data().data()); + } + + const T &operator*() const + { + return *reinterpret_cast(data().data()); + } + + T &operator*() + { + return *reinterpret_cast(data().data()); + } + +private: + Span header_; + 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 4c0b051ce65da1686323ee9c66b82e12669a754d..2b692e1a1f199d6c118af0938e1aaecef6186a2c 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, \ } } @@ -78,56 +78,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); @@ -177,44 +127,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 40450e34497a3aa71b5b0cda2bf045a1cc0e012f..c1f6b153441f236e69031f6e8f999d22c07fa4ad 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 { @@ -48,114 +45,110 @@ 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(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) + +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); - - Span data() const { return data_; } - - void setEnabled(bool enabled); - -private: - LIBCAMERA_DISABLE_COPY(RkISP1ParamsBlockBase) - - RkISP1Params *params_; - BlockType type_; - Span header_; - Span data_; -}; + static constexpr unsigned int kVersion = RKISP1_EXT_PARAM_BUFFER_V1; -template -class RkISP1ParamsBlock : public RkISP1ParamsBlockBase -{ -public: - using Type = typename details::block_type::type; - - RkISP1ParamsBlock(RkISP1Params *params, const Span &data) - : RkISP1ParamsBlockBase(params, B, data) + 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); + } } - const Type *operator->() const + template + auto block() { - return reinterpret_cast(data().data()); - } + using Type = typename details::block_type::type; - Type *operator->() - { - return reinterpret_cast(data().data()); + return RkISP1ParamsBlock(this, id, block(id)); } - const Type &operator*() const & - { - return *reinterpret_cast(data().data()); - } + uint32_t format() const { return format_; } + void setBlockEnabled(BlockType type, bool enabled); - Type &operator*() & - { - return *reinterpret_cast(data().data()); - } +private: + Span block(BlockType type); + + uint32_t format_; }; -class RkISP1Params +template +class RkISP1ParamsBlock : public V4L2ParamsBlock { public: - RkISP1Params(uint32_t format, Span data); - - template - RkISP1ParamsBlock block() + RkISP1ParamsBlock(RkISP1Params *params, BlockType type, + const Span &data) + : V4L2ParamsBlock(data) { - return RkISP1ParamsBlock(this, block(B)); + params_ = params; + type_ = type; + + /* Legacy param format has no header */ + if (params_->format() == V4L2_META_FMT_RK_ISP1_PARAMS) + data_ = data; } - uint32_t format() const { return format_; } - size_t size() const { return used_; } + void 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); + + return V4L2ParamsBlock::setEnabled(enabled); + } private: - friend class RkISP1ParamsBlockBase; - - Span block(BlockType type); - void setBlockEnabled(BlockType type, bool enabled); - - uint32_t format_; - + RkISP1Params *params_; + BlockType type_; Span data_; - size_t used_; - - std::map> blocks_; }; } /* namespace ipa::rkisp1 */ From patchwork Tue Sep 16 12:28:25 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 24371 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 3711FBE173 for ; Tue, 16 Sep 2025 12:28:50 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id CB6196937E; Tue, 16 Sep 2025 14:28:49 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="eDqiSN7q"; 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 979F169369 for ; Tue, 16 Sep 2025 14:28:46 +0200 (CEST) Received: from [192.168.0.172] (mob-5-90-51-255.net.vodafone.it [5.90.51.255]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id C4C82C6F; Tue, 16 Sep 2025 14:27:26 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1758025648; bh=9uaab0BzK4UcR6OzTV7B8pIxOxmpmNcXBoGDYeaCqYg=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=eDqiSN7q6I3S+I9pN+IMHLxXo1KW1CAc+p5kbofDP9MKiHYlWXTe3uoYPLLjjdlz6 2s3jRb741J3i35sYjk9YuH9qf4+8G9Qpwf1jXQyrunT/UuHnm+dhfUqhYRiNgMRaZ6 gpY2Fhd+G7/dCc7PgNeDS1JtWNAOQzwNV2K40CeU= From: Jacopo Mondi Date: Tue, 16 Sep 2025 14:28:25 +0200 Subject: [PATCH v2 4/4] ipa: mali-c55: Introduce MaliC55Params MIME-Version: 1.0 Message-Id: <20250916-v4l2-params-v2-4-764471ed6435@ideasonboard.com> References: <20250916-v4l2-params-v2-0-764471ed6435@ideasonboard.com> In-Reply-To: <20250916-v4l2-params-v2-0-764471ed6435@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=25052; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=9uaab0BzK4UcR6OzTV7B8pIxOxmpmNcXBoGDYeaCqYg=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBoyVfyaBzvM6txw3OMwbSRYsEWO+YhHz4sgygKB m2g4M38PHqJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCaMlX8gAKCRByNAaPFqFW PNZTEACqLNIhW18fer0/CK7zX/eBtzvhMBSAEtyU7285P6mGalQBMa8JlLqHK9lwbW4jHULNGBe nUp1kuqYa8TgvgNhrJL7RcZ+NySL5v1Ya2zGVy/Pz7u4ehXYLPdWWrajQjZcyk3su9UzpSvAOyF 5je5Zyg9Ms7Og7cu6f5WWwc1islXdcb/YihgDDNVkK19Khd1S2f3DOXDO1Z4ntOg/r8w0fkkuh6 E90xjz7vcH4iSG8eQKTRWP+aqWbabVGPSHLZfNQbcEALNIqYE/0c5PXe7wieGi5wCsNo6zU9/4r oJZzpb5Tr1yDWeztg3U++tIsQhk3RSfaYmvQILLIkRdPy4BVI0rNzoxKpvdZN+wBPwtPqauyW7W OTLyB3eWSO7TPuWobDhGg7Gsf2z9FcqgncL+HIFzd0iEPyG2Oy8Jh5UtZbOhxt4KUP2n8ge/6+o X7S/i6AY6a2KMiQHDQdNkRTAtWtyokH5sop5sP7ZrC0CUsC0zQUJzn6qG2/fEb1Ja/TF4oXGopI ocDqudykFHeyD/xa17zzq/lOH7B+B64MCj70+khbiXvXTS2DPLZTqdfqgUPVzXhLP/D4MKpjFZy ZRvIL3WwW7XzTMs1fbPE3QHipcpYrczLPLgDucVdWVdLQUR2oiXmuZVXFNIgWuDjOvgmQP/Ko1B gsG13fSBej9uoTA== 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" Implement MaliC55Params to derive from V4L2Params and use the new helpers in the Mali C55 IPA algorithms implementation. Signed-off-by: Jacopo Mondi Tested-By: Antoine Bouyer --- src/ipa/mali-c55/algorithms/agc.cpp | 87 +++++++++++++++---------------------- src/ipa/mali-c55/algorithms/agc.h | 14 +++--- src/ipa/mali-c55/algorithms/awb.cpp | 64 +++++++++++---------------- src/ipa/mali-c55/algorithms/awb.h | 10 ++--- src/ipa/mali-c55/algorithms/blc.cpp | 20 +++------ src/ipa/mali-c55/algorithms/blc.h | 3 +- src/ipa/mali-c55/algorithms/lsc.cpp | 58 ++++++++++--------------- src/ipa/mali-c55/algorithms/lsc.h | 8 ++-- src/ipa/mali-c55/mali-c55.cpp | 19 +++----- src/ipa/mali-c55/module.h | 3 +- src/ipa/mali-c55/params.h | 83 +++++++++++++++++++++++++++++++++++ 11 files changed, 197 insertions(+), 172 deletions(-) diff --git a/src/ipa/mali-c55/algorithms/agc.cpp b/src/ipa/mali-c55/algorithms/agc.cpp index 80d9d956d07d1665e61876b0429fb94a30c7cbe1..c1ed1cd78430e8ea0b3ea6998c7ee17e43ed777d 100644 --- a/src/ipa/mali-c55/algorithms/agc.cpp +++ b/src/ipa/mali-c55/algorithms/agc.cpp @@ -240,8 +240,8 @@ void Agc::queueRequest(IPAContext &context, const uint32_t frame, } } -size_t Agc::fillGainParamBlock(IPAContext &context, IPAFrameContext &frameContext, - mali_c55_params_block block) +void Agc::fillGainParamBlock(IPAContext &context, IPAFrameContext &frameContext, + MaliC55Params *params) { IPAActiveState &activeState = context.activeState; double gain; @@ -251,52 +251,50 @@ size_t Agc::fillGainParamBlock(IPAContext &context, IPAFrameContext &frameContex else gain = activeState.agc.manual.ispGain; - block.header->type = MALI_C55_PARAM_BLOCK_DIGITAL_GAIN; - block.header->flags = 0; - block.header->size = sizeof(struct mali_c55_params_digital_gain); + auto block = params->block(); + block->gain = floatingToFixedPoint<5, 8, uint16_t, double>(gain); - block.digital_gain->gain = floatingToFixedPoint<5, 8, uint16_t, double>(gain); frameContext.agc.ispGain = gain; - - return block.header->size; } -size_t Agc::fillParamsBuffer(mali_c55_params_block block, - enum mali_c55_param_block_type type) +void Agc::fillParamsBuffer(MaliC55Params *params, enum MaliC55Blocks type) { - block.header->type = type; - block.header->flags = 0; - block.header->size = sizeof(struct mali_c55_params_aexp_hist); + + assert(type == MaliC55Blocks::AexpHist || type == MaliC55Blocks::AexpIhist); + + auto block = type == MaliC55Blocks::AexpHist ? + params->block() : + params->block(); /* Collect every 3rd pixel horizontally */ - block.aexp_hist->skip_x = 1; + block->skip_x = 1; /* Start from first column */ - block.aexp_hist->offset_x = 0; + block->offset_x = 0; /* Collect every pixel vertically */ - block.aexp_hist->skip_y = 0; + block->skip_y = 0; /* Start from the first row */ - block.aexp_hist->offset_y = 0; + block->offset_y = 0; /* 1x scaling (i.e. none) */ - block.aexp_hist->scale_bottom = 0; - block.aexp_hist->scale_top = 0; + block->scale_bottom = 0; + block->scale_top = 0; /* Collect all Bayer planes into 4 separate histograms */ - block.aexp_hist->plane_mode = 1; + block->plane_mode = 1; /* Tap the data immediately after the digital gain block */ - block.aexp_hist->tap_point = MALI_C55_AEXP_HIST_TAP_FS; - - return block.header->size; + block->tap_point = MALI_C55_AEXP_HIST_TAP_FS; } -size_t Agc::fillWeightsArrayBuffer(mali_c55_params_block block, - enum mali_c55_param_block_type type) +void Agc::fillWeightsArrayBuffer(MaliC55Params *params, const enum MaliC55Blocks type) { - block.header->type = type; - block.header->flags = 0; - block.header->size = sizeof(struct mali_c55_params_aexp_weights); + assert(type == MaliC55Blocks::AexpHistWeights || + type == MaliC55Blocks::AexpIhistWeights); + + auto block = type == MaliC55Blocks::AexpHistWeights ? + params->block() : + params->block(); /* We use every zone - a 15x15 grid */ - block.aexp_weights->nodes_used_horiz = 15; - block.aexp_weights->nodes_used_vert = 15; + block->nodes_used_horiz = 15; + block->nodes_used_vert = 15; /* * We uniformly weight the zones to 1 - this results in the collected @@ -304,40 +302,25 @@ size_t Agc::fillWeightsArrayBuffer(mali_c55_params_block block, * approximate colour channel averages for the image. */ Span weights{ - block.aexp_weights->zone_weights, + block->zone_weights, MALI_C55_MAX_ZONES }; std::fill(weights.begin(), weights.end(), 1); - - return block.header->size; } void Agc::prepare(IPAContext &context, const uint32_t frame, - IPAFrameContext &frameContext, v4l2_params_buffer *params) + IPAFrameContext &frameContext, MaliC55Params *params) { - mali_c55_params_block block; - - block.data = ¶ms->data[params->data_size]; - params->data_size += fillGainParamBlock(context, frameContext, block); + fillGainParamBlock(context, frameContext, params); if (frame > 0) return; - block.data = ¶ms->data[params->data_size]; - params->data_size += fillParamsBuffer(block, - MALI_C55_PARAM_BLOCK_AEXP_HIST); - - block.data = ¶ms->data[params->data_size]; - params->data_size += fillWeightsArrayBuffer(block, - MALI_C55_PARAM_BLOCK_AEXP_HIST_WEIGHTS); - - block.data = ¶ms->data[params->data_size]; - params->data_size += fillParamsBuffer(block, - MALI_C55_PARAM_BLOCK_AEXP_IHIST); + fillParamsBuffer(params, MaliC55Blocks::AexpHist); + fillWeightsArrayBuffer(params, MaliC55Blocks::AexpHistWeights); - block.data = ¶ms->data[params->data_size]; - params->data_size += fillWeightsArrayBuffer(block, - MALI_C55_PARAM_BLOCK_AEXP_IHIST_WEIGHTS); + fillParamsBuffer(params, MaliC55Blocks::AexpIhist); + fillWeightsArrayBuffer(params, MaliC55Blocks::AexpIhistWeights); } double Agc::estimateLuminance(const double gain) const diff --git a/src/ipa/mali-c55/algorithms/agc.h b/src/ipa/mali-c55/algorithms/agc.h index 64caf99350c1d1835832311a94a88a2bfde5721c..9684fff664bc67d287bb00f8dc88e238d8dd0cea 100644 --- a/src/ipa/mali-c55/algorithms/agc.h +++ b/src/ipa/mali-c55/algorithms/agc.h @@ -57,7 +57,7 @@ public: const ControlList &controls) override; void prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, - v4l2_params_buffer *params) override; + MaliC55Params *params) override; void process(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, const mali_c55_stats_buffer *stats, @@ -65,13 +65,11 @@ public: private: double estimateLuminance(const double gain) const override; - size_t fillGainParamBlock(IPAContext &context, - IPAFrameContext &frameContext, - mali_c55_params_block block); - size_t fillParamsBuffer(mali_c55_params_block block, - enum mali_c55_param_block_type type); - size_t fillWeightsArrayBuffer(mali_c55_params_block block, - enum mali_c55_param_block_type type); + void fillGainParamBlock(IPAContext &context, + IPAFrameContext &frameContext, + MaliC55Params *params); + void fillParamsBuffer(MaliC55Params *params, enum MaliC55Blocks type); + void fillWeightsArrayBuffer(MaliC55Params *params, enum MaliC55Blocks type); AgcStatistics statistics_; }; diff --git a/src/ipa/mali-c55/algorithms/awb.cpp b/src/ipa/mali-c55/algorithms/awb.cpp index 6b2cbed9de1ebfe9a2466ebe999eceac44fe5deb..964e810882a93cce02f991675d74bbf163d51e7c 100644 --- a/src/ipa/mali-c55/algorithms/awb.cpp +++ b/src/ipa/mali-c55/algorithms/awb.cpp @@ -43,13 +43,9 @@ int Awb::configure([[maybe_unused]] IPAContext &context, return 0; } -size_t Awb::fillGainsParamBlock(mali_c55_params_block block, IPAContext &context, +void Awb::fillGainsParamBlock(MaliC55Params *params, IPAContext &context, IPAFrameContext &frameContext) { - block.header->type = MALI_C55_PARAM_BLOCK_AWB_GAINS; - block.header->flags = 0; - block.header->size = sizeof(struct mali_c55_params_awb_gains); - double rGain = context.activeState.awb.rGain; double bGain = context.activeState.awb.bGain; @@ -63,34 +59,32 @@ 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); + auto block = params->block(); + + block->gain00 = floatingToFixedPoint<4, 8, uint16_t, double>(rGain); + block->gain01 = floatingToFixedPoint<4, 8, uint16_t, double>(1.0); + block->gain10 = floatingToFixedPoint<4, 8, uint16_t, double>(1.0); + block->gain11 = floatingToFixedPoint<4, 8, uint16_t, double>(bGain); frameContext.awb.rGain = rGain; frameContext.awb.bGain = bGain; - - return sizeof(struct mali_c55_params_awb_gains); } -size_t Awb::fillConfigParamBlock(mali_c55_params_block block) +void Awb::fillConfigParamBlock(MaliC55Params *params) { - block.header->type = MALI_C55_PARAM_BLOCK_AWB_CONFIG; - block.header->flags = 0; - block.header->size = sizeof(struct mali_c55_params_awb_config); + auto block = params->block(); /* Tap the stats after the purple fringe block */ - block.awb_config->tap_point = MALI_C55_AWB_STATS_TAP_PF; + block->tap_point = MALI_C55_AWB_STATS_TAP_PF; /* Get R/G and B/G ratios as statistics */ - block.awb_config->stats_mode = MALI_C55_AWB_MODE_RGBG; + block->stats_mode = MALI_C55_AWB_MODE_RGBG; /* Default white level */ - block.awb_config->white_level = 1023; + block->white_level = 1023; /* Default black level */ - block.awb_config->black_level = 0; + block->black_level = 0; /* * By default pixels are included who's colour ratios are bounded in a @@ -104,40 +98,34 @@ size_t Awb::fillConfigParamBlock(mali_c55_params_block block) * * \todo should these perhaps be tunable? */ - block.awb_config->cr_max = 511; - block.awb_config->cr_min = 64; - block.awb_config->cb_max = 511; - block.awb_config->cb_min = 64; + block->cr_max = 511; + block->cr_min = 64; + block->cb_max = 511; + block->cb_min = 64; /* We use the full 15x15 zoning scheme */ - block.awb_config->nodes_used_horiz = 15; - block.awb_config->nodes_used_vert = 15; + block->nodes_used_horiz = 15; + block->nodes_used_vert = 15; /* * We set the trimming boundaries equivalent to the main boundaries. In * other words; no trimming. */ - block.awb_config->cr_high = 511; - block.awb_config->cr_low = 64; - block.awb_config->cb_high = 511; - block.awb_config->cb_low = 64; - - return sizeof(struct mali_c55_params_awb_config); + block->cr_high = 511; + block->cr_low = 64; + block->cb_high = 511; + block->cb_low = 64; } void Awb::prepare(IPAContext &context, const uint32_t frame, - IPAFrameContext &frameContext, v4l2_params_buffer *params) + IPAFrameContext &frameContext, MaliC55Params *params) { - mali_c55_params_block block; - block.data = ¶ms->data[params->data_size]; - - params->data_size += fillGainsParamBlock(block, context, frameContext); + fillGainsParamBlock(params, context, frameContext); if (frame > 0) return; - block.data = ¶ms->data[params->data_size]; - params->data_size += fillConfigParamBlock(block); + fillConfigParamBlock(params); } void Awb::process(IPAContext &context, const uint32_t frame, diff --git a/src/ipa/mali-c55/algorithms/awb.h b/src/ipa/mali-c55/algorithms/awb.h index b5ff121041d1a01e3a51d64b87a90fb2e1d8dd10..683a62af263a14d2f5d5b261448953ada6669b2f 100644 --- a/src/ipa/mali-c55/algorithms/awb.h +++ b/src/ipa/mali-c55/algorithms/awb.h @@ -22,17 +22,17 @@ public: const IPACameraSensorInfo &configInfo) override; void prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, - v4l2_params_buffer *params) override; + MaliC55Params *params) override; void process(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, const mali_c55_stats_buffer *stats, ControlList &metadata) override; private: - size_t fillGainsParamBlock(mali_c55_params_block block, - IPAContext &context, - IPAFrameContext &frameContext); - size_t fillConfigParamBlock(mali_c55_params_block block); + void fillGainsParamBlock(MaliC55Params *params, + IPAContext &context, + IPAFrameContext &frameContext); + void fillConfigParamBlock(MaliC55Params *params); }; } /* namespace ipa::mali_c55::algorithms */ diff --git a/src/ipa/mali-c55/algorithms/blc.cpp b/src/ipa/mali-c55/algorithms/blc.cpp index 8fd0f10c3082030a36a256830042d733ed4c8c78..d099219c3e43ec96fa452ed13fa46ada2025edc9 100644 --- a/src/ipa/mali-c55/algorithms/blc.cpp +++ b/src/ipa/mali-c55/algorithms/blc.cpp @@ -85,27 +85,19 @@ int BlackLevelCorrection::configure(IPAContext &context, void BlackLevelCorrection::prepare([[maybe_unused]] IPAContext &context, const uint32_t frame, [[maybe_unused]] IPAFrameContext &frameContext, - v4l2_params_buffer *params) + MaliC55Params *params) { - mali_c55_params_block block; - block.data = ¶ms->data[params->data_size]; - if (frame > 0) return; if (!tuningParameters_) return; - block.header->type = MALI_C55_PARAM_BLOCK_SENSOR_OFFS; - block.header->flags = 0; - block.header->size = sizeof(mali_c55_params_sensor_off_preshading); - - block.sensor_offs->chan00 = offset00; - block.sensor_offs->chan01 = offset01; - block.sensor_offs->chan10 = offset10; - block.sensor_offs->chan11 = offset11; - - params->data_size += block.header->size; + auto block = params->block(); + block->chan00 = offset00; + block->chan01 = offset01; + block->chan10 = offset10; + block->chan11 = offset11; } void BlackLevelCorrection::process([[maybe_unused]] IPAContext &context, diff --git a/src/ipa/mali-c55/algorithms/blc.h b/src/ipa/mali-c55/algorithms/blc.h index cf10505ce2908df0d5e658d3fdce663729c7ea76..fc5a7ea310cbdbcf271eb26c73b17243aea744cd 100644 --- a/src/ipa/mali-c55/algorithms/blc.h +++ b/src/ipa/mali-c55/algorithms/blc.h @@ -6,6 +6,7 @@ */ #include "algorithm.h" +#include "params.h" namespace libcamera { @@ -22,7 +23,7 @@ public: const IPACameraSensorInfo &configInfo) override; void prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, - v4l2_params_buffer *params) override; + MaliC55Params *params) override; void process(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, const mali_c55_stats_buffer *stats, diff --git a/src/ipa/mali-c55/algorithms/lsc.cpp b/src/ipa/mali-c55/algorithms/lsc.cpp index 35f1d876e60db252a45cadb771e541735749d106..5b042c757bc70fe4eb4a5aaa848266b3afce9100 100644 --- a/src/ipa/mali-c55/algorithms/lsc.cpp +++ b/src/ipa/mali-c55/algorithms/lsc.cpp @@ -108,41 +108,33 @@ int Lsc::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData return 0; } -size_t Lsc::fillConfigParamsBlock(mali_c55_params_block block) const +void Lsc::fillConfigParamsBlock(MaliC55Params *params) const { - block.header->type = MALI_C55_PARAM_MESH_SHADING_CONFIG; - block.header->flags = 0; - block.header->size = sizeof(struct mali_c55_params_mesh_shading_config); + auto block = params->block(); - block.shading_config->mesh_show = false; - block.shading_config->mesh_scale = meshScale_; - block.shading_config->mesh_page_r = 0; - block.shading_config->mesh_page_g = 1; - block.shading_config->mesh_page_b = 2; - block.shading_config->mesh_width = meshSize_; - block.shading_config->mesh_height = meshSize_; + block->mesh_show = false; + block->mesh_scale = meshScale_; + block->mesh_page_r = 0; + block->mesh_page_g = 1; + block->mesh_page_b = 2; + block->mesh_width = meshSize_; + block->mesh_height = meshSize_; - std::copy(mesh_.begin(), mesh_.end(), block.shading_config->mesh); - - return block.header->size; + std::copy(mesh_.begin(), mesh_.end(), block->mesh); } -size_t Lsc::fillSelectionParamsBlock(mali_c55_params_block block, uint8_t bank, +void Lsc::fillSelectionParamsBlock(MaliC55Params *params, uint8_t bank, uint8_t alpha) const { - block.header->type = MALI_C55_PARAM_MESH_SHADING_SELECTION; - block.header->flags = 0; - block.header->size = sizeof(struct mali_c55_params_mesh_shading_selection); - - block.shading_selection->mesh_alpha_bank_r = bank; - block.shading_selection->mesh_alpha_bank_g = bank; - block.shading_selection->mesh_alpha_bank_b = bank; - block.shading_selection->mesh_alpha_r = alpha; - block.shading_selection->mesh_alpha_g = alpha; - block.shading_selection->mesh_alpha_b = alpha; - block.shading_selection->mesh_strength = 0x1000; /* Otherwise known as 1.0 */ - - return block.header->size; + auto block = params->block(); + + block->mesh_alpha_bank_r = bank; + block->mesh_alpha_bank_g = bank; + block->mesh_alpha_bank_b = bank; + block->mesh_alpha_r = alpha; + block->mesh_alpha_g = alpha; + block->mesh_alpha_b = alpha; + block->mesh_strength = 0x1000; /* Otherwise known as 1.0 */ } std::tuple Lsc::findBankAndAlpha(uint32_t ct) const @@ -170,7 +162,7 @@ std::tuple Lsc::findBankAndAlpha(uint32_t ct) const void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, [[maybe_unused]] IPAFrameContext &frameContext, - v4l2_params_buffer *params) + MaliC55Params *params) { /* * For each frame we assess the colour temperature of the **last** frame @@ -193,10 +185,7 @@ void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, std::tie(bank, alpha) = findBankAndAlpha(temperatureK); } - mali_c55_params_block block; - block.data = ¶ms->data[params->data_size]; - - params->data_size += fillSelectionParamsBlock(block, bank, alpha); + fillSelectionParamsBlock(params, bank, alpha); if (frame > 0) return; @@ -205,8 +194,7 @@ void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, * If this is the first frame, we need to load the parsed coefficient * tables from tuning data to the ISP. */ - block.data = ¶ms->data[params->data_size]; - params->data_size += fillConfigParamsBlock(block); + fillConfigParamsBlock(params); } REGISTER_IPA_ALGORITHM(Lsc, "Lsc") diff --git a/src/ipa/mali-c55/algorithms/lsc.h b/src/ipa/mali-c55/algorithms/lsc.h index 9019a61aa547e41154615eba88547d3eee1634e2..e7092bc74a0b0301463167d16e1e888696547d10 100644 --- a/src/ipa/mali-c55/algorithms/lsc.h +++ b/src/ipa/mali-c55/algorithms/lsc.h @@ -23,15 +23,15 @@ public: int init(IPAContext &context, const YamlObject &tuningData) override; void prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, - v4l2_params_buffer *params) override; + MaliC55Params *params) override; private: static constexpr unsigned int kRedOffset = 0; static constexpr unsigned int kGreenOffset = 1024; static constexpr unsigned int kBlueOffset = 2048; - size_t fillConfigParamsBlock(mali_c55_params_block block) const; - size_t fillSelectionParamsBlock(mali_c55_params_block block, - uint8_t bank, uint8_t alpha) const; + void fillConfigParamsBlock(MaliC55Params *params) const; + void fillSelectionParamsBlock(MaliC55Params *params, + uint8_t bank, uint8_t alpha) const; std::tuple findBankAndAlpha(uint32_t ct) const; std::vector mesh_ = std::vector(3072); diff --git a/src/ipa/mali-c55/mali-c55.cpp b/src/ipa/mali-c55/mali-c55.cpp index a6d3e984a438c01509ed27469d9f20c25bc884cf..fe36d4445c3ac75abe48dbe2335fa1f3aded9609 100644 --- a/src/ipa/mali-c55/mali-c55.cpp +++ b/src/ipa/mali-c55/mali-c55.cpp @@ -28,6 +28,7 @@ #include "libipa/camera_sensor_helper.h" #include "ipa_context.h" +#include "params.h" namespace libcamera { @@ -331,23 +332,13 @@ void IPAMaliC55::queueRequest(const uint32_t request, const ControlList &control void IPAMaliC55::fillParams(unsigned int request, [[maybe_unused]] uint32_t bufferId) { - struct v4l2_params_buffer *params; IPAFrameContext &frameContext = context_.frameContexts.get(request); + MaliC55Params params(buffers_.at(bufferId).planes()[0]); - params = reinterpret_cast( - buffers_.at(bufferId).planes()[0].data()); - memset(params, 0, sizeof(v4l2_params_buffer)); - - params->version = MALI_C55_PARAM_BUFFER_V1; - - for (auto const &algo : algorithms()) { - algo->prepare(context_, request, frameContext, params); - - ASSERT(params->data_size <= MALI_C55_PARAMS_MAX_SIZE); - } + for (auto const &algo : algorithms()) + algo->prepare(context_, request, frameContext, ¶ms); - size_t bytesused = offsetof(struct v4l2_params_buffer, data) + params->data_size; - paramsComputed.emit(request, bytesused); + paramsComputed.emit(request, params.size()); } void IPAMaliC55::processStats(unsigned int request, unsigned int bufferId, diff --git a/src/ipa/mali-c55/module.h b/src/ipa/mali-c55/module.h index 434d2c585d2f4eb03402c57e87302fc82e82a0f0..13b34eb2839530a3518340165e6ca895d0f6bcaf 100644 --- a/src/ipa/mali-c55/module.h +++ b/src/ipa/mali-c55/module.h @@ -14,13 +14,14 @@ #include #include "ipa_context.h" +#include "params.h" namespace libcamera { namespace ipa::mali_c55 { using Module = ipa::Module; + MaliC55Params, mali_c55_stats_buffer>; } /* namespace ipa::mali_c55 */ diff --git a/src/ipa/mali-c55/params.h b/src/ipa/mali-c55/params.h new file mode 100644 index 0000000000000000000000000000000000000000..bb26da19a8f1336eeed91989a6c13e7630c6e5f4 --- /dev/null +++ b/src/ipa/mali-c55/params.h @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2025, Ideas On Board + * + * Mali C55 ISP Parameters + */ + +#pragma once + +#include +#include + +#include + +namespace libcamera { + +namespace ipa::mali_c55 { + +enum class MaliC55Blocks { + Bls, + AexpHist, + AexpHistWeights, + AexpIhist, + AexpIhistWeights, + Dgain, + AwbGains, + AwbConfig, + MeshShadingConfig, + MeshShadingSel, +}; + +namespace details { + +template +struct block_type { +}; + +#define MALI_C55_DEFINE_BLOCK_TYPE(id, cfgType, blkType) \ +template<> \ +struct block_type { \ + using type = struct mali_c55_params_##cfgType; \ + static constexpr mali_c55_param_block_type blockType = \ + mali_c55_param_block_type::MALI_C55_PARAM_##blkType; \ +}; + +MALI_C55_DEFINE_BLOCK_TYPE(Bls, sensor_off_preshading, BLOCK_SENSOR_OFFS) +MALI_C55_DEFINE_BLOCK_TYPE(AexpHist, aexp_hist, BLOCK_AEXP_HIST) +MALI_C55_DEFINE_BLOCK_TYPE(AexpHistWeights, aexp_weights, + BLOCK_AEXP_HIST_WEIGHTS) +MALI_C55_DEFINE_BLOCK_TYPE(AexpIhist, aexp_hist, BLOCK_AEXP_IHIST) +MALI_C55_DEFINE_BLOCK_TYPE(AexpIhistWeights, aexp_weights, + BLOCK_AEXP_IHIST_WEIGHTS) +MALI_C55_DEFINE_BLOCK_TYPE(Dgain, digital_gain, BLOCK_DIGITAL_GAIN) +MALI_C55_DEFINE_BLOCK_TYPE(AwbGains, awb_gains, BLOCK_AWB_GAINS) +MALI_C55_DEFINE_BLOCK_TYPE(AwbConfig, awb_config, BLOCK_AWB_CONFIG) +MALI_C55_DEFINE_BLOCK_TYPE(MeshShadingConfig, mesh_shading_config, + MESH_SHADING_CONFIG) +MALI_C55_DEFINE_BLOCK_TYPE(MeshShadingSel, mesh_shading_selection, + MESH_SHADING_SELECTION) + +struct param_traits { + using id_type = MaliC55Blocks; + + template + using id_to_details = block_type; +}; + +} /* namespace details */ + +class MaliC55Params : public V4L2Params +{ +public: + static constexpr unsigned int kVersion = MALI_C55_PARAM_BUFFER_V1; + + MaliC55Params(Span data) + : V4L2Params(data, kVersion) + { + } +}; + +} /* namespace ipa::mali_c55 */ + +} /* namespace libcamera */