[libcamera-devel] [PATCH v2 06/11] libcamera: ipa: ipu3: Add an IPA skeleton for the IPU3 pipeline
Jacopo Mondi
jacopo at jmondi.org
Thu Jan 7 13:32:52 CET 2021
Hi Niklas,
On Tue, Dec 29, 2020 at 05:03:13PM +0100, Niklas Söderlund wrote:
> Add an empty IPA skeleton for the IPU3 pipeline. The skeleton IPA
> handles the flow of parameter and statistic buffers but does not read or
> write anything in the buffers. It also allows the IPA to set sensor
> controls but does not implement any logic to set optimal values and
> instead sets the V4L2 exposure and gain controls to max and keeps them
> at that setting.
>
> This IPA is meant as a base to allow the pipeline handler to be wired up
> to an IPA. The image algorithms can then later be added to the IPA
> independently from also having to add plumbing to the pipeline handler.
>
> Signed-off-by: Niklas Söderlund <niklas.soderlund at ragnatech.se>
> Acked-by: Kieran Bingham <kieran.bingham at ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo at jmondi.org>
Thanks
j
> ---
> * Changes since v1
> - Updated commit message.
> - Rename IPU3_IPA_EVENT_PARSE_STAT to IPU3_IPA_EVENT_PARSE_STAT.
> - Sort and drop unused headers.
> - Fix style issue in meson.build and add dependency on libatomic.
> - Switch to MappedFrameBuffer interface.
> - Add result of IPA configuration status.
> ---
> include/libcamera/ipa/ipu3.h | 23 ++++
> src/ipa/ipu3/ipu3.cpp | 236 +++++++++++++++++++++++++++++++++++
> src/ipa/ipu3/meson.build | 21 ++++
> src/ipa/meson.build | 2 +-
> 4 files changed, 281 insertions(+), 1 deletion(-)
> create mode 100644 include/libcamera/ipa/ipu3.h
> create mode 100644 src/ipa/ipu3/ipu3.cpp
> create mode 100644 src/ipa/ipu3/meson.build
>
> diff --git a/include/libcamera/ipa/ipu3.h b/include/libcamera/ipa/ipu3.h
> new file mode 100644
> index 0000000000000000..1bcf3591f9fe36a9
> --- /dev/null
> +++ b/include/libcamera/ipa/ipu3.h
> @@ -0,0 +1,23 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2020, Google Inc.
> + *
> + * ipu3.h - Image Processing Algorithm interface for IPU3
> + */
> +#ifndef __LIBCAMERA_IPA_INTERFACE_IPU3_H__
> +#define __LIBCAMERA_IPA_INTERFACE_IPU3_H__
> +
> +#ifndef __DOXYGEN__
> +
> +enum IPU3Operations {
> + IPU3_IPA_STATUS_CONFIGURATION = 1,
> + IPU3_IPA_ACTION_SET_SENSOR_CONTROLS = 2,
> + IPU3_IPA_ACTION_PARAM_FILLED = 3,
> + IPU3_IPA_ACTION_METADATA_READY = 4,
> + IPU3_IPA_EVENT_STAT_READY = 5,
> + IPU3_IPA_EVENT_FILL_PARAMS = 6,
> +};
> +
> +#endif /* __DOXYGEN__ */
> +
> +#endif /* __LIBCAMERA_IPA_INTERFACE_IPU3_H__ */
> diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp
> new file mode 100644
> index 0000000000000000..809a3eec398a8e57
> --- /dev/null
> +++ b/src/ipa/ipu3/ipu3.cpp
> @@ -0,0 +1,236 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2020, Google Inc.
> + *
> + * ipu3.cpp - IPU3 Image Processing Algorithms
> + */
> +
> +#include <libcamera/ipa/ipu3.h>
> +
> +#include <sys/mman.h>
> +
> +#include <linux/intel-ipu3.h>
> +#include <linux/v4l2-controls.h>
> +
> +#include <libcamera/buffer.h>
> +#include <libcamera/control_ids.h>
> +#include <libcamera/ipa/ipa_interface.h>
> +#include <libcamera/ipa/ipa_module_info.h>
> +#include <libcamera/request.h>
> +
> +#include <libipa/ipa_interface_wrapper.h>
> +
> +#include "libcamera/internal/buffer.h"
> +#include "libcamera/internal/log.h"
> +
> +namespace libcamera {
> +
> +LOG_DEFINE_CATEGORY(IPAIPU3)
> +
> +class IPAIPU3 : public IPAInterface
> +{
> +public:
> + int init([[maybe_unused]] const IPASettings &settings) override
> + {
> + return 0;
> + }
> + int start([[maybe_unused]] const IPAOperationData &data,
> + [[maybe_unused]] IPAOperationData *result) override { return 0; }
> + void stop() override {}
> +
> + void configure(const CameraSensorInfo &info,
> + const std::map<unsigned int, IPAStream> &streamConfig,
> + const std::map<unsigned int, const ControlInfoMap &> &entityControls,
> + const IPAOperationData &ipaConfig,
> + IPAOperationData *response) override;
> + void mapBuffers(const std::vector<IPABuffer> &buffers) override;
> + void unmapBuffers(const std::vector<unsigned int> &ids) override;
> + void processEvent(const IPAOperationData &event) override;
> +
> +private:
> + void fillParams(unsigned int frame, ipu3_uapi_params *params,
> + const ControlList &controls);
> +
> + void parseStatistics(unsigned int frame,
> + const ipu3_uapi_stats_3a *stats);
> +
> + void setControls(unsigned int frame);
> +
> + std::map<unsigned int, MappedFrameBuffer> buffers_;
> +
> + ControlInfoMap ctrls_;
> +
> + /* Camera sensor controls. */
> + uint32_t exposure_;
> + uint32_t minExposure_;
> + uint32_t maxExposure_;
> + uint32_t gain_;
> + uint32_t minGain_;
> + uint32_t maxGain_;
> +};
> +
> +void IPAIPU3::configure([[maybe_unused]] const CameraSensorInfo &info,
> + [[maybe_unused]] const std::map<unsigned int, IPAStream> &streamConfig,
> + const std::map<unsigned int, const ControlInfoMap &> &entityControls,
> + [[maybe_unused]] const IPAOperationData &ipaConfig,
> + [[maybe_unused]] IPAOperationData *result)
> +{
> + result->operation = IPU3_IPA_STATUS_CONFIGURATION;
> +
> + if (entityControls.empty())
> + return;
> +
> + ctrls_ = entityControls.at(0);
> +
> + const auto itExp = ctrls_.find(V4L2_CID_EXPOSURE);
> + if (itExp == ctrls_.end()) {
> + LOG(IPAIPU3, Error) << "Can't find exposure control";
> + return;
> + }
> +
> + const auto itGain = ctrls_.find(V4L2_CID_ANALOGUE_GAIN);
> + if (itGain == ctrls_.end()) {
> + LOG(IPAIPU3, Error) << "Can't find gain control";
> + return;
> + }
> +
> + minExposure_ = std::max<uint32_t>(itExp->second.min().get<int32_t>(), 1);
> + maxExposure_ = itExp->second.max().get<int32_t>();
> + exposure_ = maxExposure_;
> +
> + minGain_ = std::max<uint32_t>(itGain->second.min().get<int32_t>(), 1);
> + maxGain_ = itGain->second.max().get<int32_t>();
> + gain_ = maxGain_;
> +
> + setControls(0);
> +
> + result->data.push_back(1);
> +}
> +
> +void IPAIPU3::mapBuffers(const std::vector<IPABuffer> &buffers)
> +{
> + for (const IPABuffer &buffer : buffers) {
> + const FrameBuffer fb(buffer.planes);
> + buffers_.emplace(buffer.id,
> + MappedFrameBuffer(&fb, PROT_READ | PROT_WRITE));
> + }
> +}
> +
> +void IPAIPU3::unmapBuffers(const std::vector<unsigned int> &ids)
> +{
> + for (unsigned int id : ids) {
> + auto it = buffers_.find(id);
> + if (it == buffers_.end())
> + continue;
> +
> + buffers_.erase(id);
> + }
> +}
> +
> +void IPAIPU3::processEvent(const IPAOperationData &event)
> +{
> + switch (event.operation) {
> + case IPU3_IPA_EVENT_STAT_READY: {
> + unsigned int frame = event.data[0];
> + unsigned int bufferId = event.data[1];
> +
> + auto it = buffers_.find(bufferId);
> + if (it == buffers_.end()) {
> + LOG(IPAIPU3, Error) << "Could not find stats buffer!";
> + return;
> + }
> +
> + Span<uint8_t> mem = it->second.maps()[0];
> + const ipu3_uapi_stats_3a *stats =
> + reinterpret_cast<ipu3_uapi_stats_3a *>(mem.data());
> +
> + parseStatistics(frame, stats);
> + break;
> + }
> + case IPU3_IPA_EVENT_FILL_PARAMS: {
> + unsigned int frame = event.data[0];
> + unsigned int bufferId = event.data[1];
> +
> + auto it = buffers_.find(bufferId);
> + if (it == buffers_.end()) {
> + LOG(IPAIPU3, Error) << "Could not find param buffer!";
> + return;
> + }
> +
> + Span<uint8_t> mem = it->second.maps()[0];
> + ipu3_uapi_params *params =
> + reinterpret_cast<ipu3_uapi_params *>(mem.data());
> +
> + fillParams(frame, params, event.controls[0]);
> + break;
> + }
> + default:
> + LOG(IPAIPU3, Error) << "Unknown event " << event.operation;
> + break;
> + }
> +}
> +
> +void IPAIPU3::fillParams(unsigned int frame, ipu3_uapi_params *params,
> + [[maybe_unused]] const ControlList &controls)
> +{
> + /* Prepare parameters buffer. */
> + memset(params, 0, sizeof(*params));
> +
> + /* \todo Fill in parameters buffer. */
> +
> + IPAOperationData op;
> + op.operation = IPU3_IPA_ACTION_PARAM_FILLED;
> +
> + queueFrameAction.emit(frame, op);
> +
> + /* \todo Calculate new values for exposure_ and gain_. */
> + setControls(frame);
> +}
> +
> +void IPAIPU3::parseStatistics(unsigned int frame,
> + [[maybe_unused]] const ipu3_uapi_stats_3a *stats)
> +{
> + ControlList ctrls(controls::controls);
> +
> + /* \todo React to statistics and update internal state machine. */
> + /* \todo Add meta-data information to ctrls. */
> +
> + IPAOperationData op;
> + op.operation = IPU3_IPA_ACTION_METADATA_READY;
> + op.controls.push_back(ctrls);
> +
> + queueFrameAction.emit(frame, op);
> +}
> +
> +void IPAIPU3::setControls(unsigned int frame)
> +{
> + IPAOperationData op;
> + op.operation = IPU3_IPA_ACTION_SET_SENSOR_CONTROLS;
> +
> + ControlList ctrls(ctrls_);
> + ctrls.set(V4L2_CID_EXPOSURE, static_cast<int32_t>(exposure_));
> + ctrls.set(V4L2_CID_ANALOGUE_GAIN, static_cast<int32_t>(gain_));
> + op.controls.push_back(ctrls);
> +
> + queueFrameAction.emit(frame, op);
> +}
> +
> +/*
> + * External IPA module interface
> + */
> +
> +extern "C" {
> +const struct IPAModuleInfo ipaModuleInfo = {
> + IPA_MODULE_API_VERSION,
> + 1,
> + "PipelineHandlerIPU3",
> + "ipu3",
> +};
> +
> +struct ipa_context *ipaCreate()
> +{
> + return new IPAInterfaceWrapper(std::make_unique<IPAIPU3>());
> +}
> +}
> +
> +} /* namespace libcamera */
> diff --git a/src/ipa/ipu3/meson.build b/src/ipa/ipu3/meson.build
> new file mode 100644
> index 0000000000000000..444c82453eac42ff
> --- /dev/null
> +++ b/src/ipa/ipu3/meson.build
> @@ -0,0 +1,21 @@
> +# SPDX-License-Identifier: CC0-1.0
> +
> +ipa_name = 'ipa_ipu3'
> +
> +mod = shared_module(ipa_name,
> + 'ipu3.cpp',
> + name_prefix : '',
> + include_directories : [ ipa_includes, libipa_includes ],
> + dependencies : [ libatomic, libcamera_dep ],
> + link_with : libipa,
> + install : true,
> + install_dir : ipa_install_dir)
> +
> +if ipa_sign_module
> + custom_target(ipa_name + '.so.sign',
> + input : mod,
> + output : ipa_name + '.so.sign',
> + command : [ ipa_sign, ipa_priv_key, '@INPUT@', '@OUTPUT@' ],
> + install : false,
> + build_by_default : true)
> +endif
> diff --git a/src/ipa/meson.build b/src/ipa/meson.build
> index 5a5de267c1477d24..9d623f227a1f9feb 100644
> --- a/src/ipa/meson.build
> +++ b/src/ipa/meson.build
> @@ -19,7 +19,7 @@ subdir('libipa')
>
> ipa_sign = files('ipa-sign.sh')
>
> -ipas = ['raspberrypi', 'rkisp1', 'vimc']
> +ipas = ['ipu3', 'raspberrypi', 'rkisp1', 'vimc']
> ipa_names = []
>
> foreach pipeline : get_option('pipelines')
> --
> 2.29.2
>
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel at lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel
More information about the libcamera-devel
mailing list