From bfd09aa474c9e3fa35c04f0b2fd90874fa478646 Mon Sep 17 00:00:00 2001 From: Sena Asotani Date: Fri, 3 Oct 2025 13:15:52 +0100 Subject: [PATCH] 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 Signed-off-by: Naushir Patuck Tested-by: Nick Hollinghurst Reviewed-by: David Plowman Signed-off-by: Kieran Bingham --- src/ipa/rpi/controller/decompand_status.h | 8 ++++ src/ipa/rpi/controller/meson.build | 1 + src/ipa/rpi/controller/rpi/decompand.cpp | 58 +++++++++++++++++++++++ src/ipa/rpi/controller/rpi/decompand.h | 31 ++++++++++++ src/ipa/rpi/pisp/pisp.cpp | 38 +++++++++++++++ 5 files changed, 136 insertions(+) create mode 100644 src/ipa/rpi/controller/decompand_status.h create mode 100644 src/ipa/rpi/controller/rpi/decompand.cpp create mode 100644 src/ipa/rpi/controller/rpi/decompand.h diff --git a/src/ipa/rpi/controller/decompand_status.h b/src/ipa/rpi/controller/decompand_status.h new file mode 100644 index 00000000..2d9888dc --- /dev/null +++ b/src/ipa/rpi/controller/decompand_status.h @@ -0,0 +1,8 @@ +#pragma once + +#include "libipa/pwl.h" + +struct DecompandStatus { + uint32_t bitdepth; + libcamera::ipa::Pwl decompandCurve; +}; diff --git a/src/ipa/rpi/controller/meson.build b/src/ipa/rpi/controller/meson.build index 74b74888..c13c4853 100644 --- a/src/ipa/rpi/controller/meson.build +++ b/src/ipa/rpi/controller/meson.build @@ -14,6 +14,7 @@ rpi_ipa_controller_sources = files([ 'rpi/cac.cpp', 'rpi/ccm.cpp', 'rpi/contrast.cpp', + 'rpi/decompand.cpp', 'rpi/denoise.cpp', 'rpi/dpc.cpp', 'rpi/geq.cpp', diff --git a/src/ipa/rpi/controller/rpi/decompand.cpp b/src/ipa/rpi/controller/rpi/decompand.cpp new file mode 100644 index 00000000..2036750f --- /dev/null +++ b/src/ipa/rpi/controller/rpi/decompand.cpp @@ -0,0 +1,58 @@ +#include "decompand.h" + +#include + +#include "../decompand_status.h" +#include "../histogram.h" + +using namespace RPiController; +using namespace libcamera; + +LOG_DEFINE_CATEGORY(RPiDecompand) + +#define NAME "rpi.decompand" + +Decompand::Decompand(Controller *controller) + : Algorithm(controller) +{ +} + +char const *Decompand::name() const +{ + return NAME; +} + +int Decompand::read(const libcamera::YamlObject ¶ms) +{ + config_.bitdepth = params["bitdepth"].get(0); + config_.decompandCurve = params["decompand_curve"].get(ipa::Pwl{}); + return config_.decompandCurve.empty() ? -EINVAL : 0; +} + +void Decompand::initialise() +{ +} + +void Decompand::switchMode(CameraMode const &cameraMode, + [[maybe_unused]] Metadata *metadata) +{ + mode_ = cameraMode; +} + +void Decompand::prepare(Metadata *imageMetadata) +{ + DecompandStatus decompandStatus; + + if (config_.bitdepth == 0 || mode_.bitdepth == config_.bitdepth) { + decompandStatus.decompandCurve = config_.decompandCurve; + imageMetadata->set("decompand.status", decompandStatus); + } +} + +/* Register algorithm with the system. */ +static Algorithm *create(Controller *controller) +{ + return new Decompand(controller); +} + +static RegisterAlgorithm reg(NAME, &create); diff --git a/src/ipa/rpi/controller/rpi/decompand.h b/src/ipa/rpi/controller/rpi/decompand.h new file mode 100644 index 00000000..38b26a21 --- /dev/null +++ b/src/ipa/rpi/controller/rpi/decompand.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +#include "../decompand_status.h" + +#include "algorithm.h" + +namespace RPiController { + +struct DecompandConfig { + uint32_t bitdepth; + libcamera::ipa::Pwl decompandCurve; +}; + +class Decompand : public Algorithm +{ +public: + Decompand(Controller *controller = nullptr); + char const *name() const override; + int read(const libcamera::YamlObject ¶ms) override; + void initialise() override; + void switchMode(CameraMode const &cameraMode, Metadata *metadata) override; + void prepare(Metadata *imageMetadata) override; + +private: + CameraMode mode_; + DecompandConfig config_; +}; + +} /* namespace RPiController */ diff --git a/src/ipa/rpi/pisp/pisp.cpp b/src/ipa/rpi/pisp/pisp.cpp index 829b9125..14ece12b 100644 --- a/src/ipa/rpi/pisp/pisp.cpp +++ b/src/ipa/rpi/pisp/pisp.cpp @@ -32,6 +32,7 @@ #include "controller/cac_status.h" #include "controller/ccm_status.h" #include "controller/contrast_status.h" +#include "controller/decompand_status.h" #include "controller/denoise_algorithm.h" #include "controller/denoise_status.h" #include "controller/dpc_status.h" @@ -113,6 +114,25 @@ int generateLut(const ipa::Pwl &pwl, uint32_t *lut, std::size_t lutSize, return 0; } +int generateDecompandLut(const ipa::Pwl &pwl, Span lut) +{ + if (pwl.empty()) + return -EINVAL; + + constexpr int step = 1024; + for (std::size_t i = 0; i < lut.size(); ++i) { + int x = i * step; + + int y = pwl.eval(x); + if (y < 0) + return -1; + + lut[i] = static_cast(std::min(y, 65535)); + } + + return 0; +} + void packLscLut(uint32_t packed[NumLscVertexes][NumLscVertexes], double const rgb[3][NumLscVertexes][NumLscVertexes]) { @@ -236,6 +256,7 @@ private: void applyLensShading(const AlscStatus *alscStatus, pisp_be_global_config &global); void applyDPC(const DpcStatus *dpcStatus, pisp_be_global_config &global); + void applyDecompand(const DecompandStatus *decompandStatus); void applySdn(const SdnStatus *sdnStatus, pisp_be_global_config &global); void applyTdn(const TdnStatus *tdnStatus, const DeviceStatus *deviceStatus, pisp_be_global_config &global); @@ -351,6 +372,11 @@ void IpaPiSP::platformPrepareIsp([[maybe_unused]] const PrepareParams ¶ms, if (noiseStatus) applyFocusStats(noiseStatus); + DecompandStatus *decompandStatus = + rpiMetadata.getLocked("decompand.status"); + if (decompandStatus) + applyDecompand(decompandStatus); + BlackLevelStatus *blackLevelStatus = rpiMetadata.getLocked("black_level.status"); if (blackLevelStatus) @@ -702,6 +728,18 @@ void IpaPiSP::applyDPC(const DpcStatus *dpcStatus, pisp_be_global_config &global be_->SetDpc(dpc); } +void IpaPiSP::applyDecompand(const DecompandStatus *decompandStatus) +{ + pisp_fe_global_config feGlobal; + pisp_fe_decompand_config decompand = {}; + + if (!generateDecompandLut(decompandStatus->decompandCurve, decompand.lut)) { + fe_->SetDecompand(decompand); + feGlobal.enables |= PISP_FE_ENABLE_DECOMPAND; + fe_->SetGlobal(feGlobal); + } +} + void IpaPiSP::applySdn(const SdnStatus *sdnStatus, pisp_be_global_config &global) { pisp_be_sdn_config sdn = {};