Commit Graph
1143 Commits
Author SHA1 Message Date
Milan ZamazalandKieran Bingham 07240afa12 libcamera: simple: Fix black level offsets in AWB
The black level offset subtracted in AWB is wrong.  It assumes that the
stats contain sums of the individual colour pixels.  But they actually
contain sums of the colour channels of larger "superpixels" consisting
of the individual colour pixels.  Each of the RGB colour values and the
computed luminosity (a histogram entry) are added once to the stats per
such a superpixel.  This means the offset computed from the black level
and the number of pixels should be used as it is, not divided.

The patch fixes the subtracted offset.  Since the evaluation is the same
for all the three colours now, the individual class variables are
replaced with a single RGB variable.

Fixes: 4e13c6f55b ("Honor black level in AWB")
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Robert Mader <robert.mader@collabora.com>
Tested-by: Robert Mader <robert.mader@collabora.com>
Signed-off-by: Milan Zamazal <mzamazal@redhat.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2026-01-28 12:08:21 +00:00
Peter BaileyandKieran Bingham 10e4e5ba1e ipa: rpi: pisp: vc4: Update tuning files for new AWB
Update the tuning files to include the new AWB algorithm. It is
enabled by setting "enabled" to true for the AWB algorithm that you
want, and the same field to false for the one you don't want. Note
that you may enable only one of the two algorithms!

The AWB models themselves are not included with libcamera. They will
be supplied from the Raspberry Pi software repositories.

Signed-off-by: Peter Bailey <peter.bailey@raspberrypi.com>
Reviewed-by: David Plowman <david.plowman@raspberrypi.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2026-01-28 09:14:55 +00:00
Peter BaileyandKieran Bingham 7214950ffe ipa: rpi: controller: Ignore algorithms that are not enabled
Algorithms may now contain an "enabled" field which can be set to
false to disable it and prevent it from being loaded. If not present,
algorithms are treated as enabled by default for backwards
compatability.

We additionally prevent duplicate versions of the same algorithm type
(such as AWB) from loading, and flag an error. This will prevent
undefined behaviour if (for example) two distinct AWB algorithms are
trying to run simultaneously.

Signed-off-by: Peter Bailey <peter.bailey@raspberrypi.com>
Reviewed-by: David Plowman <david.plowman@raspberrypi.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2026-01-28 09:14:55 +00:00
Peter BaileyandKieran Bingham 045bfb1b8f ipa: rpi: controller: awb: Add Neural Network AWB
Add an AWB algorithm which uses neural networks.

Signed-off-by: Peter Bailey <peter.bailey@raspberrypi.com>
Reviewed-by: David Plowman <david.plowman@raspberrypi.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2026-01-28 09:14:55 +00:00
Peter BaileyandKieran Bingham 6d38984436 ipa: rpi: controller: awb: Separate Bayesian AWB into AwbBayes
Move parts of the AWB algorithm specific to the Bayesian algorithm into a
new class. This will make it easier to add new AWB algorithms in the future.

