From a1a6253ff93ebff81984e2eac778bad32f8c88c3 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Tue, 6 Jan 2026 17:00:36 +0000 Subject: [PATCH] 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 Reviewed-by: Milan Zamazal Tested-by: Robert Mader Tested-by: Hans de Goede # ThinkPad T14s gen 6 (arm64) ov02c10 + X1c gen 12 ov08x40 Tested-by: Kieran Bingham # Lenovo X13s Signed-off-by: Kieran Bingham --- include/libcamera/internal/software_isp/debayer_params.h | 2 +- src/ipa/simple/algorithms/lut.cpp | 7 ++++--- src/ipa/simple/ipa_context.h | 1 + src/libcamera/software_isp/debayer.cpp | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/libcamera/internal/software_isp/debayer_params.h b/include/libcamera/internal/software_isp/debayer_params.h index 8033f7d5..256c7d43 100644 --- a/include/libcamera/internal/software_isp/debayer_params.h +++ b/include/libcamera/internal/software_isp/debayer_params.h @@ -59,7 +59,7 @@ struct DebayerParams { Matrix ccm; RGB blackLevel; float gamma; - float contrast; + double contrastExp; }; } /* namespace libcamera */ diff --git a/src/ipa/simple/algorithms/lut.cpp b/src/ipa/simple/algorithms/lut.cpp index 9aaab54f..7d015ac8 100644 --- a/src/ipa/simple/algorithms/lut.cpp +++ b/src/ipa/simple/algorithms/lut.cpp @@ -60,12 +60,13 @@ void Lut::updateGammaTable(IPAContext &context) const auto blackLevel = context.activeState.blc.level; const unsigned int blackIndex = blackLevel * gammaTable.size() / 256; const auto contrast = context.activeState.knobs.contrast.value_or(1.0); + /* Convert 0..2 to 0..infinity; avoid actual inifinity at tan(pi/2) */ + double contrastExp = tan(std::clamp(contrast * M_PI_4, 0.0, M_PI_2 - 0.00001)); const float divisor = gammaTable.size() - blackIndex - 1.0; for (unsigned int i = blackIndex; i < gammaTable.size(); i++) { double normalized = (i - blackIndex) / divisor; /* Convert 0..2 to 0..infinity; avoid actual inifinity at tan(pi/2) */ - double contrastExp = tan(std::clamp(contrast * M_PI_4, 0.0, M_PI_2 - 0.00001)); /* Apply simple S-curve */ if (normalized < 0.5) normalized = 0.5 * std::pow(normalized / 0.5, contrastExp); @@ -84,7 +85,7 @@ void Lut::updateGammaTable(IPAContext &context) gammaTable[blackIndex]); context.activeState.gamma.blackLevel = blackLevel; - context.activeState.gamma.contrast = contrast; + context.activeState.gamma.contrastExp = contrastExp; } int16_t Lut::ccmValue(unsigned int i, float ccm) const @@ -149,7 +150,7 @@ void Lut::prepare(IPAContext &context, } params->gamma = context.configuration.gamma; - params->contrast = context.activeState.gamma.contrast; + params->contrastExp = context.activeState.gamma.contrastExp; } void Lut::process([[maybe_unused]] IPAContext &context, diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h index 26b60fb6..7837bb4d 100644 --- a/src/ipa/simple/ipa_context.h +++ b/src/ipa/simple/ipa_context.h @@ -59,6 +59,7 @@ struct IPAActiveState { std::array gammaTable; uint8_t blackLevel; double contrast; + double contrastExp; } gamma; struct { diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp index b33f818a..4cb5b4da 100644 --- a/src/libcamera/software_isp/debayer.cpp +++ b/src/libcamera/software_isp/debayer.cpp @@ -116,7 +116,7 @@ namespace libcamera { */ /** - * \var DebayerParams::contrast + * \var DebayerParams::contrastExp * \brief Contrast value for GPUISP */