[{"id":28827,"web_url":"https://patchwork.libcamera.org/comment/28827/","msgid":"<871q8pc443.fsf@redhat.com>","date":"2024-03-04T17:13:16","subject":"Re: [PATCH v4 09/18] libcamera: ipa: add Soft IPA","submitter":{"id":177,"url":"https://patchwork.libcamera.org/api/people/177/","name":"Milan Zamazal","email":"mzamazal@redhat.com"},"content":"Hans de Goede <hdegoede@redhat.com> writes:\n\n> From: Andrey Konovalov <andrey.konovalov@linaro.org>\n>\n> Define the Soft IPA main and event interfaces, add the Soft IPA\n> implementation.\n>\n> The current src/ipa/meson.build assumes the IPA name to match the\n> pipeline name. For this reason \"-Dipas=simple\" is used for the\n> Soft IPA module.\n>\n> Auto exposure/gain and AWB implementation by Dennis, Toon and Martti.\n>\n> Auto exposure/gain targets a Mean Sample Value of 2.5 following\n> the MSV calculation algorithm from:\n> https://www.araa.asn.au/acra/acra2007/papers/paper84final.pdf\n>\n> Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> # sc8280xp Lenovo x13s\n> Tested-by: Pavel Machek <pavel@ucw.cz>\n> Reviewed-by: Pavel Machek <pavel@ucw.cz>\n> Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org>\n> Co-developed-by: Dennis Bonke <admin@dennisbonke.com>\n> Signed-off-by: Dennis Bonke <admin@dennisbonke.com>\n> Co-developed-by: Marttico <g.martti@gmail.com>\n> Signed-off-by: Marttico <g.martti@gmail.com>\n> Co-developed-by: Toon Langendam <t.langendam@gmail.com>\n> Signed-off-by: Toon Langendam <t.langendam@gmail.com>\n> Signed-off-by: Hans de Goede <hdegoede@redhat.com>\n\nAs for the white balance and exposure adjustments, the patch looks good to me.\nI leave the other stuff for other reviewers.\n\n> ---\n> Changes in v4:\n> - Use int32_t for again*_ and exposure*_ as this matches\n>   the value the corresponding ControlValue::get() returns\n> - Check for mmap() returning MAP_FAILED on error\n> - Drop std::move() called on const SharedFD & argument\n> - Replace #defines (EXPOSURE_OPTIMAL_VALUE etc) with const expressions\n> - Use std::clamp() to keep exposure_ and again_ between the *_min_ and\n>   the *_max_\n> - add comment on non-linear gain value vs gain code\n>\n> Changes in v3:\n> - Use new SwIspStats::kYHistogramSize constexpr and adjust\n>   the auto-exposure/-gain code so that it can deal with\n>   that having a different value then 16 (modify the loop\n>   to divide the histogram in 5 bins to not have hardcoded\n>   values)\n> - Rename a few foo_bar symbols to fooBar\n> ---\n>  Documentation/Doxyfile.in         |   1 +\n>  include/libcamera/ipa/meson.build |   1 +\n>  include/libcamera/ipa/soft.mojom  |  28 +++\n>  meson_options.txt                 |   2 +-\n>  src/ipa/simple/data/meson.build   |   9 +\n>  src/ipa/simple/data/soft.conf     |   3 +\n>  src/ipa/simple/meson.build        |  25 +++\n>  src/ipa/simple/soft_simple.cpp    | 326 ++++++++++++++++++++++++++++++\n>  8 files changed, 394 insertions(+), 1 deletion(-)\n>  create mode 100644 include/libcamera/ipa/soft.mojom\n>  create mode 100644 src/ipa/simple/data/meson.build\n>  create mode 100644 src/ipa/simple/data/soft.conf\n>  create mode 100644 src/ipa/simple/meson.build\n>  create mode 100644 src/ipa/simple/soft_simple.cpp\n>\n> diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in\n> index a86ea6c1..2be8d47b 100644\n> --- a/Documentation/Doxyfile.in\n> +++ b/Documentation/Doxyfile.in\n> @@ -44,6 +44,7 @@ EXCLUDE                = @TOP_SRCDIR@/include/libcamera/base/span.h \\\n>                           @TOP_SRCDIR@/src/libcamera/pipeline/ \\\n>                           @TOP_SRCDIR@/src/libcamera/tracepoints.cpp \\\n>                           @TOP_BUILDDIR@/include/libcamera/internal/tracepoints.h \\\n> +                         @TOP_BUILDDIR@/include/libcamera/ipa/soft_ipa_interface.h \\\n>                           @TOP_BUILDDIR@/src/libcamera/proxy/\n>  \n>  EXCLUDE_PATTERNS       = @TOP_BUILDDIR@/include/libcamera/ipa/*_serializer.h \\\n> diff --git a/include/libcamera/ipa/meson.build b/include/libcamera/ipa/meson.build\n> index f3b4881c..3352d08f 100644\n> --- a/include/libcamera/ipa/meson.build\n> +++ b/include/libcamera/ipa/meson.build\n> @@ -65,6 +65,7 @@ pipeline_ipa_mojom_mapping = {\n>      'ipu3': 'ipu3.mojom',\n>      'rkisp1': 'rkisp1.mojom',\n>      'rpi/vc4': 'raspberrypi.mojom',\n> +    'simple': 'soft.mojom',\n>      'vimc': 'vimc.mojom',\n>  }\n>  \n> diff --git a/include/libcamera/ipa/soft.mojom b/include/libcamera/ipa/soft.mojom\n> new file mode 100644\n> index 00000000..c249bd75\n> --- /dev/null\n> +++ b/include/libcamera/ipa/soft.mojom\n> @@ -0,0 +1,28 @@\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.soft;\n> +\n> +import \"include/libcamera/ipa/core.mojom\";\n> +\n> +interface IPASoftInterface {\n> +\tinit(libcamera.IPASettings settings,\n> +\t     libcamera.SharedFD fdStats,\n> +\t     libcamera.SharedFD fdParams,\n> +\t     libcamera.ControlInfoMap sensorCtrlInfoMap)\n> +\t\t=> (int32 ret);\n> +\tstart() => (int32 ret);\n> +\tstop();\n> +\tconfigure(libcamera.ControlInfoMap sensorCtrlInfoMap)\n> +\t\t=> (int32 ret);\n> +\n> +\t[async] processStats(libcamera.ControlList sensorControls);\n> +};\n> +\n> +interface IPASoftEventInterface {\n> +\tsetSensorControls(libcamera.ControlList sensorControls);\n> +\tsetIspParams(int32 dummy);\n> +};\n> diff --git a/meson_options.txt b/meson_options.txt\n> index 99dab96d..2644bef0 100644\n> --- a/meson_options.txt\n> +++ b/meson_options.txt\n> @@ -27,7 +27,7 @@ option('gstreamer',\n>  \n>  option('ipas',\n>          type : 'array',\n> -        choices : ['ipu3', 'rkisp1', 'rpi/vc4', 'vimc'],\n> +        choices : ['ipu3', 'rkisp1', 'rpi/vc4', 'simple', 'vimc'],\n>          description : 'Select which IPA modules to build')\n>  \n>  option('lc-compliance',\n> diff --git a/src/ipa/simple/data/meson.build b/src/ipa/simple/data/meson.build\n> new file mode 100644\n> index 00000000..33548cc6\n> --- /dev/null\n> +++ b/src/ipa/simple/data/meson.build\n> @@ -0,0 +1,9 @@\n> +# SPDX-License-Identifier: CC0-1.0\n> +\n> +conf_files = files([\n> +    'soft.conf',\n> +])\n> +\n> +install_data(conf_files,\n> +             install_dir : ipa_data_dir / 'soft',\n> +             install_tag : 'runtime')\n> diff --git a/src/ipa/simple/data/soft.conf b/src/ipa/simple/data/soft.conf\n> new file mode 100644\n> index 00000000..0c70e7c0\n> --- /dev/null\n> +++ b/src/ipa/simple/data/soft.conf\n> @@ -0,0 +1,3 @@\n> +# SPDX-License-Identifier: LGPL-2.1-or-later\n> +#\n> +# Dummy configuration file for the soft IPA.\n> diff --git a/src/ipa/simple/meson.build b/src/ipa/simple/meson.build\n> new file mode 100644\n> index 00000000..3e863db7\n> --- /dev/null\n> +++ b/src/ipa/simple/meson.build\n> @@ -0,0 +1,25 @@\n> +# SPDX-License-Identifier: CC0-1.0\n> +\n> +ipa_name = 'ipa_soft_simple'\n> +\n> +mod = shared_module(ipa_name,\n> +                    ['soft_simple.cpp', libcamera_generated_ipa_headers],\n> +                    name_prefix : '',\n> +                    include_directories : [ipa_includes, libipa_includes],\n> +                    dependencies : libcamera_private,\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> +\n> +subdir('data')\n> +\n> +ipa_names += ipa_name\n> diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp\n> new file mode 100644\n> index 00000000..312df4ba\n> --- /dev/null\n> +++ b/src/ipa/simple/soft_simple.cpp\n> @@ -0,0 +1,326 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2023, Linaro Ltd\n> + *\n> + * soft_simple.cpp - Simple Software Image Processing Algorithm module\n> + */\n> +\n> +#include <sys/mman.h>\n> +\n> +#include <libcamera/base/file.h>\n> +#include <libcamera/base/log.h>\n> +#include <libcamera/base/shared_fd.h>\n> +\n> +#include <libcamera/control_ids.h>\n> +#include <libcamera/controls.h>\n> +\n> +#include <libcamera/ipa/ipa_interface.h>\n> +#include <libcamera/ipa/ipa_module_info.h>\n> +#include <libcamera/ipa/soft_ipa_interface.h>\n> +\n> +#include \"libcamera/internal/camera_sensor.h\"\n> +#include \"libcamera/internal/software_isp/debayer_params.h\"\n> +#include \"libcamera/internal/software_isp/swisp_stats.h\"\n> +\n> +namespace libcamera {\n> +\n> +LOG_DEFINE_CATEGORY(IPASoft)\n> +\n> +namespace ipa::soft {\n> +\n> +class IPASoftSimple : public ipa::soft::IPASoftInterface\n> +{\n> +public:\n> +\tIPASoftSimple()\n> +\t\t: params_(static_cast<DebayerParams *>(MAP_FAILED)),\n> +\t\t  stats_(static_cast<SwIspStats *>(MAP_FAILED)), ignore_updates_(0)\n> +\t{\n> +\t}\n> +\n> +\t~IPASoftSimple()\n> +\t{\n> +\t\tif (stats_ != MAP_FAILED)\n> +\t\t\tmunmap(stats_, sizeof(SwIspStats));\n> +\t\tif (params_ != MAP_FAILED)\n> +\t\t\tmunmap(params_, sizeof(DebayerParams));\n> +\t}\n> +\n> +\tint init(const IPASettings &settings,\n> +\t\t const SharedFD &fdStats,\n> +\t\t const SharedFD &fdParams,\n> +\t\t const ControlInfoMap &sensorInfoMap) override;\n> +\tint configure(const ControlInfoMap &sensorInfoMap) override;\n> +\n> +\tint start() override;\n> +\tvoid stop() override;\n> +\n> +\tvoid processStats(const ControlList &sensorControls) override;\n> +\n> +private:\n> +\tvoid updateExposure(double exposureMSV);\n> +\n> +\tSharedFD fdStats_;\n> +\tSharedFD fdParams_;\n> +\tDebayerParams *params_;\n> +\tSwIspStats *stats_;\n> +\n> +\tint32_t exposure_min_, exposure_max_;\n> +\tint32_t again_min_, again_max_;\n> +\tint32_t again_, exposure_;\n> +\tunsigned int ignore_updates_;\n> +};\n> +\n> +int IPASoftSimple::init([[maybe_unused]] const IPASettings &settings,\n> +\t\t\tconst SharedFD &fdStats,\n> +\t\t\tconst SharedFD &fdParams,\n> +\t\t\tconst ControlInfoMap &sensorInfoMap)\n> +{\n> +\tfdStats_ = fdStats;\n> +\tif (!fdStats_.isValid()) {\n> +\t\tLOG(IPASoft, Error) << \"Invalid Statistics handle\";\n> +\t\treturn -ENODEV;\n> +\t}\n> +\n> +\tfdParams_ = fdParams;\n> +\tif (!fdParams_.isValid()) {\n> +\t\tLOG(IPASoft, Error) << \"Invalid Parameters handle\";\n> +\t\treturn -ENODEV;\n> +\t}\n> +\n> +\tparams_ = static_cast<DebayerParams *>(mmap(nullptr, sizeof(DebayerParams),\n> +\t\t\t\t\t\t    PROT_WRITE, MAP_SHARED,\n> +\t\t\t\t\t\t    fdParams_.get(), 0));\n> +\tif (params_ == MAP_FAILED) {\n> +\t\tLOG(IPASoft, Error) << \"Unable to map Parameters\";\n> +\t\treturn -errno;\n> +\t}\n> +\n> +\tstats_ = static_cast<SwIspStats *>(mmap(nullptr, sizeof(SwIspStats),\n> +\t\t\t\t\t\tPROT_READ, MAP_SHARED,\n> +\t\t\t\t\t\tfdStats_.get(), 0));\n> +\tif (stats_ == MAP_FAILED) {\n> +\t\tLOG(IPASoft, Error) << \"Unable to map Statistics\";\n> +\t\treturn -errno;\n> +\t}\n> +\n> +\tif (sensorInfoMap.find(V4L2_CID_EXPOSURE) == sensorInfoMap.end()) {\n> +\t\tLOG(IPASoft, Error) << \"Don't have exposure control\";\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tif (sensorInfoMap.find(V4L2_CID_ANALOGUE_GAIN) == sensorInfoMap.end()) {\n> +\t\tLOG(IPASoft, Error) << \"Don't have gain control\";\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\treturn 0;\n> +}\n> +\n> +int IPASoftSimple::configure(const ControlInfoMap &sensorInfoMap)\n> +{\n> +\tconst ControlInfo &exposure_info = sensorInfoMap.find(V4L2_CID_EXPOSURE)->second;\n> +\tconst ControlInfo &gain_info = sensorInfoMap.find(V4L2_CID_ANALOGUE_GAIN)->second;\n> +\n> +\texposure_min_ = exposure_info.min().get<int32_t>();\n> +\texposure_max_ = exposure_info.max().get<int32_t>();\n> +\tif (!exposure_min_) {\n> +\t\tLOG(IPASoft, Warning) << \"Minimum exposure is zero, that can't be linear\";\n> +\t\texposure_min_ = 1;\n> +\t}\n> +\n> +\tagain_min_ = gain_info.min().get<int32_t>();\n> +\tagain_max_ = gain_info.max().get<int32_t>();\n> +\t/*\n> +\t * The camera sensor gain (g) is usually not equal to the value written\n> +\t * into the gain register (x). But the way how the AGC algorithm changes\n> +\t * the gain value to make the total exposure closer to the optimum assumes\n> +\t * that g(x) is not too far from linear function. If the minimal gain is 0,\n> +\t * the g(x) is likely to be far from the linear, like g(x) = a / (b * x + c).\n> +\t * To avoid unexpected changes to the gain by the AGC algorithm (abrupt near\n> +\t * one edge, and very small near the other) we limit the range of the gain\n> +\t * values used.\n> +\t */\n> +\tif (!again_min_) {\n> +\t\tLOG(IPASoft, Warning) << \"Minimum gain is zero, that can't be linear\";\n> +\t\tagain_min_ = std::min(100, again_min_ / 2 + again_max_ / 2);\n> +\t}\n> +\n> +\tLOG(IPASoft, Info) << \"Exposure \" << exposure_min_ << \"-\" << exposure_max_\n> +\t\t\t   << \", gain \" << again_min_ << \"-\" << again_max_;\n> +\n> +\treturn 0;\n> +}\n> +\n> +int IPASoftSimple::start()\n> +{\n> +\treturn 0;\n> +}\n> +\n> +void IPASoftSimple::stop()\n> +{\n> +}\n> +\n> +/*\n> + * The number of bins to use for the optimal exposure calculations.\n> + */\n> +static constexpr unsigned int kExposureBinsCount = 5;\n> +/*\n> + * The exposure is optimal when the mean sample value of the histogram is\n> + * in the middle of the range.\n> + */\n> +static constexpr float kExposureOptimal = kExposureBinsCount / 2.0;\n> +/*\n> + * The below value implements the hysteresis for the exposure adjustment.\n> + * It is small enough to have the exposure close to the optimal, and is big\n> + * enough to prevent the exposure from wobbling around the optimal value.\n> + */\n> +static constexpr float kExposureSatisfactory = 0.2;\n> +\n> +void IPASoftSimple::processStats(const ControlList &sensorControls)\n> +{\n> +\t/*\n> +\t * Calculate red and blue gains for AWB.\n> +\t * Clamp max gain at 4.0, this also avoids 0 division.\n> +\t */\n> +\tif (stats_->sumR_ <= stats_->sumG_ / 4)\n> +\t\tparams_->gainR = 1024;\n> +\telse\n> +\t\tparams_->gainR = 256 * stats_->sumG_ / stats_->sumR_;\n> +\n> +\tif (stats_->sumB_ <= stats_->sumG_ / 4)\n> +\t\tparams_->gainB = 1024;\n> +\telse\n> +\t\tparams_->gainB = 256 * stats_->sumG_ / stats_->sumB_;\n> +\n> +\t/* Green gain and gamma values are fixed */\n> +\tparams_->gainG = 256;\n> +\tparams_->gamma = 0.5;\n> +\n> +\tsetIspParams.emit(0);\n> +\n> +\t/*\n> +\t * AE / AGC, use 2 frames delay to make sure that the exposure and\n> +\t * the gain set have applied to the camera sensor.\n> +\t */\n> +\tif (ignore_updates_ > 0) {\n> +\t\t--ignore_updates_;\n> +\t\treturn;\n> +\t}\n> +\n> +\t/*\n> +\t * Calculate Mean Sample Value (MSV) according to formula from:\n> +\t * https://www.araa.asn.au/acra/acra2007/papers/paper84final.pdf\n> +\t */\n> +\tconstexpr unsigned int yHistValsPerBin =\n> +\t\tSwIspStats::kYHistogramSize / kExposureBinsCount;\n> +\tconstexpr unsigned int yHistValsPerBinMod =\n> +\t\tSwIspStats::kYHistogramSize /\n> +\t\t(SwIspStats::kYHistogramSize % kExposureBinsCount + 1);\n> +\tint ExposureBins[kExposureBinsCount] = {};\n> +\tunsigned int denom = 0;\n> +\tunsigned int num = 0;\n> +\n> +\tfor (unsigned int i = 0; i < SwIspStats::kYHistogramSize; i++) {\n> +\t\tunsigned int idx = (i - (i / yHistValsPerBinMod)) / yHistValsPerBin;\n> +\t\tExposureBins[idx] += stats_->yHistogram[i];\n> +\t}\n> +\n> +\tfor (unsigned int i = 0; i < kExposureBinsCount; i++) {\n> +\t\tLOG(IPASoft, Debug) << i << \": \" << ExposureBins[i];\n> +\t\tdenom += ExposureBins[i];\n> +\t\tnum += ExposureBins[i] * (i + 1);\n> +\t}\n> +\n> +\tfloat exposureMSV = (float)num / denom;\n> +\n> +\t/* sanity check */\n> +\tif (!sensorControls.contains(V4L2_CID_EXPOSURE) ||\n> +\t    !sensorControls.contains(V4L2_CID_ANALOGUE_GAIN)) {\n> +\t\tLOG(IPASoft, Error) << \"Control(s) missing\";\n> +\t\treturn;\n> +\t}\n> +\n> +\tControlList ctrls(sensorControls);\n> +\n> +\texposure_ = ctrls.get(V4L2_CID_EXPOSURE).get<int32_t>();\n> +\tagain_ = ctrls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>();\n> +\n> +\tupdateExposure(exposureMSV);\n> +\n> +\tctrls.set(V4L2_CID_EXPOSURE, exposure_);\n> +\tctrls.set(V4L2_CID_ANALOGUE_GAIN, again_);\n> +\n> +\tignore_updates_ = 2;\n> +\n> +\tsetSensorControls.emit(ctrls);\n> +\n> +\tLOG(IPASoft, Debug) << \"exposureMSV \" << exposureMSV\n> +\t\t\t    << \" exp \" << exposure_ << \" again \" << again_\n> +\t\t\t    << \" gain R/B \" << params_->gainR << \"/\" << params_->gainB;\n> +}\n> +\n> +void IPASoftSimple::updateExposure(double exposureMSV)\n> +{\n> +\t/* DENOMINATOR of 10 gives ~10% increment/decrement; DENOMINATOR of 5 - about ~20% */\n> +\tstatic constexpr uint8_t kExpDenominator = 10;\n> +\tstatic constexpr uint8_t kExpNumeratorUp = kExpDenominator + 1;\n> +\tstatic constexpr uint8_t kExpNumeratorDown = kExpDenominator - 1;\n> +\n> +\tint next;\n> +\n> +\tif (exposureMSV < kExposureOptimal - kExposureSatisfactory) {\n> +\t\tnext = exposure_ * kExpNumeratorUp / kExpDenominator;\n> +\t\tif (next - exposure_ < 1)\n> +\t\t\texposure_ += 1;\n> +\t\telse\n> +\t\t\texposure_ = next;\n> +\t\tif (exposure_ >= exposure_max_) {\n> +\t\t\tnext = again_ * kExpNumeratorUp / kExpDenominator;\n> +\t\t\tif (next - again_ < 1)\n> +\t\t\t\tagain_ += 1;\n> +\t\t\telse\n> +\t\t\t\tagain_ = next;\n> +\t\t}\n> +\t}\n> +\n> +\tif (exposureMSV > kExposureOptimal + kExposureSatisfactory) {\n> +\t\tif (exposure_ == exposure_max_ && again_ != again_min_) {\n> +\t\t\tnext = again_ * kExpNumeratorDown / kExpDenominator;\n> +\t\t\tif (again_ - next < 1)\n> +\t\t\t\tagain_ -= 1;\n> +\t\t\telse\n> +\t\t\t\tagain_ = next;\n> +\t\t} else {\n> +\t\t\tnext = exposure_ * kExpNumeratorDown / kExpDenominator;\n> +\t\t\tif (exposure_ - next < 1)\n> +\t\t\t\texposure_ -= 1;\n> +\t\t\telse\n> +\t\t\t\texposure_ = next;\n> +\t\t}\n> +\t}\n> +\n> +\texposure_ = std::clamp(exposure_, exposure_min_, exposure_max_);\n> +\tagain_ = std::clamp(again_, again_min_, again_max_);\n> +}\n> +\n> +} /* namespace ipa::soft */\n> +\n> +/*\n> + * External IPA module interface\n> + */\n> +extern \"C\" {\n> +const struct IPAModuleInfo ipaModuleInfo = {\n> +\tIPA_MODULE_API_VERSION,\n> +\t0,\n> +\t\"SimplePipelineHandler\",\n> +\t\"simple\",\n> +};\n> +\n> +IPAInterface *ipaCreate()\n> +{\n> +\treturn new ipa::soft::IPASoftSimple();\n> +}\n> +\n> +} /* extern \"C\" */\n> +\n> +} /* namespace libcamera */","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 1905BC326B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon,  4 Mar 2024 17:13:34 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 6B7F762867;\n\tMon,  4 Mar 2024 18:13:33 +0100 (CET)","from us-smtp-delivery-124.mimecast.com\n\t(us-smtp-delivery-124.mimecast.com [170.10.133.124])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id D5A66627FC\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon,  4 Mar 2024 18:13:30 +0100 (CET)","from mail-wm1-f69.google.com (mail-wm1-f69.google.com\n\t[209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS\n\t(version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n\tus-mta-328-u7XHHOPPMiSVCrZw6CYKag-1; Mon, 04 Mar 2024 12:13:20 -0500","by mail-wm1-f69.google.com with SMTP id\n\t5b1f17b1804b1-40e435a606aso29987305e9.3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 04 Mar 2024 09:13:19 -0800 (PST)","from nuthatch (nat-pool-brq-t.redhat.com. [213.175.37.10])\n\tby smtp.gmail.com with ESMTPSA id\n\tjd20-20020a05600c68d400b004128fa77216sm18171862wmb.1.2024.03.04.09.13.16\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tMon, 04 Mar 2024 09:13:16 -0800 (PST)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=redhat.com header.i=@redhat.com\n\theader.b=\"eIQZBvgJ\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1709572405;\n\th=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n\tto:to:cc:cc:mime-version:mime-version:content-type:content-type:\n\tin-reply-to:in-reply-to:references:references;\n\tbh=chqBl3Y/xoc3fj4aq+krpGUTwoUlXi+n1k9I49+kDDY=;\n\tb=eIQZBvgJHSWMdHt2U0b1BI8Zu2ZWzFM8auTE1TLAI+haPvOIj7DRM08jzU8VE4ymug1smz\n\tmhA+64FFM6G6SG77s4Z/e5NJmcrqFFLoSSlqjwVWwbJ0Tx+6JPsLdcfqso4J2d+zHY8CvX\n\tMi/xT7lunqG++x31v4mAeKq6Ruq0mok=","X-MC-Unique":"u7XHHOPPMiSVCrZw6CYKag-1","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1709572399; x=1710177199;\n\th=mime-version:user-agent:message-id:date:references:in-reply-to\n\t:subject:cc:to:from:x-gm-message-state:from:to:cc:subject:date\n\t:message-id:reply-to;\n\tbh=chqBl3Y/xoc3fj4aq+krpGUTwoUlXi+n1k9I49+kDDY=;\n\tb=mH2XmeN04X2nfBGYLbsxg6GVr5xMbseENclKfaEOdU/30STqbFL09NZtdPaReOTiE3\n\t7Y2C2NgMOMlAUzb0ld37HyL3ynz+Bsy/rGNq8w5VEwCeyxvQmDHKpCi4J2djWeEafzdd\n\tjXw+AnlsltDhpk2jmM1FoYgsAMghm9zGp1as7HuyshmfsPIb44gWNzzV7cXbzm+o2DhP\n\tP9xWAB8E050AMrQL8+3xqntZ3eAXOeaMc3xDRWDfdURgmW8M3650uYmk6WmPeulXleWN\n\tyLSq6KKIWZexys7Q/d9RfVuJWQptumzidtjJk/4+fOR2bbS0kqtqByx23V2TWhRu0Koz\n\t0bUw==","X-Gm-Message-State":"AOJu0YyJa6Ae44RNnnD0MoQhGlwhH61EncfsYQ3MOd6Px7t1mQVRhZGO\n\tPKK+iTbTdqfVBGkiZ04fj4zlKutbWlUbUXu8r/aXkgJhg5x7dBCZoy9BauniKXRbOjEwOO7q7UG\n\tNH2WNhgunIYyNt9nKMFfAQUMwLnE80NehNWTmx8wqojBcHqhuJKUZie8Rig7LRkb+ZHgyGh0=","X-Received":["by 2002:a05:600c:4ed1:b0:412:b121:87e3 with SMTP id\n\tg17-20020a05600c4ed100b00412b12187e3mr6895180wmq.22.1709572398757; \n\tMon, 04 Mar 2024 09:13:18 -0800 (PST)","by 2002:a05:600c:4ed1:b0:412:b121:87e3 with SMTP id\n\tg17-20020a05600c4ed100b00412b12187e3mr6895163wmq.22.1709572398341; \n\tMon, 04 Mar 2024 09:13:18 -0800 (PST)"],"X-Google-Smtp-Source":"AGHT+IHKieaS1WcA0KD1hrr1qKmcmShzW0kqwHrujhKVY18zAoj2XpFLscOSI3CgKW8xSrgUYDxs/g==","From":"Milan Zamazal <mzamazal@redhat.com>","To":"Hans de Goede <hdegoede@redhat.com>","Subject":"Re: [PATCH v4 09/18] libcamera: ipa: add Soft IPA","In-Reply-To":"<20240229183654.7206-10-hdegoede@redhat.com> (Hans de Goede's\n\tmessage of \"Thu, 29 Feb 2024 19:36:20 +0100\")","References":"<20240229183654.7206-1-hdegoede@redhat.com>\n\t<20240229183654.7206-10-hdegoede@redhat.com>","Date":"Mon, 04 Mar 2024 18:13:16 +0100","Message-ID":"<871q8pc443.fsf@redhat.com>","User-Agent":"Gnus/5.13 (Gnus v5.13)","MIME-Version":"1.0","X-Mimecast-Spam-Score":"0","X-Mimecast-Originator":"redhat.com","Content-Type":"text/plain","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":"Maxime Ripard <mripard@redhat.com>, Marttico <g.martti@gmail.com>,\n\tToon Langendam <t.langendam@gmail.com>,\n\tlibcamera-devel@lists.libcamera.org, Pavel Machek <pavel@ucw.cz>,\n\tBryan O'Donoghue <bryan.odonoghue@linaro.org>, \n\tDennis Bonke <admin@dennisbonke.com>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]