Signed-off-by: Peter Bailey <peter.bailey@raspberrypi.com>
Reviewed-by: David Plowman <david.plowman@raspberrypi.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2026-01-28 09:14:55 +00:00
Jacopo Mondi ad2d317a0c ipa: ipu3: Retain Camera::controls() after ipa->configure()
Similar to what commit acfd602767 ("ipa: rkisp1: Fix algorithm controls
vanish after configure") did for the RkISP1 IPA, replace the usage of
unordered_map::merge() at updateControls() time with
unordered_map::insert().

As unordered_map::merge moves items from the source map, it deletes
controls registered at algorithms initialization time in the
ipaContext.ctrlMap. As at configure() time updateControls() is called
again and the list of Camera controls is refreshed, the controls
registered at algorithms initialization time are lost.

Fixes: 87353f2bba ("ipa: ipu3: Derive ipu3::algorithms::Agc from AgcMeanLuminance")
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Reviewed-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2026-01-23 17:40:15 +01:00
Jacopo Mondi 202e330789 ipa: mali-c55: Retain Camera::controls() after ipa->configure()
Similar to what commit acfd602767 ("ipa: rkisp1: Fix algorithm controls
vanish after configure") did for the RkISP1 IPA, replace the usage of
unordered_map::merge() at updateControls() time with
unordered_map::insert().

As unordered_map::merge moves items from the source map, it deletes
controls registered at algorithms initialization time in the
ipaContext.ctrlMap. As at configure() time updateControls() is called
again and the list of Camera controls is refreshed, the controls
registered at algorithms initialization time are lost.

Fixes: fe989ee514 ("ipa: mali-c55: Add Mali-C55 ISP IPA module")
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Reviewed-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2026-01-23 17:39:29 +01:00
Naushir PatuckandBarnabás Pőcze b9b53845fe v4l2: v4l2_camera_proxy: Fix for getting default FrameDurationLimits
The default values for controls::FrameDurationLimits is now an array but
the v4l2 proxy is fetching it as a scalar value, causing a runtime
error. Fix this by templating the getter with the correct
Span<const int64_t, 2> type.

This fix also requires the RPi initial default value for FrameDurationLimits
to be specified as a Span<const int64_t, 2>.

As a drive-by, remove the hard-coded 33ms min and 120ms max frame
duration values in the initial defaults, and use the defaultMinFrameDuration
and defaultMaxFrameDuration const values. This change is inconsequential
to runtime operation as these always get overridden on the first camera
configure call.

Fixes: 4e9be7d11b ("ipa: ipu3, mali-c55, rkisp1, rpi: Fix reporting non-scalar controls")
Closes: https://github.com/raspberrypi/libcamera/issues/321
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Reviewed-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
Reviewed-by: David Plowman <david.plowman@raspberrypi.com>
Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
2026-01-23 16:07:56 +01:00
Bryan O'DonoghueandKieran Bingham a350ad5467 libcamera: software_isp: Switch on default CCM at 65k
Switch on the uncalibrated CCM @ 65k colour temperature. This will become
the default for SoftISP where we have swtiched to GPUISP as default.

Reviewed-by: Milan Zamazal <mzamazal@redhat.com>
Tested-by: Robert Mader <robert.mader@collabora.com>
Tested-by: Hans de Goede <johannes.goede@oss.qualcomm.com> # ThinkPad T14s gen 6 (arm64) ov02c10 + X1c gen 12 ov08x40
Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com> # Lenovo X13s
Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2026-01-07 17:02:58 +00:00
Bryan O'DonoghueandKieran Bingham 852ffae2a0 libcamera: software_isp: lut: Change default Gamma to 1.0/2.2
Change the default softisp Gamma from 0.5 to 1.0/2.2.

Reviewed-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
Reviewed-by: Milan Zamazal <mzamazal@redhat.com>
Tested-by: Robert Mader <robert.mader@collabora.com>
Tested-by: Hans de Goede <johannes.goede@oss.qualcomm.com> # ThinkPad T14s gen 6 (arm64) ov02c10 + X1c gen 12 ov08x40
Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com> # Lenovo X13s
Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2026-01-07 17:02:58 +00:00
Bryan O'DonoghueandKieran Bingham 43180e12ba libcamera: software_isp: lut: Skip calculation lookup tables if gpuIspEnabled is true
On my reference platform Qualcomm RB5 sm8520 the qcam application CPU
occupancy drops from ~100% to about 95% of a single core so this one change
sheds aprox 5% CPU usage.

Reviewed-by: Milan Zamazal <mzamazal@redhat.com>
Tested-by: Robert Mader <robert.mader@collabora.com>
Tested-by: Hans de Goede <johannes.goede@oss.qualcomm.com> # ThinkPad T14s gen 6 (arm64) ov02c10 + X1c gen 12 ov08x40
Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com> # Lenovo X13s
Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2026-01-07 17:02:57 +00:00
Bryan O'DonoghueandKieran Bingham fe9e143702 ipa: simple: Add a flag to indicate gpuIspEnabled
Flag gpuIspEnabled in the simple IPA context. This flag will allow to
selectively avoid some calculations or to generate a default CCM.

Reviewed-by: Milan Zamazal <mzamazal@redhat.com>
Tested-by: Robert Mader <robert.mader@collabora.com>
Tested-by: Hans de Goede <johannes.goede@oss.qualcomm.com> # ThinkPad T14s gen 6 (arm64) ov02c10 + X1c gen 12 ov08x40
Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com> # Lenovo X13s
Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2026-01-07 17:02:57 +00:00
Bryan O'DonoghueandKieran Bingham a1a6253ff9 libcamera: software_isp: debayer: Latch contrastExp not contrast to debayer parameters
Pass contrastExp as calculated in lut to debayer params not the raw
contrast. This way we calculate contrastExp once per frame in lut and pass
the calculated value into the shaders, instead of passing contrast and
calculating contrastExp once per pixel in the shaders.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Reviewed-by: Milan Zamazal <mzamazal@redhat.com>
Tested-by: Robert Mader <robert.mader@collabora.com>
Tested-by: Hans de Goede <johannes.goede@oss.qualcomm.com> # ThinkPad T14s gen 6 (arm64) ov02c10 + X1c gen 12 ov08x40
Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com> # Lenovo X13s
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2026-01-07 17:02:57 +00:00
Hans de GoedeandKieran Bingham 03fc5f6c94 ipa: simple: agc: Make sure activeState.agc expo/again are always initialized
If the first frame of a stream is bad, the IPA will not get called with
frame == 0, leaving activeState.agc expo/again uninitialized. This causes
the agc algorithm to set a very low gain and exposure on the next run
(where it will hit the if (!stats->valid) {} path) resulting in starting
with a black image.

Fix this by using a valid flag instead of checking for frame == 0.

The entire activeState gets cleared to 0 on configure() resetting the new
valid flag.

Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
Reviewed-by: Milan Zamazal <mzamazal@redhat.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2026-01-05 14:59:44 +00:00
Vasiliy DoylovandKieran Bingham 98e5e56150 ipa: simple: fix minimal analog gain init
On most imx sensors the formula seems to be:

again_float = 512.0 / (512.0 - again_ctrl_value)

So the minimum again of 0 makes sense and actually translates to a gain of 1.0.
And the max gain of 400 leads to 512.0 / 112.0 = 4.57 which is about typical for
a maximum again. Since a minimum again value of 0 is actually normal, the special
handling of againMin == 0 is undesirable and this is actually causing problems
on these IMX sensors. again10 correctly gets set to 0 which is less than the
adjusted againMin which causes the AGC code to not work properly.

Fix this by dropping the special handling of againMin == 0.

Signed-off-by: Vasiliy Doylov <nekocwd@mainlining.org>
Reviewed-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
Reviewed-by: Milan Zamazal <mzamazal@redhat.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2026-01-05 14:49:06 +00:00
Jacopo Mondi 99e35cc9ec ipa: mali-c55: Introduce MaliC55Params
Implement MaliC55Params to derive from V4L2Params and use the new
helpers in the Mali C55 IPA algorithms implementation.

Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Tested-by: Antoine Bouyer <antoine.bouyer@nxp.com>
Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-12-16 15:02:53 +01:00
Jacopo Mondi bd7b54876d ipa: libipa: Introduce V4L2Params
The existing RkISP1Params helper class allows the RkISP1 IPA to handle
both the extensible parameters format and the legacy fixed-size format.

With the introduction of v4l2-isp.h in the Linux kernel the part of
the RkISP1Params helper class that handles extensible parameters can
be generalized so that other IPA modules can use the same helpers
to populate a parameters buffer compatible with v4l2-isp.h.

Generalize the RkISP1Params class to a new libipa component named
V4L2Params and derive the existing RkISP1Params from it, leaving
in the RkISP1-specific implementation the handling of the legacy format.

Deriving RkISP1Params from V4L2Params requires changing the size
associated to each block to include the size of v4l2_params_block_header
in the ipa:rkisp1::kBlockTypeInfo map as the V4L2Params::block()
implementation doesn't account for that as RkIS1Params::block()
implementation did.

Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Tested-by: Antoine Bouyer <antoine.bouyer@nxp.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-12-16 15:02:53 +01:00
Jacopo Mondi 907cd64a17 ipa: mali-c55: Update header file and adjust IPA
Update Mali C55 header file to the version merged in Linux v6.19-rc1 at
revision 08a99369f44e ("media: uapi: Add parameters structs to
mali-c55-config.h") with applied on top the in-review patch:
https://lore.kernel.org/all/20251215-mali-c55-header-update-for-v6-19-rc1-v1-3-69f56dee3c71@ideasonboard.com/

Adjust the IPA module to use the new header version which uses the
v4l2-isp framework.

Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Tested-by: Antoine Bouyer <antoine.bouyer@nxp.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>
2025-12-16 15:02:52 +01:00
Michael OlbrichandKieran Bingham c6a8808eba ipa: rpi: remove executable bits from data files
These are just data files. Like all other files in the same directory,
they should not be executable. So change the mode to match.

Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
Acked-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Acked-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-12-16 09:43:45 +00:00
Kieran Bingham e4a4eb0a94 ipa: simple: awb: Fix ColourGains reported
The AWB gains reported in the metadata are currently scaled against the
maximum gain, but in fact the gain itself is already stored as a
floating point gain value.

Remove the incorrect scaling and report the gains directly.

Fixes: a0b97475b1 ("ipa: simple: Report the ColourGains in metadata")
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Milan Zamazal <mzamazal@redhat.com>
Reviewed-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-12-16 09:43:44 +00:00
Bryan O'DonoghueandKieran Bingham 5f51e2e545 libcamera: software_isp: lut: Make contrast available in debayer params
Provide the contrast used in IPA to Bayer parameters. Similar to the
calculated Gamma value we will pass this value into the debayer fragment
shader for further consumption.

Reviewed-by: Milan Zamazal <mzamazal@redhat.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-12-12 23:32:53 +00:00
Bryan O'DonoghueandKieran Bingham 5bfb96661f libcamera: software_isp: lut: Make gamma from lut.cpp available in debayer params
Provide the gamma used in IPA to Bayer parameters. We will pass Gamma into
the shader via a uniform and can then tweak that value from outside at
will.

Reviewed-by: Milan Zamazal <mzamazal@redhat.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-12-12 23:32:53 +00:00
Bryan O'DonoghueandKieran Bingham 724a29e3cd libcamera: software_isp: blacklevel: Make black level available in debayer params
Populate black level gain in blacklevel::prepare(). A copy is made of the gain
value in the DebayerParams structure.

Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Milan Zamazal <mzamazal@redhat.com>
Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-12-12 23:32:53 +00:00
Bryan O'DonoghueandKieran Bingham 3d7ef342b7 libcamera: software_isp: lut: Make CCM available in debayer params
Provide the CCM calculated in LUT to the debayer params structure for
consumption in the debayer shaders.

Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Milan Zamazal <mzamazal@redhat.com>
Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-12-12 23:32:52 +00:00
Paul ElderandKieran Bingham 4e9be7d11b ipa: ipu3, mali-c55, rkisp1, rpi: Fix reporting non-scalar controls
The ControlInfos of non-scalar controls that are reported in controls()
must have non-scalar default values for controls that have a defined
size. This is because applications should be able to directly set the
default value from a ControlInfo to the control.

Currently this is relevant to the following controls:
- ColourGains
- ColourCorrectionMatrix
- FrameDurationLimits
- AfWindows

Fix the scalarness of these controls where relevant.

Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
Tested-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> # rkisp1
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-11-26 16:52:19 +00:00
Stefan Klug 4e720d5bae ipa: libipa: agc_mean_luminance: Fix yTarget handling in constraints
The yTarget loading code is broken and works neither for plain values
nor for arrays of values to form a PWL. Fix this by supporting both
cases. If a list is provided in the tuning file construct a PWL,
otherwise construct a single point PWL with the given value.

Fixes: 24247a12c7 ("ipa: libipa: Add AgcMeanLuminance base class")
Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>
Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
2025-11-25 17:47:30 +01:00
Stefan Klug 3ed8dabe5a ipa: libipa: agc_mean_luminance: Change luminance target to piecewise linear function
In some situations it is necessary to specify the target brightness
value depending on the overall lux level. Replace the float
relativeLuminanceTraget by a PWL. As the PWL loading code loads a plain
value as single point PWL, backwards compatibility to existing tuning
files is ensured.

While at it, order the class members in reverse xmas tree notation.

Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>
Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-11-25 17:47:16 +01:00
Stefan Klug 7dd713ba2e ipa: rkisp1: lux: Properly handle frame context and active state
With the upcoming regulation rework the processing order in the IPA is
updated a bit so that process() updates the active state with new
measurements and fills the metadata with the data from the corresponding
frame context. In prepare() all parameters for one frame are tied
together using the most up to date values from active state.

Change the lux algorithm to support that order of events. Also prepare
for cases where stats can be null which can happen with the upcoming
regulation rework.

While at it fix a formatting issue reported by checkstyle and drop a
unnecessary local variable.

Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-11-25 17:42:34 +01:00
Stefan Klug 3b4414ccaa ipa: libipa: pwl: Allow to parse a plain yaml value as single point PWL
In the tuning files, it is useful to specify some values as PWL that
produces a different output value depending on an input value. For
example it is useful to specify the relativeLuminanceTarget depending on
the lux level, so that the regulation regulates a bit darker in low
light scenes. For simple setups this is not necessary and a single value
is sufficient.

This patch extends the yaml loading code, so that a single point PWL can
also be specified as a plain value. This way the following yaml
expressions are all valid:

yTarget: [ 1000, 0.15, 2000, 0.17 ]  # Regular PWL
yTarget: [ 0, 0.17 ]                 # Single point PWL
yTarget: 0.17                        # Same as above

For cases (I'm not aware of any) where a single point Pwl is not allowed
there is no change as that must be checked externally anyways.

Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>
2025-11-25 17:40:38 +01:00
Stefan Klug dadeb67fcc libipa: exposure_mode_helper: Set quantizationGain in absence of a sensor helper
In commit f077c58e08 ("libipa: exposure_mode_helper: Take
exposure/gain quantization into account") calculation of the
quantization gain was added to ExposureModeHelper::clampGain(). This
works as expected when a sensor helper is configured but the gain is not
reset to 1.0 in case the sensor helper is not configured. This leads to
incorrect gain calculations in ExposureModeHelper::splitExposure() as
that expects the quantization gain to be valid in any case. Fix that by
setting the quantization gain to 1.0 in case no sensor helper is
configured.

Fixes: f077c58e08 ("libipa: exposure_mode_helper: Take exposure/gain quantization into account")
Closes: https://gitlab.freedesktop.org/camera/libcamera/-/issues/292
Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Tested-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
2025-11-25 17:32:50 +01:00
Isaac ScottandKieran Bingham 43ab0d487b libipa: module: Allow algorithms to be disabled via the tuning file
It is beneficial to have the option during development to disable and
enable algorithms via the tuning file without having to delete their
entries.

Add support for an optional "enabled" parameter to accomplish this.

Usage example:
version: 1
algorithms:
  - Agc:
      enabled: true
  - Awb:
      enabled: false

This will enable AGC, and disable AWB. If the enabled flag is not
present, the algorithm will be enabled.

Signed-off-by: Isaac Scott <isaac.scott@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
[Kieran: Reflow text]
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-11-24 17:29:11 +00:00
Milan ZamazalandKieran Bingham 443e5a6c31 libcamera: software_isp: Fix gamma table when CCM is used
Software CPU ISP computes a gamma lookup table.  The table incorporates
black level and contrast.  All entries in the table below the black
level are set to 0.  This is not necessarily correct all the time.

Let's consider this case: The CCM is

  [1 0 0]
  [0 1 0]
  [0 0 0]

and contrast is set to zero.  The gamma table has all the entries above
the black level set to 186 (due to zero contrast) and all the entries
below the black level set to 0.  CCM is applied before gamma, a
non-black level pixel has the blue component set to 0 with the CCM
above.  Now, when the gamma lookup is applied, the red and green
components are set to 186, while the blue component is set to 0.  The
resulting pixel is then yellow rather than grey (as it should be with
zero contrast).

There are two ways to fix this: Either clamping pixel colour channels to
the black level in debayering or setting the below black level entries
in the gamma lookup table to the lowest value of the gamma table rather
than 0.  Both should have the same effect.  Let's opt for the latter for
its simplicity.

Signed-off-by: Milan Zamazal <mzamazal@redhat.com>
Reviewed-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-11-19 10:38:08 +00:00
Rui WangandStefan Klug 30779421e8 ipa: rkisp1: dpf: Enable strength after enable Dpf
The filter strength configuration block was previously only enabled on the
first frame (frame == 0). Apply the strength values when denoise is active.
This prevents the strength config from being disabled on subsequent frames.

Signed-off-by: Rui Wang <rui.wang@ideasonboard.com>
Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>
2025-11-14 22:03:22 +01:00
Barnabás Pőcze 79be15a5f1 ipa: libipa: agc_mean_luminance: Avoid unnecessary copies
`constraintModes()` and `exposureModeHelpers()` need not return copies of
the internal objects, exposing const references is sufficient, so do that.

Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-11-03 17:05:45 +01:00
Benjamin MugnierandKieran Bingham b1f09c013a ipa: rpi: vd56g3: Fix frameIntegrationDiff value
In the vd56g3 user manual :

  MAX_EXPOSURE_COARSE = FRAME_LENGTH − EXP_COARSE_INTG_MARGIN − 7
  EXP_COARSE_INTG_MARGIN >= 68

Therefore, frameIntegrationDiff is EXP_COARSE_INTG_MARGIN + 7, equals
75. This value is coherent with the VD56G3_EXPOSURE_MARGIN in the kernel
driver source code.

Reported-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: Benjamin Mugnier <benjamin.mugnier@foss.st.com>
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-10-30 14:54:44 +00:00
Daniel ScallyandKieran Bingham 6a393789f3 libipa: camera_sensor_helper: Add imx708
The imx708 sensor driver has long been available, especially in raspberry
pi kernels; and the raspberry pi ipa module has had the corresponding
helper class since 2023 (952ef94ed7). The camera sensor properties
database also has an entry for it (2fb0f25019), but the camera sensor
helper class is missing from the common libipa component. So add it, with
the same gain formula present in the raspberry pi ipa module, and the black
level taken from the rpi tuning files.

Handling the raspberry pi specific "wide" / "noir" suffixes is omitted.
They are not present in the camera sensor properties database either.

Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com>
[Add black level, extend commit message.]
Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-10-30 14:50:59 +00:00
David PlowmanandKieran Bingham 36f9cdcdb4 ipa: rpi: lux: Use floating statistics region to obtain the current Y value
The Y value from the first floating region is now a better choice for
a Y value that is invariant to (for example) the metering mode.

Both VC4 and PiSP platforms store full image Y statistics here.

Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-10-26 23:32:50 +00:00
David PlowmanandKieran Bingham 0810b8a70a ipa: rpi: vc4: Use a floating statistics region for a full image Y sum
We're going to use a "floating statistics region" to store a full
image Y sum. The VC4 platform actually has no floating region for
this, but we can synthesize such a region as follows in software.

We know that the 15 AGC regions that we do have are arranged to cover
the whole image, and they cannot be changed. Adding up the R, G and B
values here will get us most of the way to Y. But we do also need to
know the most recent colour gains, so code must also be added to
remember the last AWB status.

With this change, algorithms can now look at the first floating region
on both VC4 and PiSP platforms to get a full image Y average value.

Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-10-26 23:32:50 +00:00
David PlowmanandKieran Bingham 3bc722b5da ipa: rpi: pisp: Use a floating region to get whole image Y statistics
Floating regions are currently unused on the PiSP platform, so we can
use one of them to get an average Y value for the whole image.

If an algorithm (such as the "lux" algorithm) wants a scene-referred
estimate of absolute brightness, then this would be a better choice
than a value from Y histogram as the latter is not invariant to the
metering mode (e.g. centre-weighted, spot etc.). (So note that for the
AGC/AEC algorithm, where the metering mode is relevant, the Y
histogram is the appropriate choice.)

We also fix the loop that copies the hardware's floating region values
into our statistics structure; it was using the wrong limit which was
causing it not to do anything.

A future commit will update the lux algorithm to use this feature.

Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-10-26 23:32:50 +00:00
David PlowmanandKieran Bingham 17ee3b6089 ipa: rpi: lux: Handle camera mode sensitivity correctly
The camera mode sensitivity needs to be taken into account for the lux
calculation. For example, the IMX708 binned mode (with a sensitivity
of 2.0) would otherwise show double the correct lux value.

Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-10-26 23:32:50 +00:00
David PlowmanandKieran Bingham 557622308f ipa: rpi: Fix the set function for floating statistics regions
Previously it was calling the wrong internal function which would do
nothing.

Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-10-26 23:32:50 +00:00
Jacopo MondiandLaurent Pinchart 19825d2334 ipa: meson.build: Remove duplicated variable
The 'ipa_names' variable is declared twice. Remove it.

Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Reviewed-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
2025-10-20 11:34:39 +03:00
Naushir PatuckandKieran Bingham b320b20db7 ipa: rpi: pisp: Allow an initial decompand curve to be set on the FE
In the current code, decompand will only set a curve in the prepare
phase, which will only run after 1-2 frames pass through the FE. This
is fixed by adding an initialValues() member function to the decompand
algorithm, which will be called in the IPA before we start the hardware
streaming.

Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Tested-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
Reviewed-by: David Plowman <david.plowman@raspberrypi.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-10-08 11:36:40 +01:00
Naushir PatuckandKieran Bingham 413f03a738 ipa: rpi: pisp: Add a DecompandAlgorithm class
The decompand algorithm implementation will subclass the
DecompandAlgorithm class. This will be needed for setting the initial
decompand values in a future commit.

Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Tested-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
Reviewed-by: David Plowman <david.plowman@raspberrypi.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-10-08 11:36:40 +01:00
Naushir PatuckandKieran Bingham ffcdbf0980 ipa: rpi: Add FE globals as a parameter to applyDecompand()
Don't let applyDecompand() directly change the FE global enables.
Instead pass the global mask into the function and set it in the caller.
This will be needed when a future commit will add setting the decompand
initial values.

Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Tested-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
Reviewed-by: David Plowman <david.plowman@raspberrypi.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-10-08 11:36:40 +01:00
Sena AsotaniandKieran Bingham bfd09aa474 ipa: rpi: pisp: Add decompand support using PiSP hardware block
This patch integrates a new decompand algorithm that utilizes the PiSP
FE hardware block available on Raspberry Pi 5. The implementation
enables conversion of companded sensor data into linear format prior to
ISP processing.

Changes include:
- Implementation of decompand logic for controller and pipe interfaces
- Enabling decompand block by "rpi.decompand" in tuning.json

Signed-off-by: Sena Asotani <aso.fam429@gmail.com>
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Tested-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
Reviewed-by: David Plowman <david.plowman@raspberrypi.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-10-08 11:36:40 +01:00
Milan ZamazalandKieran Bingham f0f2aca566 ipa: simple: agc: Prevent division by zero in AGC
If the histogram size is non-zero but lower than the number of bins,
yHistValsPerBin is zero and then the AGC processing crashes on division
by it.  Let's check yHistValsPerBin for being zero and stop AGC
processing in such a case.  The condition also covers the cases where
histogramSize or yHistValsPerBinMod are zero.

Tested-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
Signed-off-by: Milan Zamazal <mzamazal@redhat.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Hans de Goede <hansg@kernel.org>
Tested-by: Hans de Goede <hansg@kernel.org>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-10-02 22:07:48 +01:00
Milan ZamazalandKieran Bingham 1102a96854 ipa: simple: blc: Prevent division by zero in BLC
When there are no values in the histogram, BLC simple IPA can crash on
division by zero.  We cannot get anything meaningful in such a case
anyway, let's simply return from `process()' then.

Tested-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
Reviewed-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
Reviewed-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
Reviewed-by: Hans de Goede <hansg@kernel.org>
Tested-by: Hans de Goede <hansg@kernel.org>
Signed-off-by: Milan Zamazal <mzamazal@redhat.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-10-02 22:07:44 +01:00
Milan ZamazalandKieran Bingham 0201e11f27 ipa: simple: awb: Use correct type in std::accumulate
The result type of the std::accumulate() call is uint64_t; let's use the
same type for the initial value (rather than the default int) to prevent
summing up the values in a different integer type.

Signed-off-by: Milan Zamazal <mzamazal@redhat.com>
Reviewed-by: Hans de Goede <hansg@kernel.org>
Reviewed-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
Tested-by: Hans de Goede <hansg@kernel.org>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-10-02 22:07:38 +01:00
Milan ZamazalandKieran Bingham 6a7fe29a18 ipa: simple: awb: Avoid incorrect arithmetic in AWB
The R/G/B sums computed in AWB simple IPA may be zero or perhaps even
negative.  Let's make sure the sums are always positive, to prevent
division by zero or completely nonsense results.

Signed-off-by: Milan Zamazal <mzamazal@redhat.com>
Reviewed-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
Reviewed-by: Hans de Goede <hansg@kernel.org>
Tested-by: Hans de Goede <hansg@kernel.org>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-10-02 22:07:33 +01:00