Patch Detail
Show a patch.
GET /api/patches/24845/?format=api
{ "id": 24845, "url": "https://patchwork.libcamera.org/api/patches/24845/?format=api", "web_url": "https://patchwork.libcamera.org/patch/24845/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/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": "<20251028-exposure-limits-v2-7-a8b5a318323e@ideasonboard.com>", "date": "2025-10-28T09:31:53", "name": "[v2,07/10] ipa: libipa: agc: Set exposure limits with frame duration", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "319ac9a7012d60241cf274fe0a7d3163fd563a75", "submitter": { "id": 143, "url": "https://patchwork.libcamera.org/api/people/143/?format=api", "name": "Jacopo Mondi", "email": "jacopo.mondi@ideasonboard.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/24845/mbox/", "series": [ { "id": 5536, "url": "https://patchwork.libcamera.org/api/series/5536/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5536", "date": "2025-10-28T09:31:46", "name": "libipa: agc: Calculate exposure limits", "version": 2, "mbox": "https://patchwork.libcamera.org/series/5536/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/24845/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/24845/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 E14E6BE080\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 28 Oct 2025 09:32:25 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 91F68607EE;\n\tTue, 28 Oct 2025 10:32:23 +0100 (CET)", "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 0400C6079C\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 28 Oct 2025 10:32:11 +0100 (CET)", "from [192.168.0.172] (mob-5-90-58-13.net.vodafone.it [5.90.58.13])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 2E54B4B38; \n\tTue, 28 Oct 2025 10:30:22 +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=\"BWNDT1Yd\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1761643822;\n\tbh=RNUI2xtURg4B/VVj79hQSs2yG/gpcllwIsjZCRcUIcc=;\n\th=From:Date:Subject:References:In-Reply-To:To:Cc:From;\n\tb=BWNDT1Ydlz35KnqnsllSTZX4TXGeXHNctOLZuNnoPgdqlTH+fHHK44gvgVM3BGHDx\n\tOO+S9weB+jUHHgYEkhoVNXAc7BJZ2vkTDZGxRxxlK5CQzrEFgJLSJB/D6hEKc5eXn/\n\tVFh2Z9WOmnam82z5JGvzpHOVmYyDquo3IjADQM0E=", "From": "Jacopo Mondi <jacopo.mondi@ideasonboard.com>", "Date": "Tue, 28 Oct 2025 10:31:53 +0100", "Subject": "[PATCH v2 07/10] ipa: libipa: agc: Set exposure limits with frame\n\tduration", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=\"utf-8\"", "Content-Transfer-Encoding": "7bit", "Message-Id": "<20251028-exposure-limits-v2-7-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?= <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=9294;\n\ti=jacopo.mondi@ideasonboard.com; h=from:subject:message-id;\n\tbh=RNUI2xtURg4B/VVj79hQSs2yG/gpcllwIsjZCRcUIcc=;\n\tb=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBpAI2VV35YcZuNFy8iUrKLvGkjOfGHuCuzymYKI\n\tgm2D2YnLp6JAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCaQCNlQAKCRByNAaPFqFW\n\tPFZaD/9B6hiUApzGIQOgBdhJBME2by2fT6fdeIDYRx8ol7MuejEGQSr++xnCV8YX99N7U42txAU\n\tnK4U78eZoEzchvpjLeWkm8DJi6Hfg9CM8KS1/l/qcijnFeof5Oahm6CEudbzIvBS7PtHXXFlJ/j\n\tUNff0RuGOczKFyzgUNNrllj3PfLUuTq/b5sCvtNeuQTrItWKf9SJ+ZpHs79yoBoY70dHJPWjeaI\n\t6aOxL9tW175NyctCL1pa9BYJZfy+x7vklv6BN+wc4mN1UMZw+oAutXOxkwESIGrtLyAbV/M+8AZ\n\tKBcJ6HqEXAvzfVESbP8ihM3lWlm9pSNqbjnK5XtL9YyEPQQ5NZkgZ0gkUBs0xB7DiyUlTtadr+H\n\twH6yxdsl6vjl2tlYucx71BmcdyDTZcZwc2k2bHOD8WylVBn3zvCHKpeoTsc1sM2HOCklxF5dp3z\n\thf+841rzC+H3jFd3Gm6KKUy4an+R6SDZCO7SYpVHslyTqSFHJSA5UMbfu46NYmhW/DPWdmT9P17\n\t5PidDV7gcY/VrvB1cLicB2jWi8FZH5Rm1+ZwLXeWlPJf2n2uGBkHDFsLQkn7cDv++kSLMLLX8+3\n\tpGeGYWXPsDuCft/RFf7aZHYTn0er6hiBPIGoXk22qRdpLlCZEBn1qZiLoulhEesaLeQcaS4+gwd\n\tuP+peSkutB2dJgQ==", "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 exposure\nlimits updated at runtime with the setLimits() function are now\ncomputed using the maximum frame duration.\n\nFactor-out in the ExposureModeHelper class the exposure limits\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 | 59 +++++++++++++++++++--------------\n src/ipa/libipa/exposure_mode_helper.h | 5 ++-\n src/ipa/rkisp1/algorithms/agc.cpp | 8 ++---\n 5 files changed, 48 insertions(+), 32 deletions(-)", "diff": "diff --git a/src/ipa/libipa/agc_mean_luminance.cpp b/src/ipa/libipa/agc_mean_luminance.cpp\nindex 195de2f2e93ce229b8047909b949e1d06ef8d5bf..1098865519ca9ca2679331edd9441720366c717d 100644\n--- a/src/ipa/libipa/agc_mean_luminance.cpp\n+++ b/src/ipa/libipa/agc_mean_luminance.cpp\n@@ -453,6 +453,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@@ -462,11 +463,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 c3d52c0b1cba23af14135dace8b3c13da4ae3e4b..0f7a4f53188d8d2759076c37d186efc088ddd279 100644\n--- a/src/ipa/libipa/agc_mean_luminance.h\n+++ b/src/ipa/libipa/agc_mean_luminance.h\n@@ -61,7 +61,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 \tstd::map<int32_t, std::vector<AgcConstraint>> constraintModes()\n \t{\ndiff --git a/src/ipa/libipa/exposure_mode_helper.cpp b/src/ipa/libipa/exposure_mode_helper.cpp\nindex 8f40290959e24294ead008c7228e2f67ffc5adf8..d1d94cf46d5ef2c077508fd94dfe9715fdbc6f03 100644\n--- a/src/ipa/libipa/exposure_mode_helper.cpp\n+++ b/src/ipa/libipa/exposure_mode_helper.cpp\n@@ -79,6 +79,33 @@ 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+\t/*\n+\t * Compute the maximum exposure 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, use the\n+\t * maxFrameDuration minus the margin as upper limit for exposure\n+\t * (capped to the provided max exposure).\n+\t */\n+\tminExposureTime_ = minExposureTime;\n+\tauto margin = sensorHelper_->exposureMargin();\n+\tif (!margin.has_value()) {\n+\t\tLOG(ExposureModeHelper, Warning)\n+\t\t\t<< \"Exposure margin not known. Default to 4\";\n+\t\tmargin = { 4 };\n+\t}\n+\n+\tmaxExposureTime_ = minExposureTime != maxExposureTime\n+\t\t\t ? maxFrameDuration - margin.value() * lineDuration_\n+\t\t\t : minExposureTime;\n+}\n+\n /**\n * \\brief Configure sensor details\n * \\param[in] lineDuration The current line length of the sensor\n@@ -111,34 +138,14 @@ void ExposureModeHelper::configure(utils::Duration lineDuration,\n \tmaxGain_ = maxGain;\n \tsensorHelper_ = sensorHelper;\n \n-\tminExposureTime_ = minExposureTime;\n-\n-\t/*\n-\t * Compute the maximum exposure 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, use the\n-\t * maxFrameDuration minus the margin as upper limit for exposure\n-\t * (capped to the provided max exposure).\n-\t */\n-\tauto margin = sensorHelper_->exposureMargin();\n-\tif (!margin.has_value()) {\n-\t\tLOG(ExposureModeHelper, Warning)\n-\t\t\t<< \"Exposure margin not known. Default to 4\";\n-\t\tmargin = { 4 };\n-\t}\n-\n-\tmaxExposureTime_ = minExposureTime != maxExposureTime\n-\t\t\t ? maxFrameDuration - margin.value() * lineDuration\n-\t\t\t : minExposureTime;\n+\tsetMaxExposure(minExposureTime, maxExposureTime, 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@@ -150,15 +157,19 @@ void ExposureModeHelper::configure(utils::Duration lineDuration,\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 8a7d2161912d318c2d1c5c8d009edc8a2d0c0427..b1de96d4a3a13e3771ff2162f11201e5f9253265 100644\n--- a/src/ipa/libipa/exposure_mode_helper.h\n+++ b/src/ipa/libipa/exposure_mode_helper.h\n@@ -31,7 +31,7 @@ public:\n \t\t double minGain, double maxGain,\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@@ -43,6 +43,9 @@ public:\n \tdouble maxGain() const { return maxGain_; }\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 121e75449a6985f951c50fdc85b0298026344297..96189254885c47d29b92f3fb40f0e86d10e2a7fc 100644\n--- a/src/ipa/rkisp1/algorithms/agc.cpp\n+++ b/src/ipa/rkisp1/algorithms/agc.cpp\n@@ -579,9 +579,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@@ -600,8 +598,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": [ "v2", "07/10" ] }