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>
This commit is contained in:
Sena Asotani
2025-10-03 13:15:52 +01:00
committed by Kieran Bingham
parent f0f2aca566
commit bfd09aa474
5 changed files with 136 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
#pragma once
#include "libipa/pwl.h"
struct DecompandStatus {
uint32_t bitdepth;
libcamera::ipa::Pwl decompandCurve;
};

View File

@@ -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',

View File

@@ -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 &params)
{
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(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);

View File

@@ -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 = nullptr);
char const *name() const override;
int read(const libcamera::YamlObject &params) override;
void initialise() override;
void switchMode(CameraMode const &cameraMode, Metadata *metadata) override;
void prepare(Metadata *imageMetadata) override;
private:
CameraMode mode_;
DecompandConfig config_;
};
} /* namespace RPiController */

View File

@@ -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<uint16_t> 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<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 &params,
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,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 = {};