[RFC,v2,22/43] ipa: libipa: agc: Clamp exposure value
diff mbox series

Message ID 20260723154327.1357866-23-barnabas.pocze@ideasonboard.com
State New
Headers show
Series
  • ipa: libipa: agc rework
Related show

Commit Message

Barnabás Pőcze July 23, 2026, 3:43 p.m. UTC
It is possible that the minimum exposure time in microseconds is not an
integer. In that case the minimum `ExposureTime` in the `ControlInfo` will
therefore be actually lower than the real minimum. This can cause issues:
if the minimum published exposure time is set, the division when setting
`agc.manual.exposure` might produce a value in [0;1), leading to the manual
exposure being set to 0, leading to an assertion failure in
`ExposureModeHelper::splitExposure()`.

Note that this is theoretically possible even when the exposure time is
determined automatically by `AgcMeanLuminance`.

Store the true integer limits of the exposure as well, and ensure that
the exposure (time) -> exposure (line) conversions always clamp.

Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
---
 src/ipa/libipa/agc.cpp | 27 ++++++++++++++++++++++++---
 src/ipa/libipa/agc.h   |  2 ++
 2 files changed, 26 insertions(+), 3 deletions(-)

Patch
diff mbox series

diff --git a/src/ipa/libipa/agc.cpp b/src/ipa/libipa/agc.cpp
index e16a02fdde..8a2525ec98 100644
--- a/src/ipa/libipa/agc.cpp
+++ b/src/ipa/libipa/agc.cpp
@@ -38,6 +38,12 @@  LOG_DEFINE_CATEGORY(Agc)
  * \struct agc::Session
  * \brief Session configuration for AgcAlgorithm
  *
+ * \var agc::Session::minExposure
+ * \brief Minimum exposure (in lines) supported with the configured sensor
+ *
+ * \var agc::Session::maxExposure
+ * \brief Maximum exposure (in lines) supported with the configured sensor
+ *
  * \var agc::Session::minExposureTime
  * \brief Minimum exposure time supported with the configured sensor
  *
@@ -223,6 +229,19 @@  LOG_DEFINE_CATEGORY(Agc)
  * \brief Effective lux value of the frame
  */
 
+namespace {
+
+[[nodiscard]] uint32_t clampExposure(utils::Duration exposureTime, const agc::Session &session)
+{
+	return std::clamp<uint32_t>(
+		exposureTime / session.lineDuration,
+		session.minExposure,
+		session.maxExposure
+	);
+}
+
+} /* namespace */
+
 /**
  * \brief Load tuning data
  */
@@ -317,6 +336,8 @@  int AgcAlgorithm::configure(agc::Session &session, agc::ActiveState &state, cons
 	 *
 	 * \todo take VBLANK into account for maximum exposure time
 	 */
+	session.minExposure = minExposure;
+	session.maxExposure = maxExposure;
 	session.minExposureTime = minExposure * session.lineDuration;
 	session.maxExposureTime = maxExposure * session.lineDuration;
 	session.minAnalogueGain = minGain;
@@ -331,7 +352,7 @@  int AgcAlgorithm::configure(agc::Session &session, agc::ActiveState &state, cons
 	/* Configure the default exposure and gain. */
 	state = {};
 	state.automatic.gain = session.minAnalogueGain;
-	state.automatic.exposure = 10ms / session.lineDuration;
+	state.automatic.exposure = clampExposure(10ms, session);
 	state.automatic.quantizationGain = 1;
 	state.automatic.yTarget = impl_.effectiveYTarget(0, 1);
 	state.manual.gain = state.automatic.gain;
@@ -437,7 +458,7 @@  void AgcAlgorithm::queueRequest(const agc::Session &session, agc::ActiveState &s
 
 	const auto &exposure = controls.get(controls::ExposureTime);
 	if (exposure && !state.autoExposureEnabled) {
-		state.manual.exposure = *exposure * 1.0us / session.lineDuration;
+		state.manual.exposure = clampExposure(*exposure * 1us, session);
 
 		LOG(Agc, Debug)
 			<< "Set exposure to " << state.manual.exposure;
@@ -599,7 +620,7 @@  void AgcAlgorithm::process(const agc::Session &session, agc::ActiveState &state,
 			<< ", " << newEv.quantizationGain << " and " << newEv.digitalGain;
 
 		/* Update the estimated exposure and gain. */
-		state.automatic.exposure = newEv.exposureTime / lineDuration;
+		state.automatic.exposure = clampExposure(newEv.exposureTime, session);
 		state.automatic.gain = newEv.analogueGain;
 		state.automatic.quantizationGain = newEv.quantizationGain;
 		state.automatic.yTarget = newEv.yTarget;
diff --git a/src/ipa/libipa/agc.h b/src/ipa/libipa/agc.h
index 1eace12908..c11dbf80cd 100644
--- a/src/ipa/libipa/agc.h
+++ b/src/ipa/libipa/agc.h
@@ -49,6 +49,8 @@  prepareControls(ControlList &controls, const CameraSensorHelper *sensor,
 }
 
 struct Session {
+	uint32_t minExposure;
+	uint32_t maxExposure;
 	utils::Duration minExposureTime;
 	utils::Duration maxExposureTime;
 	double minAnalogueGain;