[libcamera-devel,v1,3/3] ipa: raspberrypi: Ensure shutter speed and gain are clipped in the AGC
diff mbox series

Message ID 20230322161317.18055-4-naush@raspberrypi.com
State Superseded
Headers show
Series
  • Raspberry Pi: Sensor limits
Related show

Commit Message

Naushir Patuck March 22, 2023, 4:13 p.m. UTC
Limit the AGC gain calculations to the minimum value given by
SensorLimits. The maximum value remains unclipped as any gain over the
SensorLimits maximum will be made up by digital gain.

Rename clipShutter to limitShutter for consistency, and have the latter
limit the shutter speed to both upper and lower bounds.

Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Reviewed-by: David Plowman <david.plowman@raspberrypi.com>
---
 src/ipa/raspberrypi/controller/rpi/agc.cpp | 47 +++++++++++++++++-----
 src/ipa/raspberrypi/controller/rpi/agc.h   |  3 +-
 2 files changed, 39 insertions(+), 11 deletions(-)

Patch
diff mbox series

diff --git a/src/ipa/raspberrypi/controller/rpi/agc.cpp b/src/ipa/raspberrypi/controller/rpi/agc.cpp
index eaabc5fa9cd0..ee81537c653c 100644
--- a/src/ipa/raspberrypi/controller/rpi/agc.cpp
+++ b/src/ipa/raspberrypi/controller/rpi/agc.cpp
@@ -309,14 +309,14 @@  void Agc::setFixedShutter(Duration fixedShutter)
 {
 	fixedShutter_ = fixedShutter;
 	/* Set this in case someone calls disableAuto() straight after. */
-	status_.shutterTime = clipShutter(fixedShutter_);
+	status_.shutterTime = limitShutter(fixedShutter_);
 }
 
 void Agc::setFixedAnalogueGain(double fixedAnalogueGain)
 {
 	fixedAnalogueGain_ = fixedAnalogueGain;
 	/* Set this in case someone calls disableAuto() straight after. */
-	status_.analogueGain = fixedAnalogueGain;
+	status_.analogueGain = limitGain(fixedAnalogueGain);
 }
 
 void Agc::setMeteringMode(std::string const &meteringModeName)
@@ -342,7 +342,7 @@  void Agc::switchMode(CameraMode const &cameraMode,
 
 	housekeepConfig();
 
-	Duration fixedShutter = clipShutter(fixedShutter_);
+	Duration fixedShutter = limitShutter(fixedShutter_);
 	if (fixedShutter && fixedAnalogueGain_) {
 		/* We're going to reset the algorithm here with these fixed values. */
 
@@ -516,7 +516,7 @@  void Agc::housekeepConfig()
 {
 	/* First fetch all the up-to-date settings, so no one else has to do it. */
 	status_.ev = ev_;
-	status_.fixedShutter = clipShutter(fixedShutter_);
+	status_.fixedShutter = limitShutter(fixedShutter_);
 	status_.fixedAnalogueGain = fixedAnalogueGain_;
 	status_.flickerPeriod = flickerPeriod_;
 	LOG(RPiAgc, Debug) << "ev " << status_.ev << " fixedShutter "
@@ -703,7 +703,7 @@  void Agc::computeTargetExposure(double gain)
 		Duration maxShutter = status_.fixedShutter
 					      ? status_.fixedShutter
 					      : exposureMode_->shutter.back();
-		maxShutter = clipShutter(maxShutter);
+		maxShutter = limitShutter(maxShutter);
 		Duration maxTotalExposure =
 			maxShutter *
 			(status_.fixedAnalogueGain != 0.0
@@ -803,15 +803,16 @@  void Agc::divideUpExposure()
 	double analogueGain;
 	shutterTime = status_.fixedShutter ? status_.fixedShutter
 					   : exposureMode_->shutter[0];
-	shutterTime = clipShutter(shutterTime);
+	shutterTime = limitShutter(shutterTime);
 	analogueGain = status_.fixedAnalogueGain != 0.0 ? status_.fixedAnalogueGain
 							: exposureMode_->gain[0];
+	analogueGain = limitGain(analogueGain);
 	if (shutterTime * analogueGain < exposureValue) {
 		for (unsigned int stage = 1;
 		     stage < exposureMode_->gain.size(); stage++) {
 			if (!status_.fixedShutter) {
 				Duration stageShutter =
-					clipShutter(exposureMode_->shutter[stage]);
+					limitShutter(exposureMode_->shutter[stage]);
 				if (stageShutter * analogueGain >= exposureValue) {
 					shutterTime = exposureValue / analogueGain;
 					break;
@@ -824,6 +825,7 @@  void Agc::divideUpExposure()
 					break;
 				}
 				analogueGain = exposureMode_->gain[stage];
+				analogueGain = limitGain(analogueGain);
 			}
 		}
 	}
@@ -846,6 +848,7 @@  void Agc::divideUpExposure()
 			 * gain as a side-effect.
 			 */
 			analogueGain = std::min(analogueGain, exposureMode_->gain.back());
+			analogueGain = limitGain(analogueGain);
 			shutterTime = newShutterTime;
 		}
 		LOG(RPiAgc, Debug) << "After flicker avoidance, shutter "
@@ -872,13 +875,37 @@  void Agc::writeAndFinish(Metadata *imageMetadata, bool desaturate)
 			   << " analogue gain " << filtered_.analogueGain;
 }
 
-Duration Agc::clipShutter(Duration shutter)
+Duration Agc::limitShutter(Duration shutter)
 {
-	if (sensorLimits_.maxShutter)
-		shutter = std::min(shutter, sensorLimits_.maxShutter);
+	/*
+	 * shutter == 0 is a special case for fixed shutter values, and must pass
+	 * through unchanged
+	 */
+	if (!shutter)
+		return shutter;
+
+	shutter = std::clamp(shutter, sensorLimits_.minShutter,
+			     sensorLimits_.maxShutter);
 	return shutter;
 }
 
+double Agc::limitGain(double gain) const
+{
+	/*
+	 * Only limit the lower bounds of the gain value to what the sensor limits.
+	 * The upper bound on analogue gain will be made up with additional digital
+	 * gain applied by the ISP.
+	 *
+	 * gain == 0.0 is a special case for fixed shutter values, and must pass
+	 * through unchanged
+	 */
+	if (!gain)
+		return gain;
+
+	gain = std::max(gain, sensorLimits_.minAnalogueGain);
+	return gain;
+}
+
 /* Register algorithm with the system. */
 static Algorithm *create(Controller *controller)
 {
diff --git a/src/ipa/raspberrypi/controller/rpi/agc.h b/src/ipa/raspberrypi/controller/rpi/agc.h
index 150a5f6e4428..c48acbba61f0 100644
--- a/src/ipa/raspberrypi/controller/rpi/agc.h
+++ b/src/ipa/raspberrypi/controller/rpi/agc.h
@@ -103,7 +103,8 @@  private:
 	void filterExposure(bool desaturate);
 	void divideUpExposure();
 	void writeAndFinish(Metadata *imageMetadata, bool desaturate);
-	libcamera::utils::Duration clipShutter(libcamera::utils::Duration shutter);
+	libcamera::utils::Duration limitShutter(libcamera::utils::Duration shutter);
+	double limitGain(double gain) const;
 	AgcMeteringMode *meteringMode_;
 	AgcExposureMode *exposureMode_;
 	AgcConstraintMode *constraintMode_;