[v3,07/11] ipa: c3-isp: Add BLC Algorithm
diff mbox series

Message ID 20250227105733.187611-8-keke.li@amlogic.com
State New
Headers show
Series
  • Add Amlogic C3 ISP pipeline handler and IPA
Related show

Commit Message

Keke Li Feb. 27, 2025, 10:57 a.m. UTC
Add a new Black Level Correction algorithm.

Signed-off-by: Keke Li <keke.li@amlogic.com>
---
 src/ipa/c3-isp/algorithms/blc.cpp     | 151 ++++++++++++++++++++++++++
 src/ipa/c3-isp/algorithms/blc.h       |  45 ++++++++
 src/ipa/c3-isp/algorithms/meson.build |   1 +
 3 files changed, 197 insertions(+)
 create mode 100644 src/ipa/c3-isp/algorithms/blc.cpp
 create mode 100644 src/ipa/c3-isp/algorithms/blc.h

Patch
diff mbox series

diff --git a/src/ipa/c3-isp/algorithms/blc.cpp b/src/ipa/c3-isp/algorithms/blc.cpp
new file mode 100644
index 00000000..4410d03f
--- /dev/null
+++ b/src/ipa/c3-isp/algorithms/blc.cpp
@@ -0,0 +1,151 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024, Amlogic
+ *
+ * C3ISP Black Level Correction control
+ */
+
+#include "blc.h"
+
+#include <cmath>
+
+#include <libcamera/base/log.h>
+#include <libcamera/control_ids.h>
+
+#include "libcamera/internal/yaml_parser.h"
+
+/**
+ * \file blc.h
+ */
+
+namespace libcamera {
+
+namespace ipa::c3isp::algorithms {
+
+/**
+ * \class Blc
+ * \brief C3 ISP Black Level Correction control
+ *
+ * The pixels output by the camera normally include a black level, because
+ * sensors do not always report a signal level of '0' for black. Pixels at or
+ * below this level should be considered black. To achieve that, the C3 ISP BLC
+ * algorithm subtracts a configurable offset from all pixels.
+ *
+ * The black level can be measured at runtime from an optical dark region of the
+ * camera sensor, or measured during the camera tuning process. The first option
+ * isn't currently supported.
+ */
+
+LOG_DEFINE_CATEGORY(C3ISPBlc)
+
+Blc::Blc()
+	: tuningBlc_(false)
+{
+}
+
+/**
+ * \copydoc libcamera::ipa::Algorithm::init
+ */
+int Blc::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData)
+{
+	offsetR_ = tuningData["offsetR"].get<uint32_t>(0);
+	offsetGr_ = tuningData["offsetGr"].get<uint32_t>(0);
+	offsetGb_ = tuningData["offsetGb"].get<uint32_t>(0);
+	offsetB_ = tuningData["offsetB"].get<uint32_t>(0);
+
+	if (!(offsetR_ + offsetGr_ + offsetGb_ + offsetB_)) {
+		LOG(C3ISPBlc, Debug) << "All black level offsets are empty";
+		tuningBlc_ = false;
+	} else {
+		tuningBlc_ = true;
+	}
+
+	return 0;
+}
+
+/**
+ * \copydoc libcamera::ipa::Algorithm::configure
+ */
+int Blc::configure(IPAContext &context,
+		   [[maybe_unused]] const IPACameraSensorInfo &configInfo)
+{
+	uint16_t blackLevel = offsetCompress(context.configuration.sensor.blackLevel);
+
+	if (blackLevel && !tuningBlc_) {
+		offsetR_ = context.configuration.sensor.blackLevel;
+		offsetGr_ = context.configuration.sensor.blackLevel;
+		offsetGb_ = context.configuration.sensor.blackLevel;
+		offsetB_ = context.configuration.sensor.blackLevel;
+	}
+
+	return 0;
+}
+
+uint16_t Blc::offsetCompress(uint32_t blackLevel)
+{
+	uint8_t shift = 0;
+	uint32_t integer = 0;
+	uint8_t highestBitPos = static_cast<uint8_t>(log2(blackLevel));
+
+	/* The compressed offset is stored in Q4.12 format */
+	if (highestBitPos < 12) {
+		shift = 0;
+		integer = blackLevel;
+	} else {
+		shift = highestBitPos - 11;
+		integer = blackLevel >> shift;
+	}
+
+	shift = (shift > 0xf) ? 0xf : shift;
+
+	return (shift & 0xf) << 12 | (integer & 0xfff);
+}
+
+/**
+ * \copydoc libcamera::ipa::Algorithm::prepare
+ */
+void Blc::prepare([[maybe_unused]] IPAContext &context, const uint32_t frame,
+		  [[maybe_unused]] IPAFrameContext &frameContext,
+		  C3ISPParams *params)
+{
+	if (frame > 0)
+		return;
+
+	if (!tuningBlc_ && !context.configuration.sensor.blackLevel)
+		return;
+
+	auto blcCfg = params->block<BlockType::Blc>();
+	blcCfg.setEnabled(C3_ISP_PARAMS_BLOCK_FL_ENABLE);
+
+	blcCfg->gr_ofst = offsetCompress(offsetGr_);
+	blcCfg->r_ofst = offsetCompress(offsetR_);
+	blcCfg->b_ofst = offsetCompress(offsetB_);
+	blcCfg->gb_ofst = offsetCompress(offsetGb_);
+}
+
+/**
+ * \copydoc libcamera::ipa::Algorithm::process
+ */
+void Blc::process([[maybe_unused]] IPAContext &context,
+		  [[maybe_unused]] const uint32_t frame,
+		  [[maybe_unused]] IPAFrameContext &frameContext,
+		  [[maybe_unused]] const c3_isp_stats_info *stats,
+		  ControlList &metadata)
+{
+	/*
+	 * Black Level Offsets in tuning data need to be 20-bit, whereas the
+	 * metadata expects values from a 16-bit range. Right-shift to remove
+	 * the 4 least significant bits.
+	 */
+	metadata.set(controls::SensorBlackLevels,
+		     { static_cast<int32_t>(offsetR_ >> 4),
+		       static_cast<int32_t>(offsetGr_ >> 4),
+		       static_cast<int32_t>(offsetGb_ >> 4),
+		       static_cast<int32_t>(offsetB_ >> 4) });
+}
+
+REGISTER_IPA_ALGORITHM(Blc, "Blc")
+
+} /* namespace ipa::c3isp::algorithms */
+
+} /* namespace libcamera */
diff --git a/src/ipa/c3-isp/algorithms/blc.h b/src/ipa/c3-isp/algorithms/blc.h
new file mode 100644
index 00000000..67244e4a
--- /dev/null
+++ b/src/ipa/c3-isp/algorithms/blc.h
@@ -0,0 +1,45 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024, Amlogic
+ *
+ * C3ISP Black Level Correction control
+ */
+
+#pragma once
+
+#include "algorithm.h"
+
+namespace libcamera {
+
+namespace ipa::c3isp::algorithms {
+
+class Blc : public Algorithm
+{
+public:
+	Blc();
+	~Blc() = default;
+
+	int init(IPAContext &context, const YamlObject &tuningData) override;
+	int configure(IPAContext &context,
+		      const IPACameraSensorInfo &configInfo) override;
+	void prepare(IPAContext &context, const uint32_t frame,
+		     IPAFrameContext &frameContext,
+		     C3ISPParams *params) override;
+	void process(IPAContext &context, const uint32_t frame,
+		     IPAFrameContext &frameContext,
+		     const c3_isp_stats_info *stats,
+		     ControlList &metadata) override;
+
+private:
+	uint16_t offsetCompress(uint32_t blackLevel);
+
+	bool tuningBlc_;
+	uint32_t offsetR_;
+	uint32_t offsetGr_;
+	uint32_t offsetGb_;
+	uint32_t offsetB_;
+};
+
+} /* namespace ipa::c3isp::algorithms */
+
+} /* namespace libcamera */
diff --git a/src/ipa/c3-isp/algorithms/meson.build b/src/ipa/c3-isp/algorithms/meson.build
index 9460da99..d91973e3 100644
--- a/src/ipa/c3-isp/algorithms/meson.build
+++ b/src/ipa/c3-isp/algorithms/meson.build
@@ -3,4 +3,5 @@ 
 c3isp_ipa_algorithms = files([
     'agc.cpp',
     'awb.cpp',
+    'blc.cpp',
 ])