Show a patch.

GET /api/1.1/patches/25062/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 25062,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/25062/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/25062/",
    "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-10-b7c07feba026@ideasonboard.com>",
    "date": "2025-11-14T14:17:05",
    "name": "[v3,10/19] ipa: libipa: agc: Make Agc::configure() set limits",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "28f1c1119b3f945445606bf393d922fc4cdb73cc",
    "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/25062/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/25062/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/25062/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 88086C32DB\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 14 Nov 2025 14:17:38 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id AC43A60AB7;\n\tFri, 14 Nov 2025 15:17:34 +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 9620160A86\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 14 Nov 2025 15:17:21 +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 92FD61A8F;\n\tFri, 14 Nov 2025 15:15:20 +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=\"p4o2mRgI\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1763129720;\n\tbh=Vnj6OMjyGCSUwrfWqA/064JQnBS2550S1SUFuChCM9g=;\n\th=From:Date:Subject:References:In-Reply-To:To:Cc:From;\n\tb=p4o2mRgITWDJ8Ifui3RgJk2zYSWoT6XgLJK2UqKSEj68dsIlLqjlyRBAKXb0vJdMr\n\tUvQuoN91ISwJynS/IOQ3oWHkbbvYVhHklxGZdrvvN66IewxUmL3WIQfAupYDN5cAOD\n\tb92Z9ygPjNBEjgKCojukKGM/Hdcd6BaXGCWd18tE=",
        "From": "Jacopo Mondi <jacopo.mondi@ideasonboard.com>",
        "Date": "Fri, 14 Nov 2025 15:17:05 +0100",
        "Subject": "[PATCH v3 10/19] ipa: libipa: agc: Make Agc::configure() set limits",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "7bit",
        "Message-Id": "<20251114-exposure-limits-v3-10-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=12196;\n\ti=jacopo.mondi@ideasonboard.com; h=from:subject:message-id;\n\tbh=Vnj6OMjyGCSUwrfWqA/064JQnBS2550S1SUFuChCM9g=;\n\tb=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBpFznrmTYC2+3ozsxraW2Av74ljty4sX4G67t/4\n\tNGUhrkYhdaJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCaRc56wAKCRByNAaPFqFW\n\tPAfxEACVg7z73MD8vMTnTkWJNu+9kHapriY5LLI12IgBO1gWsJFB80qqriBNZ+6CjWXOupB3i7x\n\tMpi/hxqOVsnTjV3rokZpibHje1NfnvPQjr9dy2HX6U0LNVyDVG1jAX8yaTlfYrn2zjnEPpxfkm1\n\t2FFxdidtRMd7+CqO0HfcEZpBTpCAR276mK9QCy5b0j+QtTgpGgXUvfri3+/Q8HCwXIEjGCVhH5v\n\tdnV1sdPfzWQ06OTo63bt4i2Okatb5QzMUMLxIUipNHMsHIEy0PCe9PnJDu/Vg/duEfaz/S9Q+w6\n\t5eZRSVcjUI4j/F4ki2G8930/way1Qfkxizi7u8O9dzSob1+faxxLn7Lo1IKIoiOLGlHbNPJiBqq\n\tK+wHy2GGgDPsZpLPeurKP/83twlCEiRvaXYHxqy0kvHEPsPRlrQGiT2C2LHR44ygTOZ0j19+0ck\n\tbmuSu+eo5Si6XR7F6S5G6H5khYelAZNnzq2YpcF65/vNHv0e6oltEo4O1mo4wmdxd/D/vc/7Dmb\n\ttWEAaK6880Xw2g+QixlBkcixQOv0uATK9VscgokvKW080IFi1PQFNhFQN3EbIbNi8r6wznS8t2B\n\tjwYjPH5sZDQ1l8ZurssJLECz6mfDnDPDdUKjpcadZ69G+sE5aOO7SViBjLwLjpc8UrDGbSGfk0J\n\tL0kM3fL0CEuStjQ==",
        "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": "The AgcMeanLuminance algorithm interface has a 'configure()' and\n'setLimits()' API. configure() doesn't actually do much if not\ninitialzing a few variables, and the Mali and IPU3 IPAs do not\neven call it. Configuring the AGC requires calling setLimits() at\nconfigure() time and at run time.\n\nIn order to prepare to differentiate between configure-time settings\nof the Agc and run-time handling of dynamic parameters such as the\nframe duration limits, make the configure() operation initialize\nthe Agc limits and provide an AgcMeanLuminance::SensorConfiguration\ntype for IPAs to be populated with the sensor's default values.\n\nThe new type mimics the ExposureModeHelper::SensorConfiguration on\nintroduced in the previous patches and both will be removed once all the\ninformation there contained will be made available from the\nCameraSensorHelper.\n\nUpdate all IPAs Agc implementation deriving from AgcMeanLuminance to\npopulate a AgcMeanLuminance::SensorConfiguration and use it in\nconfigure().\n\nSigned-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n---\n src/ipa/ipu3/algorithms/agc.cpp         | 14 +++++++--\n src/ipa/libipa/agc_mean_luminance.cpp   | 56 ++++++++++++++++++++++++++++++---\n src/ipa/libipa/agc_mean_luminance.h     | 11 ++++++-\n src/ipa/libipa/exposure_mode_helper.cpp | 20 +++++++-----\n src/ipa/libipa/exposure_mode_helper.h   |  3 +-\n src/ipa/mali-c55/algorithms/agc.cpp     | 16 ++++++----\n src/ipa/rkisp1/algorithms/agc.cpp       | 15 ++++-----\n 7 files changed, 105 insertions(+), 30 deletions(-)",
    "diff": "diff --git a/src/ipa/ipu3/algorithms/agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp\nindex 4574f3a1a9cd3f40b1b1402238809ee1a777946d..5c72806dede5f55459bde69ab8cfaebc495c7560 100644\n--- a/src/ipa/ipu3/algorithms/agc.cpp\n+++ b/src/ipa/ipu3/algorithms/agc.cpp\n@@ -115,9 +115,17 @@ int Agc::configure(IPAContext &context,\n \tcontext.activeState.agc.constraintMode = constraintModes().begin()->first;\n \tcontext.activeState.agc.exposureMode = exposureModeHelpers().begin()->first;\n \n-\t/* \\todo Run this again when FrameDurationLimits is passed in */\n-\tsetLimits(minExposureTime_, maxExposureTime_, minAnalogueGain_,\n-\t\t  maxAnalogueGain_, {});\n+\tAgcMeanLuminance::SensorConfiguration sensorConfig;\n+\tsensorConfig.lineDuration = context.configuration.sensor.lineDuration;\n+\tsensorConfig.minExposureTime = minExposureTime_;\n+\tsensorConfig.maxExposureTime = maxExposureTime_;\n+\tsensorConfig.minAnalogueGain = minAnalogueGain_;\n+\tsensorConfig.maxAnalogueGain = maxAnalogueGain_;\n+\n+\tAgcMeanLuminance::configure(sensorConfig, context.camHelper.get());\n+\n+\t/* \\todo Update AGC limits when FrameDurationLimits is passed in */\n+\n \tresetFrameCount();\n \n \treturn 0;\ndiff --git a/src/ipa/libipa/agc_mean_luminance.cpp b/src/ipa/libipa/agc_mean_luminance.cpp\nindex 64f36bd75dd213671b5a2e6810245096ed001f21..512e153791f5b98da01efad6675192a5358e7698 100644\n--- a/src/ipa/libipa/agc_mean_luminance.cpp\n+++ b/src/ipa/libipa/agc_mean_luminance.cpp\n@@ -95,6 +95,35 @@ static constexpr double kMaxRelativeLuminanceTarget = 0.95;\n  * \\brief The luminance target for the constraint\n  */\n \n+/**\n+ * \\struct AgcMeanLuminance::SensorConfiguration\n+ * \\brief The sensor configuration parameters\n+ *\n+ * This structure collects the sensor configuration parameters which need\n+ * to be provided to the AGC algorithm at configure() time.\n+ *\n+ * Each time configure() is called the sensor configuration need to be updated\n+ * with new parameters.\n+ *\n+ * \\todo Remove it once all the information are available from the\n+ * CameraSensorHelper.\n+ *\n+ * \\var AgcMeanLuminance::SensorConfiguration::lineDuration\n+ * \\brief The line duration in microseconds\n+ *\n+ * \\var AgcMeanLuminance::SensorConfiguration::minExposureTime\n+ * \\brief The sensor minimum exposure time in microseconds\n+ *\n+ * \\var AgcMeanLuminance::SensorConfiguration::maxExposureTime\n+ * \\brief The sensor maximum exposure time in microseconds\n+ *\n+ * \\var AgcMeanLuminance::SensorConfiguration::minAnalogueGain\n+ * \\brief The sensor minimum analogue gain absolute value\n+ *\n+ * \\var AgcMeanLuminance::SensorConfiguration::maxAnalogueGain\n+ * \\brief The sensor maximum analogue gain absolute value\n+ */\n+\n /**\n  * \\class AgcMeanLuminance\n  * \\brief A mean-based auto-exposure algorithm\n@@ -314,17 +343,34 @@ int AgcMeanLuminance::parseExposureModes(const YamlObject &tuningData)\n \n /**\n  * \\brief Configure the exposure mode helpers\n- * \\param[in] lineDuration The sensor line length\n+ * \\param[in] config The sensor configuration\n  * \\param[in] sensorHelper The sensor helper\n  *\n- * This function configures the exposure mode helpers so they can correctly\n+ * This function configures the exposure mode helpers by providing them the\n+ * sensor configuration parameters and the sensor helper, so they can correctly\n  * take quantization effects into account.\n  */\n-void AgcMeanLuminance::configure(utils::Duration lineDuration,\n+void AgcMeanLuminance::configure(const SensorConfiguration &config,\n \t\t\t\t const CameraSensorHelper *sensorHelper)\n {\n-\tfor (auto &[id, helper] : exposureModeHelpers_)\n-\t\thelper->configure(lineDuration, sensorHelper);\n+\tfor (auto &[id, helper] : exposureModeHelpers_) {\n+\t\t/*\n+\t\t * Translate from the SensorConfiguration to the\n+\t\t * ExposureModeHelper::SensorConfiguration.\n+\t\t *\n+\t\t * These are just place holders before all the information are\n+\t\t * available from the sensor helper.\n+\t\t */\n+\n+\t\tExposureModeHelper::SensorConfiguration sensorConfig;\n+\t\tsensorConfig.lineDuration_ = config.lineDuration;\n+\t\tsensorConfig.minExposureTime_ = config.minExposureTime;\n+\t\tsensorConfig.maxExposureTime_ = config.maxExposureTime;\n+\t\tsensorConfig.minGain_ = config.minAnalogueGain;\n+\t\tsensorConfig.maxGain_ = config.maxAnalogueGain;\n+\n+\t\thelper->configure(sensorConfig, sensorHelper);\n+\t}\n }\n \n /**\ndiff --git a/src/ipa/libipa/agc_mean_luminance.h b/src/ipa/libipa/agc_mean_luminance.h\nindex e5f164c3186b6b99cb0df5dd8dccf9026c22af20..42ead74b0cdc197bc2b27aee16918e2b42ea3d08 100644\n--- a/src/ipa/libipa/agc_mean_luminance.h\n+++ b/src/ipa/libipa/agc_mean_luminance.h\n@@ -42,7 +42,16 @@ public:\n \t\tdouble yTarget;\n \t};\n \n-\tvoid configure(utils::Duration lineDuration, const CameraSensorHelper *sensorHelper);\n+\tstruct SensorConfiguration {\n+\t\tutils::Duration lineDuration;\n+\t\tutils::Duration minExposureTime;\n+\t\tutils::Duration maxExposureTime;\n+\t\tdouble minAnalogueGain;\n+\t\tdouble maxAnalogueGain;\n+\t};\n+\n+\tvoid configure(const SensorConfiguration &config,\n+\t\t       const CameraSensorHelper *sensorHelper);\n \tint parseTuningData(const YamlObject &tuningData);\n \n \tvoid setExposureCompensation(double gain)\ndiff --git a/src/ipa/libipa/exposure_mode_helper.cpp b/src/ipa/libipa/exposure_mode_helper.cpp\nindex c3ed1601939bd28435bbbc540d9b8c9d92b81912..f771b10a28eead2976c0000cf099ba5cfbe78e0f 100644\n--- a/src/ipa/libipa/exposure_mode_helper.cpp\n+++ b/src/ipa/libipa/exposure_mode_helper.cpp\n@@ -111,24 +111,30 @@ ExposureModeHelper::ExposureModeHelper(const Span<std::pair<utils::Duration, dou\n \n /**\n  * \\brief Configure sensor details\n- * \\param[in] lineDuration The current line length of the sensor\n+ * \\param[in] sensorConfig The sensor configuration\n  * \\param[in] sensorHelper The sensor helper\n  *\n- * This function sets the line length and sensor helper. These are used in\n+ * This function initializes the exposure helper settings using the sensor\n+ * configuration parameters.\n+ *\n+ * The sensor parameters' are used to initialize the min and max limits used in\n  * splitExposure() to take the quantization of the exposure and gain into\n  * account.\n  *\n- * When this has not been called, it is assumed that exposure is in micro second\n- * granularity and gain has no quantization at all.\n- *\n  * ExposureModeHelper keeps a pointer to the CameraSensorHelper, so the caller\n  * has to ensure that sensorHelper is valid until the next call to configure().\n  */\n-void ExposureModeHelper::configure(utils::Duration lineDuration,\n+void ExposureModeHelper::configure(const SensorConfiguration &sensorConfig,\n \t\t\t\t   const CameraSensorHelper *sensorHelper)\n {\n-\tsensor_.lineDuration_ = lineDuration;\n+\tsensor_ = sensorConfig;\n \tsensorHelper_ = sensorHelper;\n+\n+\t/* Initialize run-time limits with sensor's default. */\n+\tminExposureTime_ = sensor_.minExposureTime_;\n+\tmaxExposureTime_ = sensor_.maxExposureTime_;\n+\tminGain_ = sensor_.minGain_;\n+\tmaxGain_ = sensor_.maxGain_;\n }\n \n /**\ndiff --git a/src/ipa/libipa/exposure_mode_helper.h b/src/ipa/libipa/exposure_mode_helper.h\nindex 4971cfbf5b2be9ef0e3e95a64b815902833e93a4..e41c58767eee65dd27946336beb2bc182dd4ab58 100644\n--- a/src/ipa/libipa/exposure_mode_helper.h\n+++ b/src/ipa/libipa/exposure_mode_helper.h\n@@ -38,7 +38,8 @@ public:\n \tExposureModeHelper(const Span<std::pair<utils::Duration, double>> stages);\n \t~ExposureModeHelper() = default;\n \n-\tvoid configure(utils::Duration lineLength, const CameraSensorHelper *sensorHelper);\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 \ndiff --git a/src/ipa/mali-c55/algorithms/agc.cpp b/src/ipa/mali-c55/algorithms/agc.cpp\nindex 4fa00769d201d906be357809f5af02c71201a4f1..d6a1ff5aaca136c387feb8c948053fc83bb664ee 100644\n--- a/src/ipa/mali-c55/algorithms/agc.cpp\n+++ b/src/ipa/mali-c55/algorithms/agc.cpp\n@@ -169,12 +169,16 @@ int Agc::configure(IPAContext &context,\n \tcontext.activeState.agc.constraintMode = constraintModes().begin()->first;\n \tcontext.activeState.agc.exposureMode = exposureModeHelpers().begin()->first;\n \n-\t/* \\todo Run this again when FrameDurationLimits is passed in */\n-\tsetLimits(context.configuration.sensor.minShutterSpeed,\n-\t\t  context.configuration.sensor.maxShutterSpeed,\n-\t\t  context.configuration.sensor.minAnalogueGain,\n-\t\t  context.configuration.sensor.maxAnalogueGain,\n-\t\t  {});\n+\tAgcMeanLuminance::SensorConfiguration sensorConfig;\n+\tsensorConfig.lineDuration = context.configuration.sensor.lineDuration;\n+\tsensorConfig.minExposureTime = context.configuration.sensor.minShutterSpeed;\n+\tsensorConfig.maxExposureTime = context.configuration.sensor.maxShutterSpeed;\n+\tsensorConfig.minAnalogueGain = context.configuration.sensor.minAnalogueGain;\n+\tsensorConfig.maxAnalogueGain = context.configuration.sensor.maxAnalogueGain;\n+\n+\tAgcMeanLuminance::configure(sensorConfig, context.camHelper.get());\n+\n+\t/* \\todo Update AGC limits when FrameDurationLimits is passed in */\n \n \tresetFrameCount();\n \ndiff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp\nindex aa1a90daf3ca7d0041c56000c12fc4d1ab5700eb..b0c8966eea63901640bbe16af2a5d8a303c63ece 100644\n--- a/src/ipa/rkisp1/algorithms/agc.cpp\n+++ b/src/ipa/rkisp1/algorithms/agc.cpp\n@@ -200,13 +200,14 @@ int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo)\n \tcontext.configuration.agc.measureWindow.h_size = configInfo.outputSize.width;\n \tcontext.configuration.agc.measureWindow.v_size = configInfo.outputSize.height;\n \n-\tAgcMeanLuminance::configure(context.configuration.sensor.lineDuration,\n-\t\t\t\t    context.camHelper.get());\n-\n-\tsetLimits(context.configuration.sensor.minExposureTime,\n-\t\t  context.configuration.sensor.maxExposureTime,\n-\t\t  context.configuration.sensor.minAnalogueGain,\n-\t\t  context.configuration.sensor.maxAnalogueGain, {});\n+\tAgcMeanLuminance::SensorConfiguration sensorConfig;\n+\tsensorConfig.lineDuration = context.configuration.sensor.lineDuration;\n+\tsensorConfig.minExposureTime = context.configuration.sensor.minExposureTime;\n+\tsensorConfig.maxExposureTime = context.configuration.sensor.maxExposureTime;\n+\tsensorConfig.minAnalogueGain = context.configuration.sensor.minAnalogueGain;\n+\tsensorConfig.maxAnalogueGain = context.configuration.sensor.maxAnalogueGain;\n+\n+\tAgcMeanLuminance::configure(sensorConfig, context.camHelper.get());\n \n \tcontext.activeState.agc.automatic.yTarget = effectiveYTarget();\n \n",
    "prefixes": [
        "v3",
        "10/19"
    ]
}