[{"id":39195,"web_url":"https://patchwork.libcamera.org/comment/39195/","msgid":"<20260619150955.GA3631325@ragnatech.se>","date":"2026-06-19T15:09:55","subject":"Re: [PATCH 11/14] ipa: rppx1: Add RPP-X1 IPA skeleton","submitter":{"id":230,"url":"https://patchwork.libcamera.org/api/people/230/","name":"Niklas Söderlund","email":"niklas.soderlund+renesas@ragnatech.se"},"content":"Hi Jacopo,\n\nThanks for your work.\n\nOn 2026-06-18 12:18:50 +0200, Jacopo Mondi wrote:\n> Add the infrastructure for the RPP-X1 without any registered algorithm\n> but with the definition of the IPA module interface and the IPA context.\n> \n> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n> ---\n>  Documentation/Doxyfile-common.in  |   1 +\n>  include/libcamera/ipa/meson.build |   1 +\n>  include/libcamera/ipa/rppx1.mojom |  41 ++++++\n>  meson_options.txt                 |   4 +-\n>  src/ipa/meson.build               |   1 +\n>  src/ipa/rppx1/ipa_context.cpp     |  63 +++++++++\n>  src/ipa/rppx1/ipa_context.h       |  55 ++++++++\n>  src/ipa/rppx1/meson.build         |  26 ++++\n>  src/ipa/rppx1/module.h            |  27 ++++\n>  src/ipa/rppx1/rppx1.cpp           | 280 ++++++++++++++++++++++++++++++++++++++\n>  10 files changed, 497 insertions(+), 2 deletions(-)\n> \n> diff --git a/Documentation/Doxyfile-common.in b/Documentation/Doxyfile-common.in\n> index f11ec593d5ae..131fdcc6083f 100644\n> --- a/Documentation/Doxyfile-common.in\n> +++ b/Documentation/Doxyfile-common.in\n> @@ -37,6 +37,7 @@ EXCLUDE_PATTERNS       = @TOP_BUILDDIR@/include/libcamera/ipa/*_serializer.h \\\n>                           @TOP_BUILDDIR@/include/libcamera/ipa/mali-c55_*.h \\\n>                           @TOP_BUILDDIR@/include/libcamera/ipa/raspberrypi_*.h \\\n>                           @TOP_BUILDDIR@/include/libcamera/ipa/rkisp1_*.h \\\n> +                         @TOP_BUILDDIR@/include/libcamera/ipa/rppx1_*.h \\\n>                           @TOP_BUILDDIR@/include/libcamera/ipa/vimc_*.h\n>  \n>  EXCLUDE_SYMBOLS        = libcamera::BoundMethodArgs \\\n> diff --git a/include/libcamera/ipa/meson.build b/include/libcamera/ipa/meson.build\n> index 3ee3ada303c0..9ac15546102f 100644\n> --- a/include/libcamera/ipa/meson.build\n> +++ b/include/libcamera/ipa/meson.build\n> @@ -66,6 +66,7 @@ pipeline_ipa_mojom_mapping = {\n>      'ipu3': 'ipu3.mojom',\n>      'mali-c55': 'mali-c55.mojom',\n>      'rkisp1': 'rkisp1.mojom',\n> +    'rcar-gen4': 'rppx1.mojom',\n>      'rpi/pisp': 'raspberrypi.mojom',\n>      'rpi/vc4': 'raspberrypi.mojom',\n>      'simple': 'soft.mojom',\n> diff --git a/include/libcamera/ipa/rppx1.mojom b/include/libcamera/ipa/rppx1.mojom\n> new file mode 100644\n> index 000000000000..4abbebb24f85\n> --- /dev/null\n> +++ b/include/libcamera/ipa/rppx1.mojom\n> @@ -0,0 +1,41 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +\n> +/*\n> + * \\todo Document the interface and remove the related EXCLUDE_PATTERNS entry.\n> + */\n> +\n> +module ipa.rppx1;\n> +\n> +import \"include/libcamera/ipa/core.mojom\";\n> +\n> +struct IPAConfigInfo {\n> +\tlibcamera.IPACameraSensorInfo sensorInfo;\n> +\tlibcamera.ControlInfoMap sensorControls;\n> +};\n> +\n> +interface IPARppX1Interface {\n> +\tinit(libcamera.IPASettings settings,\n> +\t     libcamera.IPACameraSensorInfo sensorInfo,\n> +\t     libcamera.ControlInfoMap sensorControls)\n> +\t\t=> (int32 ret, libcamera.ControlInfoMap ipaControls);\n> +\tstart() => (int32 ret);\n> +\tstop();\n> +\n> +\tconfigure(IPAConfigInfo configInfo,\n> +\t\t  map<uint32, libcamera.IPAStream> streamConfig)\n> +\t\t=> (int32 ret, libcamera.ControlInfoMap ipaControls);\n> +\n> +\tmapBuffers(array<libcamera.IPABuffer> buffers);\n> +\tunmapBuffers(array<uint32> ids);\n> +\n> +\t[async] queueRequest(uint32 frame, libcamera.ControlList reqControls);\n> +\t[async] computeParams(uint32 frame, uint32 bufferId);\n> +\t[async] processStats(uint32 frame, uint32 bufferId,\n> +\t\t\t     libcamera.ControlList sensorControls);\n> +};\n> +\n> +interface IPARppX1EventInterface {\n> +\tparamsComputed(uint32 frame, uint32 bytesused);\n> +\tsetSensorControls(uint32 frame, libcamera.ControlList sensorControls);\n> +\tmetadataReady(uint32 frame, libcamera.ControlList metadata);\n> +};\n> diff --git a/meson_options.txt b/meson_options.txt\n> index 20baacc4fc65..0aa3aef24edd 100644\n> --- a/meson_options.txt\n> +++ b/meson_options.txt\n> @@ -48,8 +48,8 @@ option('gstreamer',\n>  \n>  option('ipas',\n>          type : 'array',\n> -        choices : ['ipu3', 'mali-c55', 'rkisp1', 'rpi/pisp', 'rpi/vc4', 'simple',\n> -                   'vimc'],\n> +        choices : ['ipu3', 'mali-c55', 'rkisp1', 'rppx1', 'rpi/pisp', 'rpi/vc4',\n> +                   'simple', 'vimc'],\n\nnit: rppx1 should be sorted after rpi/*, no?\n\nWith this considered,\n\nReviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>\n\n>          description : 'Select which IPA modules to build')\n>  \n>  option('lc-compliance',\n> diff --git a/src/ipa/meson.build b/src/ipa/meson.build\n> index c583c7efdd35..411d043021f8 100644\n> --- a/src/ipa/meson.build\n> +++ b/src/ipa/meson.build\n> @@ -27,6 +27,7 @@ ipa_sign = files('ipa-sign.sh')\n>  supported_ipas = {\n>      'ipu3':       'ipu3',\n>      'mali-c55':   'mali-c55',\n> +    'rcar-gen4':  'rppx1',\n>      'rkisp1':     'rkisp1',\n>      'rpi/pisp':   'rpi/pisp',\n>      'rpi/vc4':    'rpi/vc4',\n> diff --git a/src/ipa/rppx1/ipa_context.cpp b/src/ipa/rppx1/ipa_context.cpp\n> new file mode 100644\n> index 000000000000..5ac60dfc7bf6\n> --- /dev/null\n> +++ b/src/ipa/rppx1/ipa_context.cpp\n> @@ -0,0 +1,63 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2026 Renesas Electronics Corp.\n> + * Copyright (C) 2026 Ideas on Board Oy\n> + * Copyright (C) 2026 Ragnatech AB\n> + *\n> + * RPP-X1 IPA Context\n> + */\n> +\n> +#include \"ipa_context.h\"\n> +\n> +/**\n> + * \\file ipa_context.h\n> + * \\brief Context and state information shared between the algorithms\n> + */\n> +\n> +namespace libcamera::ipa::rppx1 {\n> +\n> +/**\n> + * \\struct IPASessionConfiguration\n> + * \\brief Session configuration for the IPA module\n> + */\n> +\n> +/**\n> + * \\struct IPAActiveState\n> + * \\brief Active state for algorithms\n> + */\n> +\n> +/**\n> + * \\struct IPAFrameContext\n> + * \\brief Per-frame context for algorithms\n> + */\n> +\n> +/**\n> + * \\struct IPAContext\n> + * \\brief Global IPA context data shared between all algorithms\n> + *\n> + * \\var IPAContext::sensorInfo\n> + * \\brief The IPA session sensorInfo, immutable during the session\n> + *\n> + * \\var IPAContext::configuration\n> + * \\brief The IPA session configuration, immutable during the session\n> + *\n> + * \\var IPAContext::activeState\n> + * \\brief The IPA active state, storing the latest state for all algorithms\n> + *\n> + * \\var IPAContext::frameContexts\n> + * \\brief Ring buffer of per-frame contexts\n> + *\n> + * \\var IPAContext::ctrlMap\n> + * \\brief The IPA map of controls\n> + *\n> + * \\var IPAContext::camHelper\n> + * \\brief The IPA camera helper\n> + */\n> +\n> +/**\n> + * \\fn IPAContext::IPAContext\n> + * \\brief Construct the IPA context\n> + * \\param[in] frameContextSize Size of the frame context queue\n> + */\n> +\n> +} /* namespace libcamera::ipa::rppx1 */\n> diff --git a/src/ipa/rppx1/ipa_context.h b/src/ipa/rppx1/ipa_context.h\n> new file mode 100644\n> index 000000000000..f268a35081bc\n> --- /dev/null\n> +++ b/src/ipa/rppx1/ipa_context.h\n> @@ -0,0 +1,55 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2026 Renesas Electronics Corp.\n> + * Copyright (C) 2026 Ideas on Board Oy\n> + * Copyright (C) 2026 Ragnatech AB\n> + *\n> + * RPP-X1 IPA Context\n> + */\n> +\n> +#pragma once\n> +\n> +#include <memory>\n> +\n> +#include <linux/media/dreamchip/rppx1-config.h>\n> +\n> +#include <libcamera/controls.h>\n> +\n> +#include <libcamera/ipa/core_ipa_interface.h>\n> +\n> +#include <libipa/camera_sensor_helper.h>\n> +#include <libipa/fc_queue.h>\n> +\n> +namespace libcamera {\n> +\n> +namespace ipa::rppx1 {\n> +\n> +struct IPASessionConfiguration {\n> +};\n> +\n> +struct IPAActiveState {\n> +};\n> +\n> +struct IPAFrameContext : public FrameContext {\n> +};\n> +\n> +struct IPAContext {\n> +\tIPAContext(unsigned int frameContextSize)\n> +\t\t: frameContexts(frameContextSize)\n> +\t{\n> +\t}\n> +\n> +\tIPACameraSensorInfo sensorInfo;\n> +\tIPASessionConfiguration configuration;\n> +\tIPAActiveState activeState;\n> +\n> +\tFCQueue<IPAFrameContext> frameContexts;\n> +\n> +\tControlInfoMap::Map ctrlMap;\n> +\n> +\tstd::unique_ptr<CameraSensorHelper> camHelper;\n> +};\n> +\n> +} /* namespace ipa::rppx1 */\n> +\n> +} /* namespace libcamera*/\n> diff --git a/src/ipa/rppx1/meson.build b/src/ipa/rppx1/meson.build\n> new file mode 100644\n> index 000000000000..8034fe24d241\n> --- /dev/null\n> +++ b/src/ipa/rppx1/meson.build\n> @@ -0,0 +1,26 @@\n> +# SPDX-License-Identifier: CC0-1.0\n> +\n> +ipa_name = 'ipa_rppx1'\n> +\n> +rppx1_ipa_sources = files([\n> +    'ipa_context.cpp',\n> +    'rppx1.cpp',\n> +])\n> +\n> +mod = shared_module(ipa_name, rppx1_ipa_sources,\n> +                    name_prefix : '',\n> +                    include_directories : [ipa_includes],\n> +                    dependencies : [libcamera_private, libipa_dep],\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> +\n> +ipa_names += ipa_name\n> diff --git a/src/ipa/rppx1/module.h b/src/ipa/rppx1/module.h\n> new file mode 100644\n> index 000000000000..0bacff64de8f\n> --- /dev/null\n> +++ b/src/ipa/rppx1/module.h\n> @@ -0,0 +1,27 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2026 Renesas Electronics Corp.\n> + * Copyright (C) 2026 Ideas on Board Oy\n> + * Copyright (C) 2026 Ragnatech AB\n> + *\n> + * RPP-X1 IPA Module\n> + */\n> +\n> +#pragma once\n> +\n> +#include <libipa/module.h>\n> +\n> +#include \"ipa_context.h\"\n> +#include \"params.h\"\n> +#include \"stats.h\"\n> +\n> +namespace libcamera {\n> +\n> +namespace ipa::rppx1 {\n> +\n> +using Module = ipa::Module<IPAContext, IPAFrameContext, IPACameraSensorInfo,\n> +\t\t\t   RppX1Params, RppX1Stats>;\n> +\n> +} /* namespace ipa::rppx1 */\n> +\n> +} /* namespace libcamera*/\n> diff --git a/src/ipa/rppx1/rppx1.cpp b/src/ipa/rppx1/rppx1.cpp\n> new file mode 100644\n> index 000000000000..20ca2d292704\n> --- /dev/null\n> +++ b/src/ipa/rppx1/rppx1.cpp\n> @@ -0,0 +1,280 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2026 Renesas Electronics Corp.\n> + * Copyright (C) 2026 Ideas on Board Oy\n> + * Copyright (C) 2026 Ragnatech AB\n> + *\n> + * RPP-X1 Image Processing Algorithms\n> + */\n> +\n> +#include <algorithm>\n> +#include <stdint.h>\n> +#include <string.h>\n> +\n> +#include <libcamera/base/file.h>\n> +#include <libcamera/base/log.h>\n> +\n> +#include <libcamera/controls.h>\n> +#include <libcamera/framebuffer.h>\n> +\n> +#include <libcamera/ipa/ipa_interface.h>\n> +#include <libcamera/ipa/ipa_module_info.h>\n> +#include <libcamera/ipa/rppx1_ipa_interface.h>\n> +\n> +#include \"libcamera/internal/formats.h\"\n> +#include \"libcamera/internal/mapped_framebuffer.h\"\n> +#include \"libcamera/internal/yaml_parser.h\"\n> +\n> +#include \"algorithms/algorithm.h\"\n> +\n> +#include \"ipa_context.h\"\n> +#include \"params.h\"\n> +#include \"stats.h\"\n> +\n> +namespace libcamera {\n> +\n> +LOG_DEFINE_CATEGORY(IPARppX1)\n> +\n> +namespace ipa::rppx1 {\n> +\n> +/* Maximum number of frame contexts to be held */\n> +static constexpr uint32_t kMaxFrameContexts = 16;\n> +\n> +class IPARppX1 : public IPARppX1Interface, public Module\n> +{\n> +public:\n> +\tIPARppX1();\n> +\n> +\tint init(const IPASettings &settings,\n> +\t\t const IPACameraSensorInfo &sensorInfo,\n> +\t\t const ControlInfoMap &sensorControls,\n> +\t\t ControlInfoMap *ipaControls) override;\n> +\tint start() override;\n> +\tvoid stop() override;\n> +\n> +\tint configure(const IPAConfigInfo &ipaConfig,\n> +\t\t      const std::map<uint32_t, IPAStream> &streamConfig,\n> +\t\t      ControlInfoMap *ipaControls) override;\n> +\tvoid mapBuffers(const std::vector<IPABuffer> &buffers) override;\n> +\tvoid unmapBuffers(const std::vector<unsigned int> &ids) override;\n> +\n> +\tvoid queueRequest(const uint32_t frame, const ControlList &controls) override;\n> +\tvoid computeParams(const uint32_t frame, const uint32_t bufferId) override;\n> +\tvoid processStats(const uint32_t frame, const uint32_t bufferId,\n> +\t\t\t  const ControlList &sensorControls) override;\n> +\n> +protected:\n> +\tstd::string logPrefix() const override;\n> +\n> +private:\n> +\tvoid updateControls(ControlInfoMap *ipaControls);\n> +\n> +\tstd::map<unsigned int, FrameBuffer> buffers_;\n> +\tstd::map<unsigned int, MappedFrameBuffer> mappedBuffers_;\n> +\n> +\t/* Local parameter storage */\n> +\tstruct IPAContext context_;\n> +};\n> +\n> +IPARppX1::IPARppX1()\n> +\t: context_(kMaxFrameContexts)\n> +{\n> +}\n> +\n> +std::string IPARppX1::logPrefix() const\n> +{\n> +\treturn \"rppx1\";\n> +}\n> +\n> +void IPARppX1::updateControls(ControlInfoMap *ipaControls)\n> +{\n> +\tControlInfoMap::Map ctrlMap;\n> +\n> +\tctrlMap.insert(context_.ctrlMap.begin(), context_.ctrlMap.end());\n> +\t*ipaControls = ControlInfoMap(std::move(ctrlMap), controls::controls);\n> +}\n> +\n> +int IPARppX1::init(const IPASettings &settings,\n> +\t\t   const IPACameraSensorInfo &sensorInfo,\n> +\t\t   [[maybe_unused]] const ControlInfoMap &sensorControls,\n> +\t\t   [[maybe_unused]] ControlInfoMap *ipaControls)\n> +{\n> +\tcontext_.sensorInfo = sensorInfo;\n> +\n> +\tcontext_.camHelper = CameraSensorHelperFactoryBase::create(settings.sensorModel);\n> +\tif (!context_.camHelper) {\n> +\t\tLOG(IPARppX1, Error)\n> +\t\t\t<< \"Failed to create camera sensor helper for \"\n> +\t\t\t<< settings.sensorModel;\n> +\t\treturn -ENODEV;\n> +\t}\n> +\n> +\t/* Load the tuning data file. */\n> +\tFile file(settings.configurationFile);\n> +\tif (!file.open(File::OpenModeFlag::ReadOnly)) {\n> +\t\tint ret = file.error();\n> +\t\tLOG(IPARppX1, Error)\n> +\t\t\t<< \"Failed to open configuration file \"\n> +\t\t\t<< settings.configurationFile << \": \" << strerror(-ret);\n> +\t\treturn ret;\n> +\t}\n> +\n> +\tstd::unique_ptr<libcamera::ValueNode> data = YamlParser::parse(file);\n> +\tif (!data)\n> +\t\treturn -EINVAL;\n> +\n> +\tunsigned int version = (*data)[\"version\"].get<uint32_t>(0);\n> +\tif (version != 1) {\n> +\t\tLOG(IPARppX1, Error)\n> +\t\t\t<< \"Invalid tuning file version \" << version;\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tif (!data->contains(\"algorithms\")) {\n> +\t\tLOG(IPARppX1, Error)\n> +\t\t\t<< \"Tuning file doesn't contain any algorithm\";\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tint ret = createAlgorithms(context_, (*data)[\"algorithms\"]);\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n> +\t/* Initialize controls. */\n> +\tupdateControls(ipaControls);\n> +\n> +\treturn 0;\n> +}\n> +\n> +int IPARppX1::start()\n> +{\n> +\t/* \\todo Properly handle startup controls. */\n> +\treturn 0;\n> +}\n> +\n> +void IPARppX1::stop()\n> +{\n> +\tcontext_.frameContexts.clear();\n> +}\n> +\n> +int IPARppX1::configure(const IPAConfigInfo &ipaConfig,\n> +\t\t\t[[maybe_unused]] const std::map<uint32_t, IPAStream> &streamConfig,\n> +\t\t\t[[maybe_unused]] ControlInfoMap *ipaControls)\n> +{\n> +\t/* Clear the IPA context before the streaming session. */\n> +\tcontext_.configuration = {};\n> +\tcontext_.activeState = {};\n> +\tcontext_.frameContexts.clear();\n> +\n> +\tconst IPACameraSensorInfo &info = ipaConfig.sensorInfo;\n> +\n> +\t/* Update the camera controls using the new sensor settings. */\n> +\tupdateControls(ipaControls);\n> +\n> +\tfor (auto const &a : algorithms()) {\n> +\t\tAlgorithm *algo = static_cast<Algorithm *>(a.get());\n> +\n> +\t\tint ret = algo->configure(context_, info);\n> +\t\tif (ret)\n> +\t\t\treturn ret;\n> +\t}\n> +\n> +\treturn 0;\n> +}\n> +\n> +void IPARppX1::mapBuffers(const std::vector<IPABuffer> &buffers)\n> +{\n> +\tfor (const IPABuffer &buffer : buffers) {\n> +\t\tauto elem = buffers_.emplace(std::piecewise_construct,\n> +\t\t\t\t\t     std::forward_as_tuple(buffer.id),\n> +\t\t\t\t\t     std::forward_as_tuple(buffer.planes));\n> +\t\tconst FrameBuffer &fb = elem.first->second;\n> +\n> +\t\tMappedFrameBuffer mappedBuffer(&fb, MappedFrameBuffer::MapFlag::ReadWrite);\n> +\t\tif (!mappedBuffer.isValid()) {\n> +\t\t\tLOG(IPARppX1, Fatal) << \"Failed to mmap buffer: \"\n> +\t\t\t\t\t     << strerror(mappedBuffer.error());\n> +\t\t}\n> +\n> +\t\tmappedBuffers_.emplace(buffer.id, std::move(mappedBuffer));\n> +\t}\n> +}\n> +\n> +void IPARppX1::unmapBuffers(const std::vector<unsigned int> &ids)\n> +{\n> +\tfor (unsigned int id : ids) {\n> +\t\tconst auto fb = buffers_.find(id);\n> +\t\tif (fb == buffers_.end())\n> +\t\t\tcontinue;\n> +\n> +\t\tmappedBuffers_.erase(id);\n> +\t\tbuffers_.erase(id);\n> +\t}\n> +}\n> +\n> +void IPARppX1::queueRequest(const uint32_t frame, const ControlList &controls)\n> +{\n> +\tIPAFrameContext &frameContext = context_.frameContexts.alloc(frame);\n> +\n> +\tfor (auto const &a : algorithms()) {\n> +\t\tAlgorithm *algo = static_cast<Algorithm *>(a.get());\n> +\t\tif (algo->disabled_)\n> +\t\t\tcontinue;\n> +\n> +\t\talgo->queueRequest(context_, frame, frameContext, controls);\n> +\t}\n> +}\n> +\n> +void IPARppX1::computeParams(const uint32_t frame, const uint32_t bufferId)\n> +{\n> +\tIPAFrameContext &frameContext = context_.frameContexts.get(frame);\n> +\n> +\tRppX1Params params(mappedBuffers_.at(bufferId).planes()[0]);\n> +\n> +\tfor (auto const &algo : algorithms())\n> +\t\talgo->prepare(context_, frame, frameContext, &params);\n> +\n> +\tparamsComputed.emit(frame, params.bytesused());\n> +}\n> +\n> +void IPARppX1::processStats(const uint32_t frame, const uint32_t bufferId,\n> +\t\t\t    [[maybe_unused]] const ControlList &sensorControls)\n> +{\n> +\tIPAFrameContext &frameContext = context_.frameContexts.get(frame);\n> +\n> +\tControlList metadata(controls::controls);\n> +\n> +\tauto stats = RppX1Stats(mappedBuffers_.at(bufferId).planes()[0]);\n> +\tif (!stats)\n> +\t\treturn;\n> +\n> +\tfor (auto const &a : algorithms()) {\n> +\t\tAlgorithm *algo = static_cast<Algorithm *>(a.get());\n> +\t\tif (algo->disabled_)\n> +\t\t\tcontinue;\n> +\t\talgo->process(context_, frame, frameContext, &stats, metadata);\n> +\t}\n> +\n> +\tmetadataReady.emit(frame, metadata);\n> +}\n> +\n> +} /* namespace ipa::rppx1 */\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\"rppx1\",\n> +};\n> +\n> +IPAInterface *ipaCreate()\n> +{\n> +\treturn new ipa::rppx1::IPARppX1();\n> +}\n> +}\n> +\n> +} /* namespace libcamera */\n> \n> -- \n> 2.54.0\n>","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 293EDC3261\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 19 Jun 2026 15:10:03 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id EB2AF656CA;\n\tFri, 19 Jun 2026 17:10:01 +0200 (CEST)","from fhigh-a5-smtp.messagingengine.com\n\t(fhigh-a5-smtp.messagingengine.com [103.168.172.156])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 00AA562899\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 19 Jun 2026 17:09:59 +0200 (CEST)","from phl-compute-10.internal (phl-compute-10.internal\n\t[10.202.2.50])\n\tby mailfhigh.phl.internal (Postfix) with ESMTP id 8A5081400078;\n\tFri, 19 Jun 2026 11:09:58 -0400 (EDT)","from phl-frontend-04 ([10.202.2.163])\n\tby phl-compute-10.internal (MEProxy); Fri, 19 Jun 2026 11:09:58 -0400","by mail.messagingengine.com (Postfix) with ESMTPA; Fri,\n\t19 Jun 2026 11:09:57 -0400 (EDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=ragnatech.se header.i=@ragnatech.se\n\theader.b=\"4nXIXK/X\"; dkim=pass (2048-bit key;\n\tunprotected) header.d=messagingengine.com\n\theader.i=@messagingengine.com header.b=\"UvQxyDnE\"; \n\tdkim-atps=neutral","DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/relaxed; d=ragnatech.se; h=\n\tcc:cc:content-transfer-encoding:content-type:content-type:date\n\t:date:from:from:in-reply-to:in-reply-to:message-id:mime-version\n\t:references:reply-to:subject:subject:to:to; s=fm3; t=1781881798;\n\tx=1781968198; bh=rYQZv3nMKoCDq4W7CMZlfwYO9O8je3eKmWtQfoC7/IY=; b=\n\t4nXIXK/XHovkDbefWAUbncYB+d2fcJDBwEI+Iq5ggAw/asfUykqnHMV0lVYtbP3m\n\tiRY1mIgj4nXIM+pL3oug6uNR4jdtK5OCv1WcmIMDs4DBbKXYUEZzYkuHdpv7ub+S\n\t8mlxxmsQ1JRp+LMA51mD9bnqxIpXViyJJ1k+oIDPAeUQ26/EtrRVg7u/Tam2kjaE\n\tHLBPjVz1Jh1S98KOabMjINsyxTefXY24nA884EG/4GaSF/h7KuAC2YDZHx7DYnpY\n\tX3DeHvOa9PsRGC1yTlY8p33bSd+GTOnzKy+3sGvl/hPJuak8MP95OEEyL8aTwXSy\n\tOtKdq0pbeUD2eE9BgCkvMg==","v=1; a=rsa-sha256; c=relaxed/relaxed; d=\n\tmessagingengine.com; h=cc:cc:content-transfer-encoding\n\t:content-type:content-type:date:date:feedback-id:feedback-id\n\t:from:from:in-reply-to:in-reply-to:message-id:mime-version\n\t:references:reply-to:subject:subject:to:to:x-me-proxy\n\t:x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1781881798; x=\n\t1781968198; bh=rYQZv3nMKoCDq4W7CMZlfwYO9O8je3eKmWtQfoC7/IY=; b=U\n\tvQxyDnEhfw5DLWf1z3V/IZG0Qtg39Vw4FdKFJ5PiE+CdG5RdY+4t8yvwRFEIG5bG\n\tewoZ0VpidqnBNfrdfpeNAyirdgm9anJoayPpN/e88tV0jDsd5NxHAalQ/I9ijLTx\n\t/ofJvJFdIqtdHS1xNqfh7fImBWBYL1C38lzgcD7TMxt/WCrBwyZ6G83PC/bnFV2I\n\tiQqhigPy9YBsuclZfaBtKW+q2xZYQOOZ4yaeRybDXfTJHU/wJ8rO6GyQVIhaW2GS\n\t34vxQaK5Zn8RUXYm2tHOtNwtyShuJKwPFUb1J1msRX6if1O0P5qQVnba4USjD47t\n\tked6SCJ9efmMZy3mi5c9A=="],"X-ME-Sender":"<xms:xVs1ak6ZlxiV7QCfVWBJKUcK1sIGBbnvXjlcItJTh7gItvzHdhqv2g>\n\t<xme:xVs1ar75w3w5nZQIM55jaYo0xhiLg2Y4awgbiQ8Fu_1sM0Z0g1qcll0X_euaojnjh\n\txxU8TayVZvFF40_iySd-wlZHcKNAsjIAOUWu274pjWEpvYeiYaIkdY>","X-ME-Received":"<xmr:xVs1ahEAQ2UtOQO0UG10Pn9z4P3FBOKTpXB2y6vZAZTORy67f6vRrFy1YgDGuNsYRBFS5dSVcHAywEH7pIeVwn0d6jzr>","X-ME-Proxy-Cause":"dmFkZTEy4ZYb47VxXB5n7EEn7f6iLKYImekq2AT8GdCv35g77WdboYl91ieT29ELDxFR+g\n\t2lwuwkuUuFdde+NxlKzfIF+xldlkQhXR6Mb3Pc5opMqZ7LCD05WoGhQZfAIwfNOcMWdKDb\n\tyFXtuzjBwtLgm/OxJAVE57NOmy5zJzSSWYFkyKqidJnihVEmChtkICZuMUrCh3ONYVu9Rk\n\t1jqaqO0tRUfhK5lCXLIq8O4TMChdLN3A7hCHHm9B2m5zHh5TJsq9wSEQ+sk+Ekl4jBxdJ+\n\tzqmcLgiXsZuz2H/nsVSlP2v6FF/pmeABZ4myCn1NVVZvrAN7P1Am6dxHGOgBXoiLOHA5Hw\n\tsbrpA3lkLeVbFccko0A/GrqRBpSLeIYIeAzTjAF/pWzWQ04bT0RzfXhNiUpGypSeWY342f\n\t4i19jI15EC9HPNeWDZAJqAX8lKLmEqyn7laPlBdecOOoa+K2QKFp0rm6KSKsxkxQTBNZju\n\tBHnU1s5/UO9KJM/9fcPUM0l9wjB7MjZRVYr6SX767+Yg7GzHaPMXlPtx9opII16JvcfIBO\n\ta3SSReRzWdet56TwY9wrDk+y2xSjpTR2XvdSVGeGN/HQz8LthwHfwSYD8qD11Z9SS905HD\n\teblBJkDscqm3sIQLmdTxBrR8/Dv3YeHYKEgz14H6kzA4DmmVlHebNXrzZR1A","X-ME-Proxy":"<xmx:xVs1akSWHEUnO_2Q8AOkivYmvTSBTZNSGO48PsLje0xQ-7FkUtkV6g>\n\t<xmx:xVs1aquQo4Rti4Emx2a5l-wimQfGbBRprHUjbgm3solovg1dHKmtWw>\n\t<xmx:xVs1ajwm2rIv_J-vq4lylZv0DfCC4EQhEEB4f7U-Dxw3s_1v6eIMdA>\n\t<xmx:xVs1ak7iIEgkVeIKiv94gtFxX7BvHYDbNTtyXTEOlgLMCOxMyaYh_w>\n\t<xmx:xls1alP2lKzkhWX90vkkkbHrrWrzxxNKkDIt6dO7Hhw9S4C9e_q5T_dr>","Feedback-ID":"i80c9496c:Fastmail","Date":"Fri, 19 Jun 2026 17:09:55 +0200","From":"Niklas =?utf-8?q?S=C3=B6derlund?=\n\t<niklas.soderlund+renesas@ragnatech.se>","To":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH 11/14] ipa: rppx1: Add RPP-X1 IPA skeleton","Message-ID":"<20260619150955.GA3631325@ragnatech.se>","References":"<20260618-rppx1-ipa-v1-0-32337264cfcd@ideasonboard.com>\n\t<20260618-rppx1-ipa-v1-11-32337264cfcd@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20260618-rppx1-ipa-v1-11-32337264cfcd@ideasonboard.com>","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>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":39236,"web_url":"https://patchwork.libcamera.org/comment/39236/","msgid":"<ajkmsqrUSJeh6sx2@zed>","date":"2026-06-22T12:13:35","subject":"Re: [PATCH 11/14] ipa: rppx1: Add RPP-X1 IPA skeleton","submitter":{"id":143,"url":"https://patchwork.libcamera.org/api/people/143/","name":"Jacopo Mondi","email":"jacopo.mondi@ideasonboard.com"},"content":"Hi Niklas\n\nOn Fri, Jun 19, 2026 at 05:09:55PM +0200, Niklas Söderlund wrote:\n> Hi Jacopo,\n>\n> Thanks for your work.\n>\n> On 2026-06-18 12:18:50 +0200, Jacopo Mondi wrote:\n> > Add the infrastructure for the RPP-X1 without any registered algorithm\n> > but with the definition of the IPA module interface and the IPA context.\n> >\n> > Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n> > ---\n> >  Documentation/Doxyfile-common.in  |   1 +\n> >  include/libcamera/ipa/meson.build |   1 +\n> >  include/libcamera/ipa/rppx1.mojom |  41 ++++++\n> >  meson_options.txt                 |   4 +-\n> >  src/ipa/meson.build               |   1 +\n> >  src/ipa/rppx1/ipa_context.cpp     |  63 +++++++++\n> >  src/ipa/rppx1/ipa_context.h       |  55 ++++++++\n> >  src/ipa/rppx1/meson.build         |  26 ++++\n> >  src/ipa/rppx1/module.h            |  27 ++++\n> >  src/ipa/rppx1/rppx1.cpp           | 280 ++++++++++++++++++++++++++++++++++++++\n> >  10 files changed, 497 insertions(+), 2 deletions(-)\n> >\n> > diff --git a/Documentation/Doxyfile-common.in b/Documentation/Doxyfile-common.in\n> > index f11ec593d5ae..131fdcc6083f 100644\n> > --- a/Documentation/Doxyfile-common.in\n> > +++ b/Documentation/Doxyfile-common.in\n> > @@ -37,6 +37,7 @@ EXCLUDE_PATTERNS       = @TOP_BUILDDIR@/include/libcamera/ipa/*_serializer.h \\\n> >                           @TOP_BUILDDIR@/include/libcamera/ipa/mali-c55_*.h \\\n> >                           @TOP_BUILDDIR@/include/libcamera/ipa/raspberrypi_*.h \\\n> >                           @TOP_BUILDDIR@/include/libcamera/ipa/rkisp1_*.h \\\n> > +                         @TOP_BUILDDIR@/include/libcamera/ipa/rppx1_*.h \\\n> >                           @TOP_BUILDDIR@/include/libcamera/ipa/vimc_*.h\n> >\n> >  EXCLUDE_SYMBOLS        = libcamera::BoundMethodArgs \\\n> > diff --git a/include/libcamera/ipa/meson.build b/include/libcamera/ipa/meson.build\n> > index 3ee3ada303c0..9ac15546102f 100644\n> > --- a/include/libcamera/ipa/meson.build\n> > +++ b/include/libcamera/ipa/meson.build\n> > @@ -66,6 +66,7 @@ pipeline_ipa_mojom_mapping = {\n> >      'ipu3': 'ipu3.mojom',\n> >      'mali-c55': 'mali-c55.mojom',\n> >      'rkisp1': 'rkisp1.mojom',\n> > +    'rcar-gen4': 'rppx1.mojom',\n> >      'rpi/pisp': 'raspberrypi.mojom',\n> >      'rpi/vc4': 'raspberrypi.mojom',\n> >      'simple': 'soft.mojom',\n> > diff --git a/include/libcamera/ipa/rppx1.mojom b/include/libcamera/ipa/rppx1.mojom\n> > new file mode 100644\n> > index 000000000000..4abbebb24f85\n> > --- /dev/null\n> > +++ b/include/libcamera/ipa/rppx1.mojom\n> > @@ -0,0 +1,41 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +\n> > +/*\n> > + * \\todo Document the interface and remove the related EXCLUDE_PATTERNS entry.\n> > + */\n> > +\n> > +module ipa.rppx1;\n> > +\n> > +import \"include/libcamera/ipa/core.mojom\";\n> > +\n> > +struct IPAConfigInfo {\n> > +\tlibcamera.IPACameraSensorInfo sensorInfo;\n> > +\tlibcamera.ControlInfoMap sensorControls;\n> > +};\n> > +\n> > +interface IPARppX1Interface {\n> > +\tinit(libcamera.IPASettings settings,\n> > +\t     libcamera.IPACameraSensorInfo sensorInfo,\n> > +\t     libcamera.ControlInfoMap sensorControls)\n> > +\t\t=> (int32 ret, libcamera.ControlInfoMap ipaControls);\n> > +\tstart() => (int32 ret);\n> > +\tstop();\n> > +\n> > +\tconfigure(IPAConfigInfo configInfo,\n> > +\t\t  map<uint32, libcamera.IPAStream> streamConfig)\n> > +\t\t=> (int32 ret, libcamera.ControlInfoMap ipaControls);\n> > +\n> > +\tmapBuffers(array<libcamera.IPABuffer> buffers);\n> > +\tunmapBuffers(array<uint32> ids);\n> > +\n> > +\t[async] queueRequest(uint32 frame, libcamera.ControlList reqControls);\n> > +\t[async] computeParams(uint32 frame, uint32 bufferId);\n> > +\t[async] processStats(uint32 frame, uint32 bufferId,\n> > +\t\t\t     libcamera.ControlList sensorControls);\n> > +};\n> > +\n> > +interface IPARppX1EventInterface {\n> > +\tparamsComputed(uint32 frame, uint32 bytesused);\n> > +\tsetSensorControls(uint32 frame, libcamera.ControlList sensorControls);\n> > +\tmetadataReady(uint32 frame, libcamera.ControlList metadata);\n> > +};\n> > diff --git a/meson_options.txt b/meson_options.txt\n> > index 20baacc4fc65..0aa3aef24edd 100644\n> > --- a/meson_options.txt\n> > +++ b/meson_options.txt\n> > @@ -48,8 +48,8 @@ option('gstreamer',\n> >\n> >  option('ipas',\n> >          type : 'array',\n> > -        choices : ['ipu3', 'mali-c55', 'rkisp1', 'rpi/pisp', 'rpi/vc4', 'simple',\n> > -                   'vimc'],\n> > +        choices : ['ipu3', 'mali-c55', 'rkisp1', 'rppx1', 'rpi/pisp', 'rpi/vc4',\n> > +                   'simple', 'vimc'],\n>\n> nit: rppx1 should be sorted after rpi/*, no?\n\nOnly if you know the alphabet, something I don't seem to really grasp\n\nThanks for the catch\n\n>\n> With this considered,\n>\n> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>\n>\n> >          description : 'Select which IPA modules to build')\n> >\n> >  option('lc-compliance',\n> > diff --git a/src/ipa/meson.build b/src/ipa/meson.build\n> > index c583c7efdd35..411d043021f8 100644\n> > --- a/src/ipa/meson.build\n> > +++ b/src/ipa/meson.build\n> > @@ -27,6 +27,7 @@ ipa_sign = files('ipa-sign.sh')\n> >  supported_ipas = {\n> >      'ipu3':       'ipu3',\n> >      'mali-c55':   'mali-c55',\n> > +    'rcar-gen4':  'rppx1',\n> >      'rkisp1':     'rkisp1',\n> >      'rpi/pisp':   'rpi/pisp',\n> >      'rpi/vc4':    'rpi/vc4',\n> > diff --git a/src/ipa/rppx1/ipa_context.cpp b/src/ipa/rppx1/ipa_context.cpp\n> > new file mode 100644\n> > index 000000000000..5ac60dfc7bf6\n> > --- /dev/null\n> > +++ b/src/ipa/rppx1/ipa_context.cpp\n> > @@ -0,0 +1,63 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2026 Renesas Electronics Corp.\n> > + * Copyright (C) 2026 Ideas on Board Oy\n> > + * Copyright (C) 2026 Ragnatech AB\n> > + *\n> > + * RPP-X1 IPA Context\n> > + */\n> > +\n> > +#include \"ipa_context.h\"\n> > +\n> > +/**\n> > + * \\file ipa_context.h\n> > + * \\brief Context and state information shared between the algorithms\n> > + */\n> > +\n> > +namespace libcamera::ipa::rppx1 {\n> > +\n> > +/**\n> > + * \\struct IPASessionConfiguration\n> > + * \\brief Session configuration for the IPA module\n> > + */\n> > +\n> > +/**\n> > + * \\struct IPAActiveState\n> > + * \\brief Active state for algorithms\n> > + */\n> > +\n> > +/**\n> > + * \\struct IPAFrameContext\n> > + * \\brief Per-frame context for algorithms\n> > + */\n> > +\n> > +/**\n> > + * \\struct IPAContext\n> > + * \\brief Global IPA context data shared between all algorithms\n> > + *\n> > + * \\var IPAContext::sensorInfo\n> > + * \\brief The IPA session sensorInfo, immutable during the session\n> > + *\n> > + * \\var IPAContext::configuration\n> > + * \\brief The IPA session configuration, immutable during the session\n> > + *\n> > + * \\var IPAContext::activeState\n> > + * \\brief The IPA active state, storing the latest state for all algorithms\n> > + *\n> > + * \\var IPAContext::frameContexts\n> > + * \\brief Ring buffer of per-frame contexts\n> > + *\n> > + * \\var IPAContext::ctrlMap\n> > + * \\brief The IPA map of controls\n> > + *\n> > + * \\var IPAContext::camHelper\n> > + * \\brief The IPA camera helper\n> > + */\n> > +\n> > +/**\n> > + * \\fn IPAContext::IPAContext\n> > + * \\brief Construct the IPA context\n> > + * \\param[in] frameContextSize Size of the frame context queue\n> > + */\n> > +\n> > +} /* namespace libcamera::ipa::rppx1 */\n> > diff --git a/src/ipa/rppx1/ipa_context.h b/src/ipa/rppx1/ipa_context.h\n> > new file mode 100644\n> > index 000000000000..f268a35081bc\n> > --- /dev/null\n> > +++ b/src/ipa/rppx1/ipa_context.h\n> > @@ -0,0 +1,55 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2026 Renesas Electronics Corp.\n> > + * Copyright (C) 2026 Ideas on Board Oy\n> > + * Copyright (C) 2026 Ragnatech AB\n> > + *\n> > + * RPP-X1 IPA Context\n> > + */\n> > +\n> > +#pragma once\n> > +\n> > +#include <memory>\n> > +\n> > +#include <linux/media/dreamchip/rppx1-config.h>\n> > +\n> > +#include <libcamera/controls.h>\n> > +\n> > +#include <libcamera/ipa/core_ipa_interface.h>\n> > +\n> > +#include <libipa/camera_sensor_helper.h>\n> > +#include <libipa/fc_queue.h>\n> > +\n> > +namespace libcamera {\n> > +\n> > +namespace ipa::rppx1 {\n> > +\n> > +struct IPASessionConfiguration {\n> > +};\n> > +\n> > +struct IPAActiveState {\n> > +};\n> > +\n> > +struct IPAFrameContext : public FrameContext {\n> > +};\n> > +\n> > +struct IPAContext {\n> > +\tIPAContext(unsigned int frameContextSize)\n> > +\t\t: frameContexts(frameContextSize)\n> > +\t{\n> > +\t}\n> > +\n> > +\tIPACameraSensorInfo sensorInfo;\n> > +\tIPASessionConfiguration configuration;\n> > +\tIPAActiveState activeState;\n> > +\n> > +\tFCQueue<IPAFrameContext> frameContexts;\n> > +\n> > +\tControlInfoMap::Map ctrlMap;\n> > +\n> > +\tstd::unique_ptr<CameraSensorHelper> camHelper;\n> > +};\n> > +\n> > +} /* namespace ipa::rppx1 */\n> > +\n> > +} /* namespace libcamera*/\n> > diff --git a/src/ipa/rppx1/meson.build b/src/ipa/rppx1/meson.build\n> > new file mode 100644\n> > index 000000000000..8034fe24d241\n> > --- /dev/null\n> > +++ b/src/ipa/rppx1/meson.build\n> > @@ -0,0 +1,26 @@\n> > +# SPDX-License-Identifier: CC0-1.0\n> > +\n> > +ipa_name = 'ipa_rppx1'\n> > +\n> > +rppx1_ipa_sources = files([\n> > +    'ipa_context.cpp',\n> > +    'rppx1.cpp',\n> > +])\n> > +\n> > +mod = shared_module(ipa_name, rppx1_ipa_sources,\n> > +                    name_prefix : '',\n> > +                    include_directories : [ipa_includes],\n> > +                    dependencies : [libcamera_private, libipa_dep],\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> > +\n> > +ipa_names += ipa_name\n> > diff --git a/src/ipa/rppx1/module.h b/src/ipa/rppx1/module.h\n> > new file mode 100644\n> > index 000000000000..0bacff64de8f\n> > --- /dev/null\n> > +++ b/src/ipa/rppx1/module.h\n> > @@ -0,0 +1,27 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2026 Renesas Electronics Corp.\n> > + * Copyright (C) 2026 Ideas on Board Oy\n> > + * Copyright (C) 2026 Ragnatech AB\n> > + *\n> > + * RPP-X1 IPA Module\n> > + */\n> > +\n> > +#pragma once\n> > +\n> > +#include <libipa/module.h>\n> > +\n> > +#include \"ipa_context.h\"\n> > +#include \"params.h\"\n> > +#include \"stats.h\"\n> > +\n> > +namespace libcamera {\n> > +\n> > +namespace ipa::rppx1 {\n> > +\n> > +using Module = ipa::Module<IPAContext, IPAFrameContext, IPACameraSensorInfo,\n> > +\t\t\t   RppX1Params, RppX1Stats>;\n> > +\n> > +} /* namespace ipa::rppx1 */\n> > +\n> > +} /* namespace libcamera*/\n> > diff --git a/src/ipa/rppx1/rppx1.cpp b/src/ipa/rppx1/rppx1.cpp\n> > new file mode 100644\n> > index 000000000000..20ca2d292704\n> > --- /dev/null\n> > +++ b/src/ipa/rppx1/rppx1.cpp\n> > @@ -0,0 +1,280 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2026 Renesas Electronics Corp.\n> > + * Copyright (C) 2026 Ideas on Board Oy\n> > + * Copyright (C) 2026 Ragnatech AB\n> > + *\n> > + * RPP-X1 Image Processing Algorithms\n> > + */\n> > +\n> > +#include <algorithm>\n> > +#include <stdint.h>\n> > +#include <string.h>\n> > +\n> > +#include <libcamera/base/file.h>\n> > +#include <libcamera/base/log.h>\n> > +\n> > +#include <libcamera/controls.h>\n> > +#include <libcamera/framebuffer.h>\n> > +\n> > +#include <libcamera/ipa/ipa_interface.h>\n> > +#include <libcamera/ipa/ipa_module_info.h>\n> > +#include <libcamera/ipa/rppx1_ipa_interface.h>\n> > +\n> > +#include \"libcamera/internal/formats.h\"\n> > +#include \"libcamera/internal/mapped_framebuffer.h\"\n> > +#include \"libcamera/internal/yaml_parser.h\"\n> > +\n> > +#include \"algorithms/algorithm.h\"\n> > +\n> > +#include \"ipa_context.h\"\n> > +#include \"params.h\"\n> > +#include \"stats.h\"\n> > +\n> > +namespace libcamera {\n> > +\n> > +LOG_DEFINE_CATEGORY(IPARppX1)\n> > +\n> > +namespace ipa::rppx1 {\n> > +\n> > +/* Maximum number of frame contexts to be held */\n> > +static constexpr uint32_t kMaxFrameContexts = 16;\n> > +\n> > +class IPARppX1 : public IPARppX1Interface, public Module\n> > +{\n> > +public:\n> > +\tIPARppX1();\n> > +\n> > +\tint init(const IPASettings &settings,\n> > +\t\t const IPACameraSensorInfo &sensorInfo,\n> > +\t\t const ControlInfoMap &sensorControls,\n> > +\t\t ControlInfoMap *ipaControls) override;\n> > +\tint start() override;\n> > +\tvoid stop() override;\n> > +\n> > +\tint configure(const IPAConfigInfo &ipaConfig,\n> > +\t\t      const std::map<uint32_t, IPAStream> &streamConfig,\n> > +\t\t      ControlInfoMap *ipaControls) override;\n> > +\tvoid mapBuffers(const std::vector<IPABuffer> &buffers) override;\n> > +\tvoid unmapBuffers(const std::vector<unsigned int> &ids) override;\n> > +\n> > +\tvoid queueRequest(const uint32_t frame, const ControlList &controls) override;\n> > +\tvoid computeParams(const uint32_t frame, const uint32_t bufferId) override;\n> > +\tvoid processStats(const uint32_t frame, const uint32_t bufferId,\n> > +\t\t\t  const ControlList &sensorControls) override;\n> > +\n> > +protected:\n> > +\tstd::string logPrefix() const override;\n> > +\n> > +private:\n> > +\tvoid updateControls(ControlInfoMap *ipaControls);\n> > +\n> > +\tstd::map<unsigned int, FrameBuffer> buffers_;\n> > +\tstd::map<unsigned int, MappedFrameBuffer> mappedBuffers_;\n> > +\n> > +\t/* Local parameter storage */\n> > +\tstruct IPAContext context_;\n> > +};\n> > +\n> > +IPARppX1::IPARppX1()\n> > +\t: context_(kMaxFrameContexts)\n> > +{\n> > +}\n> > +\n> > +std::string IPARppX1::logPrefix() const\n> > +{\n> > +\treturn \"rppx1\";\n> > +}\n> > +\n> > +void IPARppX1::updateControls(ControlInfoMap *ipaControls)\n> > +{\n> > +\tControlInfoMap::Map ctrlMap;\n> > +\n> > +\tctrlMap.insert(context_.ctrlMap.begin(), context_.ctrlMap.end());\n> > +\t*ipaControls = ControlInfoMap(std::move(ctrlMap), controls::controls);\n> > +}\n> > +\n> > +int IPARppX1::init(const IPASettings &settings,\n> > +\t\t   const IPACameraSensorInfo &sensorInfo,\n> > +\t\t   [[maybe_unused]] const ControlInfoMap &sensorControls,\n> > +\t\t   [[maybe_unused]] ControlInfoMap *ipaControls)\n> > +{\n> > +\tcontext_.sensorInfo = sensorInfo;\n> > +\n> > +\tcontext_.camHelper = CameraSensorHelperFactoryBase::create(settings.sensorModel);\n> > +\tif (!context_.camHelper) {\n> > +\t\tLOG(IPARppX1, Error)\n> > +\t\t\t<< \"Failed to create camera sensor helper for \"\n> > +\t\t\t<< settings.sensorModel;\n> > +\t\treturn -ENODEV;\n> > +\t}\n> > +\n> > +\t/* Load the tuning data file. */\n> > +\tFile file(settings.configurationFile);\n> > +\tif (!file.open(File::OpenModeFlag::ReadOnly)) {\n> > +\t\tint ret = file.error();\n> > +\t\tLOG(IPARppX1, Error)\n> > +\t\t\t<< \"Failed to open configuration file \"\n> > +\t\t\t<< settings.configurationFile << \": \" << strerror(-ret);\n> > +\t\treturn ret;\n> > +\t}\n> > +\n> > +\tstd::unique_ptr<libcamera::ValueNode> data = YamlParser::parse(file);\n> > +\tif (!data)\n> > +\t\treturn -EINVAL;\n> > +\n> > +\tunsigned int version = (*data)[\"version\"].get<uint32_t>(0);\n> > +\tif (version != 1) {\n> > +\t\tLOG(IPARppX1, Error)\n> > +\t\t\t<< \"Invalid tuning file version \" << version;\n> > +\t\treturn -EINVAL;\n> > +\t}\n> > +\n> > +\tif (!data->contains(\"algorithms\")) {\n> > +\t\tLOG(IPARppX1, Error)\n> > +\t\t\t<< \"Tuning file doesn't contain any algorithm\";\n> > +\t\treturn -EINVAL;\n> > +\t}\n> > +\n> > +\tint ret = createAlgorithms(context_, (*data)[\"algorithms\"]);\n> > +\tif (ret)\n> > +\t\treturn ret;\n> > +\n> > +\t/* Initialize controls. */\n> > +\tupdateControls(ipaControls);\n> > +\n> > +\treturn 0;\n> > +}\n> > +\n> > +int IPARppX1::start()\n> > +{\n> > +\t/* \\todo Properly handle startup controls. */\n> > +\treturn 0;\n> > +}\n> > +\n> > +void IPARppX1::stop()\n> > +{\n> > +\tcontext_.frameContexts.clear();\n> > +}\n> > +\n> > +int IPARppX1::configure(const IPAConfigInfo &ipaConfig,\n> > +\t\t\t[[maybe_unused]] const std::map<uint32_t, IPAStream> &streamConfig,\n> > +\t\t\t[[maybe_unused]] ControlInfoMap *ipaControls)\n> > +{\n> > +\t/* Clear the IPA context before the streaming session. */\n> > +\tcontext_.configuration = {};\n> > +\tcontext_.activeState = {};\n> > +\tcontext_.frameContexts.clear();\n> > +\n> > +\tconst IPACameraSensorInfo &info = ipaConfig.sensorInfo;\n> > +\n> > +\t/* Update the camera controls using the new sensor settings. */\n> > +\tupdateControls(ipaControls);\n> > +\n> > +\tfor (auto const &a : algorithms()) {\n> > +\t\tAlgorithm *algo = static_cast<Algorithm *>(a.get());\n> > +\n> > +\t\tint ret = algo->configure(context_, info);\n> > +\t\tif (ret)\n> > +\t\t\treturn ret;\n> > +\t}\n> > +\n> > +\treturn 0;\n> > +}\n> > +\n> > +void IPARppX1::mapBuffers(const std::vector<IPABuffer> &buffers)\n> > +{\n> > +\tfor (const IPABuffer &buffer : buffers) {\n> > +\t\tauto elem = buffers_.emplace(std::piecewise_construct,\n> > +\t\t\t\t\t     std::forward_as_tuple(buffer.id),\n> > +\t\t\t\t\t     std::forward_as_tuple(buffer.planes));\n> > +\t\tconst FrameBuffer &fb = elem.first->second;\n> > +\n> > +\t\tMappedFrameBuffer mappedBuffer(&fb, MappedFrameBuffer::MapFlag::ReadWrite);\n> > +\t\tif (!mappedBuffer.isValid()) {\n> > +\t\t\tLOG(IPARppX1, Fatal) << \"Failed to mmap buffer: \"\n> > +\t\t\t\t\t     << strerror(mappedBuffer.error());\n> > +\t\t}\n> > +\n> > +\t\tmappedBuffers_.emplace(buffer.id, std::move(mappedBuffer));\n> > +\t}\n> > +}\n> > +\n> > +void IPARppX1::unmapBuffers(const std::vector<unsigned int> &ids)\n> > +{\n> > +\tfor (unsigned int id : ids) {\n> > +\t\tconst auto fb = buffers_.find(id);\n> > +\t\tif (fb == buffers_.end())\n> > +\t\t\tcontinue;\n> > +\n> > +\t\tmappedBuffers_.erase(id);\n> > +\t\tbuffers_.erase(id);\n> > +\t}\n> > +}\n> > +\n> > +void IPARppX1::queueRequest(const uint32_t frame, const ControlList &controls)\n> > +{\n> > +\tIPAFrameContext &frameContext = context_.frameContexts.alloc(frame);\n> > +\n> > +\tfor (auto const &a : algorithms()) {\n> > +\t\tAlgorithm *algo = static_cast<Algorithm *>(a.get());\n> > +\t\tif (algo->disabled_)\n> > +\t\t\tcontinue;\n> > +\n> > +\t\talgo->queueRequest(context_, frame, frameContext, controls);\n> > +\t}\n> > +}\n> > +\n> > +void IPARppX1::computeParams(const uint32_t frame, const uint32_t bufferId)\n> > +{\n> > +\tIPAFrameContext &frameContext = context_.frameContexts.get(frame);\n> > +\n> > +\tRppX1Params params(mappedBuffers_.at(bufferId).planes()[0]);\n> > +\n> > +\tfor (auto const &algo : algorithms())\n> > +\t\talgo->prepare(context_, frame, frameContext, &params);\n> > +\n> > +\tparamsComputed.emit(frame, params.bytesused());\n> > +}\n> > +\n> > +void IPARppX1::processStats(const uint32_t frame, const uint32_t bufferId,\n> > +\t\t\t    [[maybe_unused]] const ControlList &sensorControls)\n> > +{\n> > +\tIPAFrameContext &frameContext = context_.frameContexts.get(frame);\n> > +\n> > +\tControlList metadata(controls::controls);\n> > +\n> > +\tauto stats = RppX1Stats(mappedBuffers_.at(bufferId).planes()[0]);\n> > +\tif (!stats)\n> > +\t\treturn;\n> > +\n> > +\tfor (auto const &a : algorithms()) {\n> > +\t\tAlgorithm *algo = static_cast<Algorithm *>(a.get());\n> > +\t\tif (algo->disabled_)\n> > +\t\t\tcontinue;\n> > +\t\talgo->process(context_, frame, frameContext, &stats, metadata);\n> > +\t}\n> > +\n> > +\tmetadataReady.emit(frame, metadata);\n> > +}\n> > +\n> > +} /* namespace ipa::rppx1 */\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\"rppx1\",\n> > +};\n> > +\n> > +IPAInterface *ipaCreate()\n> > +{\n> > +\treturn new ipa::rppx1::IPARppX1();\n> > +}\n> > +}\n> > +\n> > +} /* namespace libcamera */\n> >\n> > --\n> > 2.54.0\n> >\n>\n> --\n> Kind Regards,\n> Niklas Söderlund","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 6E91BBF415\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 22 Jun 2026 12:13:43 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id DB00C65728;\n\tMon, 22 Jun 2026 14:13:41 +0200 (CEST)","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 5DFB5656D3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 22 Jun 2026 14:13:39 +0200 (CEST)","from ideasonboard.com (mob-109-113-9-173.net.vodafone.it\n\t[109.113.9.173])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 9A3C5492;\n\tMon, 22 Jun 2026 14:13:00 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"pC2ouM7m\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1782130381;\n\tbh=BJba+1OyO4gCqV+SrdBQFH1eH/MKGUfftuh32w4vuQs=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=pC2ouM7me/EFqxLgBukLGc5acu8WGMX4eYYSKM0fPOJIqe9CXiFrf7KDaykZJTpLq\n\tv9Wa/YYgYlmaUv0hOOGvNyJXWgRF9swTta4moDk0JsKd3/r1gDn0AHzTvEvp9Qgofm\n\ts3CyWsQw2Xkdv9Xdl4nkMLM2ls5jkfmpNnDZZkA0=","Date":"Mon, 22 Jun 2026 14:13:35 +0200","From":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"Niklas =?utf-8?q?S=C3=B6derlund?= <niklas.soderlund+renesas@ragnatech.se>","Cc":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>, \n\tlibcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH 11/14] ipa: rppx1: Add RPP-X1 IPA skeleton","Message-ID":"<ajkmsqrUSJeh6sx2@zed>","References":"<20260618-rppx1-ipa-v1-0-32337264cfcd@ideasonboard.com>\n\t<20260618-rppx1-ipa-v1-11-32337264cfcd@ideasonboard.com>\n\t<20260619150955.GA3631325@ragnatech.se>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20260619150955.GA3631325@ragnatech.se>","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>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]