[v3,03/19] ipa: rkisp1: Store FrameDurationLimits as sensor config
diff mbox series

Message ID 20251114-exposure-limits-v3-3-b7c07feba026@ideasonboard.com
State New
Headers show
Series
  • libipa: agc: Calculate exposure limits
Related show

Commit Message

Jacopo Mondi Nov. 14, 2025, 2:16 p.m. UTC
The RkISP1 IPA context stores a control list ctrlMap which is used by the
AGC algorithm to initialize controls that are then added to the list of the
ones registered by the IPA module.

The FrameDurationLimits control is a bit of an outlier, as it's the only
control that is registered by the IPA in the context ctrlMap and is then
used by the AGC algorithm.

As the purpose of the context ctrlMap is to be populated by algorithms for
the IPA, do not abuse it by registering a control there in the main IPA
module and only store the control limits in the active context.

Removing FrameDurationLimits from the ctrlMap requires to store it as
a sensor configuration parameter in the IPA context and use it for
clamping the FrameDurationLimits control and to initialize the AGC
active state.

Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
---
 src/ipa/rkisp1/algorithms/agc.cpp | 28 ++++++++++++------------
 src/ipa/rkisp1/ipa_context.h      |  2 ++
 src/ipa/rkisp1/rkisp1.cpp         | 46 ++++++++++++++++++++++++---------------
 3 files changed, 44 insertions(+), 32 deletions(-)

Patch
diff mbox series

diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp
index f5a3c917cb6909f6ef918e5ee8e46cf97ba55010..aa1a90daf3ca7d0041c56000c12fc4d1ab5700eb 100644
--- a/src/ipa/rkisp1/algorithms/agc.cpp
+++ b/src/ipa/rkisp1/algorithms/agc.cpp
@@ -190,10 +190,10 @@  int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo)
 	context.activeState.agc.meteringMode =
 		static_cast<controls::AeMeteringModeEnum>(meteringModes_.begin()->first);
 
-	/* Limit the frame duration to match current initialisation */
-	ControlInfo &frameDurationLimits = context.ctrlMap[&controls::FrameDurationLimits];
-	context.activeState.agc.minFrameDuration = std::chrono::microseconds(frameDurationLimits.min().get<int64_t>());
-	context.activeState.agc.maxFrameDuration = std::chrono::microseconds(frameDurationLimits.max().get<int64_t>());
+	context.activeState.agc.minFrameDuration =
+		context.configuration.sensor.minFrameDuration;
+	context.activeState.agc.maxFrameDuration =
+		context.configuration.sensor.maxFrameDuration;
 
 	context.configuration.agc.measureWindow.h_offs = 0;
 	context.configuration.agc.measureWindow.v_offs = 0;
