[v3,17/35] ipa: libipa: lsc_table: Move LscTable from RkISP1
diff mbox series

Message ID 20260706-libipa-algorithms-v3-17-968757b038bb@ideasonboard.com
State Superseded
Headers show
Series
  • ipa: libipa: Introduce libipa algorithms
Related show

Commit Message

Jacopo Mondi July 6, 2026, 8:01 a.m. UTC
Move the LscTableImpl class to libipa from RkISP1.

Rename the class from LscTableImpl to a simpler LscTable.
The class is copied verbatim, only documntation has been added.

The implementation still contains RkISP1 specific data which will be
removed once the class is generalized.

Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
---
 src/ipa/libipa/lsc_table.cpp      | 95 +++++++++++++++++++++++++++++++++++++++
 src/ipa/libipa/lsc_table.h        | 50 +++++++++++++++++++++
 src/ipa/libipa/meson.build        |  2 +
 src/ipa/rkisp1/algorithms/lsc.cpp | 81 +--------------------------------
 4 files changed, 149 insertions(+), 79 deletions(-)

Comments

Kieran Bingham July 6, 2026, 6:35 p.m. UTC | #1
Quoting Jacopo Mondi (2026-07-06 09:01:37)
> Move the LscTableImpl class to libipa from RkISP1.
> 
> Rename the class from LscTableImpl to a simpler LscTable.
> The class is copied verbatim, only documntation has been added.
> 
> The implementation still contains RkISP1 specific data which will be
> removed once the class is generalized.

Ack.

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

