From patchwork Tue Oct 28 09:31:50 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 24842 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 6B31ABE080 for ; Tue, 28 Oct 2025 09:32:21 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 473B76079C; Tue, 28 Oct 2025 10:32:18 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="G3WQFCST"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7326D607A8 for ; Tue, 28 Oct 2025 10:32:09 +0100 (CET) Received: from [192.168.0.172] (mob-5-90-58-13.net.vodafone.it [5.90.58.13]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 8D6424B22; Tue, 28 Oct 2025 10:30:20 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1761643820; bh=o/vOnHG6w0sMiJ7WhNcZD8nDa3NU32S4u0gAPh+/RTc=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=G3WQFCSThAO5NQwNYSEOT3Tvd5A/BdazT8Obq4q+r5QOxd7jNCPPZC+hS66Mc603A amS6pKSFgI2jV/5h15+YBdWfkbBbLI0Gs1YAyI32wprCSFhb0oTNGtKnGvh8iJ+wov a73Z3n5IKKoSksU0OQVhUvTwhRGiMz+rYSGOb3h8= From: Jacopo Mondi Date: Tue, 28 Oct 2025 10:31:50 +0100 Subject: [PATCH v2 04/10] ipa: libipa: agc: Make Agc::configure() set limits MIME-Version: 1.0 Message-Id: <20251028-exposure-limits-v2-4-a8b5a318323e@ideasonboard.com> References: <20251028-exposure-limits-v2-0-a8b5a318323e@ideasonboard.com> In-Reply-To: <20251028-exposure-limits-v2-0-a8b5a318323e@ideasonboard.com> To: =?utf-8?q?Niklas_S=C3=B6derlund?= , Robert Mader , libcamera-devel@lists.libcamera.org Cc: Jacopo Mondi X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=11498; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=o/vOnHG6w0sMiJ7WhNcZD8nDa3NU32S4u0gAPh+/RTc=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBpAI2VaKV6zhP/RlZUglT+ZkgjLvuriV2xccTyL DT5LawF1Q2JAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCaQCNlQAKCRByNAaPFqFW PB+oD/9r6elOz3j1DMbnz3TSKZ7ezVcyN7mvPsooaW431qgSyzicu18rCC6ldo0AKfvMa45eRNF FuWoDZlEV9kswZ5HxsywDFiWiGWuI4DwIZ0amKp3hW+gEo/jBkTMrPhKrmDcKqvh+Dv3pQ5KIES Ue1h/U+o5oXaXMXYCFlsSEW8yoPSJ8npP3DgXfKO6X2urjt+GYROy5aNQteYER0EXStAKJqjdCq Ni2PSVF1YwJYyfJQrNc6q7l3/ANdIO/ygpVAc/B1Gpa30A6pngvJ5JOPYbJWYDHGUpXEoY1Ag8S MAuEo15sAixeInvz8mghbqq2WEeugKii9it8VGOREFG8mhiyNpGhACBFCUmpbu+6/dtrhK0gIkx TVk43Lwy6QnKWigm2hl5hfVpD0g8Zujv5kt97eR955iG7eqdMitQZnVgk3bibNBY7ZvhUYvHIfX d9qEjMSX1Oqxvs9oG4p1jv/B+IWo4C2Lgq+Ba4EEkY+VIcWCmRr0mNSfghAVaRu9mjYu2eKP/pP ljm9N94eDqlubKiOzmc0iltHRMiT5TYrzDmfFk5QfX0EZ1AWtFhbWqVs7muqL/1Q0hG7oJezRo/ rGFxEgSmjE4QJ5cRPzw+GeDpttX8vc6xswuBVhT+oRLAD4T+8CoVibAkMLi+B1UDo5/LSdDYHSb DnUJegcPydFVC6A== 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 AgcMeanLuminance algorithm interface has a 'configure()' and 'setLimits()' API. configure() doesn't actually do much if not initialzing a few variables, and the Mali and IPU3 IPAs do not even call it. Configuring the AGC requires calling setLimits() at configure() time and at run time. In order to prepare to differentiate between configure-time settings of the Agc and run-time handling of dynamic parameters such as the frame duration limits, make the configure() operation initialize the Agc limits. Update all IPAs Agc implementation deriving from AgcMeanLuminance. Signed-off-by: Jacopo Mondi --- src/ipa/ipu3/algorithms/agc.cpp | 14 +++++++--- src/ipa/libipa/agc_mean_luminance.cpp | 48 ++++++++++++++++++++++++++++++--- src/ipa/libipa/agc_mean_luminance.h | 11 +++++++- src/ipa/libipa/exposure_mode_helper.cpp | 20 ++++++++++---- src/ipa/libipa/exposure_mode_helper.h | 4 ++- src/ipa/mali-c55/algorithms/agc.cpp | 16 ++++++----- src/ipa/rkisp1/algorithms/agc.cpp | 15 ++++++----- 7 files changed, 101 insertions(+), 27 deletions(-) diff --git a/src/ipa/ipu3/algorithms/agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp index b0d89541da8550bd50472779da7fa8e33b96e2f0..e303d724ab165bac03ac6bb9d3891a76049cff47 100644 --- a/src/ipa/ipu3/algorithms/agc.cpp +++ b/src/ipa/ipu3/algorithms/agc.cpp @@ -115,9 +115,17 @@ int Agc::configure(IPAContext &context, context.activeState.agc.constraintMode = constraintModes().begin()->first; context.activeState.agc.exposureMode = exposureModeHelpers().begin()->first; - /* \todo Run this again when FrameDurationLimits is passed in */ - setLimits(minExposureTime_, maxExposureTime_, minAnalogueGain_, - maxAnalogueGain_, {}); + AgcMeanLuminance::AgcSensorConfiguration sensorConfig; + sensorConfig.lineDuration = context.configuration.sensor.lineDuration; + sensorConfig.minExposureTime = minExposureTime_; + sensorConfig.maxExposureTime = maxExposureTime_; + sensorConfig.minAnalogueGain = minAnalogueGain_; + sensorConfig.maxAnalogueGain = maxAnalogueGain_; + + AgcMeanLuminance::configure(sensorConfig, context.camHelper.get()); + + /* \todo Update AGC limits when FrameDurationLimits is passed in */ + resetFrameCount(); return 0; diff --git a/src/ipa/libipa/agc_mean_luminance.cpp b/src/ipa/libipa/agc_mean_luminance.cpp index 64f36bd75dd213671b5a2e6810245096ed001f21..9886864fc42514040eadb4c0b424796df1f1b6e1 100644 --- a/src/ipa/libipa/agc_mean_luminance.cpp +++ b/src/ipa/libipa/agc_mean_luminance.cpp @@ -95,6 +95,42 @@ static constexpr double kMaxRelativeLuminanceTarget = 0.95; * \brief The luminance target for the constraint */ +/** + * \struct AgcMeanLuminance::AgcSensorConfiguration + * \brief The sensor configuration parameters + * + * This structure collects the sensor configuration parameters which need + * to be provided to the AGC algorithm at configure() time. + * + * Each time configure() is called the sensor configuration need to be updated + * with new parameters. + */ + +/** + * \var AgcMeanLuminance::AgcSensorConfiguration::lineDuration + * \brief The line duration in microseconds + */ + +/** + * \var AgcMeanLuminance::AgcSensorConfiguration::minExposureTime + * \brief The sensor minimum exposure time in microseconds + */ + +/** + * \var AgcMeanLuminance::AgcSensorConfiguration::maxExposureTime + * \brief The sensor maximum exposure time in microseconds + */ + +/** + * \var AgcMeanLuminance::AgcSensorConfiguration::minAnalogueGain + * \brief The sensor minimum analogue gain absolute value + */ + +/** + * \var AgcMeanLuminance::AgcSensorConfiguration::maxAnalogueGain + * \brief The sensor maximum analogue gain absolute value + */ + /** * \class AgcMeanLuminance * \brief A mean-based auto-exposure algorithm @@ -314,17 +350,21 @@ int AgcMeanLuminance::parseExposureModes(const YamlObject &tuningData) /** * \brief Configure the exposure mode helpers - * \param[in] lineDuration The sensor line length + * \param[in] config The sensor configuration * \param[in] sensorHelper The sensor helper * - * This function configures the exposure mode helpers so they can correctly + * This function configures the exposure mode helpers by providing them the + * sensor configuration parameters and the sensor helper, so they can correctly * take quantization effects into account. */ -void AgcMeanLuminance::configure(utils::Duration lineDuration, +void AgcMeanLuminance::configure(const AgcSensorConfiguration &config, const CameraSensorHelper *sensorHelper) { for (auto &[id, helper] : exposureModeHelpers_) - helper->configure(lineDuration, sensorHelper); + helper->configure(config.lineDuration, + config.minExposureTime, config.maxExposureTime, + config.minAnalogueGain, config.maxAnalogueGain, + sensorHelper); } /** diff --git a/src/ipa/libipa/agc_mean_luminance.h b/src/ipa/libipa/agc_mean_luminance.h index d7ec548e3e585e28fd03b956c8de7eaac5dc6e99..5ab75a3ac6c550a655f4bb7c8c30419ad8249183 100644 --- a/src/ipa/libipa/agc_mean_luminance.h +++ b/src/ipa/libipa/agc_mean_luminance.h @@ -42,7 +42,16 @@ public: double yTarget; }; - void configure(utils::Duration lineDuration, const CameraSensorHelper *sensorHelper); + struct AgcSensorConfiguration { + utils::Duration lineDuration; + utils::Duration minExposureTime; + utils::Duration maxExposureTime; + double minAnalogueGain; + double maxAnalogueGain; + }; + + void configure(const AgcSensorConfiguration &config, + const CameraSensorHelper *sensorHelper); int parseTuningData(const YamlObject &tuningData); void setExposureCompensation(double gain) diff --git a/src/ipa/libipa/exposure_mode_helper.cpp b/src/ipa/libipa/exposure_mode_helper.cpp index 29e316d9d09181cd65cb08f26babb1a680bee62a..557e14230ba4e0f120653bc09ea23a29a54cb4c8 100644 --- a/src/ipa/libipa/exposure_mode_helper.cpp +++ b/src/ipa/libipa/exposure_mode_helper.cpp @@ -82,22 +82,32 @@ ExposureModeHelper::ExposureModeHelper(const Span> stages); ~ExposureModeHelper() = default; - void configure(utils::Duration lineLength, const CameraSensorHelper *sensorHelper); + void configure(utils::Duration lineLength, utils::Duration minExposureTime, + utils::Duration maxExposureTime, double minGain, double maxGain, + const CameraSensorHelper *sensorHelper); void setLimits(utils::Duration minExposureTime, utils::Duration maxExposureTime, double minGain, double maxGain); diff --git a/src/ipa/mali-c55/algorithms/agc.cpp b/src/ipa/mali-c55/algorithms/agc.cpp index f60fddac3f04fd6f09dc782e929ff1593758c29b..ccf72cc9e8c33b1a516322c2445efa1684b7f751 100644 --- a/src/ipa/mali-c55/algorithms/agc.cpp +++ b/src/ipa/mali-c55/algorithms/agc.cpp @@ -169,12 +169,16 @@ int Agc::configure(IPAContext &context, context.activeState.agc.constraintMode = constraintModes().begin()->first; context.activeState.agc.exposureMode = exposureModeHelpers().begin()->first; - /* \todo Run this again when FrameDurationLimits is passed in */ - setLimits(context.configuration.agc.minShutterSpeed, - context.configuration.agc.maxShutterSpeed, - context.configuration.agc.minAnalogueGain, - context.configuration.agc.maxAnalogueGain, - {}); + AgcMeanLuminance::AgcSensorConfiguration sensorConfig; + sensorConfig.lineDuration = context.configuration.sensor.lineDuration; + sensorConfig.minExposureTime = context.configuration.agc.minShutterSpeed; + sensorConfig.maxExposureTime = context.configuration.agc.maxShutterSpeed; + sensorConfig.minAnalogueGain = context.configuration.agc.minAnalogueGain; + sensorConfig.maxAnalogueGain = context.configuration.agc.maxAnalogueGain; + + AgcMeanLuminance::configure(sensorConfig, context.camHelper.get()); + + /* \todo Update AGC limits when FrameDurationLimits is passed in */ resetFrameCount(); diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp index f5a3c917cb6909f6ef918e5ee8e46cf97ba55010..8c07e6a6eac091d949ad71ee967c893897313cc8 100644 --- a/src/ipa/rkisp1/algorithms/agc.cpp +++ b/src/ipa/rkisp1/algorithms/agc.cpp @@ -200,13 +200,14 @@ int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo) context.configuration.agc.measureWindow.h_size = configInfo.outputSize.width; context.configuration.agc.measureWindow.v_size = configInfo.outputSize.height; - AgcMeanLuminance::configure(context.configuration.sensor.lineDuration, - context.camHelper.get()); - - setLimits(context.configuration.sensor.minExposureTime, - context.configuration.sensor.maxExposureTime, - context.configuration.sensor.minAnalogueGain, - context.configuration.sensor.maxAnalogueGain, {}); + AgcMeanLuminance::AgcSensorConfiguration sensorConfig; + sensorConfig.lineDuration = context.configuration.sensor.lineDuration; + sensorConfig.minExposureTime = context.configuration.sensor.minExposureTime; + sensorConfig.maxExposureTime = context.configuration.sensor.maxExposureTime; + sensorConfig.minAnalogueGain = context.configuration.sensor.minAnalogueGain; + sensorConfig.maxAnalogueGain = context.configuration.sensor.maxAnalogueGain; + + AgcMeanLuminance::configure(sensorConfig, context.camHelper.get()); context.activeState.agc.automatic.yTarget = effectiveYTarget();