[libcamera-devel] [PATCH v2 13/18] libcamera: software_isp: add Simple SoftwareIsp implementation

Barnabás Pőcze pobrn at protonmail.com
Sat Jan 13 17:30:05 CET 2024


Hi


2024. január 13., szombat 15:22 keltezéssel, Hans de Goede via libcamera-devel írta:

> From: Andrey Konovalov <andrey.konovalov at linaro.org>
> 
> 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 at linaro.org>
> Co-authored-by: Dennis Bonke <admin at dennisbonke.com>
> Signed-off-by: Dennis Bonke <admin at dennisbonke.com>
> Co-authored-by: Hans de Goede <hdegoede at redhat.com>
> Signed-off-by: Hans de Goede <hdegoede at redhat.com>
> Tested-by: Bryan O'Donoghue <bryan.odonoghue at linaro.org> # sc8280xp Lenovo x13s
> Tested-by: Pavel Machek <pavel at 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() {}

~SwIspSimple() = default;


> +
> +	/**
> +	 * \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>();

You can just say

  auto stats = std::make_unique<SwStatsCpu>();


> +	if (!stats) {

std::make_unique should never return nullptr.


> +		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_) {

Same here.


> +		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_);
> +}
> [...]


Regards,
Barnabás Pőcze


More information about the libcamera-devel mailing list