Patch Detail
Show a patch.
GET /api/1.1/patches/25065/?format=api
{ "id": 25065, "url": "https://patchwork.libcamera.org/api/1.1/patches/25065/?format=api", "web_url": "https://patchwork.libcamera.org/patch/25065/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/1.1/projects/1/?format=api", "name": "libcamera", "link_name": "libcamera", "list_id": "libcamera_core", "list_email": "libcamera-devel@lists.libcamera.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20251114-exposure-limits-v3-13-b7c07feba026@ideasonboard.com>", "date": "2025-11-14T14:17:08", "name": "[v3,13/19] ipa: libipa: agc: Calculate exposure limits with frame duration", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "110f25994ac9f80f443cc579bfdd576f386ecdfe", "submitter": { "id": 143, "url": "https://patchwork.libcamera.org/api/1.1/people/143/?format=api", "name": "Jacopo Mondi", "email": "jacopo.mondi@ideasonboard.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/25065/mbox/", "series": [ { "id": 5590, "url": "https://patchwork.libcamera.org/api/1.1/series/5590/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5590", "date": "2025-11-14T14:16:55", "name": "libipa: agc: Calculate exposure limits", "version": 3, "mbox": "https://patchwork.libcamera.org/series/5590/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/25065/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/25065/checks/", "tags": {}, "headers": { "Return-Path": "<libcamera-devel-bounces@lists.libcamera.org>", "X-Original-To": "parsemail@patchwork.libcamera.org", "Delivered-To": "parsemail@patchwork.libcamera.org", "Received": [ "from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id D9956C3333\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 14 Nov 2025 14:17:40 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 2B3E260B2F;\n\tFri, 14 Nov 2025 15:17:38 +0100 (CET)", "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id D707560AB1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 14 Nov 2025 15:17:22 +0100 (CET)", "from [192.168.1.101] (93-61-96-190.ip145.fastwebnet.it\n\t[93.61.96.190])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id C8B141E1B;\n\tFri, 14 Nov 2025 15:15:21 +0100 (CET)" ], "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"lxS4vk15\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1763129722;\n\tbh=iYzyCp/zPGlYBdF4UutFJ3h+dospQqXQ5PWcTaVGjvI=;\n\th=From:Date:Subject:References:In-Reply-To:To:Cc:From;\n\tb=lxS4vk15lcJcKgdvgl70g50Eu/4jlet3Zhhb6uhbb73/fUK/amms7RNN1sjaZZURU\n\tgjvwHupJYfXpXvt9Lcl1J0SQMhTZYpAb1sda8DyrTSVffk7IttVn4JA9SQ5lGNSgkQ\n\tRybGZgKG7KqTNczdA31fLK8469mVWlcCUbz8TRY0=", "From": "Jacopo Mondi <jacopo.mondi@ideasonboard.com>", "Date": "Fri, 14 Nov 2025 15:17:08 +0100", "Subject": "[PATCH v3 13/19] ipa: libipa: agc: Calculate exposure limits with\n\tframe duration", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=\"utf-8\"", "Content-Transfer-Encoding": "7bit", "Message-Id": "<20251114-exposure-limits-v3-13-b7c07feba026@ideasonboard.com>", "References": "<20251114-exposure-limits-v3-0-b7c07feba026@ideasonboard.com>", "In-Reply-To": "<20251114-exposure-limits-v3-0-b7c07feba026@ideasonboard.com>", "To": "=?utf-8?q?Niklas_S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>,\n\tRobert Mader <robert.mader@collabora.com>, \n\tlibcamera-devel@lists.libcamera.org", "Cc": "Jacopo Mondi <jacopo.mondi@ideasonboard.com>", "X-Mailer": "b4 0.14.2", "X-Developer-Signature": "v=1; a=openpgp-sha256; l=8940;\n\ti=jacopo.mondi@ideasonboard.com; h=from:subject:message-id;\n\tbh=iYzyCp/zPGlYBdF4UutFJ3h+dospQqXQ5PWcTaVGjvI=;\n\tb=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBpFznrCjePb8iR8uvULI4MogZSVXGV6RI1SsHOT\n\tNwC0GpX3FOJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCaRc56wAKCRByNAaPFqFW\n\tPEb7D/4t4YPeatYPATmn+7ZrsG1q+DmIjTSkRGYa/MjNXUMmdp+c1QzM+x0OUpsMkKFaCFLT7AJ\n\to+DJSTZTd6f4z6fxGZ8gFCKzlDfXZ0tlnwz48QF/bC0bLjVR3V/GgLAbM0TdO/fIsV6QNbFY+Gs\n\tIjbDDEQBris1EwvG9Aq1ZJJzbsZwmotpKviodH6UgOTQ4ZfHXOlkGHFaZfz9IBo3qCMMkicHxLx\n\tGPierFSKwe5+tu+e2rd6eXIZQziBu8kap2S8cApcFHG0TKfnaEwJ1oG3cp49llJx9gIWKHfjaeB\n\tmWq4fts5zm3Jn2SHur1f4q3hHSfH/tbPEvF1c+fnizNaGOac3UyCtiawnZ/V2IN2ECavSPCADUw\n\tUTiVcYAMTBl3vDHkVqYaP5bDofNU4e8fKMpLAhVRg7hWbfSXunAwvbnCKrxWo+SPTw6UMO9I48+\n\thO1mdlwpEcqpyRkZl0QNt63c0FJ1zYrURTOgg9hZknqIicPEImIrlVsDIa/V4NjT1ZDppYwrdwh\n\tFmgwk44/WjvGpiH6GWRp5bixtm6eo8gSXpQ9kOH8TY4JThfLb2ywGDeNUsBoed7SFnxre/lXXfg\n\tz2spKB/ir+VRGxX7ECgrlXQtCvQJPgmjq4DyrDYxnsR8ntozgZF1M5DXdmyR4g5hcl9LQ1XRDIC\n\tE5Xc0J+Nggh9sDg==", "X-Developer-Key": "i=jacopo.mondi@ideasonboard.com; a=openpgp;\n\tfpr=72392EDC88144A65C701EA9BA5826A2587AD026B", "X-BeenThere": "libcamera-devel@lists.libcamera.org", "X-Mailman-Version": "2.1.29", "Precedence": "list", "List-Id": "<libcamera-devel.lists.libcamera.org>", "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>", "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>", "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>", "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>", "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>", "Errors-To": "libcamera-devel-bounces@lists.libcamera.org", "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>" }, "content": "Similarly to what now happens at configure() time, the AGC maximum\nshutter time is calculated at runtime in the setLimits() function using\nthe CameraSensorHelper.\n\nFactor-out in the ExposureModeHelper class the maximum shutter time\ncalculation from the configure() function so that it can be performed at\nsetLimits() time too.\n\nUpdate the only IPA that handles limits update at runtime (RkISP1)\nto pass to the AGC the updated frame durations.\n\nSigned-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n---\n src/ipa/libipa/agc_mean_luminance.cpp | 5 +++-\n src/ipa/libipa/agc_mean_luminance.h | 3 ++-\n src/ipa/libipa/exposure_mode_helper.cpp | 47 +++++++++++++++++++++------------\n src/ipa/libipa/exposure_mode_helper.h | 5 +++-\n src/ipa/rkisp1/algorithms/agc.cpp | 8 +++---\n 5 files changed, 43 insertions(+), 25 deletions(-)", "diff": "diff --git a/src/ipa/libipa/agc_mean_luminance.cpp b/src/ipa/libipa/agc_mean_luminance.cpp\nindex 602050729fd08649e2db8d07623a8a39e7a53a77..0c8e15030c377ac0797dbdc9d53694ee894cd9b8 100644\n--- a/src/ipa/libipa/agc_mean_luminance.cpp\n+++ b/src/ipa/libipa/agc_mean_luminance.cpp\n@@ -461,6 +461,7 @@ int AgcMeanLuminance::parseTuningData(const YamlObject &tuningData)\n * \\brief Set the ExposureModeHelper limits for this class\n * \\param[in] minExposureTime Minimum exposure time to allow\n * \\param[in] maxExposureTime Maximum ewposure time to allow\n+ * \\param[in] maxFrameDuration Maximum frame duration\n * \\param[in] minGain Minimum gain to allow\n * \\param[in] maxGain Maximum gain to allow\n * \\param[in] constraints Additional constraints to apply\n@@ -470,11 +471,13 @@ int AgcMeanLuminance::parseTuningData(const YamlObject &tuningData)\n */\n void AgcMeanLuminance::setLimits(utils::Duration minExposureTime,\n \t\t\t\t utils::Duration maxExposureTime,\n+\t\t\t\t utils::Duration maxFrameDuration,\n \t\t\t\t double minGain, double maxGain,\n \t\t\t\t std::vector<AgcMeanLuminance::AgcConstraint> constraints)\n {\n \tfor (auto &[id, helper] : exposureModeHelpers_)\n-\t\thelper->setLimits(minExposureTime, maxExposureTime, minGain, maxGain);\n+\t\thelper->setLimits(minExposureTime, maxExposureTime, maxFrameDuration,\n+\t\t\t\t minGain, maxGain);\n \n \tadditionalConstraints_ = std::move(constraints);\n }\ndiff --git a/src/ipa/libipa/agc_mean_luminance.h b/src/ipa/libipa/agc_mean_luminance.h\nindex c3c8ce1cdda9229eca400b730f2ee896e9a0af93..535f94502dc2649a5f4ba49a7040de12f9f74179 100644\n--- a/src/ipa/libipa/agc_mean_luminance.h\n+++ b/src/ipa/libipa/agc_mean_luminance.h\n@@ -62,7 +62,8 @@ public:\n \t}\n \n \tvoid setLimits(utils::Duration minExposureTime, utils::Duration maxExposureTime,\n-\t\t double minGain, double maxGain, std::vector<AgcConstraint> constraints);\n+\t\t utils::Duration maxFrameDuration, double minGain, double maxGain,\n+\t\t std::vector<AgcConstraint> constraints);\n \n \tconst std::map<int32_t, std::vector<AgcConstraint>> &constraintModes() const\n \t{\ndiff --git a/src/ipa/libipa/exposure_mode_helper.cpp b/src/ipa/libipa/exposure_mode_helper.cpp\nindex 45f51f9088170c983bb0de2c18714627514c5641..fad13ff1521498244224a8a5f375738ee3fc9ff2 100644\n--- a/src/ipa/libipa/exposure_mode_helper.cpp\n+++ b/src/ipa/libipa/exposure_mode_helper.cpp\n@@ -109,6 +109,27 @@ ExposureModeHelper::ExposureModeHelper(const Span<std::pair<utils::Duration, dou\n \t}\n }\n \n+void ExposureModeHelper::setMaxExposure(utils::Duration minExposureTime,\n+\t\t\t\t\tutils::Duration maxExposureTime,\n+\t\t\t\t\tutils::Duration maxFrameDuration)\n+{\n+\tminExposureTime_ = minExposureTime;\n+\n+\t/*\n+\t * Compute the maximum shutter time.\n+\t *\n+\t * If maxExposureTime is equal to minExposureTime then we use them\n+\t * to fix the exposure time.\n+\t *\n+\t * Otherwise, if the exposure can range between a min and max delegate\n+\t * the maximum shutter time calculation to the sensor helper.\n+\t */\n+\tmaxExposureTime_ = minExposureTime != maxExposureTime\n+\t\t\t ? sensorHelper_->maxShutterTime(maxFrameDuration,\n+\t\t\t\t\t\t\t sensor_.lineDuration_)\n+\t\t\t : minExposureTime;\n+}\n+\n /**\n * \\brief Configure sensor details\n * \\param[in] sensorConfig The sensor configuration\n@@ -136,27 +157,15 @@ void ExposureModeHelper::configure(const SensorConfiguration &sensorConfig,\n \tminGain_ = sensor_.minGain_;\n \tmaxGain_ = sensor_.maxGain_;\n \n-\tminExposureTime_ = sensor_.minExposureTime_;\n-\n-\t/*\n-\t * Compute the maximum shutter time.\n-\t *\n-\t * If maxExposureTime is equal to minExposureTime then we use them\n-\t * to fix the exposure time.\n-\t *\n-\t * Otherwise, if the exposure can range between a min and max delegate\n-\t * the maximum shutter time calculation to the sensor helper.\n-\t */\n-\tmaxExposureTime_ = minExposureTime_ != sensorConfig.maxExposureTime_\n-\t\t\t ? sensorHelper_->maxShutterTime(sensorConfig.maxFrameDuration_,\n-\t\t\t\t\t\t\t sensorConfig.lineDuration_)\n-\t\t\t : minExposureTime_;\n+\tsetMaxExposure(sensorConfig.minExposureTime_, sensorConfig.maxExposureTime_,\n+\t\t sensorConfig.maxFrameDuration_);\n }\n \n /**\n * \\brief Set the exposure time and gain limits\n * \\param[in] minExposureTime The minimum exposure time supported\n * \\param[in] maxExposureTime The maximum exposure time supported\n+ * \\param[in] maxFrameDuration The maximum frame duration\n * \\param[in] minGain The minimum analogue gain supported\n * \\param[in] maxGain The maximum analogue gain supported\n *\n@@ -168,15 +177,19 @@ void ExposureModeHelper::configure(const SensorConfiguration &sensorConfig,\n * If the algorithm using the helpers needs to indicate that either exposure time\n * or analogue gain or both should be fixed it can do so by setting both the\n * minima and maxima to the same value.\n+ *\n+ * The exposure time limits are calculated using \\a maxFrameDuration as the\n+ * upper bound, the \\a maxExposureTime paramter effectivelly only serves\n+ * to indicate that the caller wants a fixed exposure value.\n */\n void ExposureModeHelper::setLimits(utils::Duration minExposureTime,\n \t\t\t\t utils::Duration maxExposureTime,\n+\t\t\t\t utils::Duration maxFrameDuration,\n \t\t\t\t double minGain, double maxGain)\n {\n-\tminExposureTime_ = minExposureTime;\n-\tmaxExposureTime_ = maxExposureTime;\n \tminGain_ = minGain;\n \tmaxGain_ = maxGain;\n+\tsetMaxExposure(minExposureTime, maxExposureTime, maxFrameDuration);\n }\n \n utils::Duration ExposureModeHelper::clampExposureTime(utils::Duration exposureTime,\ndiff --git a/src/ipa/libipa/exposure_mode_helper.h b/src/ipa/libipa/exposure_mode_helper.h\nindex e41c58767eee65dd27946336beb2bc182dd4ab58..36791c99face056835b0bb2d28b533380e8d9b95 100644\n--- a/src/ipa/libipa/exposure_mode_helper.h\n+++ b/src/ipa/libipa/exposure_mode_helper.h\n@@ -41,12 +41,15 @@ public:\n \tvoid configure(const SensorConfiguration &sensorConfig,\n \t\t const CameraSensorHelper *sensorHelper);\n \tvoid setLimits(utils::Duration minExposureTime, utils::Duration maxExposureTime,\n-\t\t double minGain, double maxGain);\n+\t\t utils::Duration maxFrameDuration, double minGain, double maxGain);\n \n \tstd::tuple<utils::Duration, double, double, double>\n \tsplitExposure(utils::Duration exposure) const;\n \n private:\n+\tvoid setMaxExposure(utils::Duration minExposureTime,\n+\t\t\t utils::Duration maxExposureTime,\n+\t\t\t utils::Duration maxFrameDuration);\n \tutils::Duration clampExposureTime(utils::Duration exposureTime,\n \t\t\t\t\t double *quantizationGain = nullptr) const;\n \tdouble clampGain(double gain, double *quantizationGain = nullptr) const;\ndiff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp\nindex de2980485f2d3a8973f065981f8cdd520e3dfc47..db318a2c49f2fbd9b00222ec699a657eed131595 100644\n--- a/src/ipa/rkisp1/algorithms/agc.cpp\n+++ b/src/ipa/rkisp1/algorithms/agc.cpp\n@@ -580,9 +580,7 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n \n \tif (frameContext.agc.autoExposureEnabled) {\n \t\tminExposureTime = context.configuration.sensor.minExposureTime;\n-\t\tmaxExposureTime = std::clamp(frameContext.agc.maxFrameDuration,\n-\t\t\t\t\t context.configuration.sensor.minExposureTime,\n-\t\t\t\t\t context.configuration.sensor.maxExposureTime);\n+\t\tmaxExposureTime = context.configuration.sensor.maxExposureTime;\n \t} else {\n \t\tminExposureTime = context.configuration.sensor.lineDuration\n \t\t\t\t* frameContext.agc.exposure;\n@@ -601,8 +599,8 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n \tif (context.activeState.wdr.mode != controls::WdrOff)\n \t\tadditionalConstraints.push_back(context.activeState.wdr.constraint);\n \n-\tsetLimits(minExposureTime, maxExposureTime, minAnalogueGain, maxAnalogueGain,\n-\t\t std::move(additionalConstraints));\n+\tsetLimits(minExposureTime, maxExposureTime, frameContext.agc.maxFrameDuration,\n+\t\t minAnalogueGain, maxAnalogueGain, std::move(additionalConstraints));\n \n \t/*\n \t * The Agc algorithm needs to know the effective exposure value that was\n", "prefixes": [ "v3", "13/19" ] }