[libcamera-devel,v2] ipa: rkisp1: Add support for manual gain and exposure
diff mbox series

Message ID 20220920062351.3697066-1-paul.elder@ideasonboard.com
State Superseded
Headers show
Series
  • [libcamera-devel,v2] ipa: rkisp1: Add support for manual gain and exposure
Related show

Commit Message

Paul Elder Sept. 20, 2022, 6:23 a.m. UTC
Add support for manual gain and exposure in the rkisp1 IPA.

Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>

---
This patch depends on v4 of the series: "ipa: Frame context queue, IPU3
& RkISP consolidation, and RkISP1 improvements"

Changes in v2:
- set the min and max values of ExposureTime and AnalogueGain properly
  - to that end, plumb the sensorControls through the pipeline handler's
    loadIPA() and the IPA's init()
---
 include/libcamera/ipa/rkisp1.mojom       |  2 +-
 src/ipa/rkisp1/algorithms/agc.cpp        | 59 +++++++++++++++++++++---
 src/ipa/rkisp1/algorithms/agc.h          |  4 ++
 src/ipa/rkisp1/ipa_context.h             | 13 +++++-
 src/ipa/rkisp1/rkisp1.cpp                | 17 +++++++
 src/libcamera/pipeline/rkisp1/rkisp1.cpp |  9 ++--
 6 files changed, 91 insertions(+), 13 deletions(-)

Patch
diff mbox series

diff --git a/include/libcamera/ipa/rkisp1.mojom b/include/libcamera/ipa/rkisp1.mojom
index eaf3955e..b526450d 100644
--- a/include/libcamera/ipa/rkisp1.mojom
+++ b/include/libcamera/ipa/rkisp1.mojom
@@ -10,7 +10,7 @@  import "include/libcamera/ipa/core.mojom";
 
 interface IPARkISP1Interface {
 	init(libcamera.IPASettings settings,
-	     uint32 hwRevision)
+	     uint32 hwRevision, libcamera.ControlInfoMap sensorControls)
 		=> (int32 ret, libcamera.ControlInfoMap ipaControls);
 	start() => (int32 ret);
 	stop();
diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp
index bc764142..d26b35ed 100644
--- a/src/ipa/rkisp1/algorithms/agc.cpp
+++ b/src/ipa/rkisp1/algorithms/agc.cpp
@@ -14,6 +14,7 @@ 
 #include <libcamera/base/log.h>
 #include <libcamera/base/utils.h>
 
+#include <libcamera/control_ids.h>
 #include <libcamera/ipa/core_ipa_interface.h>
 
 #include "libipa/histogram.h"
@@ -73,8 +74,11 @@  Agc::Agc()
 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.automatic.gain = std::max(context.configuration.agc.minAnalogueGain, kMinAnalogueGain);
+	context.activeState.agc.automatic.exposure = 10ms / context.configuration.sensor.lineDuration;
+	context.activeState.agc.manual.gain = context.activeState.agc.automatic.gain;
+	context.activeState.agc.manual.exposure = context.activeState.agc.automatic.exposure;
+	context.activeState.agc.autoEnabled = true;
 
 	/*
 	 * According to the RkISP1 documentation:
@@ -221,8 +225,8 @@  void Agc::computeExposure(IPAContext &context, RkISP1FrameContext &frameContext,
 			      << stepGain;
 
 	/* Update the estimated exposure and gain. */
-	activeState.agc.exposure = shutterTime / configuration.sensor.lineDuration;
-	activeState.agc.gain = stepGain;
+	activeState.agc.automatic.exposure = shutterTime / configuration.sensor.lineDuration;
+	activeState.agc.automatic.gain = stepGain;
 }
 
 /**
@@ -331,8 +335,10 @@  void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,
 void Agc::prepare(IPAContext &context, const uint32_t frame,
 		  RkISP1FrameContext &frameContext, rkisp1_params_cfg *params)
 {
-	frameContext.agc.exposure = context.activeState.agc.exposure;
-	frameContext.agc.gain = context.activeState.agc.gain;
+	if (frameContext.agc.autoEnabled) {
+		frameContext.agc.exposure = context.activeState.agc.automatic.exposure;
+		frameContext.agc.gain = context.activeState.agc.automatic.gain;
+	}
 
 	if (frame > 0)
 		return;
@@ -365,6 +371,47 @@  void Agc::prepare(IPAContext &context, const uint32_t frame,
 	params->module_en_update |= RKISP1_CIF_ISP_MODULE_HST;
 }
 
+/**
+ * \copydoc libcamera::ipa::Algorithm::queueRequest
+ */
+void Agc::queueRequest(IPAContext &context,
+		       [[maybe_unused]] const uint32_t frame,
+		       RkISP1FrameContext &frameContext,
+		       const ControlList &controls)
+{
+	auto &agc = context.activeState.agc;
+
+	const auto &agcEnable = controls.get(controls::AeEnable);
+	if (agcEnable && *agcEnable != agc.autoEnabled) {
+		agc.autoEnabled = *agcEnable;
+
+		LOG(RkISP1Agc, Debug)
+			<< (*agcEnable ? "Enabling" : "Disabling") << " AGC";
+	}
+
+	const auto &exposure = controls.get(controls::ExposureTime);
+	if (exposure && !agc.autoEnabled) {
+		agc.manual.exposure = *exposure;
+
+		LOG(RkISP1Agc, Debug)
+			<< "Set exposure to: " << agc.manual.exposure;
+	}
+
+	const auto &gain = controls.get(controls::AnalogueGain);
+	if (gain && !agc.autoEnabled) {
+		agc.manual.gain = *gain;
+
+		LOG(RkISP1Agc, Debug) << "Set gain to: " << agc.manual.gain;
+	}
+
+	frameContext.agc.autoEnabled = agc.autoEnabled;
+
+	if (!frameContext.agc.autoEnabled) {
+		frameContext.agc.exposure = agc.manual.exposure;
+		frameContext.agc.gain = agc.manual.gain;
+	}
+}
+
 REGISTER_IPA_ALGORITHM(Agc, "Agc")
 
 } /* namespace ipa::rkisp1::algorithms */
