about summary refs log tree commit diff
path: root/users/flokli/ipu6-softisp/libcamera/0019-libcamera-Soft-IPA-use-CameraSensorHelper-for-analog.patch
blob: 5b562c603c52d97c6d2d0c3be738f842f6267ff6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
From b0c07674abecb05dc0af93a4b749971f057bc3c6 Mon Sep 17 00:00:00 2001
From: Andrei Konovalov <andrey.konovalov.ynk@gmail.com>
Date: Mon, 11 Mar 2024 15:15:22 +0100
Subject: [PATCH 19/21] libcamera: Soft IPA: use CameraSensorHelper for
 analogue gain

Use CameraSensorHelper to convert the analogue gain code read from the
camera sensor into real analogue gain value. In the future this makes
it possible to use faster AE/AGC algorithm. For now the same AE/AGC
algorithm is used, but even then the CameraSensorHelper lets us use the
full range of analogue gain values.

If there is no CameraSensorHelper for the camera sensor in use, a
warning log message is printed, and the AE/AGC works exactly as before
this change.

Signed-off-by: Andrei Konovalov <andrey.konovalov.ynk@gmail.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Milan Zamazal <mzamazal@redhat.com>
---
 .../internal/software_isp/software_isp.h      |  3 +-
 src/ipa/simple/soft_simple.cpp                | 77 ++++++++++++-------
 src/libcamera/pipeline/simple/simple.cpp      |  2 +-
 src/libcamera/software_isp/software_isp.cpp   |  8 +-
 4 files changed, 57 insertions(+), 33 deletions(-)

diff --git a/include/libcamera/internal/software_isp/software_isp.h b/include/libcamera/internal/software_isp/software_isp.h
index 8d25e979..2a6db7ba 100644
--- a/include/libcamera/internal/software_isp/software_isp.h
+++ b/include/libcamera/internal/software_isp/software_isp.h
@@ -26,6 +26,7 @@
 #include <libcamera/ipa/soft_ipa_interface.h>
 #include <libcamera/ipa/soft_ipa_proxy.h>
 
+#include "libcamera/internal/camera_sensor.h"
 #include "libcamera/internal/dma_heaps.h"
 #include "libcamera/internal/pipeline_handler.h"
 #include "libcamera/internal/shared_mem_object.h"
@@ -43,7 +44,7 @@ LOG_DECLARE_CATEGORY(SoftwareIsp)
 class SoftwareIsp
 {
 public:
-	SoftwareIsp(PipelineHandler *pipe, const ControlInfoMap &sensorControls);
+	SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor);
 	~SoftwareIsp();
 
 	int loadConfiguration([[maybe_unused]] const std::string &filename) { return 0; }
diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp
index ac027568..e4d64762 100644
--- a/src/ipa/simple/soft_simple.cpp
+++ b/src/ipa/simple/soft_simple.cpp
@@ -22,6 +22,8 @@
 #include "libcamera/internal/software_isp/debayer_params.h"
 #include "libcamera/internal/software_isp/swisp_stats.h"
 
+#include "libipa/camera_sensor_helper.h"
+
 #include "black_level.h"
 
 namespace libcamera {
@@ -67,18 +69,27 @@ private:
 	DebayerParams *params_;
 	SwIspStats *stats_;
 	BlackLevel blackLevel_;
+	std::unique_ptr<CameraSensorHelper> camHelper_;
 
 	int32_t exposure_min_, exposure_max_;
-	int32_t again_min_, again_max_;
-	int32_t again_, exposure_;
+	int32_t exposure_;
+	double again_min_, again_max_, againMinStep_;
+	double again_;
 	unsigned int ignore_updates_;
 };
 
