about summary refs log tree commit diff
path: root/users/flokli/ipu6-softisp/libcamera/0013-libcamera-software_isp-add-Simple-SoftwareIsp-implem.patch
diff options
context:
space:
mode:
Diffstat (limited to 'users/flokli/ipu6-softisp/libcamera/0013-libcamera-software_isp-add-Simple-SoftwareIsp-implem.patch')
-rw-r--r--users/flokli/ipu6-softisp/libcamera/0013-libcamera-software_isp-add-Simple-SoftwareIsp-implem.patch483
1 files changed, 483 insertions, 0 deletions
diff --git a/users/flokli/ipu6-softisp/libcamera/0013-libcamera-software_isp-add-Simple-SoftwareIsp-implem.patch b/users/flokli/ipu6-softisp/libcamera/0013-libcamera-software_isp-add-Simple-SoftwareIsp-implem.patch
new file mode 100644
index 0000000000..24636ed756
--- /dev/null
+++ b/users/flokli/ipu6-softisp/libcamera/0013-libcamera-software_isp-add-Simple-SoftwareIsp-implem.patch
@@ -0,0 +1,483 @@
+From 21f1dd954a44b4e8f81abbfea276e4b60f8a8297 Mon Sep 17 00:00:00 2001
+From: Andrey Konovalov <andrey.konovalov@linaro.org>
+Date: Thu, 23 Nov 2023 16:47:15 +0300
+Subject: [PATCH 13/25] libcamera: software_isp: add Simple SoftwareIsp
+ implementation
+
+The implementation of SoftwareIsp handles creation of Soft IPA
+and interactions with it, so that the pipeline handler wouldn't
+need to care about the Soft IPA.
+
+Doxygen documentation by Dennis Bonke.
+
+Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org>
+Co-authored-by: Dennis Bonke <admin@dennisbonke.com>
+Signed-off-by: Dennis Bonke <admin@dennisbonke.com>
+Co-authored-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> # sc8280xp Lenovo x13s
+Tested-by: Pavel Machek <pavel@ucw.cz>
+---
+ .../internal/software_isp/meson.build         |   1 +
+ .../internal/software_isp/swisp_simple.h      | 163 ++++++++++++
+ src/libcamera/software_isp/meson.build        |  19 ++
+ src/libcamera/software_isp/swisp_simple.cpp   | 238 ++++++++++++++++++
+ 4 files changed, 421 insertions(+)
+ create mode 100644 include/libcamera/internal/software_isp/swisp_simple.h
+ create mode 100644 src/libcamera/software_isp/swisp_simple.cpp
+
+diff --git a/include/libcamera/internal/software_isp/meson.build b/include/libcamera/internal/software_isp/meson.build
+index b5a0d737..cf21ace5 100644
+--- a/include/libcamera/internal/software_isp/meson.build
++++ b/include/libcamera/internal/software_isp/meson.build
+@@ -4,6 +4,7 @@ libcamera_internal_headers += files([
+     'debayer.h',
+     'debayer_cpu.h',
+     'debayer_params.h',
++    'swisp_simple.h',
+     'swisp_stats.h',
+     'swstats.h',
+     'swstats_cpu.h',
+diff --git a/include/libcamera/internal/software_isp/swisp_simple.h b/include/libcamera/internal/software_isp/swisp_simple.h
+new file mode 100644
+index 00000000..87613c23
+--- /dev/null
++++ b/include/libcamera/internal/software_isp/swisp_simple.h
+@@ -0,0 +1,163 @@
++/* SPDX-License-Identifier: LGPL-2.1-or-later */
++/*
++ * Copyright (C) 2023, Linaro Ltd
++ *
++ * swisp_simple.h - Simple software ISP implementation
++ */
++
++#pragma once
++
++#include <libcamera/base/log.h>
++#include <libcamera/base/thread.h>
++
++#include <libcamera/pixel_format.h>
++
++#include <libcamera/ipa/soft_ipa_interface.h>
++#include <libcamera/ipa/soft_ipa_proxy.h>
++
++#include "libcamera/internal/dma_heaps.h"
++#include "libcamera/internal/software_isp.h"
++#include "libcamera/internal/software_isp/debayer_cpu.h"
++
++namespace libcamera {
++
++/**
++ * \brief Class for the Simple Software ISP.
++ *
++ * Implementation of the SoftwareIsp interface.
++ */
++class SwIspSimple : public SoftwareIsp
++{
++public:
++	/**
++	 * \brief Constructor for the SwIspSimple object.
++	 *
++	 * \param[in] pipe The pipeline handler in use.
++	 * \param[in] sensorControls The sensor controls.
++	 */
++	SwIspSimple(PipelineHandler *pipe, const ControlInfoMap &sensorControls);
++	~SwIspSimple() {}
++
++	/**
++	 * \brief Load a configuration from a file.
++	 * \param[in] filename The file to load from.
++	 *
++	 * \return 0 on success.
++	 */
++	int loadConfiguration([[maybe_unused]] const std::string &filename) { return 0; }
++
++	/**
++	 * \brief Gets if there is a valid debayer object.
++	 *
++	 * \returns true if there is, false otherwise.
++	 */
++	bool isValid() const;
++
++	/**
++	 * \brief Get the supported output formats.
++	 * \param[in] input The input format.
++	 *
++	 * \return all supported output formats or an empty vector if there are none.
++	 */
++	std::vector<PixelFormat> formats(PixelFormat input);
++
++	/**
++	 * \brief Get the supported output sizes for the given input format and size.
++	 * \param[in] inputFormat The input format.
++	 * \param[in] inputSize The input size.
++	 *
++	 * \return The valid size ranges or an empty range if there are none.
++	 */
++	SizeRange sizes(PixelFormat inputFormat, const Size &inputSize);
++
++	/**
++	 * \brief Get the stride and the frame size.
++	 * \param[in] outputFormat The output format.
++	 * \param[in] size The output size.
++	 *
++	 * \return a tuple of the stride and the frame size, or a tuple with 0,0 if there is no valid output config.
++	 */
++	std::tuple<unsigned int, unsigned int>
++	strideAndFrameSize(const PixelFormat &outputFormat, const Size &size);
++
++	/**
++	 * \brief Configure the SwIspSimple object according to the passed in parameters.
++	 * \param[in] inputCfg The input configuration.
++	 * \param[in] outputCfgs The output configurations.
++	 * \param[in] sensorControls The sensor controls.
++	 *
++	 * \return 0 on success, a negative errno on failure.
++	 */
++	int configure(const StreamConfiguration &inputCfg,
++		      const std::vector<std::reference_wrapper<StreamConfiguration>> &outputCfgs,
++		      const ControlInfoMap &sensorControls);
++
++	/**
++	 * \brief Exports the buffers for use in processing.
++	 * \param[in] output The number of outputs requested.
++	 * \param[in] count The number of planes.
++	 * \param[out] buffers The exported buffers.
++	 *
++	 * \return count when successful, a negative return value if an error occurred.
++	 */
++	int exportBuffers(unsigned int output, unsigned int count,
++			  std::vector<std::unique_ptr<FrameBuffer>> *buffers);
++
++	/**
++	 * \brief Process the statistics gathered.
++	 * \param[in] sensorControls The sensor controls.
++	 */
++	void processStats(const ControlList &sensorControls);
++
++	/**
++	 * \brief Starts the Software ISP worker.
++	 *
++	 * \return 0 on success, any other value indicates an error.
++	 */
++	int start();
++
++	/**
++	 * \brief Stops the Software ISP worker.
++	 */
++	void stop();
++
++	/**
++	 * \brief Queues buffers for processing.
++	 * \param[in] input The input framebuffer.
++	 * \param[in] outputs The output framebuffers.
++	 *
++	 * \return 0 on success, a negative errno on failure
++	 */
++	int queueBuffers(FrameBuffer *input,
++			 const std::map<unsigned int, FrameBuffer *> &outputs);
++
++	/**
++	 * \brief Get the signal for when the sensor controls are set.
++	 *
++	 * \return The control list of the sensor controls.
++	 */
++	Signal<const ControlList &> &getSignalSetSensorControls();
++
++	/**
++	 * \brief Process the input framebuffer.
++	 * \param[in] input The input framebuffer.
++	 * \param[out] output The output framebuffer.
++	 */
++	void process(FrameBuffer *input, FrameBuffer *output);
++
++private:
++	void saveIspParams(int dummy);
++	void statsReady(int dummy);
++	void inputReady(FrameBuffer *input);
++	void outputReady(FrameBuffer *output);
++
++	std::unique_ptr<DebayerCpu> debayer_;
++	Thread ispWorkerThread_;
++	SharedMemObject<DebayerParams> sharedParams_;
++	DebayerParams debayerParams_;
++	DmaHeap dmaHeap_;
++
++	std::unique_ptr<ipa::soft::IPAProxySoft> ipa_;
++};
++
++} /* namespace libcamera */
+diff --git a/src/libcamera/software_isp/meson.build b/src/libcamera/software_isp/meson.build
+index 6d7a44d7..9464f2fd 100644
+--- a/src/libcamera/software_isp/meson.build
++++ b/src/libcamera/software_isp/meson.build
+@@ -6,3 +6,22 @@ libcamera_sources += files([
+ 	'swstats.cpp',
+ 	'swstats_cpu.cpp',
+ ])
++
++# Software ISP is enabled for 'simple' pipeline handler.
++# The 'pipelines' option value should be
++# 'simple/<Software ISP implementation>' e.g.:
++#   -Dpipelines=simple/simple
++# The source file should be named swisp_<Software ISP implementation>.cpp,
++# e.g. 'swisp_simple.cpp'.
++
++foreach pipeline : pipelines
++    pipeline = pipeline.split('/')
++    if pipeline.length() == 2 and pipeline[0] == 'simple'
++        libcamera_sources += files([
++            'swisp_' + pipeline[1] + '.cpp',
++        ])
++        # the 'break' below can be removed if/when multiple
++        # Software ISP implementations are allowed in single build
++        break
++    endif
++endforeach
+diff --git a/src/libcamera/software_isp/swisp_simple.cpp b/src/libcamera/software_isp/swisp_simple.cpp
+new file mode 100644
+index 00000000..0884166e
+--- /dev/null
++++ b/src/libcamera/software_isp/swisp_simple.cpp
+@@ -0,0 +1,238 @@
++/* SPDX-License-Identifier: LGPL-2.1-or-later */
++/*
++ * Copyright (C) 2023, Linaro Ltd
++ *
++ * swisp_simple.cpp - Simple software ISP implementation
++ */
++
++#include "libcamera/internal/software_isp/swisp_simple.h"
++
++#include <sys/mman.h>
++#include <sys/types.h>
++#include <unistd.h>
++
++#include <libcamera/formats.h>
++#include <libcamera/stream.h>
++
++#include "libcamera/internal/bayer_format.h"
++#include "libcamera/internal/framebuffer.h"
++#include "libcamera/internal/ipa_manager.h"
++#include "libcamera/internal/mapped_framebuffer.h"
++
++namespace libcamera {
++
++SwIspSimple::SwIspSimple(PipelineHandler *pipe, const ControlInfoMap &sensorControls)
++	: SoftwareIsp(pipe, sensorControls), debayer_(nullptr), debayerParams_{ 256, 256, 256, 0.5f },
++	  dmaHeap_(DmaHeap::DmaHeapFlag::Cma | DmaHeap::DmaHeapFlag::System)
++{
++	if (!dmaHeap_.isValid()) {
++		LOG(SoftwareIsp, Error) << "Failed to create DmaHeap object";
++		return;
++	}
++
++	sharedParams_ = SharedMemObject<DebayerParams>("softIsp_params");
++	if (!sharedParams_.fd().isValid()) {
++		LOG(SoftwareIsp, Error) << "Failed to create shared memory for parameters";
++		return;
++	}
++
++	std::unique_ptr<SwStatsCpu> stats;
++
++	stats = std::make_unique<SwStatsCpu>();
++	if (!stats) {
++		LOG(SoftwareIsp, Error) << "Failed to create SwStatsCpu object";
++		return;
++	}
++
++	stats->statsReady.connect(this, &SwIspSimple::statsReady);
++
++	debayer_ = std::make_unique<DebayerCpu>(std::move(stats));
++	if (!debayer_) {
++		LOG(SoftwareIsp, Error) << "Failed to create DebayerCpu object";
++		return;
++	}
++
++	debayer_->inputBufferReady.connect(this, &SwIspSimple::inputReady);
++	debayer_->outputBufferReady.connect(this, &SwIspSimple::outputReady);
++
++	ipa_ = IPAManager::createIPA<ipa::soft::IPAProxySoft>(pipe, 0, 0);
++	if (!ipa_) {
++		LOG(SoftwareIsp, Error)
++			<< "Creating IPA for software ISP failed";
++		debayer_.reset();
++		return;
++	}
++
++	int ret = ipa_->init(IPASettings{ "No cfg file", "No sensor model" },
++			     debayer_->getStatsFD(),
++			     sharedParams_.fd(),
++			     sensorControls);
++	if (ret) {
++		LOG(SoftwareIsp, Error) << "IPA init failed";
++		debayer_.reset();
++		return;
++	}
++
++	ipa_->setIspParams.connect(this, &SwIspSimple::saveIspParams);
++
++	debayer_->moveToThread(&ispWorkerThread_);
++}
++
++void SwIspSimple::processStats(const ControlList &sensorControls)
++{
++	ASSERT(ipa_);
++	ipa_->processStats(sensorControls);
++}
++
++Signal<const ControlList &> &SwIspSimple::getSignalSetSensorControls()
++{
++	ASSERT(ipa_);
++	return ipa_->setSensorControls;
++}
++
++bool SwIspSimple::isValid() const
++{
++	return !!debayer_;
++}
++
++std::vector<PixelFormat> SwIspSimple::formats(PixelFormat inputFormat)
++{
++	ASSERT(debayer_ != nullptr);
++
++	return debayer_->formats(inputFormat);
++}
++
++SizeRange SwIspSimple::sizes(PixelFormat inputFormat, const Size &inputSize)
++{
++	ASSERT(debayer_ != nullptr);
++
++	return debayer_->sizes(inputFormat, inputSize);
++}
++
++std::tuple<unsigned int, unsigned int>
++SwIspSimple::strideAndFrameSize(const PixelFormat &outputFormat, const Size &size)
++{
++	ASSERT(debayer_ != nullptr);
++
++	return debayer_->strideAndFrameSize(outputFormat, size);
++}
++
++int SwIspSimple::configure(const StreamConfiguration &inputCfg,
++			   const std::vector<std::reference_wrapper<StreamConfiguration>> &outputCfgs,
++			   const ControlInfoMap &sensorControls)
++{
++	ASSERT(ipa_ != nullptr && debayer_ != nullptr);
++
++	int ret = ipa_->configure(sensorControls);
++	if (ret < 0)
++		return ret;
++
++	return debayer_->configure(inputCfg, outputCfgs);
++}
++
++int SwIspSimple::exportBuffers(unsigned int output, unsigned int count,
++			       std::vector<std::unique_ptr<FrameBuffer>> *buffers)
++{
++	ASSERT(debayer_ != nullptr);
++
++	/* single output for now */
++	if (output >= 1)
++		return -EINVAL;
++
++	for (unsigned int i = 0; i < count; i++) {
++		const std::string name = "frame-" + std::to_string(i);
++		const size_t frameSize = debayer_->frameSize();
++
++		FrameBuffer::Plane outPlane;
++		outPlane.fd = SharedFD(dmaHeap_.alloc(name.c_str(), frameSize));
++		if (!outPlane.fd.isValid()) {
++			LOG(SoftwareIsp, Error)
++				<< "failed to allocate a dma_buf";
++			return -ENOMEM;
++		}
++		outPlane.offset = 0;
++		outPlane.length = frameSize;
++
++		std::vector<FrameBuffer::Plane> planes{ outPlane };
++		buffers->emplace_back(std::make_unique<FrameBuffer>(std::move(planes)));
++	}
++
++	return count;
++}
++
++int SwIspSimple::queueBuffers(FrameBuffer *input,
++			      const std::map<unsigned int, FrameBuffer *> &outputs)
++{
++	unsigned int mask = 0;
++
++	/*
++	 * Validate the outputs as a sanity check: at least one output is
++	 * required, all outputs must reference a valid stream and no two
++	 * outputs can reference the same stream.
++	 */
++	if (outputs.empty())
++		return -EINVAL;
++
++	for (auto [index, buffer] : outputs) {
++		if (!buffer)
++			return -EINVAL;
++		if (index >= 1) /* only single stream atm */
++			return -EINVAL;
++		if (mask & (1 << index))
++			return -EINVAL;
++
++		mask |= 1 << index;
++	}
++
++	process(input, outputs.at(0));
++
++	return 0;
++}
++
++int SwIspSimple::start()
++{
++	int ret = ipa_->start();
++	if (ret)
++		return ret;
++
++	ispWorkerThread_.start();
++	return 0;
++}
++
++void SwIspSimple::stop()
++{
++	ispWorkerThread_.exit();
++	ispWorkerThread_.wait();
++
++	ipa_->stop();
++}
++
++void SwIspSimple::process(FrameBuffer *input, FrameBuffer *output)
++{
++	debayer_->invokeMethod(&DebayerCpu::process,
++			       ConnectionTypeQueued, input, output, debayerParams_);
++}
++
++void SwIspSimple::saveIspParams([[maybe_unused]] int dummy)
++{
++	debayerParams_ = *sharedParams_;
++}
++
++void SwIspSimple::statsReady(int dummy)
++{
++	ispStatsReady.emit(dummy);
++}
++
++void SwIspSimple::inputReady(FrameBuffer *input)
++{
++	inputBufferReady.emit(input);
++}
++
++void SwIspSimple::outputReady(FrameBuffer *output)
++{
++	outputBufferReady.emit(output);
++}
++
++REGISTER_SOFTWAREISP(SwIspSimple)
++
++} /* namespace libcamera */
+-- 
+2.43.0
+