Files
pmaports-rtwo/temp/libcamera/0004-ipa-simple-Derive-AGC-minimum-gain-step-from-sensor-.patch
T
Robert Mader d9587b2fea temp/libcamera: Add some patches and tuning files
Notably:
1. Add the in-review quad-debayer patch required for the imx371 - the OP6
   front camera.
2. Fix GLES 2.0 devices like the Librem5 and PinePhone
3. Small tuning file adjustments, including CCMS for the imx371 and
   imx800 (FP5 main rear camera).
4. A small patch allowing to set maximum resolutions via config file.

Part-of: <https://gitlab.postmarketos.org/postmarketOS/pmaports/-/merge_requests/9449>
2026-08-29 16:38:11 +00:00

86 lines
3.7 KiB
Diff

From b0728a7d0ad5462a7e7e39d28e209ede9cbd63ef Mon Sep 17 00:00:00 2001
From: Emilio Miranda <gemilio@gmail.com>
Date: Tue, 25 Aug 2026 14:06:30 +0200
Subject: [PATCH 4/8] ipa: simple: Derive AGC minimum gain step from sensor
granularity
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The minimum gain step is computed as 1% of the sensor's gain range. For a
sensor with a wide gain range that is far larger than the hardware can
resolve: the OV01A10 spans 1-63.9961, giving a step of 0.629961, which is
63% at unity gain where the sensor resolves 1/256 = 0.0039.
updateExposure() substitutes againMinStep whenever the proportional
correction is smaller than it. Once the exposure saturates and gain is
the only remaining control, the AGC therefore applies a 63% change every
time it computes a 2% one, and never settles:
again 1.00000 exposureMSV 1.99 error +0.51 factor 1.020 -> 1.62996
again 1.62996 exposureMSV 2.90 error -0.41 factor 0.984 -> 1.00000
That is 0.7 EV of brightness flicker at frame rate, observed on a Dell
XPS 13 9315 (IPU6, simple pipeline and software ISP).
This is not specific to one sensor. Without a CameraSensorHelper the gain
values are raw register codes, where a step of 1.0 is by definition the
smallest possible change in gain; adding a helper switches the units to
real multipliers, and 1% of the range then bears no relation to what the
sensor can resolve. Any sensor with a wide gain range is exposed to this
once it gains a helper.
Sample the step at both ends of the gain range and take the smaller one,
so that non-uniform gain models are covered as well. This yields
0.00390625 for the OV01A10, and the gain then tracks continuously
instead of alternating between two values.
Link: https://bugzilla.redhat.com/show_bug.cgi?id=2483190
Suggested-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
Signed-off-by: Emilio Miranda <gemilio@gmail.com>
---
src/ipa/simple/soft_simple.cpp | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp
index 629e1a32de8a..8bffd2a441fd 100644
--- a/src/ipa/simple/soft_simple.cpp
+++ b/src/ipa/simple/soft_simple.cpp
@@ -6,6 +6,7 @@
*/
#include <chrono>
+#include <cmath>
#include <stdint.h>
#include <sys/mman.h>
@@ -228,10 +229,21 @@ int IPASoftSimple::configure(const IPAConfigInfo &configInfo)
context_.configuration.agc.againMin = camHelper_->gain(againMin);
context_.configuration.agc.againMax = camHelper_->gain(againMax);
context_.configuration.agc.again10 = std::max(context_.configuration.agc.againMin, 1.0);
- context_.configuration.agc.againMinStep =
- (context_.configuration.agc.againMax -
- context_.configuration.agc.againMin) /
- 100.0;
+ /*
+ * The minimum gain step must reflect what the sensor can
+ * actually resolve. Deriving it from a fraction of the gain
+ * range yields a huge step for sensors with a wide range: the
+ * OV01A10 spans 1-63.9961, giving 0.63 at unity gain where the
+ * hardware resolves 1/256. The AGC can then make no correction
+ * smaller than 63%, and oscillates around the target once the
+ * exposure saturates and gain is the only remaining control.
+ *
+ * Sample the step at both ends of the range and take the
+ * smaller one, so that non-uniform gain models are covered.
+ */
+ context_.configuration.agc.againMinStep = std::min(
+ std::abs(camHelper_->gain(againMin + 1) - camHelper_->gain(againMin)),
+ std::abs(camHelper_->gain(againMax) - camHelper_->gain(againMax - 1)));
if (camHelper_->blackLevel().has_value()) {
/*
* The black level from camHelper_ is a 16 bit value, software ISP
--
2.55.0