[v3,15/15] ipa: rkisp1: Implement LensShadingCorrectionEnable control
diff mbox series

Message ID 20260114-sklug-lsc-resampling-v2-dev-v3-15-80cd24f4dd61@ideasonboard.com
State Superseded
Headers show
Series
  • Add resampling support for polynomial LSC data
Related show

Commit Message

Stefan Klug Jan. 14, 2026, 11:58 a.m. UTC
Implement the LensShadingCorrectionEnable control for rkisp1.

Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>
Tested-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>

---

Changes in v3:
- Include LensShadingCorrectionEnable in metadata
- Add the queueRequest function in the header in logical order instead
  of alphabetical order

Changes in v2:
- Add the control only if LSC is properly configured in the tuning file
- Introduce enable flag in frame context for per frame control
---
 src/ipa/rkisp1/algorithms/dpf.cpp |  2 +-
 src/ipa/rkisp1/algorithms/lsc.cpp | 67 +++++++++++++++++++++++++++++++++------
 src/ipa/rkisp1/algorithms/lsc.h   |  7 ++++
 src/ipa/rkisp1/ipa_context.h      | 13 +++++---
 4 files changed, 74 insertions(+), 15 deletions(-)

Comments

Kieran Bingham Jan. 16, 2026, 12:53 p.m. UTC | #1
Quoting Stefan Klug (2026-01-14 11:58:08)
> Implement the LensShadingCorrectionEnable control for rkisp1.
> 
> Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>
> Tested-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
> 
> ---
> 
> Changes in v3:
> - Include LensShadingCorrectionEnable in metadata
> - Add the queueRequest function in the header in logical order instead
>   of alphabetical order
> 
> Changes in v2:
> - Add the control only if LSC is properly configured in the tuning file
> - Introduce enable flag in frame context for per frame control
> ---
>  src/ipa/rkisp1/algorithms/dpf.cpp |  2 +-
>  src/ipa/rkisp1/algorithms/lsc.cpp | 67 +++++++++++++++++++++++++++++++++------
>  src/ipa/rkisp1/algorithms/lsc.h   |  7 ++++
>  src/ipa/rkisp1/ipa_context.h      | 13 +++++---
>  4 files changed, 74 insertions(+), 15 deletions(-)
> 
> diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp
> index 39f3e461f313dfbf35cb5d6a0daca0540bdf7b6b..83c1e4b7b355041295cbe0498a8dd70877ea6636 100644
> --- a/src/ipa/rkisp1/algorithms/dpf.cpp
> +++ b/src/ipa/rkisp1/algorithms/dpf.cpp
> @@ -233,7 +233,7 @@ void Dpf::prepare(IPAContext &context, const uint32_t frame,
>                 *strengthConfig = strengthConfig_;
>  
>                 const auto &awb = context.configuration.awb;
> -               const auto &lsc = context.configuration.lsc;
> +               const auto &lsc = context.activeState.lsc;
>  
>                 auto &mode = config->gain.mode;
>  
> diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp
> index 8427c48f65b2e6e200f834db506939c6c85fd2a3..bcf44e83a0b99cc617a1d849d56ca4f288f472a3 100644
> --- a/src/ipa/rkisp1/algorithms/lsc.cpp
> +++ b/src/ipa/rkisp1/algorithms/lsc.cpp
> @@ -416,6 +416,8 @@ int LensShadingCorrection::init([[maybe_unused]] IPAContext &context,
>         if (ret)
>                 return ret;
>  
> +       context.ctrlMap[&controls::LensShadingCorrectionEnable] = ControlInfo(false, true, true);
> +
>         shadingDescriptors_ = std::move(lscData);
>  
>         return 0;
> @@ -460,7 +462,7 @@ int LensShadingCorrection::configure(IPAContext &context,
>  
>         sets_.setData(std::move(shadingData));
>  
> -       context.configuration.lsc.enabled = true;
> +       context.activeState.lsc.enabled = true;
>         return 0;
>  }
>  
> @@ -481,6 +483,29 @@ void LensShadingCorrection::copyTable(rkisp1_cif_isp_lsc_config &config,
>         std::copy(set.b.begin(), set.b.end(), &config.b_data_tbl[0][0]);
>  }
>  
> +/**
> + * \copydoc libcamera::ipa::Algorithm::queueRequest
> + */
> +void LensShadingCorrection::queueRequest(IPAContext &context,
> +                                        [[maybe_unused]] const uint32_t frame,
> +                                        IPAFrameContext &frameContext,
> +                                        const ControlList &controls)
> +{
> +       auto &lsc = context.activeState.lsc;
> +
> +       const auto &lscEnable = controls.get(controls::LensShadingCorrectionEnable);
> +       if (lscEnable && *lscEnable != lsc.enabled) {
> +               lsc.enabled = *lscEnable;
> +
> +               LOG(RkISP1Lsc, Debug)
> +                       << (lsc.enabled ? "Enabling" : "Disabling") << " Lsc";
> +
> +               frameContext.lsc.update = true;
> +       }
> +
> +       frameContext.lsc.enabled = lsc.enabled;
> +}
> +
>  /**
>   * \copydoc libcamera::ipa::Algorithm::prepare
>   */
> @@ -493,18 +518,28 @@ void LensShadingCorrection::prepare([[maybe_unused]] IPAContext &context,
>         unsigned int quantizedCt = quantize(ct, kColourTemperatureQuantization);
>         int ctDiff = static_cast<int>(ct) - static_cast<int>(lastAppliedCt_);
>  
> -       /*
> -        * Add a threshold so that oscillations around a quantization step don't
> -        * lead to constant changes.
> -        */
> -       if (std::abs(ctDiff) < kColourTemperatureQuantization / 2)
> -               return;
> +       /* Check if we can skip the update. */
> +       if (!frameContext.lsc.update) {
> +               if (!frameContext.lsc.enabled)
> +                       return;
>  
> -       if (quantizedCt == lastAppliedQuantizedCt_)
> -               return;
> +               /*
> +                * Add a threshold so that oscillations around a quantization
> +                * step don't lead to constant changes.
> +                */
> +               if (std::abs(ctDiff) < kColourTemperatureQuantization / 2)

If you update std::abs on ctDiff to utils::abs_diff be sure to catch
this move which might otherwise be easy to miss.

But I like that this means we'll be able to visually see the impact of
the Lsc in realtime in camshark (or other tuning use cases perhaps)!

Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

> +                       return;
> +
> +               if (quantizedCt == lastAppliedQuantizedCt_)
> +                       return;
> +       }
>  
>         auto config = params->block<BlockType::Lsc>();
> -       config.setEnabled(true);
> +       config.setEnabled(frameContext.lsc.enabled);
> +
> +       if (!frameContext.lsc.enabled)
> +               return;
> +
>         setParameters(*config);
>  
>         const Components &set = sets_.getInterpolated(quantizedCt);
> @@ -518,6 +553,18 @@ void LensShadingCorrection::prepare([[maybe_unused]] IPAContext &context,
>                 << quantizedCt;
>  }
>  
> +/**
> + * \copydoc libcamera::ipa::Algorithm::process
> + */
> +void LensShadingCorrection::process([[maybe_unused]] IPAContext &context,
> +                                   [[maybe_unused]] const uint32_t frame,
> +                                   IPAFrameContext &frameContext,
> +                                   [[maybe_unused]] const rkisp1_stat_buffer *stats,
> +                                   ControlList &metadata)
> +{
> +       metadata.set(controls::LensShadingCorrectionEnable, frameContext.lsc.enabled);
> +}
> +
>  REGISTER_IPA_ALGORITHM(LensShadingCorrection, "LensShadingCorrection")
>  
>  } /* namespace ipa::rkisp1::algorithms */
> diff --git a/src/ipa/rkisp1/algorithms/lsc.h b/src/ipa/rkisp1/algorithms/lsc.h
> index 3097740a6cb2ce9063a4ba087856987a489b0ab6..fb9dcc1a52af4a88a52808346b5da99e3f2b1c87 100644
> --- a/src/ipa/rkisp1/algorithms/lsc.h
> +++ b/src/ipa/rkisp1/algorithms/lsc.h
> @@ -26,9 +26,16 @@ public:
>  
>         int init(IPAContext &context, const YamlObject &tuningData) override;
>         int configure(IPAContext &context, const IPACameraSensorInfo &configInfo) override;
> +       void queueRequest(IPAContext &context, const uint32_t frame,
> +                         IPAFrameContext &frameContext,
> +                         const ControlList &controls) override;
>         void prepare(IPAContext &context, const uint32_t frame,
>                      IPAFrameContext &frameContext,
>                      RkISP1Params *params) override;
> +       void process(IPAContext &context, const uint32_t frame,
> +                    IPAFrameContext &frameContext,
> +                    const rkisp1_stat_buffer *stats,
> +                    ControlList &metadata) override;
>  
>         struct Components {
>                 std::vector<uint16_t> r;
> diff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h
> index b257cee55379ad932b42e613f94eccbe69a939e3..fa748811be743b43ce6ee289408c054c6f9a7046 100644
> --- a/src/ipa/rkisp1/ipa_context.h
> +++ b/src/ipa/rkisp1/ipa_context.h
> @@ -55,10 +55,6 @@ struct IPASessionConfiguration {
>                 bool supported;
>         } compress;
>  
> -       struct {
> -               bool enabled;
> -       } lsc;
> -
>         struct {
>                 utils::Duration minExposureTime;
>                 utils::Duration maxExposureTime;
> @@ -143,6 +139,10 @@ struct IPAActiveState {
>                 double gain;
>                 double strength;
>         } wdr;
> +
> +       struct {
> +               bool enabled;
> +       } lsc;
>  };
>  
>  struct IPAFrameContext : public FrameContext {
> @@ -218,6 +218,11 @@ struct IPAFrameContext : public FrameContext {
>                 double strength;
>                 double gain;
>         } wdr;
> +
> +       struct {
> +               bool enabled;
> +               bool update;
> +       } lsc;
>  };
>  
>  struct IPAContext {
> 
> -- 
> 2.51.0
>

Patch
diff mbox series

diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp
index 39f3e461f313dfbf35cb5d6a0daca0540bdf7b6b..83c1e4b7b355041295cbe0498a8dd70877ea6636 100644
--- a/src/ipa/rkisp1/algorithms/dpf.cpp
+++ b/src/ipa/rkisp1/algorithms/dpf.cpp
@@ -233,7 +233,7 @@  void Dpf::prepare(IPAContext &context, const uint32_t frame,
 		*strengthConfig = strengthConfig_;
 
 		const auto &awb = context.configuration.awb;
-		const auto &lsc = context.configuration.lsc;
+		const auto &lsc = context.activeState.lsc;
 
 		auto &mode = config->gain.mode;
 
diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp
index 8427c48f65b2e6e200f834db506939c6c85fd2a3..bcf44e83a0b99cc617a1d849d56ca4f288f472a3 100644
--- a/src/ipa/rkisp1/algorithms/lsc.cpp
+++ b/src/ipa/rkisp1/algorithms/lsc.cpp
@@ -416,6 +416,8 @@  int LensShadingCorrection::init([[maybe_unused]] IPAContext &context,
 	if (ret)
 		return ret;
 
+	context.ctrlMap[&controls::LensShadingCorrectionEnable] = ControlInfo(false, true, true);
+
 	shadingDescriptors_ = std::move(lscData);
 
 	return 0;
@@ -460,7 +462,7 @@  int LensShadingCorrection::configure(IPAContext &context,
 
 	sets_.setData(std::move(shadingData));
 
-	context.configuration.lsc.enabled = true;
+	context.activeState.lsc.enabled = true;
 	return 0;
 }
 
@@ -481,6 +483,29 @@  void LensShadingCorrection::copyTable(rkisp1_cif_isp_lsc_config &config,
 	std::copy(set.b.begin(), set.b.end(), &config.b_data_tbl[0][0]);
 }
 
+/**
+ * \copydoc libcamera::ipa::Algorithm::queueRequest
+ */
+void LensShadingCorrection::queueRequest(IPAContext &context,
+					 [[maybe_unused]] const uint32_t frame,
+					 IPAFrameContext &frameContext,
+					 const ControlList &controls)
+{
+	auto &lsc = context.activeState.lsc;
+
+	const auto &lscEnable = controls.get(controls::LensShadingCorrectionEnable);
+	if (lscEnable && *lscEnable != lsc.enabled) {
+		lsc.enabled = *lscEnable;
+
+		LOG(RkISP1Lsc, Debug)
+			<< (lsc.enabled ? "Enabling" : "Disabling") << " Lsc";
+
+		frameContext.lsc.update = true;
+	}
+
+	frameContext.lsc.enabled = lsc.enabled;
+}
+
 /**
  * \copydoc libcamera::ipa::Algorithm::prepare
  */
@@ -493,18 +518,28 @@  void LensShadingCorrection::prepare([[maybe_unused]] IPAContext &context,
 	unsigned int quantizedCt = quantize(ct, kColourTemperatureQuantization);
 	int ctDiff = static_cast<int>(ct) - static_cast<int>(lastAppliedCt_);
 
-	/*
-	 * Add a threshold so that oscillations around a quantization step don't
-	 * lead to constant changes.
-	 */
-	if (std::abs(ctDiff) < kColourTemperatureQuantization / 2)
-		return;
+	/* Check if we can skip the update. */
+	if (!frameContext.lsc.update) {
+		if (!frameContext.lsc.enabled)
+			return;
 
-	if (quantizedCt == lastAppliedQuantizedCt_)
-		return;
+		/*
+		 * Add a threshold so that oscillations around a quantization
+		 * step don't lead to constant changes.
+		 */
+		if (std::abs(ctDiff) < kColourTemperatureQuantization / 2)
+			return;
+
+		if (quantizedCt == lastAppliedQuantizedCt_)
+			return;
+	}
 
 	auto config = params->block<BlockType::Lsc>();
-	config.setEnabled(true);
+	config.setEnabled(frameContext.lsc.enabled);
+
+	if (!frameContext.lsc.enabled)
+		return;
+
 	setParameters(*config);
 
 	const Components &set = sets_.getInterpolated(quantizedCt);
@@ -518,6 +553,18 @@  void LensShadingCorrection::prepare([[maybe_unused]] IPAContext &context,
 		<< quantizedCt;
 }
 
+/**
+ * \copydoc libcamera::ipa::Algorithm::process
+ */
+void LensShadingCorrection::process([[maybe_unused]] IPAContext &context,
+				    [[maybe_unused]] const uint32_t frame,
+				    IPAFrameContext &frameContext,
+				    [[maybe_unused]] const rkisp1_stat_buffer *stats,
+				    ControlList &metadata)
+{
+	metadata.set(controls::LensShadingCorrectionEnable, frameContext.lsc.enabled);
+}
+
 REGISTER_IPA_ALGORITHM(LensShadingCorrection, "LensShadingCorrection")
 
 } /* namespace ipa::rkisp1::algorithms */
diff --git a/src/ipa/rkisp1/algorithms/lsc.h b/src/ipa/rkisp1/algorithms/lsc.h
index 3097740a6cb2ce9063a4ba087856987a489b0ab6..fb9dcc1a52af4a88a52808346b5da99e3f2b1c87 100644
--- a/src/ipa/rkisp1/algorithms/lsc.h
+++ b/src/ipa/rkisp1/algorithms/lsc.h
@@ -26,9 +26,16 @@  public:
 
 	int init(IPAContext &context, const YamlObject &tuningData) override;
 	int configure(IPAContext &context, const IPACameraSensorInfo &configInfo) override;
+	void queueRequest(IPAContext &context, const uint32_t frame,
+			  IPAFrameContext &frameContext,
+			  const ControlList &controls) override;
 	void prepare(IPAContext &context, const uint32_t frame,
 		     IPAFrameContext &frameContext,
 		     RkISP1Params *params) override;
+	void process(IPAContext &context, const uint32_t frame,
+		     IPAFrameContext &frameContext,
+		     const rkisp1_stat_buffer *stats,
+		     ControlList &metadata) override;
 
 	struct Components {
 		std::vector<uint16_t> r;
diff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h
index b257cee55379ad932b42e613f94eccbe69a939e3..fa748811be743b43ce6ee289408c054c6f9a7046 100644
--- a/src/ipa/rkisp1/ipa_context.h
+++ b/src/ipa/rkisp1/ipa_context.h
@@ -55,10 +55,6 @@  struct IPASessionConfiguration {
 		bool supported;
 	} compress;
 
-	struct {
-		bool enabled;
-	} lsc;
-
 	struct {
 		utils::Duration minExposureTime;
 		utils::Duration maxExposureTime;
@@ -143,6 +139,10 @@  struct IPAActiveState {
 		double gain;
 		double strength;
 	} wdr;
+
+	struct {
+		bool enabled;
+	} lsc;
 };
 
 struct IPAFrameContext : public FrameContext {
@@ -218,6 +218,11 @@  struct IPAFrameContext : public FrameContext {
 		double strength;
 		double gain;
 	} wdr;
+
+	struct {
+		bool enabled;
+		bool update;
+	} lsc;
 };
 
 struct IPAContext {