Message ID | 20251001091143.2051905-1-naush@raspberrypi.com |
---|---|
State | Rejected |
Headers | show |
Series |
|
Related | show |
Hi all, Please disregard this patch for the time being, we want to add another feature before reviewing and merging. Regards, Naush On Wed, 1 Oct 2025 at 10:11, Naushir Patuck <naush@raspberrypi.com> wrote: > From: Sena Asotani <aso.fam429@gmail.com> > > 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> > --- > 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 | 40 ++++++++++++++++ > 5 files changed, 138 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 000000000000..2d9888dca4f3 > --- /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 74b74888bbff..c13c48539d10 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 000000000000..911b04bc0da0 > --- /dev/null > +++ b/src/ipa/rpi/controller/rpi/decompand.cpp > @@ -0,0 +1,58 @@ > +#include "decompand.h" > + > +#include <libcamera/base/log.h> > + > +#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<uint32_t>(0); > + config_.decompandCurve = > params["decompand_curve"].get<ipa::Pwl>(ipa::Pwl{}); > + return config_.decompandCurve.empty() ? -EINVAL : 0; > +} > + > +void Decompand::initialise() > +{ > +} > + > +void Decompand::switchMode([[maybe_unused]] 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 (Algorithm *)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 000000000000..5ef35946efa5 > --- /dev/null > +++ b/src/ipa/rpi/controller/rpi/decompand.h > @@ -0,0 +1,31 @@ > +#pragma once > + > +#include <libipa/pwl.h> > + > +#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 = NULL); > + 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 829b91258522..e75c87df1924 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, uint16_t *lut, std::size_t > lutSize = 65) > +{ > + if (pwl.empty()) > + return -EINVAL; > + > + constexpr int step = 1024; > + for (std::size_t i = 0; i < lutSize; ++i) { > + int x = i * step; > + > + int y = pwl.eval(x); > + if (y < 0) > + return -1; > + > + lut[i] = static_cast<uint16_t>(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<DecompandStatus>("decompand.status"); > + if (decompandStatus) > + applyDecompand(decompandStatus); > + > BlackLevelStatus *blackLevelStatus = > > rpiMetadata.getLocked<BlackLevelStatus>("black_level.status"); > if (blackLevelStatus) > @@ -702,6 +728,20 @@ 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 = {}; > + > + fe_->GetGlobal(feGlobal); > + > + if (!generateDecompandLut(decompandStatus->decompandCurve, > decompand.lut, PISP_FE_DECOMPAND_LUT_SIZE)) { > + 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 = {}; > -- > 2.43.0 > >
diff --git a/src/ipa/rpi/controller/decompand_status.h b/src/ipa/rpi/controller/decompand_status.h new file mode 100644 index 000000000000..2d9888dca4f3 --- /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 74b74888bbff..c13c48539d10 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 000000000000..911b04bc0da0 --- /dev/null +++ b/src/ipa/rpi/controller/rpi/decompand.cpp @@ -0,0 +1,58 @@ +#include "decompand.h" + +#include <libcamera/base/log.h> + +#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<uint32_t>(0); + config_.decompandCurve = params["decompand_curve"].get<ipa::Pwl>(ipa::Pwl{}); + return config_.decompandCurve.empty() ? -EINVAL : 0; +} + +void Decompand::initialise() +{ +} + +void Decompand::switchMode([[maybe_unused]] 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 (Algorithm *)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 000000000000..5ef35946efa5 --- /dev/null +++ b/src/ipa/rpi/controller/rpi/decompand.h @@ -0,0 +1,31 @@ +#pragma once + +#include <libipa/pwl.h> + +#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 = NULL); + 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 829b91258522..e75c87df1924 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, uint16_t *lut, std::size_t lutSize = 65) +{ + if (pwl.empty()) + return -EINVAL; + + constexpr int step = 1024; + for (std::size_t i = 0; i < lutSize; ++i) { + int x = i * step; + + int y = pwl.eval(x); + if (y < 0) + return -1; + + lut[i] = static_cast<uint16_t>(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<DecompandStatus>("decompand.status"); + if (decompandStatus) + applyDecompand(decompandStatus); + BlackLevelStatus *blackLevelStatus = rpiMetadata.getLocked<BlackLevelStatus>("black_level.status"); if (blackLevelStatus) @@ -702,6 +728,20 @@ 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 = {}; + + fe_->GetGlobal(feGlobal); + + if (!generateDecompandLut(decompandStatus->decompandCurve, decompand.lut, PISP_FE_DECOMPAND_LUT_SIZE)) { + 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 = {};