about summary refs log tree commit diff
path: root/users/flokli/ipu6-softisp/libcamera/0010-libcamera-introduce-SoftwareIsp.patch
diff options
context:
space:
mode:
Diffstat (limited to 'users/flokli/ipu6-softisp/libcamera/0010-libcamera-introduce-SoftwareIsp.patch')
-rw-r--r--users/flokli/ipu6-softisp/libcamera/0010-libcamera-introduce-SoftwareIsp.patch507
1 files changed, 507 insertions, 0 deletions
diff --git a/users/flokli/ipu6-softisp/libcamera/0010-libcamera-introduce-SoftwareIsp.patch b/users/flokli/ipu6-softisp/libcamera/0010-libcamera-introduce-SoftwareIsp.patch
new file mode 100644
index 000000000000..9f2d66c2f8b6
--- /dev/null
+++ b/users/flokli/ipu6-softisp/libcamera/0010-libcamera-introduce-SoftwareIsp.patch
@@ -0,0 +1,507 @@
+From ad41ea12fe4b8ca0ace20781c775a63ed0d66f4c Mon Sep 17 00:00:00 2001
+From: Andrey Konovalov <andrey.konovalov@linaro.org>
+Date: Mon, 11 Mar 2024 15:15:14 +0100
+Subject: [PATCH 10/21] libcamera: introduce SoftwareIsp
+
+Doxygen documentation by Dennis Bonke.
+
+Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> # sc8280xp Lenovo x13s
+Tested-by: Pavel Machek <pavel@ucw.cz>
+Reviewed-by: Pavel Machek <pavel@ucw.cz>
+Co-developed-by: Dennis Bonke <admin@dennisbonke.com>
+Signed-off-by: Dennis Bonke <admin@dennisbonke.com>
+Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ .../internal/software_isp/meson.build         |   1 +
+ .../internal/software_isp/software_isp.h      |  98 +++++
+ src/libcamera/software_isp/meson.build        |   1 +
+ src/libcamera/software_isp/software_isp.cpp   | 349 ++++++++++++++++++
+ 4 files changed, 449 insertions(+)
+ create mode 100644 include/libcamera/internal/software_isp/software_isp.h
+ create mode 100644 src/libcamera/software_isp/software_isp.cpp
+
+diff --git a/include/libcamera/internal/software_isp/meson.build b/include/libcamera/internal/software_isp/meson.build
+index a620e16d..508ddddc 100644
+--- a/include/libcamera/internal/software_isp/meson.build
++++ b/include/libcamera/internal/software_isp/meson.build
+@@ -2,5 +2,6 @@
+ 
+ libcamera_internal_headers += files([
+     'debayer_params.h',
++    'software_isp.h',
+     'swisp_stats.h',
+ ])
+diff --git a/include/libcamera/internal/software_isp/software_isp.h b/include/libcamera/internal/software_isp/software_isp.h
+new file mode 100644
+index 00000000..8d25e979
+--- /dev/null
++++ b/include/libcamera/internal/software_isp/software_isp.h
+@@ -0,0 +1,98 @@
++/* SPDX-License-Identifier: LGPL-2.1-or-later */
++/*
++ * Copyright (C) 2023, Linaro Ltd
++ *
++ * software_isp.h - Simple software ISP implementation
++ */
++
++#pragma once
++
++#include <functional>
++#include <initializer_list>
++#include <map>
++#include <memory>
++#include <string>
++#include <tuple>
++#include <vector>
++
++#include <libcamera/base/class.h>
++#include <libcamera/base/log.h>
++#include <libcamera/base/signal.h>
++#include <libcamera/base/thread.h>
++
++#include <libcamera/geometry.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/pipeline_handler.h"
++#include "libcamera/internal/shared_mem_object.h"
++#include "libcamera/internal/software_isp/debayer_params.h"
++
++namespace libcamera {
++
++class DebayerCpu;
++class FrameBuffer;
++class PixelFormat;
++struct StreamConfiguration;
++
++LOG_DECLARE_CATEGORY(SoftwareIsp)
++
++class SoftwareIsp
++{
++public:
++	SoftwareIsp(PipelineHandler *pipe, const ControlInfoMap &sensorControls);
++	~SoftwareIsp();
++
++	int loadConfiguration([[maybe_unused]] const std::string &filename) { return 0; }
++
++	bool isValid() const;
++
++	std::vector<PixelFormat> formats(PixelFormat input);
++
++	SizeRange sizes(PixelFormat inputFormat, const Size &inputSize);
++
++	std::tuple<unsigned int, unsigned int>
++	strideAndFrameSize(const PixelFormat &outputFormat, const Size &size);
++
++	int configure(const StreamConfiguration &inputCfg,
++		      const std::vector<std::reference_wrapper<StreamConfiguration>> &outputCfgs,
++		      const ControlInfoMap &sensorControls);
++
++	int exportBuffers(unsigned int output, unsigned int count,
++			  std::vector<std::unique_ptr<FrameBuffer>> *buffers);
++
++	void processStats(const ControlList &sensorControls);
++
++	int start();
++	void stop();
++
++	int queueBuffers(FrameBuffer *input,
++			 const std::map<unsigned int, FrameBuffer *> &outputs);
++
++	void process(FrameBuffer *input, FrameBuffer *output);
++
++	Signal<FrameBuffer *> inputBufferReady;
++	Signal<FrameBuffer *> outputBufferReady;
++	Signal<int> ispStatsReady;
++	Signal<const ControlList &> setSensorControls;
++
++private:
++	void saveIspParams(int dummy);
++	void setSensorCtrls(const ControlList &sensorControls);
++	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 71b46539..e9266e54 100644
+--- a/src/libcamera/software_isp/meson.build
++++ b/src/libcamera/software_isp/meson.build
+@@ -10,5 +10,6 @@ endif
+ libcamera_sources += files([
+     'debayer.cpp',
+     'debayer_cpu.cpp',
++    'software_isp.cpp',
+     'swstats_cpu.cpp',
+ ])
+diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp
+new file mode 100644
+index 00000000..388b4496
+--- /dev/null
++++ b/src/libcamera/software_isp/software_isp.cpp
+@@ -0,0 +1,349 @@
++/* SPDX-License-Identifier: LGPL-2.1-or-later */
++/*
++ * Copyright (C) 2023, Linaro Ltd
++ *
++ * software_isp.cpp - Simple software ISP implementation
++ */
++
++#include "libcamera/internal/software_isp/software_isp.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"
++
++#include "debayer_cpu.h"
++
++/**
++ * \file software_isp.cpp
++ * \brief Simple software ISP implementation
++ */
++
++namespace libcamera {
++
++LOG_DEFINE_CATEGORY(SoftwareIsp)
++
++/**
++ * \class SoftwareIsp
++ * \brief Class for the Software ISP
++ */
++
++/**
++ * \var SoftwareIsp::inputBufferReady
++ * \brief A signal emitted when the input frame buffer completes
++ */
++
++/**
++ * \var SoftwareIsp::outputBufferReady
++ * \brief A signal emitted when the output frame buffer completes
++ */
++
++/**
++ * \var SoftwareIsp::ispStatsReady
++ * \brief A signal emitted when the statistics for IPA are ready
++ *
++ * The int parameter isn't actually used.
++ */
++
++/**
++ * \var SoftwareIsp::setSensorControls
++ * \brief A signal emitted when the values to write to the sensor controls are ready
++ */
++
++/**
++ * \brief Constructs SoftwareIsp object
++ * \param[in] pipe The pipeline handler in use
++ * \param[in] sensorControls ControlInfoMap describing the controls supported by the sensor
++ */
++SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const ControlInfoMap &sensorControls)
++	: debayer_(nullptr),
++	  debayerParams_{ DebayerParams::kGain10, DebayerParams::kGain10, DebayerParams::kGain10, 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_) {
++		LOG(SoftwareIsp, Error) << "Failed to create shared memory for parameters";
++		return;
++	}
++
++	auto stats = std::make_unique<SwStatsCpu>();
++	if (!stats->isValid()) {
++		LOG(SoftwareIsp, Error) << "Failed to create SwStatsCpu object";
++		return;
++	}
++	stats->statsReady.connect(this, &SoftwareIsp::statsReady);
++
++	debayer_ = std::make_unique<DebayerCpu>(std::move(stats));
++	debayer_->inputBufferReady.connect(this, &SoftwareIsp::inputReady);
++	debayer_->outputBufferReady.connect(this, &SoftwareIsp::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, &SoftwareIsp::saveIspParams);
++	ipa_->setSensorControls.connect(this, &SoftwareIsp::setSensorCtrls);
++
++	debayer_->moveToThread(&ispWorkerThread_);
++}
++
++SoftwareIsp::~SoftwareIsp()
++{
++	/* make sure to destroy the DebayerCpu before the ispWorkerThread_ is gone */
++	debayer_.reset();
++}
++
++/**
++ * \fn int SoftwareIsp::loadConfiguration([[maybe_unused]] const std::string &filename)
++ * \brief Load a configuration from a file
++ * \param[in] filename The file to load the configuration data from
++ *
++ * Currently is a stub doing nothing and always returning "success".
++ *
++ * \return 0 on success
++ */
++
++/**
++ * \brief Process the statistics gathered
++ * \param[in] sensorControls The sensor controls
++ *
++ * Requests the IPA to calculate new parameters for ISP and new control
++ * values for the sensor.
++ */
++void SoftwareIsp::processStats(const ControlList &sensorControls)
++{
++	ASSERT(ipa_);
++	ipa_->processStats(sensorControls);
++}
++
++/**
++ * \brief Check the validity of Software Isp object
++ * \return True if Software Isp is valid, false otherwise
++ */
++bool SoftwareIsp::isValid() const
++{
++	return !!debayer_;
++}
++
++/**
++  * \brief Get the output formats supported for the given input format
++  * \param[in] inputFormat The input format
++  * \return All the supported output formats or an empty vector if there are none
++  */
++std::vector<PixelFormat> SoftwareIsp::formats(PixelFormat inputFormat)
++{
++	ASSERT(debayer_ != nullptr);
++
++	return debayer_->formats(inputFormat);
++}
++
++/**
++ * \brief Get the supported output sizes for the given input format and size
++ * \param[in] inputFormat The input format
++ * \param[in] inputSize The input frame size
++ * \return The valid size range or an empty range if there are none
++ */
++SizeRange SoftwareIsp::sizes(PixelFormat inputFormat, const Size &inputSize)
++{
++	ASSERT(debayer_ != nullptr);
++
++	return debayer_->sizes(inputFormat, inputSize);
++}
++
++/**
++ * Get the output stride and the frame size in bytes for the given output format and size
++ * \param[in] outputFormat The output format
++ * \param[in] size The output size (width and height in pixels)
++ * \return A tuple of the stride and the frame size in bytes, or a tuple of 0,0
++ * if there is no valid output config
++ */
++std::tuple<unsigned int, unsigned int>
++SoftwareIsp::strideAndFrameSize(const PixelFormat &outputFormat, const Size &size)
++{
++	ASSERT(debayer_ != nullptr);
++
++	return debayer_->strideAndFrameSize(outputFormat, size);
++}
++
++/**
++ * \brief Configure the SoftwareIsp object according to the passed in parameters
++ * \param[in] inputCfg The input configuration
++ * \param[in] outputCfgs The output configurations
++ * \param[in] sensorControls ControlInfoMap of the controls supported by the sensor
++ * \return 0 on success, a negative errno on failure
++ */
++int SoftwareIsp::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);
++}
++
++/**
++ * \brief Export the buffers from the Software ISP
++ * \param[in] output Output stream index exporting the buffers
++ * \param[in] count Number of buffers to allocate
++ * \param[out] buffers Vector to store the allocated buffers
++ * \return The number of allocated buffers on success or a negative error code
++ * otherwise
++ */
++int SoftwareIsp::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;
++}
++
++/**
++ * \brief Queue buffers to Software ISP
++ * \param[in] input The input framebuffer
++ * \param[in] outputs The container holding the output stream indexes and
++ * their respective frame buffer outputs
++ * \return 0 on success, a negative errno on failure
++ */
++int SoftwareIsp::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;
++}
++
++/**
++ * \brief Starts the Software ISP streaming operation
++ * \return 0 on success, any other value indicates an error
++ */
++int SoftwareIsp::start()
++{
++	int ret = ipa_->start();
++	if (ret)
++		return ret;
++
++	ispWorkerThread_.start();
++	return 0;
++}
++
++/**
++ * \brief Stops the Software ISP streaming operation
++ */
++void SoftwareIsp::stop()
++{
++	ispWorkerThread_.exit();
++	ispWorkerThread_.wait();
++
++	ipa_->stop();
++}
++
++/**
++ * \brief Passes the input framebuffer to the ISP worker to process
++ * \param[in] input The input framebuffer
++ * \param[out] output The framebuffer to write the processed frame to
++ */
++void SoftwareIsp::process(FrameBuffer *input, FrameBuffer *output)
++{
++	debayer_->invokeMethod(&DebayerCpu::process,
++			       ConnectionTypeQueued, input, output, debayerParams_);
++}
++
++void SoftwareIsp::saveIspParams([[maybe_unused]] int dummy)
++{
++	debayerParams_ = *sharedParams_;
++}
++
++void SoftwareIsp::setSensorCtrls(const ControlList &sensorControls)
++{
++	setSensorControls.emit(sensorControls);
++}
++
++void SoftwareIsp::statsReady(int dummy)
++{
++	ispStatsReady.emit(dummy);
++}
++
++void SoftwareIsp::inputReady(FrameBuffer *input)
++{
++	inputBufferReady.emit(input);
++}
++
++void SoftwareIsp::outputReady(FrameBuffer *output)
++{
++	outputBufferReady.emit(output);
++}
++
++} /* namespace libcamera */
+-- 
+2.43.2
+