diff --git a/src/ipa/rkisp1/algorithms/agc.h b/src/ipa/rkisp1/algorithms/agc.h
index d6c6fb13..e624f101 100644
--- a/src/ipa/rkisp1/algorithms/agc.h
+++ b/src/ipa/rkisp1/algorithms/agc.h
@@ -32,6 +32,10 @@  public:
 	void process(IPAContext &context, const uint32_t frame,
 		     RkISP1FrameContext &frameContext,
 		     const rkisp1_stat_buffer *stats) override;
+	void queueRequest(IPAContext &context,
+			  const uint32_t frame,
+			  RkISP1FrameContext &frameContext,
+			  const ControlList &controls) override;
 
 private:
 	void computeExposure(IPAContext &Context, RkISP1FrameContext &frameContext,
diff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h
index d0bc9090..df72ec87 100644
--- a/src/ipa/rkisp1/ipa_context.h
+++ b/src/ipa/rkisp1/ipa_context.h
@@ -50,8 +50,16 @@  struct IPASessionConfiguration {
 
 struct IPAActiveState {
 	struct {
-		uint32_t exposure;
-		double gain;
+		struct {
+			uint32_t exposure;
+			double gain;
+		} manual;
+		struct {
+			uint32_t exposure;
+			double gain;
+		} automatic;
+
+		bool autoEnabled;
 	} agc;
 
 	struct {
@@ -92,6 +100,7 @@  struct RkISP1FrameContext : public FrameContext {
 	struct {
 		uint32_t exposure;
 		double gain;
+		bool autoEnabled;
 	} agc;
 
 	struct {
diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp
index 75370ac8..5be045a0 100644
--- a/src/ipa/rkisp1/rkisp1.cpp
+++ b/src/ipa/rkisp1/rkisp1.cpp
@@ -49,6 +49,7 @@  public:
 	IPARkISP1();
 
 	int init(const IPASettings &settings, unsigned int hwRevision,
+		 const ControlInfoMap &sensorControls,
 		 ControlInfoMap *ipaControls) override;
 	int start() override;
 	void stop() override;
@@ -116,6 +117,7 @@  std::string IPARkISP1::logPrefix() const
 }
 
 int IPARkISP1::init(const IPASettings &settings, unsigned int hwRevision,
+		    const ControlInfoMap &sensorControls,
 		    ControlInfoMap *ipaControls)
 {
 	/* \todo Add support for other revisions */
@@ -183,6 +185,21 @@  int IPARkISP1::init(const IPASettings &settings, unsigned int hwRevision,
 
 	/* Return the controls handled by the IPA. */
 	ControlInfoMap::Map ctrlMap = rkisp1Controls;
+
+	auto exposureTimeInfo = sensorControls.find(V4L2_CID_EXPOSURE);
+	if (exposureTimeInfo != sensorControls.end()) {
+		ctrlMap.emplace(&controls::ExposureTime,
+				ControlInfo(exposureTimeInfo->second.min(),
+					    exposureTimeInfo->second.max()));
+	}
+
+	auto analogueGainInfo = sensorControls.find(V4L2_CID_ANALOGUE_GAIN);
+	if (analogueGainInfo != sensorControls.end()) {
+		ctrlMap.emplace(&controls::AnalogueGain,
+				ControlInfo(static_cast<float>(analogueGainInfo->second.min().get<int32_t>()),
+					    static_cast<float>(analogueGainInfo->second.max().get<int32_t>())));
+	}
+
 	*ipaControls = ControlInfoMap(std::move(ctrlMap), controls::controls);
 
 	return 0;
diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
index 25fbf9f1..3b9f77e8 100644
--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
@@ -89,7 +89,7 @@  public:
 	}
 
 	PipelineHandlerRkISP1 *pipe();
-	int loadIPA(unsigned int hwRevision);
+	int loadIPA(unsigned int hwRevision, const ControlInfoMap &sensorControls);
 
 	Stream mainPathStream_;
 	Stream selfPathStream_;
@@ -317,7 +317,8 @@  PipelineHandlerRkISP1 *RkISP1CameraData::pipe()
 	return static_cast<PipelineHandlerRkISP1 *>(Camera::Private::pipe());
 }
 
-int RkISP1CameraData::loadIPA(unsigned int hwRevision)
+int RkISP1CameraData::loadIPA(unsigned int hwRevision,
+			      const ControlInfoMap &sensorControls)
 {
 	ipa_ = IPAManager::createIPA<ipa::rkisp1::IPAProxyRkISP1>(pipe(), 1, 1);
 	if (!ipa_)
@@ -346,7 +347,7 @@  int RkISP1CameraData::loadIPA(unsigned int hwRevision)
 	}
 
 	int ret = ipa_->init({ ipaTuningFile, sensor_->model() }, hwRevision,
-			     &controlInfo_);
+			     sensorControls, &controlInfo_);
 	if (ret < 0) {
 		LOG(RkISP1, Error) << "IPA initialization failure";
 		return ret;
@@ -1019,7 +1020,7 @@  int PipelineHandlerRkISP1::createCamera(MediaEntity *sensor)
 	isp_->frameStart.connect(data->delayedCtrls_.get(),
 				 &DelayedControls::applyControls);
 
-	ret = data->loadIPA(media_->hwRevision());
+	ret = data->loadIPA(media_->hwRevision(), data->sensor_->controls());
 	if (ret)
 		return ret;