[{"id":14463,"web_url":"https://patchwork.libcamera.org/comment/14463/","msgid":"<X/aY4c9Nryc3ze3h@pendragon.ideasonboard.com>","date":"2021-01-07T05:15:13","subject":"Re: [libcamera-devel] [PATCH v2 06/11] libcamera: ipa: ipu3: Add an\n\tIPA skeleton for the IPU3 pipeline","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Niklas,\n\nThank you for the patch.\n\nOn Tue, Dec 29, 2020 at 05:03:13PM +0100, Niklas Söderlund wrote:\n> Add an empty IPA skeleton for the IPU3 pipeline. The skeleton IPA\n> handles the flow of parameter and statistic buffers but does not read or\n> write anything in the buffers. It also allows the IPA to set sensor\n> controls but does not implement any logic to set optimal values and\n> instead sets the V4L2 exposure and gain controls to max and keeps them\n> at that setting.\n> \n> This IPA is meant as a base to allow the pipeline handler to be wired up\n> to an IPA. The image algorithms can then later be added to the IPA\n> independently from also having to add plumbing to the pipeline handler.\n> \n> Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> Acked-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> ---\n> * Changes since v1\n> - Updated commit message.\n> - Rename IPU3_IPA_EVENT_PARSE_STAT to IPU3_IPA_EVENT_PARSE_STAT.\n> - Sort and drop unused headers.\n> - Fix style issue in meson.build and add dependency on libatomic.\n> - Switch to MappedFrameBuffer interface.\n> - Add result of IPA configuration status.\n> ---\n>  include/libcamera/ipa/ipu3.h |  23 ++++\n>  src/ipa/ipu3/ipu3.cpp        | 236 +++++++++++++++++++++++++++++++++++\n>  src/ipa/ipu3/meson.build     |  21 ++++\n>  src/ipa/meson.build          |   2 +-\n>  4 files changed, 281 insertions(+), 1 deletion(-)\n>  create mode 100644 include/libcamera/ipa/ipu3.h\n>  create mode 100644 src/ipa/ipu3/ipu3.cpp\n>  create mode 100644 src/ipa/ipu3/meson.build\n> \n> diff --git a/include/libcamera/ipa/ipu3.h b/include/libcamera/ipa/ipu3.h\n> new file mode 100644\n> index 0000000000000000..1bcf3591f9fe36a9\n> --- /dev/null\n> +++ b/include/libcamera/ipa/ipu3.h\n> @@ -0,0 +1,23 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2020, Google Inc.\n> + *\n> + * ipu3.h - Image Processing Algorithm interface for IPU3\n> + */\n> +#ifndef __LIBCAMERA_IPA_INTERFACE_IPU3_H__\n> +#define __LIBCAMERA_IPA_INTERFACE_IPU3_H__\n> +\n> +#ifndef __DOXYGEN__\n> +\n> +enum IPU3Operations {\n> +\tIPU3_IPA_STATUS_CONFIGURATION = 1,\n> +\tIPU3_IPA_ACTION_SET_SENSOR_CONTROLS = 2,\n> +\tIPU3_IPA_ACTION_PARAM_FILLED = 3,\n> +\tIPU3_IPA_ACTION_METADATA_READY = 4,\n> +\tIPU3_IPA_EVENT_STAT_READY = 5,\n> +\tIPU3_IPA_EVENT_FILL_PARAMS = 6,\n> +};\n> +\n> +#endif /* __DOXYGEN__ */\n> +\n> +#endif /* __LIBCAMERA_IPA_INTERFACE_IPU3_H__ */\n> diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp\n> new file mode 100644\n> index 0000000000000000..809a3eec398a8e57\n> --- /dev/null\n> +++ b/src/ipa/ipu3/ipu3.cpp\n> @@ -0,0 +1,236 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2020, Google Inc.\n> + *\n> + * ipu3.cpp - IPU3 Image Processing Algorithms\n> + */\n> +\n> +#include <libcamera/ipa/ipu3.h>\n> +\n\nI think you need stdint.h for uint32_t.\n\n> +#include <sys/mman.h>\n> +\n> +#include <linux/intel-ipu3.h>\n> +#include <linux/v4l2-controls.h>\n> +\n> +#include <libcamera/buffer.h>\n> +#include <libcamera/control_ids.h>\n> +#include <libcamera/ipa/ipa_interface.h>\n> +#include <libcamera/ipa/ipa_module_info.h>\n> +#include <libcamera/request.h>\n> +\n> +#include <libipa/ipa_interface_wrapper.h>\n> +\n> +#include \"libcamera/internal/buffer.h\"\n> +#include \"libcamera/internal/log.h\"\n> +\n> +namespace libcamera {\n> +\n> +LOG_DEFINE_CATEGORY(IPAIPU3)\n> +\n> +class IPAIPU3 : public IPAInterface\n> +{\n> +public:\n> +\tint init([[maybe_unused]] const IPASettings &settings) override\n> +\t{\n> +\t\treturn 0;\n> +\t}\n> +\tint start([[maybe_unused]] const IPAOperationData &data,\n> +\t\t  [[maybe_unused]] IPAOperationData *result) override { return 0; }\n> +\tvoid stop() override {}\n> +\n> +\tvoid configure(const CameraSensorInfo &info,\n> +\t\t       const std::map<unsigned int, IPAStream> &streamConfig,\n> +\t\t       const std::map<unsigned int, const ControlInfoMap &> &entityControls,\n> +\t\t       const IPAOperationData &ipaConfig,\n> +\t\t       IPAOperationData *response) override;\n> +\tvoid mapBuffers(const std::vector<IPABuffer> &buffers) override;\n> +\tvoid unmapBuffers(const std::vector<unsigned int> &ids) override;\n> +\tvoid processEvent(const IPAOperationData &event) override;\n> +\n> +private:\n> +\tvoid fillParams(unsigned int frame, ipu3_uapi_params *params,\n> +\t\t\tconst ControlList &controls);\n> +\n> +\tvoid parseStatistics(unsigned int frame,\n> +\t\t\t     const ipu3_uapi_stats_3a *stats);\n> +\n> +\tvoid setControls(unsigned int frame);\n> +\n> +\tstd::map<unsigned int, MappedFrameBuffer> buffers_;\n> +\n> +\tControlInfoMap ctrls_;\n> +\n> +\t/* Camera sensor controls. */\n> +\tuint32_t exposure_;\n> +\tuint32_t minExposure_;\n> +\tuint32_t maxExposure_;\n> +\tuint32_t gain_;\n> +\tuint32_t minGain_;\n> +\tuint32_t maxGain_;\n> +};\n> +\n> +void IPAIPU3::configure([[maybe_unused]] const CameraSensorInfo &info,\n> +\t\t\t[[maybe_unused]] const std::map<unsigned int, IPAStream> &streamConfig,\n> +\t\t\tconst std::map<unsigned int, const ControlInfoMap &> &entityControls,\n> +\t\t\t[[maybe_unused]] const IPAOperationData &ipaConfig,\n> +\t\t\t[[maybe_unused]] IPAOperationData *result)\n> +{\n> +\tresult->operation = IPU3_IPA_STATUS_CONFIGURATION;\n> +\n> +\tif (entityControls.empty())\n> +\t\treturn;\n> +\n> +\tctrls_ = entityControls.at(0);\n> +\n> +\tconst auto itExp = ctrls_.find(V4L2_CID_EXPOSURE);\n> +\tif (itExp == ctrls_.end()) {\n> +\t\tLOG(IPAIPU3, Error) << \"Can't find exposure control\";\n> +\t\treturn;\n> +\t}\n> +\n> +\tconst auto itGain = ctrls_.find(V4L2_CID_ANALOGUE_GAIN);\n> +\tif (itGain == ctrls_.end()) {\n> +\t\tLOG(IPAIPU3, Error) << \"Can't find gain control\";\n> +\t\treturn;\n> +\t}\n> +\n> +\tminExposure_ = std::max<uint32_t>(itExp->second.min().get<int32_t>(), 1);\n\nWon't this convert both arguments to uint32_t, having the effect of\nturning a negative value into a large positive value for the first\nargument ? I think you want\n\n\tminExposure_ = std::max(itExp->second.min().get<int32_t>(), 1);\n\ninstead.\n\n> +\tmaxExposure_ = itExp->second.max().get<int32_t>();\n> +\texposure_ = maxExposure_;\n> +\n> +\tminGain_ = std::max<uint32_t>(itGain->second.min().get<int32_t>(), 1);\n\nSame here.\n\n> +\tmaxGain_ = itGain->second.max().get<int32_t>();\n> +\tgain_ = maxGain_;\n> +\n> +\tsetControls(0);\n> +\n> +\tresult->data.push_back(1);\n> +}\n> +\n> +void IPAIPU3::mapBuffers(const std::vector<IPABuffer> &buffers)\n> +{\n> +\tfor (const IPABuffer &buffer : buffers) {\n> +\t\tconst FrameBuffer fb(buffer.planes);\n> +\t\tbuffers_.emplace(buffer.id,\n> +\t\t\t\t MappedFrameBuffer(&fb, PROT_READ | PROT_WRITE));\n> +\t}\n> +}\n> +\n> +void IPAIPU3::unmapBuffers(const std::vector<unsigned int> &ids)\n> +{\n> +\tfor (unsigned int id : ids) {\n> +\t\tauto it = buffers_.find(id);\n> +\t\tif (it == buffers_.end())\n> +\t\t\tcontinue;\n> +\n> +\t\tbuffers_.erase(id);\n\ns/id/it/ ?\n\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\n> +\t}\n> +}\n> +\n> +void IPAIPU3::processEvent(const IPAOperationData &event)\n> +{\n> +\tswitch (event.operation) {\n> +\tcase IPU3_IPA_EVENT_STAT_READY: {\n> +\t\tunsigned int frame = event.data[0];\n> +\t\tunsigned int bufferId = event.data[1];\n> +\n> +\t\tauto it = buffers_.find(bufferId);\n> +\t\tif (it == buffers_.end()) {\n> +\t\t\tLOG(IPAIPU3, Error) << \"Could not find stats buffer!\";\n> +\t\t\treturn;\n> +\t\t}\n> +\n> +\t\tSpan<uint8_t> mem = it->second.maps()[0];\n> +\t\tconst ipu3_uapi_stats_3a *stats =\n> +\t\t\treinterpret_cast<ipu3_uapi_stats_3a *>(mem.data());\n> +\n> +\t\tparseStatistics(frame, stats);\n> +\t\tbreak;\n> +\t}\n> +\tcase IPU3_IPA_EVENT_FILL_PARAMS: {\n> +\t\tunsigned int frame = event.data[0];\n> +\t\tunsigned int bufferId = event.data[1];\n> +\n> +\t\tauto it = buffers_.find(bufferId);\n> +\t\tif (it == buffers_.end()) {\n> +\t\t\tLOG(IPAIPU3, Error) << \"Could not find param buffer!\";\n> +\t\t\treturn;\n> +\t\t}\n> +\n> +\t\tSpan<uint8_t> mem = it->second.maps()[0];\n> +\t\tipu3_uapi_params *params =\n> +\t\t\treinterpret_cast<ipu3_uapi_params *>(mem.data());\n> +\n> +\t\tfillParams(frame, params, event.controls[0]);\n> +\t\tbreak;\n> +\t}\n> +\tdefault:\n> +\t\tLOG(IPAIPU3, Error) << \"Unknown event \" << event.operation;\n> +\t\tbreak;\n> +\t}\n> +}\n> +\n> +void IPAIPU3::fillParams(unsigned int frame, ipu3_uapi_params *params,\n> +\t\t\t [[maybe_unused]] const ControlList &controls)\n> +{\n> +\t/* Prepare parameters buffer. */\n> +\tmemset(params, 0, sizeof(*params));\n> +\n> +\t/* \\todo Fill in parameters buffer. */\n> +\n> +\tIPAOperationData op;\n> +\top.operation = IPU3_IPA_ACTION_PARAM_FILLED;\n> +\n> +\tqueueFrameAction.emit(frame, op);\n> +\n> +\t/* \\todo Calculate new values for exposure_ and gain_. */\n> +\tsetControls(frame);\n> +}\n> +\n> +void IPAIPU3::parseStatistics(unsigned int frame,\n> +\t\t\t      [[maybe_unused]] const ipu3_uapi_stats_3a *stats)\n> +{\n> +\tControlList ctrls(controls::controls);\n> +\n> +\t/* \\todo React to statistics and update internal state machine. */\n> +\t/* \\todo Add meta-data information to ctrls. */\n> +\n> +\tIPAOperationData op;\n> +\top.operation = IPU3_IPA_ACTION_METADATA_READY;\n> +\top.controls.push_back(ctrls);\n> +\n> +\tqueueFrameAction.emit(frame, op);\n> +}\n> +\n> +void IPAIPU3::setControls(unsigned int frame)\n> +{\n> +\tIPAOperationData op;\n> +\top.operation = IPU3_IPA_ACTION_SET_SENSOR_CONTROLS;\n> +\n> +\tControlList ctrls(ctrls_);\n> +\tctrls.set(V4L2_CID_EXPOSURE, static_cast<int32_t>(exposure_));\n> +\tctrls.set(V4L2_CID_ANALOGUE_GAIN, static_cast<int32_t>(gain_));\n> +\top.controls.push_back(ctrls);\n> +\n> +\tqueueFrameAction.emit(frame, op);\n> +}\n> +\n> +/*\n> + * External IPA module interface\n> + */\n> +\n> +extern \"C\" {\n> +const struct IPAModuleInfo ipaModuleInfo = {\n> +\tIPA_MODULE_API_VERSION,\n> +\t1,\n> +\t\"PipelineHandlerIPU3\",\n> +\t\"ipu3\",\n> +};\n> +\n> +struct ipa_context *ipaCreate()\n> +{\n> +\treturn new IPAInterfaceWrapper(std::make_unique<IPAIPU3>());\n> +}\n> +}\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/ipa/ipu3/meson.build b/src/ipa/ipu3/meson.build\n> new file mode 100644\n> index 0000000000000000..444c82453eac42ff\n> --- /dev/null\n> +++ b/src/ipa/ipu3/meson.build\n> @@ -0,0 +1,21 @@\n> +# SPDX-License-Identifier: CC0-1.0\n> +\n> +ipa_name = 'ipa_ipu3'\n> +\n> +mod = shared_module(ipa_name,\n> +                    'ipu3.cpp',\n> +                    name_prefix : '',\n> +                    include_directories : [ ipa_includes, libipa_includes ],\n> +                    dependencies : [ libatomic, libcamera_dep ],\n> +                    link_with : libipa,\n> +                    install : true,\n> +                    install_dir : ipa_install_dir)\n> +\n> +if ipa_sign_module\n> +    custom_target(ipa_name + '.so.sign',\n> +                  input : mod,\n> +                  output : ipa_name + '.so.sign',\n> +                  command : [ ipa_sign, ipa_priv_key, '@INPUT@', '@OUTPUT@' ],\n> +                  install : false,\n> +                  build_by_default : true)\n> +endif\n> diff --git a/src/ipa/meson.build b/src/ipa/meson.build\n> index 5a5de267c1477d24..9d623f227a1f9feb 100644\n> --- a/src/ipa/meson.build\n> +++ b/src/ipa/meson.build\n> @@ -19,7 +19,7 @@ subdir('libipa')\n>  \n>  ipa_sign = files('ipa-sign.sh')\n>  \n> -ipas = ['raspberrypi', 'rkisp1', 'vimc']\n> +ipas = ['ipu3', 'raspberrypi', 'rkisp1', 'vimc']\n>  ipa_names = []\n>  \n>  foreach pipeline : get_option('pipelines')","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 51716C0F1A\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  7 Jan 2021 05:15:28 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id BFC41632E1;\n\tThu,  7 Jan 2021 06:15:27 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 8AC6C6010E\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  7 Jan 2021 06:15:26 +0100 (CET)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 05C052E0;\n\tThu,  7 Jan 2021 06:15:25 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"ZgMs898F\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1609996526;\n\tbh=eDHNRMsObOSkZhwthMx2oh3dLawLwVyXVmVkCj4HDnE=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=ZgMs898Fidx4mCuCXl+K+QfCZTHBiL8S/Spwvw9mWxVDaDGj7juuHkdj8YzDUXxqk\n\ti7jZhLPUbwRukfwA92QeEG2tJ6nXgi4Y5q+16KgdptTUvjMlI+PS0gpPY7XUgHd94b\n\tIrZ4Jh4QpHPD9kYn06IDNOr+20HaLBF7NSxyKeU4=","Date":"Thu, 7 Jan 2021 07:15:13 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Niklas =?utf-8?q?S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>","Message-ID":"<X/aY4c9Nryc3ze3h@pendragon.ideasonboard.com>","References":"<20201229160318.77536-1-niklas.soderlund@ragnatech.se>\n\t<20201229160318.77536-7-niklas.soderlund@ragnatech.se>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<20201229160318.77536-7-niklas.soderlund@ragnatech.se>","Subject":"Re: [libcamera-devel] [PATCH v2 06/11] libcamera: ipa: ipu3: Add an\n\tIPA skeleton for the IPU3 pipeline","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Cc":"libcamera-devel@lists.libcamera.org","Content-Type":"text/plain; charset=\"utf-8\"","Content-Transfer-Encoding":"base64","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":14468,"web_url":"https://patchwork.libcamera.org/comment/14468/","msgid":"<20210107123252.5azlic5kkubfybz6@uno.localdomain>","date":"2021-01-07T12:32:52","subject":"Re: [libcamera-devel] [PATCH v2 06/11] libcamera: ipa: ipu3: Add an\n\tIPA skeleton for the IPU3 pipeline","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Niklas,\n\nOn Tue, Dec 29, 2020 at 05:03:13PM +0100, Niklas Söderlund wrote:\n> Add an empty IPA skeleton for the IPU3 pipeline. The skeleton IPA\n> handles the flow of parameter and statistic buffers but does not read or\n> write anything in the buffers. It also allows the IPA to set sensor\n> controls but does not implement any logic to set optimal values and\n> instead sets the V4L2 exposure and gain controls to max and keeps them\n> at that setting.\n>\n> This IPA is meant as a base to allow the pipeline handler to be wired up\n> to an IPA. The image algorithms can then later be added to the IPA\n> independently from also having to add plumbing to the pipeline handler.\n>\n> Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> Acked-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\nReviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n\nThanks\n   j\n\n> ---\n> * Changes since v1\n> - Updated commit message.\n> - Rename IPU3_IPA_EVENT_PARSE_STAT to IPU3_IPA_EVENT_PARSE_STAT.\n> - Sort and drop unused headers.\n> - Fix style issue in meson.build and add dependency on libatomic.\n> - Switch to MappedFrameBuffer interface.\n> - Add result of IPA configuration status.\n> ---\n>  include/libcamera/ipa/ipu3.h |  23 ++++\n>  src/ipa/ipu3/ipu3.cpp        | 236 +++++++++++++++++++++++++++++++++++\n>  src/ipa/ipu3/meson.build     |  21 ++++\n>  src/ipa/meson.build          |   2 +-\n>  4 files changed, 281 insertions(+), 1 deletion(-)\n>  create mode 100644 include/libcamera/ipa/ipu3.h\n>  create mode 100644 src/ipa/ipu3/ipu3.cpp\n>  create mode 100644 src/ipa/ipu3/meson.build\n>\n> diff --git a/include/libcamera/ipa/ipu3.h b/include/libcamera/ipa/ipu3.h\n> new file mode 100644\n> index 0000000000000000..1bcf3591f9fe36a9\n> --- /dev/null\n> +++ b/include/libcamera/ipa/ipu3.h\n> @@ -0,0 +1,23 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2020, Google Inc.\n> + *\n> + * ipu3.h - Image Processing Algorithm interface for IPU3\n> + */\n> +#ifndef __LIBCAMERA_IPA_INTERFACE_IPU3_H__\n> +#define __LIBCAMERA_IPA_INTERFACE_IPU3_H__\n> +\n> +#ifndef __DOXYGEN__\n> +\n> +enum IPU3Operations {\n> +\tIPU3_IPA_STATUS_CONFIGURATION = 1,\n> +\tIPU3_IPA_ACTION_SET_SENSOR_CONTROLS = 2,\n> +\tIPU3_IPA_ACTION_PARAM_FILLED = 3,\n> +\tIPU3_IPA_ACTION_METADATA_READY = 4,\n> +\tIPU3_IPA_EVENT_STAT_READY = 5,\n> +\tIPU3_IPA_EVENT_FILL_PARAMS = 6,\n> +};\n> +\n> +#endif /* __DOXYGEN__ */\n> +\n> +#endif /* __LIBCAMERA_IPA_INTERFACE_IPU3_H__ */\n> diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp\n> new file mode 100644\n> index 0000000000000000..809a3eec398a8e57\n> --- /dev/null\n> +++ b/src/ipa/ipu3/ipu3.cpp\n> @@ -0,0 +1,236 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2020, Google Inc.\n> + *\n> + * ipu3.cpp - IPU3 Image Processing Algorithms\n> + */\n> +\n> +#include <libcamera/ipa/ipu3.h>\n> +\n> +#include <sys/mman.h>\n> +\n> +#include <linux/intel-ipu3.h>\n> +#include <linux/v4l2-controls.h>\n> +\n> +#include <libcamera/buffer.h>\n> +#include <libcamera/control_ids.h>\n> +#include <libcamera/ipa/ipa_interface.h>\n> +#include <libcamera/ipa/ipa_module_info.h>\n> +#include <libcamera/request.h>\n> +\n> +#include <libipa/ipa_interface_wrapper.h>\n> +\n> +#include \"libcamera/internal/buffer.h\"\n> +#include \"libcamera/internal/log.h\"\n> +\n> +namespace libcamera {\n> +\n> +LOG_DEFINE_CATEGORY(IPAIPU3)\n> +\n> +class IPAIPU3 : public IPAInterface\n> +{\n> +public:\n> +\tint init([[maybe_unused]] const IPASettings &settings) override\n> +\t{\n> +\t\treturn 0;\n> +\t}\n> +\tint start([[maybe_unused]] const IPAOperationData &data,\n> +\t\t  [[maybe_unused]] IPAOperationData *result) override { return 0; }\n> +\tvoid stop() override {}\n> +\n> +\tvoid configure(const CameraSensorInfo &info,\n> +\t\t       const std::map<unsigned int, IPAStream> &streamConfig,\n> +\t\t       const std::map<unsigned int, const ControlInfoMap &> &entityControls,\n> +\t\t       const IPAOperationData &ipaConfig,\n> +\t\t       IPAOperationData *response) override;\n> +\tvoid mapBuffers(const std::vector<IPABuffer> &buffers) override;\n> +\tvoid unmapBuffers(const std::vector<unsigned int> &ids) override;\n> +\tvoid processEvent(const IPAOperationData &event) override;\n> +\n> +private:\n> +\tvoid fillParams(unsigned int frame, ipu3_uapi_params *params,\n> +\t\t\tconst ControlList &controls);\n> +\n> +\tvoid parseStatistics(unsigned int frame,\n> +\t\t\t     const ipu3_uapi_stats_3a *stats);\n> +\n> +\tvoid setControls(unsigned int frame);\n> +\n> +\tstd::map<unsigned int, MappedFrameBuffer> buffers_;\n> +\n> +\tControlInfoMap ctrls_;\n> +\n> +\t/* Camera sensor controls. */\n> +\tuint32_t exposure_;\n> +\tuint32_t minExposure_;\n> +\tuint32_t maxExposure_;\n> +\tuint32_t gain_;\n> +\tuint32_t minGain_;\n> +\tuint32_t maxGain_;\n> +};\n> +\n> +void IPAIPU3::configure([[maybe_unused]] const CameraSensorInfo &info,\n> +\t\t\t[[maybe_unused]] const std::map<unsigned int, IPAStream> &streamConfig,\n> +\t\t\tconst std::map<unsigned int, const ControlInfoMap &> &entityControls,\n> +\t\t\t[[maybe_unused]] const IPAOperationData &ipaConfig,\n> +\t\t\t[[maybe_unused]] IPAOperationData *result)\n> +{\n> +\tresult->operation = IPU3_IPA_STATUS_CONFIGURATION;\n> +\n> +\tif (entityControls.empty())\n> +\t\treturn;\n> +\n> +\tctrls_ = entityControls.at(0);\n> +\n> +\tconst auto itExp = ctrls_.find(V4L2_CID_EXPOSURE);\n> +\tif (itExp == ctrls_.end()) {\n> +\t\tLOG(IPAIPU3, Error) << \"Can't find exposure control\";\n> +\t\treturn;\n> +\t}\n> +\n> +\tconst auto itGain = ctrls_.find(V4L2_CID_ANALOGUE_GAIN);\n> +\tif (itGain == ctrls_.end()) {\n> +\t\tLOG(IPAIPU3, Error) << \"Can't find gain control\";\n> +\t\treturn;\n> +\t}\n> +\n> +\tminExposure_ = std::max<uint32_t>(itExp->second.min().get<int32_t>(), 1);\n> +\tmaxExposure_ = itExp->second.max().get<int32_t>();\n> +\texposure_ = maxExposure_;\n> +\n> +\tminGain_ = std::max<uint32_t>(itGain->second.min().get<int32_t>(), 1);\n> +\tmaxGain_ = itGain->second.max().get<int32_t>();\n> +\tgain_ = maxGain_;\n> +\n> +\tsetControls(0);\n> +\n> +\tresult->data.push_back(1);\n> +}\n> +\n> +void IPAIPU3::mapBuffers(const std::vector<IPABuffer> &buffers)\n> +{\n> +\tfor (const IPABuffer &buffer : buffers) {\n> +\t\tconst FrameBuffer fb(buffer.planes);\n> +\t\tbuffers_.emplace(buffer.id,\n> +\t\t\t\t MappedFrameBuffer(&fb, PROT_READ | PROT_WRITE));\n> +\t}\n> +}\n> +\n> +void IPAIPU3::unmapBuffers(const std::vector<unsigned int> &ids)\n> +{\n> +\tfor (unsigned int id : ids) {\n> +\t\tauto it = buffers_.find(id);\n> +\t\tif (it == buffers_.end())\n> +\t\t\tcontinue;\n> +\n> +\t\tbuffers_.erase(id);\n> +\t}\n> +}\n> +\n> +void IPAIPU3::processEvent(const IPAOperationData &event)\n> +{\n> +\tswitch (event.operation) {\n> +\tcase IPU3_IPA_EVENT_STAT_READY: {\n> +\t\tunsigned int frame = event.data[0];\n> +\t\tunsigned int bufferId = event.data[1];\n> +\n> +\t\tauto it = buffers_.find(bufferId);\n> +\t\tif (it == buffers_.end()) {\n> +\t\t\tLOG(IPAIPU3, Error) << \"Could not find stats buffer!\";\n> +\t\t\treturn;\n> +\t\t}\n> +\n> +\t\tSpan<uint8_t> mem = it->second.maps()[0];\n> +\t\tconst ipu3_uapi_stats_3a *stats =\n> +\t\t\treinterpret_cast<ipu3_uapi_stats_3a *>(mem.data());\n> +\n> +\t\tparseStatistics(frame, stats);\n> +\t\tbreak;\n> +\t}\n> +\tcase IPU3_IPA_EVENT_FILL_PARAMS: {\n> +\t\tunsigned int frame = event.data[0];\n> +\t\tunsigned int bufferId = event.data[1];\n> +\n> +\t\tauto it = buffers_.find(bufferId);\n> +\t\tif (it == buffers_.end()) {\n> +\t\t\tLOG(IPAIPU3, Error) << \"Could not find param buffer!\";\n> +\t\t\treturn;\n> +\t\t}\n> +\n> +\t\tSpan<uint8_t> mem = it->second.maps()[0];\n> +\t\tipu3_uapi_params *params =\n> +\t\t\treinterpret_cast<ipu3_uapi_params *>(mem.data());\n> +\n> +\t\tfillParams(frame, params, event.controls[0]);\n> +\t\tbreak;\n> +\t}\n> +\tdefault:\n> +\t\tLOG(IPAIPU3, Error) << \"Unknown event \" << event.operation;\n> +\t\tbreak;\n> +\t}\n> +}\n> +\n> +void IPAIPU3::fillParams(unsigned int frame, ipu3_uapi_params *params,\n> +\t\t\t [[maybe_unused]] const ControlList &controls)\n> +{\n> +\t/* Prepare parameters buffer. */\n> +\tmemset(params, 0, sizeof(*params));\n> +\n> +\t/* \\todo Fill in parameters buffer. */\n> +\n> +\tIPAOperationData op;\n> +\top.operation = IPU3_IPA_ACTION_PARAM_FILLED;\n> +\n> +\tqueueFrameAction.emit(frame, op);\n> +\n> +\t/* \\todo Calculate new values for exposure_ and gain_. */\n> +\tsetControls(frame);\n> +}\n> +\n> +void IPAIPU3::parseStatistics(unsigned int frame,\n> +\t\t\t      [[maybe_unused]] const ipu3_uapi_stats_3a *stats)\n> +{\n> +\tControlList ctrls(controls::controls);\n> +\n> +\t/* \\todo React to statistics and update internal state machine. */\n> +\t/* \\todo Add meta-data information to ctrls. */\n> +\n> +\tIPAOperationData op;\n> +\top.operation = IPU3_IPA_ACTION_METADATA_READY;\n> +\top.controls.push_back(ctrls);\n> +\n> +\tqueueFrameAction.emit(frame, op);\n> +}\n> +\n> +void IPAIPU3::setControls(unsigned int frame)\n> +{\n> +\tIPAOperationData op;\n> +\top.operation = IPU3_IPA_ACTION_SET_SENSOR_CONTROLS;\n> +\n> +\tControlList ctrls(ctrls_);\n> +\tctrls.set(V4L2_CID_EXPOSURE, static_cast<int32_t>(exposure_));\n> +\tctrls.set(V4L2_CID_ANALOGUE_GAIN, static_cast<int32_t>(gain_));\n> +\top.controls.push_back(ctrls);\n> +\n> +\tqueueFrameAction.emit(frame, op);\n> +}\n> +\n> +/*\n> + * External IPA module interface\n> + */\n> +\n> +extern \"C\" {\n> +const struct IPAModuleInfo ipaModuleInfo = {\n> +\tIPA_MODULE_API_VERSION,\n> +\t1,\n> +\t\"PipelineHandlerIPU3\",\n> +\t\"ipu3\",\n> +};\n> +\n> +struct ipa_context *ipaCreate()\n> +{\n> +\treturn new IPAInterfaceWrapper(std::make_unique<IPAIPU3>());\n> +}\n> +}\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/ipa/ipu3/meson.build b/src/ipa/ipu3/meson.build\n> new file mode 100644\n> index 0000000000000000..444c82453eac42ff\n> --- /dev/null\n> +++ b/src/ipa/ipu3/meson.build\n> @@ -0,0 +1,21 @@\n> +# SPDX-License-Identifier: CC0-1.0\n> +\n> +ipa_name = 'ipa_ipu3'\n> +\n> +mod = shared_module(ipa_name,\n> +                    'ipu3.cpp',\n> +                    name_prefix : '',\n> +                    include_directories : [ ipa_includes, libipa_includes ],\n> +                    dependencies : [ libatomic, libcamera_dep ],\n> +                    link_with : libipa,\n> +                    install : true,\n> +                    install_dir : ipa_install_dir)\n> +\n> +if ipa_sign_module\n> +    custom_target(ipa_name + '.so.sign',\n> +                  input : mod,\n> +                  output : ipa_name + '.so.sign',\n> +                  command : [ ipa_sign, ipa_priv_key, '@INPUT@', '@OUTPUT@' ],\n> +                  install : false,\n> +                  build_by_default : true)\n> +endif\n> diff --git a/src/ipa/meson.build b/src/ipa/meson.build\n> index 5a5de267c1477d24..9d623f227a1f9feb 100644\n> --- a/src/ipa/meson.build\n> +++ b/src/ipa/meson.build\n> @@ -19,7 +19,7 @@ subdir('libipa')\n>\n>  ipa_sign = files('ipa-sign.sh')\n>\n> -ipas = ['raspberrypi', 'rkisp1', 'vimc']\n> +ipas = ['ipu3', 'raspberrypi', 'rkisp1', 'vimc']\n>  ipa_names = []\n>\n>  foreach pipeline : get_option('pipelines')\n> --\n> 2.29.2\n>\n> _______________________________________________\n> libcamera-devel mailing list\n> libcamera-devel@lists.libcamera.org\n> https://lists.libcamera.org/listinfo/libcamera-devel","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id B75B6C0F1A\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  7 Jan 2021 12:32:39 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4282F6344D;\n\tThu,  7 Jan 2021 13:32:39 +0100 (CET)","from relay2-d.mail.gandi.net (relay2-d.mail.gandi.net\n\t[217.70.183.194])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id E968F62013\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  7 Jan 2021 13:32:37 +0100 (CET)","from uno.localdomain (unknown [93.56.74.111])\n\t(Authenticated sender: jacopo@jmondi.org)\n\tby relay2-d.mail.gandi.net (Postfix) with ESMTPSA id 031FE40010;\n\tThu,  7 Jan 2021 12:32:36 +0000 (UTC)"],"X-Originating-IP":"93.56.74.111","Date":"Thu, 7 Jan 2021 13:32:52 +0100","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"Niklas =?utf-8?q?S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>","Message-ID":"<20210107123252.5azlic5kkubfybz6@uno.localdomain>","References":"<20201229160318.77536-1-niklas.soderlund@ragnatech.se>\n\t<20201229160318.77536-7-niklas.soderlund@ragnatech.se>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<20201229160318.77536-7-niklas.soderlund@ragnatech.se>","Subject":"Re: [libcamera-devel] [PATCH v2 06/11] libcamera: ipa: ipu3: Add an\n\tIPA skeleton for the IPU3 pipeline","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Cc":"libcamera-devel@lists.libcamera.org","Content-Type":"text/plain; charset=\"utf-8\"","Content-Transfer-Encoding":"base64","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]