> 
> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
> ---
>  src/ipa/libipa/lsc_table.cpp      | 95 +++++++++++++++++++++++++++++++++++++++
>  src/ipa/libipa/lsc_table.h        | 50 +++++++++++++++++++++
>  src/ipa/libipa/meson.build        |  2 +
>  src/ipa/rkisp1/algorithms/lsc.cpp | 81 +--------------------------------
>  4 files changed, 149 insertions(+), 79 deletions(-)
> 
> diff --git a/src/ipa/libipa/lsc_table.cpp b/src/ipa/libipa/lsc_table.cpp
> new file mode 100644
> index 000000000000..41a862b92e88
> --- /dev/null
> +++ b/src/ipa/libipa/lsc_table.cpp
> @@ -0,0 +1,95 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2026, Ideas On Board
> + *
> + * Table-based Lsc implementation
> + */
> +
> +#include "lsc_table.h"
> +
> +/* \todo Remove RkISP1 from libipa. */
> +#include "linux/rkisp1-config.h"
> +
> +namespace libcamera {
> +
> +LOG_DEFINE_CATEGORY(LscTable)
> +
> +namespace ipa {
> +
> +/**
> + * \class LscTable
> + * \brief Table based lsc algorithm implementation
> + *
> + * Table based lsc algorithm implementation. The LscTable class implements lsc
> + * support using tabular lsc data.
> + *
> + * \sa LscImplementation
> + */
> +
> +/**
> + * \brief Parse tabular lsc data
> + * \param[in] sets The tuning file content
> + *
> + * Parse the lsc data in tabular form from the \a sets tuning data.
> + *
> + * \return 0 on success or a negative error number otherwise
> + */
> +int LscTable::parseLscData(const ValueNode &sets)
> +{
> +       for (const auto &set : sets.asList()) {
> +               uint32_t ct = set["ct"].get<uint32_t>(0);
> +
> +               if (lscData_.count(ct)) {
> +                       LOG(LscTable, Error)
> +                               << "Multiple sets found for color temperature "
> +                               << ct;
> +                       return -EINVAL;
> +               }
> +
> +               lsc::Components components;
> +               components.r = parseTable(set, "r");
> +               components.gr = parseTable(set, "gr");
> +               components.gb = parseTable(set, "gb");
> +               components.b = parseTable(set, "b");
> +
> +               if (components.r.empty() || components.gr.empty() ||
> +                   components.gb.empty() || components.b.empty()) {
> +                       LOG(LscTable, Error)
> +                               << "Set for color temperature " << ct
> +                               << " is missing tables";
> +                       return -EINVAL;
> +               }
> +
> +               lscData_.emplace(ct, std::move(components));
> +       }
> +
> +       if (lscData_.empty()) {
> +               LOG(LscTable, Error) << "Failed to load any sets";
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +std::vector<uint16_t> LscTable::parseTable(const ValueNode &tuningData,
> +                                          const char *prop)
> +{
> +       static constexpr unsigned int kLscNumSamples =
> +               RKISP1_CIF_ISP_LSC_SAMPLES_MAX * RKISP1_CIF_ISP_LSC_SAMPLES_MAX;
> +
> +       std::vector<uint16_t> table =
> +               tuningData[prop].get<std::vector<uint16_t>>().value_or(utils::defopt);
> +       if (table.size() != kLscNumSamples) {
> +               LOG(LscTable, Error)
> +                       << "Invalid '" << prop << "' values: expected "
> +                       << kLscNumSamples
> +                       << " elements, got " << table.size();
> +               return {};
> +       }
> +
> +       return table;
> +}
> +
> +} /* namespace ipa */
> +
> +} /* namespace libcamera */
> diff --git a/src/ipa/libipa/lsc_table.h b/src/ipa/libipa/lsc_table.h
> new file mode 100644
> index 000000000000..0983b78c3f6b
> --- /dev/null
> +++ b/src/ipa/libipa/lsc_table.h
> @@ -0,0 +1,50 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2026, Ideas On Board
> + *
> + * Table-based Lsc implementation
> + */
> +#pragma once
> +
> +#include <vector>
> +
> +#include <libcamera/base/log.h>
> +#include <libcamera/base/span.h>
> +
> +#include <libcamera/geometry.h>
> +
> +#include "libcamera/internal/value_node.h"
> +
> +#include "lsc_base.h"
> +
> +namespace libcamera {
> +
> +LOG_DECLARE_CATEGORY(LscTable)
> +
> +namespace ipa {
> +
> +class LscTable : public LscImplementation
> +{
> +public:
> +       int parseLscData(const ValueNode &sets) override;
> +
> +       lsc::ComponentsMap
> +       sampleForCrop([[maybe_unused]] const Rectangle &cropRectangle,
> +                     [[maybe_unused]] Span<const double> xSizes,
> +                     [[maybe_unused]] Span<const double> ySizes) override
> +       {
> +               LOG(LscTable, Warning)
> +                       << "Tabular LSC data doesn't support resampling";
> +               return lscData_;
> +       }
> +
> +private:
> +       std::vector<uint16_t> parseTable(const ValueNode &tuningData,
> +                                        const char *prop);
> +
> +       lsc::ComponentsMap lscData_;
> +};
> +
> +} /* namespace ipa */
> +
> +} /* namespace libcamera */
> diff --git a/src/ipa/libipa/meson.build b/src/ipa/libipa/meson.build
> index 96611e90ee1e..95d398d99fd6 100644
> --- a/src/ipa/libipa/meson.build
> +++ b/src/ipa/libipa/meson.build
> @@ -16,6 +16,7 @@ libipa_headers = files([
>      'interpolator.h',
>      'lsc_base.h',
>      'lsc_polynomial.h',
> +    'lsc_table.h',
>      'lux.h',
>      'module.h',
>      'pwl.h',
> @@ -39,6 +40,7 @@ libipa_sources = files([
>      'interpolator.cpp',
>      'lsc_base.cpp',
>      'lsc_polynomial.cpp',
> +    'lsc_table.cpp',
>      'lux.cpp',
>      'module.cpp',
>      'pwl.cpp',
> diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp
> index a4ea879aaa83..974534175e06 100644
> --- a/src/ipa/rkisp1/algorithms/lsc.cpp
> +++ b/src/ipa/rkisp1/algorithms/lsc.cpp
> @@ -17,6 +17,7 @@
>  #include "libcamera/internal/value_node.h"
>  
>  #include "libipa/lsc_polynomial.h"
> +#include "libipa/lsc_table.h"
>  #include "linux/rkisp1-config.h"
>  
>  /**
> @@ -33,84 +34,6 @@ namespace {
>  
>  constexpr int kColourTemperatureQuantization = 10;
>  
> -class LscTableImpl : public LscImplementation
> -{
> -public:
> -       int parseLscData(const ValueNode &sets) override;
> -
> -       lsc::ComponentsMap
> -       sampleForCrop([[maybe_unused]] const Rectangle &cropRectangle,
> -                     [[maybe_unused]] Span<const double> xSizes,
> -                     [[maybe_unused]] Span<const double> ySizes) override
> -       {
> -               LOG(RkISP1Lsc, Warning)
> -                       << "Tabular LSC data doesn't support resampling";
> -               return lscData_;
> -       }
> -
> -private:
> -       std::vector<uint16_t> parseTable(const ValueNode &tuningData,
> -                                        const char *prop);
> -
> -       lsc::ComponentsMap lscData_;
> -};
> -
> -int LscTableImpl::parseLscData(const ValueNode &sets)
> -{
> -       for (const auto &set : sets.asList()) {
> -               uint32_t ct = set["ct"].get<uint32_t>(0);
> -
> -               if (lscData_.count(ct)) {
> -                       LOG(RkISP1Lsc, Error)
> -                               << "Multiple sets found for color temperature "
> -                               << ct;
> -                       return -EINVAL;
> -               }
> -
> -               lsc::Components components;
> -               components.r = parseTable(set, "r");
> -               components.gr = parseTable(set, "gr");
> -               components.gb = parseTable(set, "gb");
> -               components.b = parseTable(set, "b");
> -
> -               if (components.r.empty() || components.gr.empty() ||
> -                   components.gb.empty() || components.b.empty()) {
> -                       LOG(RkISP1Lsc, Error)
> -                               << "Set for color temperature " << ct
> -                               << " is missing tables";
> -                       return -EINVAL;
> -               }
> -
> -               lscData_.emplace(ct, std::move(components));
> -       }
> -
> -       if (lscData_.empty()) {
> -               LOG(RkISP1Lsc, Error) << "Failed to load any sets";
> -               return -EINVAL;
> -       }
> -
> -       return 0;
> -}
> -
> -std::vector<uint16_t> LscTableImpl::parseTable(const ValueNode &tuningData,
> -                                                const char *prop)
> -{
> -       static constexpr unsigned int kLscNumSamples =
> -               RKISP1_CIF_ISP_LSC_SAMPLES_MAX * RKISP1_CIF_ISP_LSC_SAMPLES_MAX;
> -
> -       std::vector<uint16_t> table =
> -               tuningData[prop].get<std::vector<uint16_t>>().value_or(utils::defopt);
> -       if (table.size() != kLscNumSamples) {
> -               LOG(RkISP1Lsc, Error)
> -                       << "Invalid '" << prop << "' values: expected "
> -                       << kLscNumSamples
> -                       << " elements, got " << table.size();
> -               return {};
> -       }
> -
> -       return table;
> -}
> -
>  std::vector<double> parseSizes(const ValueNode &tuningData,
>                                const char *prop)
>  {
> @@ -190,7 +113,7 @@ int LensShadingCorrection::init([[maybe_unused]] IPAContext &context,
>         std::string type = tuningData["type"].get<std::string>("table");
>         if (type == "table") {
>                 LOG(RkISP1Lsc, Debug) << "Loading tabular LSC data.";
> -               algo_ = std::make_unique<LscTableImpl>();
> +               algo_ = std::make_unique<LscTable>();
>                 ret = algo_->parseLscData(sets);
>         } else if (type == "polynomial") {
>                 LOG(RkISP1Lsc, Debug) << "Loading polynomial LSC data.";
> 
> -- 
> 2.54.0
>

Patch
diff mbox series

diff --git a/src/ipa/libipa/lsc_table.cpp b/src/ipa/libipa/lsc_table.cpp
new file mode 100644
index 000000000000..41a862b92e88
--- /dev/null
+++ b/src/ipa/libipa/lsc_table.cpp
@@ -0,0 +1,95 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2026, Ideas On Board
+ *
+ * Table-based Lsc implementation
+ */
+
+#include "lsc_table.h"
+
+/* \todo Remove RkISP1 from libipa. */
+#include "linux/rkisp1-config.h"
+
+namespace libcamera {
+
+LOG_DEFINE_CATEGORY(LscTable)
+
+namespace ipa {
+
+/**
+ * \class LscTable
+ * \brief Table based lsc algorithm implementation
+ *
+ * Table based lsc algorithm implementation. The LscTable class implements lsc
+ * support using tabular lsc data.
+ *
+ * \sa LscImplementation
+ */
+
+/**
+ * \brief Parse tabular lsc data
+ * \param[in] sets The tuning file content
+ *
+ * Parse the lsc data in tabular form from the \a sets tuning data.
+ *
+ * \return 0 on success or a negative error number otherwise
+ */
+int LscTable::parseLscData(const ValueNode &sets)
+{
+	for (const auto &set : sets.asList()) {
+		uint32_t ct = set["ct"].get<uint32_t>(0);
+
+		if (lscData_.count(ct)) {
+			LOG(LscTable, Error)
+				<< "Multiple sets found for color temperature "
+				<< ct;
+			return -EINVAL;
+		}
+
+		lsc::Components components;
+		components.r = parseTable(set, "r");
+		components.gr = parseTable(set, "gr");
+		components.gb = parseTable(set, "gb");
+		components.b = parseTable(set, "b");
+
+		if (components.r.empty() || components.gr.empty() ||
+		    components.gb.empty() || components.b.empty()) {
+			LOG(LscTable, Error)
+				<< "Set for color temperature " << ct
+				<< " is missing tables";
+			return -EINVAL;
+		}
+
+		lscData_.emplace(ct, std::move(components));
+	}
+
+	if (lscData_.empty()) {
+		LOG(LscTable, Error) << "Failed to load any sets";
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+std::vector<uint16_t> LscTable::parseTable(const ValueNode &tuningData,
+					   const char *prop)
+{
+	static constexpr unsigned int kLscNumSamples =
+		RKISP1_CIF_ISP_LSC_SAMPLES_MAX * RKISP1_CIF_ISP_LSC_SAMPLES_MAX;
+
+	std::vector<uint16_t> table =
+		tuningData[prop].get<std::vector<uint16_t>>().value_or(utils::defopt);
+	if (table.size() != kLscNumSamples) {
+		LOG(LscTable, Error)
+			<< "Invalid '" << prop << "' values: expected "
+			<< kLscNumSamples
+			<< " elements, got " << table.size();
+		return {};
+	}
+
+	return table;
+}
+
+} /* namespace ipa */
+
+} /* namespace libcamera */
diff --git a/src/ipa/libipa/lsc_table.h b/src/ipa/libipa/lsc_table.h
new file mode 100644
index 000000000000..0983b78c3f6b
--- /dev/null
+++ b/src/ipa/libipa/lsc_table.h
@@ -0,0 +1,50 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2026, Ideas On Board
+ *
+ * Table-based Lsc implementation
+ */
+#pragma once
+
+#include <vector>
+
+#include <libcamera/base/log.h>
+#include <libcamera/base/span.h>
+
+#include <libcamera/geometry.h>
+
+#include "libcamera/internal/value_node.h"
+
+#include "lsc_base.h"
+
+namespace libcamera {
+
+LOG_DECLARE_CATEGORY(LscTable)
+
+namespace ipa {
+
+class LscTable : public LscImplementation
+{
+public:
+	int parseLscData(const ValueNode &sets) override;
+
+	lsc::ComponentsMap
+	sampleForCrop([[maybe_unused]] const Rectangle &cropRectangle,
+		      [[maybe_unused]] Span<const double> xSizes,
+		      [[maybe_unused]] Span<const double> ySizes) override
+	{
+		LOG(LscTable, Warning)
+			<< "Tabular LSC data doesn't support resampling";
+		return lscData_;
+	}
+
+private:
+	std::vector<uint16_t> parseTable(const ValueNode &tuningData,
+					 const char *prop);
+
+	lsc::ComponentsMap lscData_;
+};
+
+} /* namespace ipa */
+
+} /* namespace libcamera */
diff --git a/src/ipa/libipa/meson.build b/src/ipa/libipa/meson.build
index 96611e90ee1e..95d398d99fd6 100644
--- a/src/ipa/libipa/meson.build
+++ b/src/ipa/libipa/meson.build
@@ -16,6 +16,7 @@  libipa_headers = files([
     'interpolator.h',
     'lsc_base.h',
     'lsc_polynomial.h',
+    'lsc_table.h',
     'lux.h',
     'module.h',
     'pwl.h',
@@ -39,6 +40,7 @@  libipa_sources = files([
     'interpolator.cpp',
     'lsc_base.cpp',
     'lsc_polynomial.cpp',
+    'lsc_table.cpp',
     'lux.cpp',
     'module.cpp',
     'pwl.cpp',
diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp
index a4ea879aaa83..974534175e06 100644
--- a/src/ipa/rkisp1/algorithms/lsc.cpp
+++ b/src/ipa/rkisp1/algorithms/lsc.cpp
@@ -17,6 +17,7 @@ 
 #include "libcamera/internal/value_node.h"
 
 #include "libipa/lsc_polynomial.h"
+#include "libipa/lsc_table.h"
 #include "linux/rkisp1-config.h"
 
 /**
@@ -33,84 +34,6 @@  namespace {
 
 constexpr int kColourTemperatureQuantization = 10;
 
-class LscTableImpl : public LscImplementation
-{
-public:
-	int parseLscData(const ValueNode &sets) override;
-
-	lsc::ComponentsMap
-	sampleForCrop([[maybe_unused]] const Rectangle &cropRectangle,
-		      [[maybe_unused]] Span<const double> xSizes,
-		      [[maybe_unused]] Span<const double> ySizes) override
-	{
-		LOG(RkISP1Lsc, Warning)
-			<< "Tabular LSC data doesn't support resampling";
-		return lscData_;
-	}
-
-private:
-	std::vector<uint16_t> parseTable(const ValueNode &tuningData,
-					 const char *prop);
-
-	lsc::ComponentsMap lscData_;
-};
-
-int LscTableImpl::parseLscData(const ValueNode &sets)
-{
-	for (const auto &set : sets.asList()) {
-		uint32_t ct = set["ct"].get<uint32_t>(0);
-
-		if (lscData_.count(ct)) {
-			LOG(RkISP1Lsc, Error)
-				<< "Multiple sets found for color temperature "
-				<< ct;
-			return -EINVAL;
-		}
-
-		lsc::Components components;
-		components.r = parseTable(set, "r");
-		components.gr = parseTable(set, "gr");
-		components.gb = parseTable(set, "gb");
-		components.b = parseTable(set, "b");
-
-		if (components.r.empty() || components.gr.empty() ||
-		    components.gb.empty() || components.b.empty()) {
-			LOG(RkISP1Lsc, Error)
-				<< "Set for color temperature " << ct
-				<< " is missing tables";
-			return -EINVAL;
-		}
-
-		lscData_.emplace(ct, std::move(components));
-	}
-
-	if (lscData_.empty()) {
-		LOG(RkISP1Lsc, Error) << "Failed to load any sets";
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-std::vector<uint16_t> LscTableImpl::parseTable(const ValueNode &tuningData,
-						 const char *prop)
-{
-	static constexpr unsigned int kLscNumSamples =
-		RKISP1_CIF_ISP_LSC_SAMPLES_MAX * RKISP1_CIF_ISP_LSC_SAMPLES_MAX;
-
-	std::vector<uint16_t> table =
-		tuningData[prop].get<std::vector<uint16_t>>().value_or(utils::defopt);
-	if (table.size() != kLscNumSamples) {
-		LOG(RkISP1Lsc, Error)
-			<< "Invalid '" << prop << "' values: expected "
-			<< kLscNumSamples
-			<< " elements, got " << table.size();
-		return {};
-	}
-
-	return table;
-}
-
 std::vector<double> parseSizes(const ValueNode &tuningData,
 			       const char *prop)
 {
@@ -190,7 +113,7 @@  int LensShadingCorrection::init([[maybe_unused]] IPAContext &context,
 	std::string type = tuningData["type"].get<std::string>("table");
 	if (type == "table") {
 		LOG(RkISP1Lsc, Debug) << "Loading tabular LSC data.";
-		algo_ = std::make_unique<LscTableImpl>();
+		algo_ = std::make_unique<LscTable>();
 		ret = algo_->parseLscData(sets);
 	} else if (type == "polynomial") {
 		LOG(RkISP1Lsc, Debug) << "Loading polynomial LSC data.";