[2/3] libcamera: rkisp1: Update camera::controls() on limit changes
diff mbox series

Message ID 20251017-exposure-limits-v1-2-6288cd86e719@ideasonboard.com
State New
Headers show
Series
  • rkisp1: Update exposure limits on vblank change
Related show

Commit Message

Jacopo Mondi Oct. 17, 2025, 9 a.m. UTC
The limits (min and max values) for the Camera controls are
registered at Camera configuration time and never updated.
Some controls, like FrameDurationLimits have a direct impact on
the limits of other controls, such as the ExposureTime and as they
can be configured by the application, this has to be taken into account.

Currently, when a user changes the frame duration, the limits for
both the ExposureTime and FrameDurationControls are not updated.

The timing at which the controls limits should be updated is also
critical: the new control values take effect once the Request they
belong to is completed.

To support this operation model introduce a new IPA function
'updateControlsLimits()' which the pipeline handler calls before
completing a Request.

Store the exposure time limits in the FrameContext (frame
duration limits were already there) and update the Camera::controls()
control info map with the limits as computed for the Request that has
just completed.

Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
---
 include/libcamera/ipa/rkisp1.mojom       |  2 ++
 src/ipa/rkisp1/algorithms/agc.cpp        |  3 +++
 src/ipa/rkisp1/ipa_context.h             |  3 +++
 src/ipa/rkisp1/rkisp1.cpp                | 26 ++++++++++++++++++++++++++
 src/libcamera/pipeline/rkisp1/rkisp1.cpp |  3 +++
 5 files changed, 37 insertions(+)

Patch
diff mbox series

diff --git a/include/libcamera/ipa/rkisp1.mojom b/include/libcamera/ipa/rkisp1.mojom
index 068e898848c4943282b4a6a05362a99016560afd..8d9446f5cbe9851886832f5cf7fd41d1a6d23a11 100644
--- a/include/libcamera/ipa/rkisp1.mojom
+++ b/include/libcamera/ipa/rkisp1.mojom
@@ -27,6 +27,8 @@  interface IPARkISP1Interface {
 		  map<uint32, libcamera.IPAStream> streamConfig)
 		=> (int32 ret, libcamera.ControlInfoMap ipaControls);
 
+	updateControlsLimits(uint32 frame) => (int32 ret, libcamera.ControlInfoMap ipaControls);
+
 	mapBuffers(array<libcamera.IPABuffer> buffers);
 	unmapBuffers(array<uint32> ids);
 
diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp
index f5a3c917cb6909f6ef918e5ee8e46cf97ba55010..0fd7541c9f1ab9b4cbae1f8fa60c39b032c3bcd1 100644
--- a/src/ipa/rkisp1/algorithms/agc.cpp
+++ b/src/ipa/rkisp1/algorithms/agc.cpp
@@ -585,6 +585,8 @@  void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,
 				* frameContext.agc.exposure;
 		maxExposureTime = minExposureTime;
 	}
+	frameContext.agc.minExposureTime = minExposureTime;
+	frameContext.agc.maxExposureTime = maxExposureTime;
 
 	if (frameContext.agc.autoGainEnabled) {
 		minAnalogueGain = context.configuration.sensor.minAnalogueGain;
@@ -606,6 +608,7 @@  void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,
 	 * applied to the sensor when the statistics were collected.
 	 */
 	utils::Duration exposureTime = lineDuration * frameContext.sensor.exposure;
+	frameContext.agc.exposureTime = exposureTime;
 	double analogueGain = frameContext.sensor.gain;
 	utils::Duration effectiveExposureValue = exposureTime * analogueGain;
 
diff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h
index af66a749052bc82bbbe7fbb0c4626f2422700926..54ff5c114f5c6cdfaf515475a3892f76e2e022d6 100644
--- a/src/ipa/rkisp1/ipa_context.h
+++ b/src/ipa/rkisp1/ipa_context.h
@@ -143,6 +143,9 @@  struct IPAActiveState {
 
 struct IPAFrameContext : public FrameContext {
 	struct {
+		utils::Duration minExposureTime;
+		utils::Duration maxExposureTime;
+		utils::Duration exposureTime;
 		uint32_t exposure;
 		double gain;
 		double exposureValue;
diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp
index 54bd1434e0f4e34834beb1f9e9c39b77590f8b34..ad5c24a7159a8634aae883915b54ae0f4456692b 100644
--- a/src/ipa/rkisp1/rkisp1.cpp
+++ b/src/ipa/rkisp1/rkisp1.cpp
@@ -62,6 +62,8 @@  public:
 	int configure(const IPAConfigInfo &ipaConfig,
 		      const std::map<uint32_t, IPAStream> &streamConfig,
 		      ControlInfoMap *ipaControls) override;
+	int updateControlsLimits(const uint32_t frame,
+				 ControlInfoMap *ipaControls) override;
 	void mapBuffers(const std::vector<IPABuffer> &buffers) override;
 	void unmapBuffers(const std::vector<unsigned int> &ids) override;
 
@@ -294,6 +296,30 @@  int IPARkISP1::configure(const IPAConfigInfo &ipaConfig,
 	return 0;
 }
 
+int IPARkISP1::updateControlsLimits(const uint32_t frame, ControlInfoMap *ipaControls)
+{
+	IPAFrameContext &frameContext = context_.frameContexts.get(frame);
+
+	/*
+	 * Update the exposure time and frame duration limits with the
+	 * settings computed by the AGC for the frame at hand.
+	 */
+	assert(ipaControls->find(&controls::ExposureTime) != ipaControls->end());
+	assert(ipaControls->find(&controls::FrameDurationLimits) != ipaControls->end());
+
+	ControlValue eMin(static_cast<int32_t>(frameContext.agc.minExposureTime.get<std::micro>()));
+	ControlValue eMax(static_cast<int32_t>(frameContext.agc.maxExposureTime.get<std::micro>()));
+	ControlValue eDef(static_cast<int32_t>(frameContext.agc.exposureTime.get<std::micro>()));
+	ipaControls->at(controls::ExposureTime.id()) = ControlInfo(eMin, eMax, eDef);
+
+	ControlValue fMin(static_cast<int32_t>(frameContext.agc.minFrameDuration.get<std::micro>()));
+	ControlValue fMax(static_cast<int32_t>(frameContext.agc.maxFrameDuration.get<std::micro>()));
+	ControlValue fDef(static_cast<int32_t>(frameContext.agc.frameDuration.get<std::micro>()));
+	ipaControls->at(controls::FrameDurationLimits.id()) = ControlInfo(fMin, fMax, fDef);
+
+	return 0;
+}
+
 void IPARkISP1::mapBuffers(const std::vector<IPABuffer> &buffers)
 {
 	for (const IPABuffer &buffer : buffers) {
diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
index ecd13831539fdf5cb79da2ea4b33a353514328ae..ad1ff7a8be8d6e3268e21ec92ae4e07500b38c66 100644
--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
@@ -1494,6 +1494,9 @@  void PipelineHandlerRkISP1::tryCompleteRequest(RkISP1FrameInfo *info)
 	if (!isRaw_ && !info->paramDequeued)
 		return;
 
+	/* Update controls before completing the request */
+	data->ipa_->updateControlsLimits(info->frame, &data->controlInfo_);
+
 	data->frameInfo_.destroy(info->frame);
 
 	completeRequest(request);