[libcamera-devel,v4,01/10] ipa: workaround libcxx duration limitation
diff mbox series

Message ID 20221027224135.348115-2-nicholas@rothemail.net
State Superseded
Headers show
Series
  • [libcamera-devel,v4,01/10] ipa: workaround libcxx duration limitation
Related show

Commit Message

Nicolas Dufresne via libcamera-devel Oct. 27, 2022, 10:41 p.m. UTC
From: Nicholas Roth <nicholas@rothemail.net>

A bug in libcxx [0] used by clang version 11.0.2 is prevalent when
building libcamera for Android SDK30. This has been fixed and
integrated upstream with [1].

As a workaround, directly cast libcamera::utils::Duration objects to
std::chrono::duration when dividing.

Alternatives evaluated:
Considered: Enable public inheritance of std::chrono::duration and
override operator/ in the class.
Outcome: Does not fix the original compiler error.

Considered: Enable public inheritance of std::chrono::duration and
override operator/ in the libcamera namespace.
Outcome: new compiler error:
ld.lld: error: duplicate symbol: libcamera::operator/
(libcamera::utils::Duration const&, libcamera::utils::Duration const&)

Considered: Use private inheritance of std::chrono::duration and
re-implement a pass-through version of each std::chrono::duration
operator within libcamera::utils::Duration and use template
metaprogramming to fix the division operator.
Outcome: Testing shows that this would introduce substantial
limitations, i.e. requring the Duration object to be on the LHS of any
arithmetic operation with other numeric types. This also substantially
increases implementation complexity.

Considered: Extract double values from libcamera::utils::Duration
objects and use those to divide.
Outcome: This creates substantial readability and unit-safety issues.

[0] https://github.com/llvm/llvm-project/issues/40475
[1] https://github.com/llvm/llvm-project/commit/efa6d803c624f9251d0ab7881122501bb9d27368
Bug: https://bugs.libcamera.org/show_bug.cgi?id=156

Signed-off-by: Nicholas Roth <nicholas@rothemail.net>
---
 src/ipa/ipu3/algorithms/agc.cpp                 |  16 ++++++++++------
 src/ipa/raspberrypi/cam_helper.cpp              |   6 +++---
 src/ipa/raspberrypi/cam_helper_imx296.cpp       |   3 ++-
 src/ipa/raspberrypi/controller/rpi/.agc.cpp.swp | Bin 0 -> 45056 bytes
 src/ipa/raspberrypi/controller/rpi/agc.cpp      |  12 ++++++++----
 src/ipa/raspberrypi/controller/rpi/lux.cpp      |   3 ++-
 src/ipa/rkisp1/algorithms/agc.cpp               |  12 ++++++++----
 7 files changed, 33 insertions(+), 19 deletions(-)
 create mode 100644 src/ipa/raspberrypi/controller/rpi/.agc.cpp.swp

Patch
diff mbox series