-int IPASoftSimple::init([[maybe_unused]] const IPASettings &settings,
+int IPASoftSimple::init(const IPASettings &settings,
 			const SharedFD &fdStats,
 			const SharedFD &fdParams,
 			const ControlInfoMap &sensorInfoMap)
 {
+	camHelper_ = CameraSensorHelperFactoryBase::create(settings.sensorModel);
+	if (camHelper_ == nullptr) {
+		LOG(IPASoft, Warning)
+			<< "Failed to create camera sensor helper for "
+			<< settings.sensorModel;
+	}
+
 	fdStats_ = fdStats;
 	if (!fdStats_.isValid()) {
 		LOG(IPASoft, Error) << "Invalid Statistics handle";
@@ -132,25 +143,35 @@ int IPASoftSimple::configure(const ControlInfoMap &sensorInfoMap)
 		exposure_min_ = 1;
 	}
 
-	again_min_ = gain_info.min().get<int32_t>();
-	again_max_ = gain_info.max().get<int32_t>();
-	/*
-	 * The camera sensor gain (g) is usually not equal to the value written
-	 * into the gain register (x). But the way how the AGC algorithm changes
-	 * the gain value to make the total exposure closer to the optimum assumes
-	 * that g(x) is not too far from linear function. If the minimal gain is 0,
-	 * the g(x) is likely to be far from the linear, like g(x) = a / (b * x + c).
-	 * To avoid unexpected changes to the gain by the AGC algorithm (abrupt near
-	 * one edge, and very small near the other) we limit the range of the gain
-	 * values used.
-	 */
-	if (!again_min_) {
-		LOG(IPASoft, Warning) << "Minimum gain is zero, that can't be linear";
-		again_min_ = std::min(100, again_min_ / 2 + again_max_ / 2);
+	int32_t again_min = gain_info.min().get<int32_t>();
+	int32_t again_max = gain_info.max().get<int32_t>();
+
+	if (camHelper_) {
+		again_min_ = camHelper_->gain(again_min);
+		again_max_ = camHelper_->gain(again_max);
+		againMinStep_ = (again_max_ - again_min_) / 100.0;
+	} else {
+		/*
+		 * The camera sensor gain (g) is usually not equal to the value written
+		 * into the gain register (x). But the way how the AGC algorithm changes
+		 * the gain value to make the total exposure closer to the optimum assumes
+		 * that g(x) is not too far from linear function. If the minimal gain is 0,
+		 * the g(x) is likely to be far from the linear, like g(x) = a / (b * x + c).
+		 * To avoid unexpected changes to the gain by the AGC algorithm (abrupt near
+		 * one edge, and very small near the other) we limit the range of the gain
+		 * values used.
+		 */
+		again_max_ = again_max;
+		if (!again_min) {
+			LOG(IPASoft, Warning) << "Minimum gain is zero, that can't be linear";
+			again_min_ = std::min(100, again_min / 2 + again_max / 2);
+		}
+		againMinStep_ = 1.0;
 	}
 
 	LOG(IPASoft, Info) << "Exposure " << exposure_min_ << "-" << exposure_max_
-			   << ", gain " << again_min_ << "-" << again_max_;
+			   << ", gain " << again_min_ << "-" << again_max_
+			   << " (" << againMinStep_ << ")";
 
 	return 0;
 }
@@ -252,12 +273,14 @@ void IPASoftSimple::processStats(const ControlList &sensorControls)
 	ControlList ctrls(sensorControls);
 
 	exposure_ = ctrls.get(V4L2_CID_EXPOSURE).get<int32_t>();
-	again_ = ctrls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>();
+	int32_t again = ctrls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>();
+	again_ = camHelper_ ? camHelper_->gain(again) : again;
 
 	updateExposure(exposureMSV);
 
 	ctrls.set(V4L2_CID_EXPOSURE, exposure_);
-	ctrls.set(V4L2_CID_ANALOGUE_GAIN, again_);
+	ctrls.set(V4L2_CID_ANALOGUE_GAIN,
+		  static_cast<int32_t>(camHelper_ ? camHelper_->gainCode(again_) : again_));
 
 	ignore_updates_ = 2;
 
@@ -276,7 +299,7 @@ void IPASoftSimple::updateExposure(double exposureMSV)
 	static constexpr uint8_t kExpNumeratorUp = kExpDenominator + 1;
 	static constexpr uint8_t kExpNumeratorDown = kExpDenominator - 1;
 
-	int next;
+	double next;
 
 	if (exposureMSV < kExposureOptimal - kExposureSatisfactory) {
 		next = exposure_ * kExpNumeratorUp / kExpDenominator;
@@ -286,18 +309,18 @@ void IPASoftSimple::updateExposure(double exposureMSV)
 			exposure_ = next;
 		if (exposure_ >= exposure_max_) {
 			next = again_ * kExpNumeratorUp / kExpDenominator;
-			if (next - again_ < 1)
-				again_ += 1;
+			if (next - again_ < againMinStep_)
+				again_ += againMinStep_;
 			else
 				again_ = next;
 		}
 	}
 
 	if (exposureMSV > kExposureOptimal + kExposureSatisfactory) {
-		if (exposure_ == exposure_max_ && again_ != again_min_) {
+		if (exposure_ == exposure_max_ && again_ > again_min_) {
 			next = again_ * kExpNumeratorDown / kExpDenominator;
-			if (again_ - next < 1)
-				again_ -= 1;
+			if (again_ - next < againMinStep_)
+				again_ -= againMinStep_;
 			else
 				again_ = next;
 		} else {
diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
index c3ebb7b7..7e932a14 100644
--- a/src/libcamera/pipeline/simple/simple.cpp
+++ b/src/libcamera/pipeline/simple/simple.cpp
@@ -525,7 +525,7 @@ int SimpleCameraData::init()
 	 * Instantiate Soft ISP if this is enabled for the given driver and no converter is used.
 	 */
 	if (!converter_ && pipe->swIspEnabled()) {
-		swIsp_ = std::make_unique<SoftwareIsp>(pipe, sensor_->controls());
+		swIsp_ = std::make_unique<SoftwareIsp>(pipe, sensor_.get());
 		if (!swIsp_->isValid()) {
 			LOG(SimplePipeline, Warning)
 				<< "Failed to create software ISP, disabling software debayering";
diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp
index 9b49be41..ea4d96e4 100644
--- a/src/libcamera/software_isp/software_isp.cpp
+++ b/src/libcamera/software_isp/software_isp.cpp
@@ -60,9 +60,9 @@ LOG_DEFINE_CATEGORY(SoftwareIsp)
 /**
  * \brief Constructs SoftwareIsp object
  * \param[in] pipe The pipeline handler in use
- * \param[in] sensorControls ControlInfoMap describing the controls supported by the sensor
+ * \param[in] sensor Pointer to the CameraSensor instance owned by the pipeline handler
  */
-SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const ControlInfoMap &sensorControls)
+SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor)
 	: debayer_(nullptr),
 	  debayerParams_{ DebayerParams::kGain10, DebayerParams::kGain10, DebayerParams::kGain10, 0.5f, 0 },
 	  dmaHeap_(DmaHeap::DmaHeapFlag::Cma | DmaHeap::DmaHeapFlag::System)
@@ -97,10 +97,10 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const ControlInfoMap &sensorCont
 		return;
 	}
 
-	int ret = ipa_->init(IPASettings{ "No cfg file", "No sensor model" },
+	int ret = ipa_->init(IPASettings{ "No cfg file", sensor->model() },
 			     debayer_->getStatsFD(),
 			     sharedParams_.fd(),
-			     sensorControls);
+			     sensor->controls());
 	if (ret) {
 		LOG(SoftwareIsp, Error) << "IPA init failed";
 		debayer_.reset();
-- 
2.43.2