@@ -320,16 +320,16 @@  void Agc::queueRequest(IPAContext &context,
 
 	const auto &frameDurationLimits = controls.get(controls::FrameDurationLimits);
 	if (frameDurationLimits) {
-		/* Limit the control value to the limits in ControlInfo */
-		ControlInfo &limits = context.ctrlMap[&controls::FrameDurationLimits];
-		int64_t minFrameDuration =
-			std::clamp((*frameDurationLimits).front(),
-				   limits.min().get<int64_t>(),
-				   limits.max().get<int64_t>());
-		int64_t maxFrameDuration =
-			std::clamp((*frameDurationLimits).back(),
-				   limits.min().get<int64_t>(),
-				   limits.max().get<int64_t>());
+		/* Limit the control value to the sensor constraints. */
+		int64_t sensorMinFrameDuration =
+			context.configuration.sensor.minFrameDuration.get<std::micro>();
+		int64_t sensorMaxFrameDuration =
+			context.configuration.sensor.maxFrameDuration.get<std::micro>();
+
+		int64_t minFrameDuration = std::clamp((*frameDurationLimits).front(),
+						      sensorMinFrameDuration, sensorMaxFrameDuration);
+		int64_t maxFrameDuration = std::clamp((*frameDurationLimits).back(),
+						      sensorMinFrameDuration, sensorMaxFrameDuration);
 
 		agc.minFrameDuration = std::chrono::microseconds(minFrameDuration);
 		agc.maxFrameDuration = std::chrono::microseconds(maxFrameDuration);
diff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h
index f85a130d9c23dba7987f388e395239e4b141d776..5fe727bd0b508617d993d226ae785056a3771ce0 100644
--- a/src/ipa/rkisp1/ipa_context.h
+++ b/src/ipa/rkisp1/ipa_context.h
@@ -62,6 +62,8 @@  struct IPASessionConfiguration {
 	struct {
 		utils::Duration minExposureTime;
 		utils::Duration maxExposureTime;
+		utils::Duration minFrameDuration;
+		utils::Duration maxFrameDuration;
 		double minAnalogueGain;
 		double maxAnalogueGain;
 
diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp
index fa22bfc349043002345d275b11a60ac983e329d7..f25e477f0fb77241bd1ccddb7778205e58bdc8a9 100644
--- a/src/ipa/rkisp1/rkisp1.cpp
+++ b/src/ipa/rkisp1/rkisp1.cpp
@@ -227,6 +227,7 @@  int IPARkISP1::configure(const IPAConfigInfo &ipaConfig,
 			 const std::map<uint32_t, IPAStream> &streamConfig,
 			 ControlInfoMap *ipaControls)
 {
+	const IPACameraSensorInfo &info = ipaConfig.sensorInfo;
 	sensorControls_ = ipaConfig.sensorControls;
 
 	const auto itExp = sensorControls_.find(V4L2_CID_EXPOSURE);
@@ -237,6 +238,12 @@  int IPARkISP1::configure(const IPAConfigInfo &ipaConfig,
 	int32_t minGain = itGain->second.min().get<int32_t>();
 	int32_t maxGain = itGain->second.max().get<int32_t>();
 
+	const auto itVBlank = sensorControls_.find(V4L2_CID_VBLANK);
+	std::array<uint32_t, 2> frameHeights{
+		itVBlank->second.min().get<int32_t>() + info.outputSize.height,
+		itVBlank->second.max().get<int32_t>() + info.outputSize.height,
+	};
+
 	LOG(IPARkISP1, Debug)
 		<< "Exposure: [" << minExposure << ", " << maxExposure
 		<< "], gain: [" << minGain << ", " << maxGain << "]";
@@ -248,11 +255,10 @@  int IPARkISP1::configure(const IPAConfigInfo &ipaConfig,
 
 	context_.configuration.paramFormat = ipaConfig.paramFormat;
 
-	const IPACameraSensorInfo &info = ipaConfig.sensorInfo;
-	const ControlInfo vBlank = sensorControls_.find(V4L2_CID_VBLANK)->second;
-	context_.configuration.sensor.defVBlank = vBlank.def().get<int32_t>();
+	utils::Duration lineDuration = info.minLineLength * 1.0s / info.pixelRate;
+	context_.configuration.sensor.defVBlank = itVBlank->second.def().get<int32_t>();
 	context_.configuration.sensor.size = info.outputSize;
-	context_.configuration.sensor.lineDuration = info.minLineLength * 1.0s / info.pixelRate;
+	context_.configuration.sensor.lineDuration = lineDuration;
 
 	/* Update the camera controls using the new sensor settings. */
 	updateControls(info, sensorControls_, ipaControls);
@@ -261,17 +267,13 @@  int IPARkISP1::configure(const IPAConfigInfo &ipaConfig,
 	 * When the AGC computes the new exposure values for a frame, it needs
 	 * to know the limits for exposure time and analogue gain. As it depends
 	 * on the sensor, update it with the controls.
-	 *
-	 * \todo take VBLANK into account for maximum exposure time
 	 */
-	context_.configuration.sensor.minExposureTime =
-		minExposure * context_.configuration.sensor.lineDuration;
-	context_.configuration.sensor.maxExposureTime =
-		maxExposure * context_.configuration.sensor.lineDuration;
-	context_.configuration.sensor.minAnalogueGain =
-		context_.camHelper->gain(minGain);
-	context_.configuration.sensor.maxAnalogueGain =
-		context_.camHelper->gain(maxGain);
+	context_.configuration.sensor.minExposureTime = minExposure * lineDuration;
+	context_.configuration.sensor.maxExposureTime = maxExposure * lineDuration;
+	context_.configuration.sensor.minFrameDuration = frameHeights[0] * lineDuration;
+	context_.configuration.sensor.maxFrameDuration = frameHeights[1] * lineDuration;
+	context_.configuration.sensor.minAnalogueGain = context_.camHelper->gain(minGain);
+	context_.configuration.sensor.maxAnalogueGain = context_.camHelper->gain(maxGain);
 
 	context_.configuration.raw = std::any_of(streamConfig.begin(), streamConfig.end(),
 		[](auto &cfg) -> bool {
@@ -436,12 +438,20 @@  void IPARkISP1::updateControls(const IPACameraSensorInfo &sensorInfo,
 		uint64_t frameSize = lineLength * frameHeights[i];
 		frameDurations[i] = frameSize / (sensorInfo.pixelRate / 1000000U);
 	}
-
-	/* \todo Move this (and other agc-related controls) to agc */
-	context_.ctrlMap[&controls::FrameDurationLimits] =
+	ctrlMap[&controls::FrameDurationLimits] =
 		ControlInfo(frameDurations[0], frameDurations[1], frameDurations[2]);
 
-	ctrlMap.insert(context_.ctrlMap.begin(), context_.ctrlMap.end());
+	/*
+	 * Store the min/max frame duration in the active context to initialize
+	 * the AGC algorithm.
+	 *
+	 * \todo Move this (and other agc-related controls) to agc
+	 */
+	context_.activeState.agc.minFrameDuration = std::chrono::microseconds(frameDurations[0]);
+	context_.activeState.agc.maxFrameDuration = std::chrono::microseconds(frameDurations[1]);
+
+	ctrlMap.merge(context_.ctrlMap);
+
 	*ipaControls = ControlInfoMap(std::move(ctrlMap), controls::controls);
 }