diff --git a/src/ipa/ipu3/algorithms/agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp
index a1a3c38f..f1650468 100644
--- a/src/ipa/ipu3/algorithms/agc.cpp
+++ b/src/ipa/ipu3/algorithms/agc.cpp
@@ -100,7 +100,8 @@  int Agc::configure(IPAContext &context,
 
 	/* Configure the default exposure and gain. */
 	activeState.agc.gain = std::max(minAnalogueGain_, kMinAnalogueGain);
-	activeState.agc.exposure = 10ms / configuration.sensor.lineDuration;
+	activeState.agc.exposure = 10ms /
+				std::chrono::duration(configuration.sensor.lineDuration);
 
 	frameCount_ = 0;
 	return 0;
@@ -240,17 +241,20 @@  void Agc::computeExposure(IPAContext &context, IPAFrameContext &frameContext,
 	 * increase the gain.
 	 */
 	utils::Duration shutterTime =
-		std::clamp<utils::Duration>(exposureValue / minAnalogueGain_,
-					    minShutterSpeed_, maxShutterSpeed_);
-	double stepGain = std::clamp(exposureValue / shutterTime,
-				     minAnalogueGain_, maxAnalogueGain_);
+		std::clamp<utils::Duration>(std::chrono::duration(exposureValue) /
+						minAnalogueGain_,
+					minShutterSpeed_, maxShutterSpeed_);
+	double stepGain = std::clamp(std::chrono::duration(exposureValue) /
+					std::chrono::duration(shutterTime),
+				minAnalogueGain_, maxAnalogueGain_);
 	LOG(IPU3Agc, Debug) << "Divided up shutter and gain are "
 			    << shutterTime << " and "
 			    << stepGain;
 
 	IPAActiveState &activeState = context.activeState;
 	/* Update the estimated exposure and gain. */
-	activeState.agc.exposure = shutterTime / configuration.sensor.lineDuration;
+	activeState.agc.exposure = std::chrono::duration(shutterTime) /
+				std::chrono::duration(configuration.sensor.lineDuration);
 	activeState.agc.gain = stepGain;
 }
 
diff --git a/src/ipa/raspberrypi/cam_helper.cpp b/src/ipa/raspberrypi/cam_helper.cpp
index d90ac1de..48a8a068 100644
--- a/src/ipa/raspberrypi/cam_helper.cpp
+++ b/src/ipa/raspberrypi/cam_helper.cpp
@@ -63,7 +63,7 @@  void CamHelper::process([[maybe_unused]] StatisticsPtr &stats,
 
 uint32_t CamHelper::exposureLines(const Duration exposure, const Duration lineLength) const
 {
-	return exposure / lineLength;
+	return std::chrono::duration(exposure) / std::chrono::duration(lineLength);
 }
 
 Duration CamHelper::exposure(uint32_t exposureLines, const Duration lineLength) const
@@ -85,8 +85,8 @@  std::pair<uint32_t, uint32_t> CamHelper::getBlanking(Duration &exposure,
 	 * frameLengthMax gets calculated on the smallest line length as we do
 	 * not want to extend that unless absolutely necessary.
 	 */
-	frameLengthMin = minFrameDuration / mode_.minLineLength;
-	frameLengthMax = maxFrameDuration / mode_.minLineLength;
+	frameLengthMin = std::chrono::duration(minFrameDuration) / std::chrono::duration(mode_.minLineLength);
+	frameLengthMax = std::chrono::duration(maxFrameDuration) / std::chrono::duration(mode_.minLineLength);
 
 	/*
 	 * Watch out for (exposureLines + frameIntegrationDiff_) overflowing a
diff --git a/src/ipa/raspberrypi/cam_helper_imx296.cpp b/src/ipa/raspberrypi/cam_helper_imx296.cpp
index ecb845e7..c5180de5 100644
--- a/src/ipa/raspberrypi/cam_helper_imx296.cpp
+++ b/src/ipa/raspberrypi/cam_helper_imx296.cpp
@@ -57,7 +57,8 @@  double CamHelperImx296::gain(uint32_t gainCode) const
 uint32_t CamHelperImx296::exposureLines(const Duration exposure,
 					[[maybe_unused]] const Duration lineLength) const
 {
-	return std::max<uint32_t>(minExposureLines, (exposure - 14.26us) / timePerLine);
+	return std::max<uint32_t>(minExposureLines, std::chrono::duration(exposure - 14.26us) /
+							std::chrono::duration(timePerLine));
 }
 
 Duration CamHelperImx296::exposure(uint32_t exposureLines,
diff --git a/src/ipa/raspberrypi/controller/rpi/.agc.cpp.swp b/src/ipa/raspberrypi/controller/rpi/.agc.cpp.swp
new file mode 100644
index 0000000000000000000000000000000000000000..7b26d5511f7338b4cd3f28246243c9110c39aab0
GIT binary patch
literal 45056
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
E2js%%=l}o!

literal 0
HcmV?d00001

diff --git a/src/ipa/raspberrypi/controller/rpi/agc.cpp b/src/ipa/raspberrypi/controller/rpi/agc.cpp
index bd54a639..65baab99 100644
--- a/src/ipa/raspberrypi/controller/rpi/agc.cpp
+++ b/src/ipa/raspberrypi/controller/rpi/agc.cpp
@@ -418,7 +418,8 @@  void Agc::prepare(Metadata *imageMetadata)
 			Duration actualExposure = deviceStatus.shutterSpeed *
 						  deviceStatus.analogueGain;
 			if (actualExposure) {
-				status_.digitalGain = status_.totalExposureValue / actualExposure;
+				status_.digitalGain = std::chrono::duration(status_.totalExposureValue) /
+							std::chrono::duration(actualExposure);
 				LOG(RPiAgc, Debug) << "Want total exposure " << status_.totalExposureValue;
 				/*
 				 * Never ask for a gain < 1.0, and also impose
@@ -823,7 +824,8 @@  void Agc::divideUpExposure()
 			}
 			if (status_.fixedAnalogueGain == 0.0) {
 				if (exposureMode_->gain[stage] * shutterTime >= exposureValue) {
-					analogueGain = exposureValue / shutterTime;
+					analogueGain = std::chrono::duration(exposureValue) /
+							std::chrono::duration(shutterTime);
 					break;
 				}
 				analogueGain = exposureMode_->gain[stage];
@@ -838,10 +840,12 @@  void Agc::divideUpExposure()
 	 */
 	if (!status_.fixedShutter && !status_.fixedAnalogueGain &&
 	    status_.flickerPeriod) {
-		int flickerPeriods = shutterTime / status_.flickerPeriod;
+		int flickerPeriods = std::chrono::duration(shutterTime) /
+				std::chrono::duration(status_.flickerPeriod);
 		if (flickerPeriods) {
 			Duration newShutterTime = flickerPeriods * status_.flickerPeriod;
-			analogueGain *= shutterTime / newShutterTime;
+			analogueGain *= std::chrono::duration(shutterTime) /
+					std::chrono::duration(newShutterTime);
 			/*
 			 * We should still not allow the ag to go over the
 			 * largest value in the exposure mode. Note that this
diff --git a/src/ipa/raspberrypi/controller/rpi/lux.cpp b/src/ipa/raspberrypi/controller/rpi/lux.cpp
index 9759186a..410f6f44 100644
--- a/src/ipa/raspberrypi/controller/rpi/lux.cpp
+++ b/src/ipa/raspberrypi/controller/rpi/lux.cpp
@@ -94,7 +94,8 @@  void Lux::process(StatisticsPtr &stats, Metadata *imageMetadata)
 		double currentY = sum / (double)num + .5;
 		double gainRatio = referenceGain_ / currentGain;
 		double shutterSpeedRatio =
-			referenceShutterSpeed_ / deviceStatus.shutterSpeed;
+			std::chrono::duration(referenceShutterSpeed_) /
+			std::chrono::duration(deviceStatus.shutterSpeed);
 		double apertureRatio = referenceAperture_ / currentAperture;
 		double yRatio = currentY * (65536 / numBins) / referenceY_;
 		double estimatedLux = shutterSpeedRatio * gainRatio *
diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp
index 04062a36..bb874356 100644
--- a/src/ipa/rkisp1/algorithms/agc.cpp
+++ b/src/ipa/rkisp1/algorithms/agc.cpp
@@ -74,7 +74,8 @@  int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo)
 {
 	/* Configure the default exposure and gain. */
 	context.activeState.agc.gain = std::max(context.configuration.agc.minAnalogueGain, kMinAnalogueGain);
-	context.activeState.agc.exposure = 10ms / context.configuration.sensor.lineDuration;
+	context.activeState.agc.exposure = 10ms /
+					std::chrono::duration(context.configuration.sensor.lineDuration);
 
 	/*
 	 * According to the RkISP1 documentation:
@@ -212,16 +213,19 @@  void Agc::computeExposure(IPAContext &context, IPAFrameContext &frameContext,
 	 * Push the shutter time up to the maximum first, and only then
 	 * increase the gain.
 	 */
-	utils::Duration shutterTime = std::clamp<utils::Duration>(exposureValue / minAnalogueGain,
+	utils::Duration shutterTime = std::clamp<utils::Duration>(std::chrono::duration(exposureValue) /
+									minAnalogueGain,
 								  minShutterSpeed, maxShutterSpeed);
-	double stepGain = std::clamp(exposureValue / shutterTime,
+	double stepGain = std::clamp(std::chrono::duration(exposureValue) /
+						std::chrono::duration(shutterTime),
 				     minAnalogueGain, maxAnalogueGain);
 	LOG(RkISP1Agc, Debug) << "Divided up shutter and gain are "
 			      << shutterTime << " and "
 			      << stepGain;
 
 	/* Update the estimated exposure and gain. */
-	activeState.agc.exposure = shutterTime / configuration.sensor.lineDuration;
+	activeState.agc.exposure = std::chrono::duration(shutterTime) /
+				std::chrono::duration(configuration.sensor.lineDuration);
 	activeState.agc.gain = stepGain;
 }