diff --git a/src/ipa/rpi/controller/decompand_algorithm.h b/src/ipa/rpi/controller/decompand_algorithm.h new file mode 100644 index 000000000..6d2467490 --- /dev/null +++ b/src/ipa/rpi/controller/decompand_algorithm.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (C) 2025, Raspberry Pi Ltd + * + * Decompand control algorithm interface + */ +#pragma once + +#include "libipa/pwl.h" + +#include "algorithm.h" + +namespace RPiController { + +class DecompandAlgorithm : public Algorithm +{ +public: + DecompandAlgorithm(Controller *controller = NULL) + : Algorithm(controller) + { + } + /* A decompand algorithm must provide the following: */ + virtual void initialValues(libcamera::ipa::Pwl &decompandCurve) = 0; +}; + +} /* namespace RPiController */ diff --git a/src/ipa/rpi/controller/rpi/decompand.cpp b/src/ipa/rpi/controller/rpi/decompand.cpp index 911b04bc0..2c3bf7ee4 100644 --- a/src/ipa/rpi/controller/rpi/decompand.cpp +++ b/src/ipa/rpi/controller/rpi/decompand.cpp @@ -13,7 +13,7 @@ LOG_DEFINE_CATEGORY(RPiDecompand) #define NAME "rpi.decompand" Decompand::Decompand(Controller *controller) - : Algorithm(controller) + : DecompandAlgorithm(controller) { } @@ -39,6 +39,14 @@ void Decompand::switchMode([[maybe_unused]] CameraMode const &cameraMode, mode_ = cameraMode; } +void Decompand::initialValues(libcamera::ipa::Pwl &decompandCurve) +{ + if (config_.bitdepth == 0 || mode_.bitdepth == config_.bitdepth) { + decompandCurve = config_.decompandCurve; + } else + decompandCurve = {}; +} + void Decompand::prepare(Metadata *imageMetadata) { DecompandStatus decompandStatus; diff --git a/src/ipa/rpi/controller/rpi/decompand.h b/src/ipa/rpi/controller/rpi/decompand.h index 5ef35946e..2c44b09e4 100644 --- a/src/ipa/rpi/controller/rpi/decompand.h +++ b/src/ipa/rpi/controller/rpi/decompand.h @@ -2,10 +2,9 @@ #include +#include "../decompand_algorithm.h" #include "../decompand_status.h" -#include "algorithm.h" - namespace RPiController { struct DecompandConfig { @@ -13,7 +12,7 @@ struct DecompandConfig { libcamera::ipa::Pwl decompandCurve; }; -class Decompand : public Algorithm +class Decompand : public DecompandAlgorithm { public: Decompand(Controller *controller = NULL); @@ -21,6 +20,7 @@ class Decompand : public Algorithm int read(const libcamera::YamlObject ¶ms) override; void initialise() override; void switchMode(CameraMode const &cameraMode, Metadata *metadata) override; + void initialValues(libcamera::ipa::Pwl &decompandCurve) override; void prepare(Metadata *imageMetadata) override; private: diff --git a/src/ipa/rpi/pisp/pisp.cpp b/src/ipa/rpi/pisp/pisp.cpp index e75c87df1..134fc5aab 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_algorithm.h" #include "controller/decompand_status.h" #include "controller/denoise_algorithm.h" #include "controller/denoise_status.h" @@ -256,7 +257,7 @@ class IpaPiSP final : public IpaBase 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 applyDecompand(const DecompandStatus *decompandStatus, pisp_fe_global_config &feGlobal); void applySdn(const SdnStatus *sdnStatus, pisp_be_global_config &global); void applyTdn(const TdnStatus *tdnStatus, const DeviceStatus *deviceStatus, pisp_be_global_config &global); @@ -335,6 +336,20 @@ int32_t IpaPiSP::platformStart([[maybe_unused]] const ControlList &controls, /* Cause the stitch block to be reset correctly. */ lastStitchHdrStatus_ = HdrStatus(); + /* Setup a default decompand curve on startup if needed. */ + RPiController::DecompandAlgorithm *decompand = dynamic_cast( + controller_.getAlgorithm("decompand")); + if (decompand) { + std::scoped_lock l(*fe_); + pisp_fe_global_config feGlobal; + DecompandStatus decompandStatus; + + fe_->GetGlobal(feGlobal); + decompand->initialValues(decompandStatus.decompandCurve); + applyDecompand(&decompandStatus, feGlobal); + fe_->SetGlobal(feGlobal); + } + return 0; } @@ -368,6 +383,9 @@ void IpaPiSP::platformPrepareIsp([[maybe_unused]] const PrepareParams ¶ms, { /* All Frontend config goes first, we do not want to hold the FE lock for long! */ std::scoped_lock lf(*fe_); + pisp_fe_global_config feGlobal; + + fe_->GetGlobal(feGlobal); if (noiseStatus) applyFocusStats(noiseStatus); @@ -375,13 +393,14 @@ void IpaPiSP::platformPrepareIsp([[maybe_unused]] const PrepareParams ¶ms, DecompandStatus *decompandStatus = rpiMetadata.getLocked("decompand.status"); if (decompandStatus) - applyDecompand(decompandStatus); + applyDecompand(decompandStatus, feGlobal); BlackLevelStatus *blackLevelStatus = rpiMetadata.getLocked("black_level.status"); if (blackLevelStatus) applyBlackLevel(blackLevelStatus, global); + fe_->SetGlobal(feGlobal); } CacStatus *cacStatus = rpiMetadata.getLocked("cac.status"); @@ -728,18 +747,15 @@ void IpaPiSP::applyDPC(const DpcStatus *dpcStatus, pisp_be_global_config &global be_->SetDpc(dpc); } -void IpaPiSP::applyDecompand(const DecompandStatus *decompandStatus) +void IpaPiSP::applyDecompand(const DecompandStatus *decompandStatus, pisp_fe_global_config &feGlobal) { - 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); - } + } else + feGlobal.enables &= ~PISP_FE_ENABLE_DECOMPAND; } void IpaPiSP::applySdn(const SdnStatus *sdnStatus, pisp_be_global_config &global)