[{"id":38125,"web_url":"https://patchwork.libcamera.org/comment/38125/","msgid":"<177039187820.607498.5411123134664035838@neptunite.rasen.tech>","date":"2026-02-06T15:31:18","subject":"Re: [PATCH v3 11/19] ipa: libipa: agc: Pass the frame duration to\n\tconfigure()","submitter":{"id":17,"url":"https://patchwork.libcamera.org/api/people/17/","name":"Paul Elder","email":"paul.elder@ideasonboard.com"},"content":"Quoting Jacopo Mondi (2025-11-14 23:17:06)\n> Pass the min/max sensor frame duration to the AGC configure()\n> operation.\n> \n> This prepares for limiting the exposure time to the frame duration.\n> \n> In order to be able to provide to the AGC the frame duration in the IPU3\n> and Mali-C55 IPAs it is necessary to store the FrameDurationLimits in\n> the context sensor configuration, like it was already done for the\n> RkISP1 IPA.\n> \n> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n\nReviewed-by: Paul Elder <paul.elder@ideasonboard.com>\n\n> ---\n>  src/ipa/ipu3/algorithms/agc.cpp       |  2 ++\n>  src/ipa/ipu3/ipa_context.h            |  4 ++++\n>  src/ipa/ipu3/ipu3.cpp                 | 18 +++++++++++++++---\n>  src/ipa/libipa/agc_mean_luminance.cpp |  8 ++++++++\n>  src/ipa/libipa/agc_mean_luminance.h   |  2 ++\n>  src/ipa/mali-c55/algorithms/agc.cpp   |  6 ++++++\n>  src/ipa/mali-c55/ipa_context.h        |  4 ++++\n>  src/ipa/mali-c55/mali-c55.cpp         | 17 ++++++++++++-----\n>  src/ipa/rkisp1/algorithms/agc.cpp     |  2 ++\n>  9 files changed, 55 insertions(+), 8 deletions(-)\n> \n> diff --git a/src/ipa/ipu3/algorithms/agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp\n> index 5c72806dede5f55459bde69ab8cfaebc495c7560..002ee574c02b79c25834a9d87a5881a9de52e39e 100644\n> --- a/src/ipa/ipu3/algorithms/agc.cpp\n> +++ b/src/ipa/ipu3/algorithms/agc.cpp\n> @@ -118,6 +118,8 @@ int Agc::configure(IPAContext &context,\n>         AgcMeanLuminance::SensorConfiguration sensorConfig;\n>         sensorConfig.lineDuration = context.configuration.sensor.lineDuration;\n>         sensorConfig.minExposureTime = minExposureTime_;\n> +       sensorConfig.minFrameDuration = context.configuration.sensor.minFrameDuration;\n> +       sensorConfig.maxFrameDuration = context.configuration.sensor.maxFrameDuration;\n>         sensorConfig.maxExposureTime = maxExposureTime_;\n>         sensorConfig.minAnalogueGain = minAnalogueGain_;\n>         sensorConfig.maxAnalogueGain = maxAnalogueGain_;\n> diff --git a/src/ipa/ipu3/ipa_context.h b/src/ipa/ipu3/ipa_context.h\n> index baf84b8cbc9a1ff9411c0a994e35317b613580dd..33f3fe3ae1b503d47887873046def0835cd53894 100644\n> --- a/src/ipa/ipu3/ipa_context.h\n> +++ b/src/ipa/ipu3/ipa_context.h\n> @@ -39,6 +39,8 @@ struct IPASessionConfiguration {\n>                 Size size;\n>                 utils::Duration minExposureTime;\n>                 utils::Duration maxExposureTime;\n> +               utils::Duration minFrameDuration;\n> +               utils::Duration maxFrameDuration;\n>                 double minAnalogueGain;\n>                 double maxAnalogueGain;\n>         } sensor;\n> @@ -56,6 +58,8 @@ struct IPAActiveState {\n>                 double gain;\n>                 uint32_t constraintMode;\n>                 uint32_t exposureMode;\n> +               utils::Duration minFrameDuration;\n> +               utils::Duration maxFrameDuration;\n>         } agc;\n>  \n>         struct {\n> diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp\n> index 60f22727a0f75e374b53fb6d3185946b70c25582..0c8651c5235f9e4e9944eb88595aeef41f016310 100644\n> --- a/src/ipa/ipu3/ipu3.cpp\n> +++ b/src/ipa/ipu3/ipu3.cpp\n> @@ -167,7 +167,8 @@ private:\n>         void updateControls(const IPACameraSensorInfo &sensorInfo,\n>                             const ControlInfoMap &sensorControls,\n>                             ControlInfoMap *ipaControls);\n> -       void updateSessionConfiguration(const ControlInfoMap &sensorControls);\n> +       void updateSessionConfiguration(const IPACameraSensorInfo &sensorInfo,\n> +                                       const ControlInfoMap &sensorControls);\n>  \n>         void setControls(unsigned int frame);\n>         void calculateBdsGrid(const Size &bdsOutputSize);\n> @@ -197,7 +198,8 @@ std::string IPAIPU3::logPrefix() const\n>   * \\brief Compute IPASessionConfiguration using the sensor information and the\n>   * sensor V4L2 controls\n>   */\n> -void IPAIPU3::updateSessionConfiguration(const ControlInfoMap &sensorControls)\n> +void IPAIPU3::updateSessionConfiguration(const IPACameraSensorInfo &sensorInfo,\n> +                                        const ControlInfoMap &sensorControls)\n>  {\n>         const ControlInfo vBlank = sensorControls.find(V4L2_CID_VBLANK)->second;\n>         context_.configuration.sensor.defVBlank = vBlank.def().get<int32_t>();\n> @@ -210,6 +212,12 @@ void IPAIPU3::updateSessionConfiguration(const ControlInfoMap &sensorControls)\n>         int32_t minGain = v4l2Gain.min().get<int32_t>();\n>         int32_t maxGain = v4l2Gain.max().get<int32_t>();\n>  \n> +       const ControlInfo &v4l2VBlank = sensorControls.find(V4L2_CID_VBLANK)->second;\n> +       std::array<uint32_t, 2> frameHeights{\n> +               v4l2VBlank.min().get<int32_t>() + sensorInfo.outputSize.height,\n> +               v4l2VBlank.max().get<int32_t>() + sensorInfo.outputSize.height,\n> +       };\n> +\n>         /*\n>          * When the AGC computes the new exposure values for a frame, it needs\n>          * to know the limits for exposure time and analogue gain.\n> @@ -219,6 +227,10 @@ void IPAIPU3::updateSessionConfiguration(const ControlInfoMap &sensorControls)\n>          */\n>         context_.configuration.sensor.minExposureTime = minExposure * context_.configuration.sensor.lineDuration;\n>         context_.configuration.sensor.maxExposureTime = maxExposure * context_.configuration.sensor.lineDuration;\n> +       context_.configuration.sensor.minFrameDuration = frameHeights[0] *\n> +                                                        context_.configuration.sensor.lineDuration;\n> +       context_.configuration.sensor.maxFrameDuration = frameHeights[1] *\n> +                                                        context_.configuration.sensor.lineDuration;\n>         context_.configuration.sensor.minAnalogueGain = context_.camHelper->gain(minGain);\n>         context_.configuration.sensor.maxAnalogueGain = context_.camHelper->gain(maxGain);\n>  }\n> @@ -488,7 +500,7 @@ int IPAIPU3::configure(const IPAConfigInfo &configInfo,\n>         updateControls(sensorInfo_, sensorCtrls_, ipaControls);\n>  \n>         /* Update the IPASessionConfiguration using the sensor settings. */\n> -       updateSessionConfiguration(sensorCtrls_);\n> +       updateSessionConfiguration(sensorInfo_, sensorCtrls_);\n>  \n>         for (auto const &algo : algorithms()) {\n>                 int ret = algo->configure(context_, configInfo);\n> diff --git a/src/ipa/libipa/agc_mean_luminance.cpp b/src/ipa/libipa/agc_mean_luminance.cpp\n> index 512e153791f5b98da01efad6675192a5358e7698..602050729fd08649e2db8d07623a8a39e7a53a77 100644\n> --- a/src/ipa/libipa/agc_mean_luminance.cpp\n> +++ b/src/ipa/libipa/agc_mean_luminance.cpp\n> @@ -117,6 +117,12 @@ static constexpr double kMaxRelativeLuminanceTarget = 0.95;\n>   * \\var AgcMeanLuminance::SensorConfiguration::maxExposureTime\n>   * \\brief The sensor maximum exposure time in microseconds\n>   *\n> + * \\var AgcMeanLuminance::SensorConfiguration::minFrameDuration\n> + * \\brief The sensor minimum frame duration in microseconds\n> + *\n> + * \\var AgcMeanLuminance::SensorConfiguration::maxFrameDuration\n> + * \\brief The sensor maximum frame duration in microseconds\n> + *\n>   * \\var AgcMeanLuminance::SensorConfiguration::minAnalogueGain\n>   * \\brief The sensor minimum analogue gain absolute value\n>   *\n> @@ -366,6 +372,8 @@ void AgcMeanLuminance::configure(const SensorConfiguration &config,\n>                 sensorConfig.lineDuration_ = config.lineDuration;\n>                 sensorConfig.minExposureTime_ = config.minExposureTime;\n>                 sensorConfig.maxExposureTime_ = config.maxExposureTime;\n> +               sensorConfig.minFrameDuration_ = config.minFrameDuration;\n> +               sensorConfig.maxFrameDuration_ = config.maxFrameDuration;\n>                 sensorConfig.minGain_ = config.minAnalogueGain;\n>                 sensorConfig.maxGain_ = config.maxAnalogueGain;\n>  \n> diff --git a/src/ipa/libipa/agc_mean_luminance.h b/src/ipa/libipa/agc_mean_luminance.h\n> index 42ead74b0cdc197bc2b27aee16918e2b42ea3d08..c3c8ce1cdda9229eca400b730f2ee896e9a0af93 100644\n> --- a/src/ipa/libipa/agc_mean_luminance.h\n> +++ b/src/ipa/libipa/agc_mean_luminance.h\n> @@ -46,6 +46,8 @@ public:\n>                 utils::Duration lineDuration;\n>                 utils::Duration minExposureTime;\n>                 utils::Duration maxExposureTime;\n> +               utils::Duration minFrameDuration;\n> +               utils::Duration maxFrameDuration;\n>                 double minAnalogueGain;\n>                 double maxAnalogueGain;\n>         };\n> diff --git a/src/ipa/mali-c55/algorithms/agc.cpp b/src/ipa/mali-c55/algorithms/agc.cpp\n> index d6a1ff5aaca136c387feb8c948053fc83bb664ee..731b29ced1030ecb3f44b83ad28a0691dd5d2f0d 100644\n> --- a/src/ipa/mali-c55/algorithms/agc.cpp\n> +++ b/src/ipa/mali-c55/algorithms/agc.cpp\n> @@ -168,11 +168,17 @@ int Agc::configure(IPAContext &context,\n>         context.activeState.agc.manual.ispGain = kMinDigitalGain;\n>         context.activeState.agc.constraintMode = constraintModes().begin()->first;\n>         context.activeState.agc.exposureMode = exposureModeHelpers().begin()->first;\n> +       context.activeState.agc.minFrameDuration =\n> +                               context.configuration.sensor.minFrameDuration;\n> +       context.activeState.agc.maxFrameDuration =\n> +                               context.configuration.sensor.maxFrameDuration;\n>  \n>         AgcMeanLuminance::SensorConfiguration sensorConfig;\n>         sensorConfig.lineDuration = context.configuration.sensor.lineDuration;\n>         sensorConfig.minExposureTime = context.configuration.sensor.minShutterSpeed;\n>         sensorConfig.maxExposureTime = context.configuration.sensor.maxShutterSpeed;\n> +       sensorConfig.minFrameDuration = context.configuration.sensor.minFrameDuration;\n> +       sensorConfig.maxFrameDuration = context.configuration.sensor.maxFrameDuration;\n>         sensorConfig.minAnalogueGain = context.configuration.sensor.minAnalogueGain;\n>         sensorConfig.maxAnalogueGain = context.configuration.sensor.maxAnalogueGain;\n>  \n> diff --git a/src/ipa/mali-c55/ipa_context.h b/src/ipa/mali-c55/ipa_context.h\n> index fe75590ec93302e61a31e4832f5c497aab80cf4d..3b64cb7571729d4af162def5b2316331b3561af1 100644\n> --- a/src/ipa/mali-c55/ipa_context.h\n> +++ b/src/ipa/mali-c55/ipa_context.h\n> @@ -30,6 +30,8 @@ struct IPASessionConfiguration {\n>                 uint32_t blackLevel;\n>                 utils::Duration minShutterSpeed;\n>                 utils::Duration maxShutterSpeed;\n> +               utils::Duration minFrameDuration;\n> +               utils::Duration maxFrameDuration;\n>                 double minAnalogueGain;\n>                 double maxAnalogueGain;\n>         } sensor;\n> @@ -51,6 +53,8 @@ struct IPAActiveState {\n>                 uint32_t constraintMode;\n>                 uint32_t exposureMode;\n>                 uint32_t temperatureK;\n> +               utils::Duration minFrameDuration;\n> +               utils::Duration maxFrameDuration;\n>         } agc;\n>  \n>         struct {\n> diff --git a/src/ipa/mali-c55/mali-c55.cpp b/src/ipa/mali-c55/mali-c55.cpp\n> index 9375facf7ab559853986f66634d4e36b896361c8..491ae71a06dbede967bfbe1bcdcab25d177ad691 100644\n> --- a/src/ipa/mali-c55/mali-c55.cpp\n> +++ b/src/ipa/mali-c55/mali-c55.cpp\n> @@ -177,16 +177,23 @@ void IPAMaliC55::updateSessionConfiguration(const IPACameraSensorInfo &info,\n>         int32_t minGain = v4l2Gain.min().get<int32_t>();\n>         int32_t maxGain = v4l2Gain.max().get<int32_t>();\n>  \n> +       const ControlInfo &v4l2VBlank = sensorControls.find(V4L2_CID_VBLANK)->second;\n> +       std::array<uint32_t, 2> frameHeights{\n> +               v4l2VBlank.min().get<int32_t>() + info.outputSize.height,\n> +               v4l2VBlank.max().get<int32_t>() + info.outputSize.height,\n> +       };\n> +\n>         /*\n>          * When the AGC computes the new exposure values for a frame, it needs\n>          * to know the limits for shutter speed and analogue gain.\n>          * As it depends on the sensor, update it with the controls.\n> -        *\n> -        * \\todo take VBLANK into account for maximum shutter speed\n>          */\n> -       context_.configuration.sensor.lineDuration = info.minLineLength * 1.0s / info.pixelRate;\n> -       context_.configuration.sensor.minShutterSpeed = minExposure * context_.configuration.sensor.lineDuration;\n> -       context_.configuration.sensor.maxShutterSpeed = maxExposure * context_.configuration.sensor.lineDuration;\n> +       utils::Duration lineDuration = info.minLineLength * 1.0s / info.pixelRate;\n> +       context_.configuration.sensor.lineDuration = lineDuration;\n> +       context_.configuration.sensor.minShutterSpeed = minExposure * lineDuration;\n> +       context_.configuration.sensor.maxShutterSpeed = maxExposure * lineDuration;\n> +       context_.configuration.sensor.minFrameDuration = frameHeights[0] * lineDuration;\n> +       context_.configuration.sensor.maxFrameDuration = frameHeights[1] * lineDuration;\n>         context_.configuration.sensor.minAnalogueGain = context_.camHelper->gain(minGain);\n>         context_.configuration.sensor.maxAnalogueGain = context_.camHelper->gain(maxGain);\n>  \n> diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp\n> index b0c8966eea63901640bbe16af2a5d8a303c63ece..de2980485f2d3a8973f065981f8cdd520e3dfc47 100644\n> --- a/src/ipa/rkisp1/algorithms/agc.cpp\n> +++ b/src/ipa/rkisp1/algorithms/agc.cpp\n> @@ -204,6 +204,8 @@ int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo)\n>         sensorConfig.lineDuration = context.configuration.sensor.lineDuration;\n>         sensorConfig.minExposureTime = context.configuration.sensor.minExposureTime;\n>         sensorConfig.maxExposureTime = context.configuration.sensor.maxExposureTime;\n> +       sensorConfig.minFrameDuration = context.configuration.sensor.minFrameDuration;\n> +       sensorConfig.maxFrameDuration = context.configuration.sensor.maxFrameDuration;\n>         sensorConfig.minAnalogueGain = context.configuration.sensor.minAnalogueGain;\n>         sensorConfig.maxAnalogueGain = context.configuration.sensor.maxAnalogueGain;\n>  \n> \n> -- \n> 2.51.1\n>","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 D698AC32F1\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri,  6 Feb 2026 15:31:26 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id C21CA620B8;\n\tFri,  6 Feb 2026 16:31:25 +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 183AB6209B\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  6 Feb 2026 16:31:24 +0100 (CET)","from neptunite.rasen.tech (unknown\n\t[IPv6:2404:7a81:160:2100:5247:7b72:2b7:10da])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 0A31D2E0;\n\tFri,  6 Feb 2026 16:30:39 +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=\"k2PGU/2W\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1770391840;\n\tbh=TtuHWJ3M0ZwTCjvRl1cKe/K1zLSEGotdQ17v+waMHsA=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=k2PGU/2WT+GmMey5CoNHoa5PfIsZec1Dtggavs9gPuQ1PNisGgZmWvsizex7Ly7TU\n\t2rBn5Qy6v6lrZ5/3s8AgJCRruvRTK+mJ0khdBBDAJY72CE0N5GFr0u/KY6hRdSNNRz\n\tAs83vtBD1sktOcC5pL1CRelI1JLRIDJU2drkL99Y=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20251114-exposure-limits-v3-11-b7c07feba026@ideasonboard.com>","References":"<20251114-exposure-limits-v3-0-b7c07feba026@ideasonboard.com>\n\t<20251114-exposure-limits-v3-11-b7c07feba026@ideasonboard.com>","Subject":"Re: [PATCH v3 11/19] ipa: libipa: agc: Pass the frame duration to\n\tconfigure()","From":"Paul Elder <paul.elder@ideasonboard.com>","Cc":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>, Niklas =?utf-8?b?U8O2?=\n\t=?utf-8?q?derlund?= <niklas.soderlund@ragnatech.se>, Robert Mader\n\t<robert.mader@collabora.com>, libcamera-devel@lists.libcamera.org","Date":"Sat, 07 Feb 2026 00:31:18 +0900","Message-ID":"<177039187820.607498.5411123134664035838@neptunite.rasen.tech>","User-Agent":"alot/0.0.0","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>"}}]