[{"id":36107,"web_url":"https://patchwork.libcamera.org/comment/36107/","msgid":"<CAHW6GYKvcEVJOApRLqpQZq=T51WsdqmpMynzcgrRqstNUSQE=A@mail.gmail.com>","date":"2025-10-03T13:59:50","subject":"Re: [PATCH v2 1/4] ipa: rpi: pisp: Add decompand support using PiSP\n\thardware block","submitter":{"id":42,"url":"https://patchwork.libcamera.org/api/people/42/","name":"David Plowman","email":"david.plowman@raspberrypi.com"},"content":"Hi Naush\n\nThanks for the patch.\n\nOn Fri, 3 Oct 2025 at 13:18, Naushir Patuck <naush@raspberrypi.com> wrote:\n>\n> From: Sena Asotani <aso.fam429@gmail.com>\n>\n> This patch integrates a new decompand algorithm that utilizes the PiSP\n> FE hardware block available on Raspberry Pi 5. The implementation\n> enables conversion of companded sensor data into linear format prior to\n> ISP processing.\n>\n> Changes include:\n> - Implementation of decompand logic for controller and pipe interfaces\n> - Enabling decompand block by \"rpi.decompand\" in tuning.json\n>\n> Signed-off-by: Sena Asotani <aso.fam429@gmail.com>\n> Signed-off-by: Naushir Patuck <naush@raspberrypi.com>\n> Tested-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>\n> ---\n>  src/ipa/rpi/controller/decompand_status.h |  8 ++++\n>  src/ipa/rpi/controller/meson.build        |  1 +\n>  src/ipa/rpi/controller/rpi/decompand.cpp  | 58 +++++++++++++++++++++++\n>  src/ipa/rpi/controller/rpi/decompand.h    | 31 ++++++++++++\n>  src/ipa/rpi/pisp/pisp.cpp                 | 38 +++++++++++++++\n>  5 files changed, 136 insertions(+)\n>  create mode 100644 src/ipa/rpi/controller/decompand_status.h\n>  create mode 100644 src/ipa/rpi/controller/rpi/decompand.cpp\n>  create mode 100644 src/ipa/rpi/controller/rpi/decompand.h\n>\n> diff --git a/src/ipa/rpi/controller/decompand_status.h b/src/ipa/rpi/controller/decompand_status.h\n> new file mode 100644\n> index 000000000000..2d9888dca4f3\n> --- /dev/null\n> +++ b/src/ipa/rpi/controller/decompand_status.h\n> @@ -0,0 +1,8 @@\n> +#pragma once\n> +\n> +#include \"libipa/pwl.h\"\n> +\n> +struct DecompandStatus {\n> +       uint32_t bitdepth;\n\nI wonder if a short comment somewhere explaining how we use the\nbitdepth would be useful? It wasn't immediately clear to me that we're\nexpecting a single mode with a single bit depth to need decompanding,\nor all the modes (when bitdepth is zero).\n\nBut this minor point notwithstanding:\n\nReviewed-by: David Plowman <david.plowman@raspberrypi.com>\n\nThanks!\nDavid\n\n> +       libcamera::ipa::Pwl decompandCurve;\n> +};\n> diff --git a/src/ipa/rpi/controller/meson.build b/src/ipa/rpi/controller/meson.build\n> index 74b74888bbff..c13c48539d10 100644\n> --- a/src/ipa/rpi/controller/meson.build\n> +++ b/src/ipa/rpi/controller/meson.build\n> @@ -14,6 +14,7 @@ rpi_ipa_controller_sources = files([\n>      'rpi/cac.cpp',\n>      'rpi/ccm.cpp',\n>      'rpi/contrast.cpp',\n> +    'rpi/decompand.cpp',\n>      'rpi/denoise.cpp',\n>      'rpi/dpc.cpp',\n>      'rpi/geq.cpp',\n> diff --git a/src/ipa/rpi/controller/rpi/decompand.cpp b/src/ipa/rpi/controller/rpi/decompand.cpp\n> new file mode 100644\n> index 000000000000..2036750f82f4\n> --- /dev/null\n> +++ b/src/ipa/rpi/controller/rpi/decompand.cpp\n> @@ -0,0 +1,58 @@\n> +#include \"decompand.h\"\n> +\n> +#include <libcamera/base/log.h>\n> +\n> +#include \"../decompand_status.h\"\n> +#include \"../histogram.h\"\n> +\n> +using namespace RPiController;\n> +using namespace libcamera;\n> +\n> +LOG_DEFINE_CATEGORY(RPiDecompand)\n> +\n> +#define NAME \"rpi.decompand\"\n> +\n> +Decompand::Decompand(Controller *controller)\n> +       : Algorithm(controller)\n> +{\n> +}\n> +\n> +char const *Decompand::name() const\n> +{\n> +       return NAME;\n> +}\n> +\n> +int Decompand::read(const libcamera::YamlObject &params)\n> +{\n> +       config_.bitdepth = params[\"bitdepth\"].get<uint32_t>(0);\n> +       config_.decompandCurve = params[\"decompand_curve\"].get<ipa::Pwl>(ipa::Pwl{});\n> +       return config_.decompandCurve.empty() ? -EINVAL : 0;\n> +}\n> +\n> +void Decompand::initialise()\n> +{\n> +}\n> +\n> +void Decompand::switchMode(CameraMode const &cameraMode,\n> +                          [[maybe_unused]] Metadata *metadata)\n> +{\n> +       mode_ = cameraMode;\n> +}\n> +\n> +void Decompand::prepare(Metadata *imageMetadata)\n> +{\n> +       DecompandStatus decompandStatus;\n> +\n> +       if (config_.bitdepth == 0 || mode_.bitdepth == config_.bitdepth) {\n> +               decompandStatus.decompandCurve = config_.decompandCurve;\n> +               imageMetadata->set(\"decompand.status\", decompandStatus);\n> +       }\n> +}\n> +\n> +/* Register algorithm with the system. */\n> +static Algorithm *create(Controller *controller)\n> +{\n> +       return new Decompand(controller);\n> +}\n> +\n> +static RegisterAlgorithm reg(NAME, &create);\n> diff --git a/src/ipa/rpi/controller/rpi/decompand.h b/src/ipa/rpi/controller/rpi/decompand.h\n> new file mode 100644\n> index 000000000000..38b26a21e6d5\n> --- /dev/null\n> +++ b/src/ipa/rpi/controller/rpi/decompand.h\n> @@ -0,0 +1,31 @@\n> +#pragma once\n> +\n> +#include <libipa/pwl.h>\n> +\n> +#include \"../decompand_status.h\"\n> +\n> +#include \"algorithm.h\"\n> +\n> +namespace RPiController {\n> +\n> +struct DecompandConfig {\n> +       uint32_t bitdepth;\n> +       libcamera::ipa::Pwl decompandCurve;\n> +};\n> +\n> +class Decompand : public Algorithm\n> +{\n> +public:\n> +       Decompand(Controller *controller = nullptr);\n> +       char const *name() const override;\n> +       int read(const libcamera::YamlObject &params) override;\n> +       void initialise() override;\n> +       void switchMode(CameraMode const &cameraMode, Metadata *metadata) override;\n> +       void prepare(Metadata *imageMetadata) override;\n> +\n> +private:\n> +       CameraMode mode_;\n> +       DecompandConfig config_;\n> +};\n> +\n> +} /* namespace RPiController */\n> diff --git a/src/ipa/rpi/pisp/pisp.cpp b/src/ipa/rpi/pisp/pisp.cpp\n> index 829b91258522..14ece12b0895 100644\n> --- a/src/ipa/rpi/pisp/pisp.cpp\n> +++ b/src/ipa/rpi/pisp/pisp.cpp\n> @@ -32,6 +32,7 @@\n>  #include \"controller/cac_status.h\"\n>  #include \"controller/ccm_status.h\"\n>  #include \"controller/contrast_status.h\"\n> +#include \"controller/decompand_status.h\"\n>  #include \"controller/denoise_algorithm.h\"\n>  #include \"controller/denoise_status.h\"\n>  #include \"controller/dpc_status.h\"\n> @@ -113,6 +114,25 @@ int generateLut(const ipa::Pwl &pwl, uint32_t *lut, std::size_t lutSize,\n>         return 0;\n>  }\n>\n> +int generateDecompandLut(const ipa::Pwl &pwl, Span<uint16_t> lut)\n> +{\n> +       if (pwl.empty())\n> +               return -EINVAL;\n> +\n> +       constexpr int step = 1024;\n> +       for (std::size_t i = 0; i < lut.size(); ++i) {\n> +               int x = i * step;\n> +\n> +               int y = pwl.eval(x);\n> +               if (y < 0)\n> +                       return -1;\n> +\n> +               lut[i] = static_cast<uint16_t>(std::min(y, 65535));\n> +       }\n> +\n> +       return 0;\n> +}\n> +\n>  void packLscLut(uint32_t packed[NumLscVertexes][NumLscVertexes],\n>                 double const rgb[3][NumLscVertexes][NumLscVertexes])\n>  {\n> @@ -236,6 +256,7 @@ private:\n>         void applyLensShading(const AlscStatus *alscStatus,\n>                               pisp_be_global_config &global);\n>         void applyDPC(const DpcStatus *dpcStatus, pisp_be_global_config &global);\n> +       void applyDecompand(const DecompandStatus *decompandStatus);\n>         void applySdn(const SdnStatus *sdnStatus, pisp_be_global_config &global);\n>         void applyTdn(const TdnStatus *tdnStatus, const DeviceStatus *deviceStatus,\n>                       pisp_be_global_config &global);\n> @@ -351,6 +372,11 @@ void IpaPiSP::platformPrepareIsp([[maybe_unused]] const PrepareParams &params,\n>                 if (noiseStatus)\n>                         applyFocusStats(noiseStatus);\n>\n> +               DecompandStatus *decompandStatus =\n> +                       rpiMetadata.getLocked<DecompandStatus>(\"decompand.status\");\n> +               if (decompandStatus)\n> +                       applyDecompand(decompandStatus);\n> +\n>                 BlackLevelStatus *blackLevelStatus =\n>                         rpiMetadata.getLocked<BlackLevelStatus>(\"black_level.status\");\n>                 if (blackLevelStatus)\n> @@ -702,6 +728,18 @@ void IpaPiSP::applyDPC(const DpcStatus *dpcStatus, pisp_be_global_config &global\n>         be_->SetDpc(dpc);\n>  }\n>\n> +void IpaPiSP::applyDecompand(const DecompandStatus *decompandStatus)\n> +{\n> +       pisp_fe_global_config feGlobal;\n> +       pisp_fe_decompand_config decompand = {};\n> +\n> +       if (!generateDecompandLut(decompandStatus->decompandCurve, decompand.lut)) {\n> +               fe_->SetDecompand(decompand);\n> +               feGlobal.enables |= PISP_FE_ENABLE_DECOMPAND;\n> +               fe_->SetGlobal(feGlobal);\n> +       }\n> +}\n> +\n>  void IpaPiSP::applySdn(const SdnStatus *sdnStatus, pisp_be_global_config &global)\n>  {\n>         pisp_be_sdn_config sdn = {};\n> --\n> 2.43.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 7B42FBF415\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri,  3 Oct 2025 14:00:07 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id E9C736B5C2;\n\tFri,  3 Oct 2025 16:00:05 +0200 (CEST)","from mail-qk1-x72c.google.com (mail-qk1-x72c.google.com\n\t[IPv6:2607:f8b0:4864:20::72c])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 2F47269318\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  3 Oct 2025 16:00:03 +0200 (CEST)","by mail-qk1-x72c.google.com with SMTP id\n\taf79cd13be357-8572d7b2457so258483985a.1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 03 Oct 2025 07:00:03 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=raspberrypi.com header.i=@raspberrypi.com\n\theader.b=\"MBDNU4o+\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google; t=1759500002; x=1760104802;\n\tdarn=lists.libcamera.org; \n\th=cc:to:subject:message-id:date:from:in-reply-to:references\n\t:mime-version:from:to:cc:subject:date:message-id:reply-to;\n\tbh=cTHtViobLHFdk4BCkXeckifHpPGRgJHGcXAbloz8CzE=;\n\tb=MBDNU4o+ksjTdEAH5BYXa4JgMvNUW9GS0qGq4u/TKYwJKO0qHt8VuQRJQvTiFCJoZ0\n\tdy40qztKkgrYauoeOck9Ho+QyHWpDPn66qxJfGgfHcJAl5+xlnfrz3w3zpEdrIY9S/JF\n\txtm0wOt5T85a0g6Q7wdRISRWcMCI8QEDxe7Yc+w8QhPZS59n5FYDgx6VBBktAJvFvt5J\n\tLR82qXGXQmTu0ddFG+sk/5Rq4D4BP4dcz1N/mlMWFueR2S23bWnP1kwnVW4byPnXgnnI\n\tuiEiF9SbHI+xXTOQo1+Wp9tGCgq6Ma/14TCwTCBUJeLrzAD3kFvy9rTNZmhni8+dLq1m\n\t9w/Q==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1759500002; x=1760104802;\n\th=cc:to:subject:message-id:date:from:in-reply-to:references\n\t:mime-version:x-gm-message-state:from:to:cc:subject:date:message-id\n\t:reply-to;\n\tbh=cTHtViobLHFdk4BCkXeckifHpPGRgJHGcXAbloz8CzE=;\n\tb=VBC7i8bDG177z2Vgu/DPMwxXMz+IvYDaX5GKoQdZ5wrZdOAgfZ4KLNNvW1/+KKxN1v\n\tQtzORXCfjVHVtUZ3qfyXyKHO6Dt7KbZGMhZt1gDRPYpuH5OK+rfup9iwDru8yu7Pq4/v\n\tSW/0ZdnnG5zJCnFzXk2Sb6fjEuQ+iaEIubaDNgMdunn65DZqB/C56UwOPk4XBtq09edP\n\tvX8T2d1U5Y5QFRuGyu0U5iXbrzpEAykgVZaBl0aDW2388pxuNUyiGFMicV/w4OoBqATe\n\tXO0v0AXrI5AA3Z9C9HPwDx/Kqza0lpPeyItBVhko9lRUWrIZFeKjgaPpVrRBS9XsNwxs\n\tE17w==","X-Gm-Message-State":"AOJu0YxVkHgqeZY+9ZtzZVN7gPjmyAn05NDzdr4FOoYDZpnQ7dRh09Rq\n\t6q7XaiAJj9Df5H43mr1eektKpss3B2fe6IAiqFl2haZHXKCAhMmia+FccnU+z5j3RiiKN2NPC2x\n\t1iVxcq8R75wgKScF1AR/0LBzSa2JOoeBhxec9226X/w==","X-Gm-Gg":"ASbGncstJXdiR/jv2JJ2XgfPpEubJd0SyGNJboKeKLf9KkfovEVhKcskCHfuHG6lLB1\n\toCpvaSHnzdw4PMiVKbFNgQKndQIGuFKPG4FuqPfPA0IUiYXoQbgvTsPto/yPJtSq9bL5Xnq6RGd\n\tAADPbQ4rHXOzXLd3wf3/mrxloXjT6hQmuVUbr5MZDhPeWT87k3tVsIBfQ+k/rehragw4/dilyk7\n\tZ89kzlOZ7uXVuiOzq8PHA+W0nOKhtRgex24+ekqPkZ9lo4Fj1pepuuBGWMf2fNpiN6URfQgHQ==","X-Google-Smtp-Source":"AGHT+IG3WNva4qQiX455JPCj4tFZbHBMZx2HHuHjQZKcBR1qHugLtaOLkLoK925xyRTsC939tDGk3fiINQCjc+v7gl0=","X-Received":"by 2002:a05:620a:4725:b0:7e8:8086:cb83 with SMTP id\n\taf79cd13be357-8776b71354fmr1146350685a.28.1759500001771;\n\tFri, 03 Oct 2025 07:00:01 -0700 (PDT)","MIME-Version":"1.0","References":"<20251003121821.659081-1-naush@raspberrypi.com>\n\t<20251003121821.659081-2-naush@raspberrypi.com>","In-Reply-To":"<20251003121821.659081-2-naush@raspberrypi.com>","From":"David Plowman <david.plowman@raspberrypi.com>","Date":"Fri, 3 Oct 2025 14:59:50 +0100","X-Gm-Features":"AS18NWBxDoduLD_ezmOeWMe3m6pW8_eLp3ATOdOfSimGaEsQV2fP8jwQJZ3Z3oY","Message-ID":"<CAHW6GYKvcEVJOApRLqpQZq=T51WsdqmpMynzcgrRqstNUSQE=A@mail.gmail.com>","Subject":"Re: [PATCH v2 1/4] ipa: rpi: pisp: Add decompand support using PiSP\n\thardware block","To":"Naushir Patuck <naush@raspberrypi.com>","Cc":"libcamera-devel@lists.libcamera.org, \n\tNick Hollinghurst <nick.hollinghurst@raspberrypi.com>,\n\tSena Asotani <aso.fam429@gmail.com>","Content-Type":"text/plain; charset=\"UTF-8\"","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":36230,"web_url":"https://patchwork.libcamera.org/comment/36230/","msgid":"<20251013145001.GK16422@pendragon.ideasonboard.com>","date":"2025-10-13T14:50:01","subject":"Re: [PATCH v2 1/4] ipa: rpi: pisp: Add decompand support using PiSP\n\thardware block","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hello Naush, Sena,\n\nOn Fri, Oct 03, 2025 at 01:15:52PM +0100, Naushir Patuck wrote:\n> From: Sena Asotani <aso.fam429@gmail.com>\n> \n> This patch integrates a new decompand algorithm that utilizes the PiSP\n> FE hardware block available on Raspberry Pi 5. The implementation\n> enables conversion of companded sensor data into linear format prior to\n> ISP processing.\n> \n> Changes include:\n> - Implementation of decompand logic for controller and pipe interfaces\n> - Enabling decompand block by \"rpi.decompand\" in tuning.json\n\nI've worked on something similar for i.MX8MP, with a different approach.\n\nThe companding curve is an intrinsic property of the sensor. Depending\non the sensor, it can be\n\n- hardcoded or configurable\n- when configurable, specified in different ways (e.g. piecewise linear\n  function, parametric formula or selectable from presets)\n- always enabled or controllable\n\nThis creates a relatively large problem space. libcamera needs to know\nwhen a compression curve is applied by the sensor, and what curve is\nbeing applied. Additionally, it may require the ability to\nenable/disable compression, as well as the ability to configure the\ncurve.\n\nSpecifying the curve in a tuning file doesn't seem to be a good\nsolution. I've opted to support hardcoded curves only to start with (in\norder to simplify the problem), and report the curve from the sensor\nhelper. I've also added a V4L2 control ([1]) to enable and disable\ncompression, with support in the AR0144 driver([2]).\n\nDo you plan to implement proper companding support for the RPi pipeline\nhandler and IPA module ?\n\n[1] https://lore.kernel.org/linux-media/20240905225308.11267-9-laurent.pinchart@ideasonboard.com/\n[2] https://lore.kernel.org/linux-media/20240905225308.11267-10-laurent.pinchart@ideasonboard.com/\n\n> Signed-off-by: Sena Asotani <aso.fam429@gmail.com>\n> Signed-off-by: Naushir Patuck <naush@raspberrypi.com>\n> Tested-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>\n> ---\n>  src/ipa/rpi/controller/decompand_status.h |  8 ++++\n>  src/ipa/rpi/controller/meson.build        |  1 +\n>  src/ipa/rpi/controller/rpi/decompand.cpp  | 58 +++++++++++++++++++++++\n>  src/ipa/rpi/controller/rpi/decompand.h    | 31 ++++++++++++\n>  src/ipa/rpi/pisp/pisp.cpp                 | 38 +++++++++++++++\n>  5 files changed, 136 insertions(+)\n>  create mode 100644 src/ipa/rpi/controller/decompand_status.h\n>  create mode 100644 src/ipa/rpi/controller/rpi/decompand.cpp\n>  create mode 100644 src/ipa/rpi/controller/rpi/decompand.h\n> \n> diff --git a/src/ipa/rpi/controller/decompand_status.h b/src/ipa/rpi/controller/decompand_status.h\n> new file mode 100644\n> index 000000000000..2d9888dca4f3\n> --- /dev/null\n> +++ b/src/ipa/rpi/controller/decompand_status.h\n> @@ -0,0 +1,8 @@\n> +#pragma once\n> +\n> +#include \"libipa/pwl.h\"\n> +\n> +struct DecompandStatus {\n> +\tuint32_t bitdepth;\n> +\tlibcamera::ipa::Pwl decompandCurve;\n> +};\n> diff --git a/src/ipa/rpi/controller/meson.build b/src/ipa/rpi/controller/meson.build\n> index 74b74888bbff..c13c48539d10 100644\n> --- a/src/ipa/rpi/controller/meson.build\n> +++ b/src/ipa/rpi/controller/meson.build\n> @@ -14,6 +14,7 @@ rpi_ipa_controller_sources = files([\n>      'rpi/cac.cpp',\n>      'rpi/ccm.cpp',\n>      'rpi/contrast.cpp',\n> +    'rpi/decompand.cpp',\n>      'rpi/denoise.cpp',\n>      'rpi/dpc.cpp',\n>      'rpi/geq.cpp',\n> diff --git a/src/ipa/rpi/controller/rpi/decompand.cpp b/src/ipa/rpi/controller/rpi/decompand.cpp\n> new file mode 100644\n> index 000000000000..2036750f82f4\n> --- /dev/null\n> +++ b/src/ipa/rpi/controller/rpi/decompand.cpp\n> @@ -0,0 +1,58 @@\n> +#include \"decompand.h\"\n> +\n> +#include <libcamera/base/log.h>\n> +\n> +#include \"../decompand_status.h\"\n> +#include \"../histogram.h\"\n> +\n> +using namespace RPiController;\n> +using namespace libcamera;\n> +\n> +LOG_DEFINE_CATEGORY(RPiDecompand)\n> +\n> +#define NAME \"rpi.decompand\"\n> +\n> +Decompand::Decompand(Controller *controller)\n> +\t: Algorithm(controller)\n> +{\n> +}\n> +\n> +char const *Decompand::name() const\n> +{\n> +\treturn NAME;\n> +}\n> +\n> +int Decompand::read(const libcamera::YamlObject &params)\n> +{\n> +\tconfig_.bitdepth = params[\"bitdepth\"].get<uint32_t>(0);\n> +\tconfig_.decompandCurve = params[\"decompand_curve\"].get<ipa::Pwl>(ipa::Pwl{});\n> +\treturn config_.decompandCurve.empty() ? -EINVAL : 0;\n> +}\n> +\n> +void Decompand::initialise()\n> +{\n> +}\n> +\n> +void Decompand::switchMode(CameraMode const &cameraMode,\n> +\t\t\t   [[maybe_unused]] Metadata *metadata)\n> +{\n> +\tmode_ = cameraMode;\n> +}\n> +\n> +void Decompand::prepare(Metadata *imageMetadata)\n> +{\n> +\tDecompandStatus decompandStatus;\n> +\n> +\tif (config_.bitdepth == 0 || mode_.bitdepth == config_.bitdepth) {\n> +\t\tdecompandStatus.decompandCurve = config_.decompandCurve;\n> +\t\timageMetadata->set(\"decompand.status\", decompandStatus);\n> +\t}\n> +}\n> +\n> +/* Register algorithm with the system. */\n> +static Algorithm *create(Controller *controller)\n> +{\n> +\treturn new Decompand(controller);\n> +}\n> +\n> +static RegisterAlgorithm reg(NAME, &create);\n> diff --git a/src/ipa/rpi/controller/rpi/decompand.h b/src/ipa/rpi/controller/rpi/decompand.h\n> new file mode 100644\n> index 000000000000..38b26a21e6d5\n> --- /dev/null\n> +++ b/src/ipa/rpi/controller/rpi/decompand.h\n> @@ -0,0 +1,31 @@\n> +#pragma once\n> +\n> +#include <libipa/pwl.h>\n> +\n> +#include \"../decompand_status.h\"\n> +\n> +#include \"algorithm.h\"\n> +\n> +namespace RPiController {\n> +\n> +struct DecompandConfig {\n> +\tuint32_t bitdepth;\n> +\tlibcamera::ipa::Pwl decompandCurve;\n> +};\n> +\n> +class Decompand : public Algorithm\n> +{\n> +public:\n> +\tDecompand(Controller *controller = nullptr);\n> +\tchar const *name() const override;\n> +\tint read(const libcamera::YamlObject &params) override;\n> +\tvoid initialise() override;\n> +\tvoid switchMode(CameraMode const &cameraMode, Metadata *metadata) override;\n> +\tvoid prepare(Metadata *imageMetadata) override;\n> +\n> +private:\n> +\tCameraMode mode_;\n> +\tDecompandConfig config_;\n> +};\n> +\n> +} /* namespace RPiController */\n> diff --git a/src/ipa/rpi/pisp/pisp.cpp b/src/ipa/rpi/pisp/pisp.cpp\n> index 829b91258522..14ece12b0895 100644\n> --- a/src/ipa/rpi/pisp/pisp.cpp\n> +++ b/src/ipa/rpi/pisp/pisp.cpp\n> @@ -32,6 +32,7 @@\n>  #include \"controller/cac_status.h\"\n>  #include \"controller/ccm_status.h\"\n>  #include \"controller/contrast_status.h\"\n> +#include \"controller/decompand_status.h\"\n>  #include \"controller/denoise_algorithm.h\"\n>  #include \"controller/denoise_status.h\"\n>  #include \"controller/dpc_status.h\"\n> @@ -113,6 +114,25 @@ int generateLut(const ipa::Pwl &pwl, uint32_t *lut, std::size_t lutSize,\n>  \treturn 0;\n>  }\n>  \n> +int generateDecompandLut(const ipa::Pwl &pwl, Span<uint16_t> lut)\n> +{\n> +\tif (pwl.empty())\n> +\t\treturn -EINVAL;\n> +\n> +\tconstexpr int step = 1024;\n> +\tfor (std::size_t i = 0; i < lut.size(); ++i) {\n> +\t\tint x = i * step;\n> +\n> +\t\tint y = pwl.eval(x);\n> +\t\tif (y < 0)\n> +\t\t\treturn -1;\n> +\n> +\t\tlut[i] = static_cast<uint16_t>(std::min(y, 65535));\n> +\t}\n> +\n> +\treturn 0;\n> +}\n> +\n>  void packLscLut(uint32_t packed[NumLscVertexes][NumLscVertexes],\n>  \t\tdouble const rgb[3][NumLscVertexes][NumLscVertexes])\n>  {\n> @@ -236,6 +256,7 @@ private:\n>  \tvoid applyLensShading(const AlscStatus *alscStatus,\n>  \t\t\t      pisp_be_global_config &global);\n>  \tvoid applyDPC(const DpcStatus *dpcStatus, pisp_be_global_config &global);\n> +\tvoid applyDecompand(const DecompandStatus *decompandStatus);\n>  \tvoid applySdn(const SdnStatus *sdnStatus, pisp_be_global_config &global);\n>  \tvoid applyTdn(const TdnStatus *tdnStatus, const DeviceStatus *deviceStatus,\n>  \t\t      pisp_be_global_config &global);\n> @@ -351,6 +372,11 @@ void IpaPiSP::platformPrepareIsp([[maybe_unused]] const PrepareParams &params,\n>  \t\tif (noiseStatus)\n>  \t\t\tapplyFocusStats(noiseStatus);\n>  \n> +\t\tDecompandStatus *decompandStatus =\n> +\t\t\trpiMetadata.getLocked<DecompandStatus>(\"decompand.status\");\n> +\t\tif (decompandStatus)\n> +\t\t\tapplyDecompand(decompandStatus);\n> +\n>  \t\tBlackLevelStatus *blackLevelStatus =\n>  \t\t\trpiMetadata.getLocked<BlackLevelStatus>(\"black_level.status\");\n>  \t\tif (blackLevelStatus)\n> @@ -702,6 +728,18 @@ void IpaPiSP::applyDPC(const DpcStatus *dpcStatus, pisp_be_global_config &global\n>  \tbe_->SetDpc(dpc);\n>  }\n>  \n> +void IpaPiSP::applyDecompand(const DecompandStatus *decompandStatus)\n> +{\n> +\tpisp_fe_global_config feGlobal;\n> +\tpisp_fe_decompand_config decompand = {};\n> +\n> +\tif (!generateDecompandLut(decompandStatus->decompandCurve, decompand.lut)) {\n> +\t\tfe_->SetDecompand(decompand);\n> +\t\tfeGlobal.enables |= PISP_FE_ENABLE_DECOMPAND;\n> +\t\tfe_->SetGlobal(feGlobal);\n> +\t}\n> +}\n> +\n>  void IpaPiSP::applySdn(const SdnStatus *sdnStatus, pisp_be_global_config &global)\n>  {\n>  \tpisp_be_sdn_config sdn = {};","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 49DECBE080\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 13 Oct 2025 14:50:10 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 718D66054E;\n\tMon, 13 Oct 2025 16:50:09 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 311B26031A\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 13 Oct 2025 16:50:08 +0200 (CEST)","from pendragon.ideasonboard.com (82-203-166-19.bb.dnainternet.fi\n\t[82.203.166.19])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 0D5DE557;\n\tMon, 13 Oct 2025 16:48:29 +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=\"oCWP8RSn\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1760366910;\n\tbh=obpxNQDVXxQYRz+vVWwl/EkP9Zib3xBQKDroPkxKscM=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=oCWP8RSnQsUIWHEzcfbtov3NhfSKouWw6XXtT/ZgRhW3+vyeBB6OhcAa5gwi3Ucrd\n\tQ+3vANIpY325ntAikdPPVMYOr30+iZi6F4UPPvYWGYRIVDC2vriBOyR1HkjLUsRNvp\n\tVmy5ZtZnK1pGRPV6n6rxVwP/NtBElJ38DEJVXrMM=","Date":"Mon, 13 Oct 2025 17:50:01 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Naushir Patuck <naush@raspberrypi.com>","Cc":"libcamera-devel@lists.libcamera.org,\n\tDavid Plowman <david.plowman@raspberrypi.com>,\n\tNick Hollinghurst <nick.hollinghurst@raspberrypi.com>,\n\tSena Asotani <aso.fam429@gmail.com>","Subject":"Re: [PATCH v2 1/4] ipa: rpi: pisp: Add decompand support using PiSP\n\thardware block","Message-ID":"<20251013145001.GK16422@pendragon.ideasonboard.com>","References":"<20251003121821.659081-1-naush@raspberrypi.com>\n\t<20251003121821.659081-2-naush@raspberrypi.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20251003121821.659081-2-naush@raspberrypi.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":36232,"web_url":"https://patchwork.libcamera.org/comment/36232/","msgid":"<CAEmqJPoP+khFqwN3mOo+=jNFTTKOZaHRnyOEjFj1mUMVSpz-AQ@mail.gmail.com>","date":"2025-10-14T07:26:33","subject":"Re: [PATCH v2 1/4] ipa: rpi: pisp: Add decompand support using PiSP\n\thardware block","submitter":{"id":34,"url":"https://patchwork.libcamera.org/api/people/34/","name":"Naushir Patuck","email":"naush@raspberrypi.com"},"content":"Hi Laurent,\n\nOn Mon, 13 Oct 2025 at 15:50, Laurent Pinchart <\nlaurent.pinchart@ideasonboard.com> wrote:\n\n> Hello Naush, Sena,\n>\n> On Fri, Oct 03, 2025 at 01:15:52PM +0100, Naushir Patuck wrote:\n> > From: Sena Asotani <aso.fam429@gmail.com>\n> >\n> > This patch integrates a new decompand algorithm that utilizes the PiSP\n> > FE hardware block available on Raspberry Pi 5. The implementation\n> > enables conversion of companded sensor data into linear format prior to\n> > ISP processing.\n> >\n> > Changes include:\n> > - Implementation of decompand logic for controller and pipe interfaces\n> > - Enabling decompand block by \"rpi.decompand\" in tuning.json\n>\n> I've worked on something similar for i.MX8MP, with a different approach.\n>\n> The companding curve is an intrinsic property of the sensor. Depending\n> on the sensor, it can be\n>\n> - hardcoded or configurable\n> - when configurable, specified in different ways (e.g. piecewise linear\n>   function, parametric formula or selectable from presets)\n> - always enabled or controllable\n>\n> This creates a relatively large problem space. libcamera needs to know\n> when a compression curve is applied by the sensor, and what curve is\n> being applied. Additionally, it may require the ability to\n> enable/disable compression, as well as the ability to configure the\n> curve.\n>\n> Specifying the curve in a tuning file doesn't seem to be a good\n> solution. I've opted to support hardcoded curves only to start with (in\n> order to simplify the problem), and report the curve from the sensor\n> helper. I've also added a V4L2 control ([1]) to enable and disable\n> compression, with support in the AR0144 driver([2]).\n>\n\nThis work for implementing decompanding was done by Sena (cc'ed) for the\nIMX585 which is not yet upstreamed.  I've not worked on any sensors myself\nthat use this feature, so I can't really tell if a hard-coded curve vs a\nuser programmable one is the best approach.  Having said that, I would\nagree that a V4L2 control to enable/disable companding (+ a libcamera\ncontrol of course) on the sensor is the right approach!\n\n\n> Do you plan to implement proper companding support for the RPi pipeline\n> handler and IPA module ?\n>\n\nDo you mean adding the relevant libcamera controls for use by an\napplication?  Apart from that, and having a user programmable curve, this\npatch set does include everything else required for the IPA/PH to enable\nthe \"decomand\" feature in the frontend.  It seems to do the right thing for\nthe IMX585 as reported by Sena.\n\nRegards,\nNaush\n\n\n> [1]\n> https://lore.kernel.org/linux-media/20240905225308.11267-9-laurent.pinchart@ideasonboard.com/\n> [2]\n> https://lore.kernel.org/linux-media/20240905225308.11267-10-laurent.pinchart@ideasonboard.com/\n>\n> > Signed-off-by: Sena Asotani <aso.fam429@gmail.com>\n> > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>\n> > Tested-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>\n> > ---\n> >  src/ipa/rpi/controller/decompand_status.h |  8 ++++\n> >  src/ipa/rpi/controller/meson.build        |  1 +\n> >  src/ipa/rpi/controller/rpi/decompand.cpp  | 58 +++++++++++++++++++++++\n> >  src/ipa/rpi/controller/rpi/decompand.h    | 31 ++++++++++++\n> >  src/ipa/rpi/pisp/pisp.cpp                 | 38 +++++++++++++++\n> >  5 files changed, 136 insertions(+)\n> >  create mode 100644 src/ipa/rpi/controller/decompand_status.h\n> >  create mode 100644 src/ipa/rpi/controller/rpi/decompand.cpp\n> >  create mode 100644 src/ipa/rpi/controller/rpi/decompand.h\n> >\n> > diff --git a/src/ipa/rpi/controller/decompand_status.h\n> b/src/ipa/rpi/controller/decompand_status.h\n> > new file mode 100644\n> > index 000000000000..2d9888dca4f3\n> > --- /dev/null\n> > +++ b/src/ipa/rpi/controller/decompand_status.h\n> > @@ -0,0 +1,8 @@\n> > +#pragma once\n> > +\n> > +#include \"libipa/pwl.h\"\n> > +\n> > +struct DecompandStatus {\n> > +     uint32_t bitdepth;\n> > +     libcamera::ipa::Pwl decompandCurve;\n> > +};\n> > diff --git a/src/ipa/rpi/controller/meson.build\n> b/src/ipa/rpi/controller/meson.build\n> > index 74b74888bbff..c13c48539d10 100644\n> > --- a/src/ipa/rpi/controller/meson.build\n> > +++ b/src/ipa/rpi/controller/meson.build\n> > @@ -14,6 +14,7 @@ rpi_ipa_controller_sources = files([\n> >      'rpi/cac.cpp',\n> >      'rpi/ccm.cpp',\n> >      'rpi/contrast.cpp',\n> > +    'rpi/decompand.cpp',\n> >      'rpi/denoise.cpp',\n> >      'rpi/dpc.cpp',\n> >      'rpi/geq.cpp',\n> > diff --git a/src/ipa/rpi/controller/rpi/decompand.cpp\n> b/src/ipa/rpi/controller/rpi/decompand.cpp\n> > new file mode 100644\n> > index 000000000000..2036750f82f4\n> > --- /dev/null\n> > +++ b/src/ipa/rpi/controller/rpi/decompand.cpp\n> > @@ -0,0 +1,58 @@\n> > +#include \"decompand.h\"\n> > +\n> > +#include <libcamera/base/log.h>\n> > +\n> > +#include \"../decompand_status.h\"\n> > +#include \"../histogram.h\"\n> > +\n> > +using namespace RPiController;\n> > +using namespace libcamera;\n> > +\n> > +LOG_DEFINE_CATEGORY(RPiDecompand)\n> > +\n> > +#define NAME \"rpi.decompand\"\n> > +\n> > +Decompand::Decompand(Controller *controller)\n> > +     : Algorithm(controller)\n> > +{\n> > +}\n> > +\n> > +char const *Decompand::name() const\n> > +{\n> > +     return NAME;\n> > +}\n> > +\n> > +int Decompand::read(const libcamera::YamlObject &params)\n> > +{\n> > +     config_.bitdepth = params[\"bitdepth\"].get<uint32_t>(0);\n> > +     config_.decompandCurve =\n> params[\"decompand_curve\"].get<ipa::Pwl>(ipa::Pwl{});\n> > +     return config_.decompandCurve.empty() ? -EINVAL : 0;\n> > +}\n> > +\n> > +void Decompand::initialise()\n> > +{\n> > +}\n> > +\n> > +void Decompand::switchMode(CameraMode const &cameraMode,\n> > +                        [[maybe_unused]] Metadata *metadata)\n> > +{\n> > +     mode_ = cameraMode;\n> > +}\n> > +\n> > +void Decompand::prepare(Metadata *imageMetadata)\n> > +{\n> > +     DecompandStatus decompandStatus;\n> > +\n> > +     if (config_.bitdepth == 0 || mode_.bitdepth == config_.bitdepth) {\n> > +             decompandStatus.decompandCurve = config_.decompandCurve;\n> > +             imageMetadata->set(\"decompand.status\", decompandStatus);\n> > +     }\n> > +}\n> > +\n> > +/* Register algorithm with the system. */\n> > +static Algorithm *create(Controller *controller)\n> > +{\n> > +     return new Decompand(controller);\n> > +}\n> > +\n> > +static RegisterAlgorithm reg(NAME, &create);\n> > diff --git a/src/ipa/rpi/controller/rpi/decompand.h\n> b/src/ipa/rpi/controller/rpi/decompand.h\n> > new file mode 100644\n> > index 000000000000..38b26a21e6d5\n> > --- /dev/null\n> > +++ b/src/ipa/rpi/controller/rpi/decompand.h\n> > @@ -0,0 +1,31 @@\n> > +#pragma once\n> > +\n> > +#include <libipa/pwl.h>\n> > +\n> > +#include \"../decompand_status.h\"\n> > +\n> > +#include \"algorithm.h\"\n> > +\n> > +namespace RPiController {\n> > +\n> > +struct DecompandConfig {\n> > +     uint32_t bitdepth;\n> > +     libcamera::ipa::Pwl decompandCurve;\n> > +};\n> > +\n> > +class Decompand : public Algorithm\n> > +{\n> > +public:\n> > +     Decompand(Controller *controller = nullptr);\n> > +     char const *name() const override;\n> > +     int read(const libcamera::YamlObject &params) override;\n> > +     void initialise() override;\n> > +     void switchMode(CameraMode const &cameraMode, Metadata *metadata)\n> override;\n> > +     void prepare(Metadata *imageMetadata) override;\n> > +\n> > +private:\n> > +     CameraMode mode_;\n> > +     DecompandConfig config_;\n> > +};\n> > +\n> > +} /* namespace RPiController */\n> > diff --git a/src/ipa/rpi/pisp/pisp.cpp b/src/ipa/rpi/pisp/pisp.cpp\n> > index 829b91258522..14ece12b0895 100644\n> > --- a/src/ipa/rpi/pisp/pisp.cpp\n> > +++ b/src/ipa/rpi/pisp/pisp.cpp\n> > @@ -32,6 +32,7 @@\n> >  #include \"controller/cac_status.h\"\n> >  #include \"controller/ccm_status.h\"\n> >  #include \"controller/contrast_status.h\"\n> > +#include \"controller/decompand_status.h\"\n> >  #include \"controller/denoise_algorithm.h\"\n> >  #include \"controller/denoise_status.h\"\n> >  #include \"controller/dpc_status.h\"\n> > @@ -113,6 +114,25 @@ int generateLut(const ipa::Pwl &pwl, uint32_t *lut,\n> std::size_t lutSize,\n> >       return 0;\n> >  }\n> >\n> > +int generateDecompandLut(const ipa::Pwl &pwl, Span<uint16_t> lut)\n> > +{\n> > +     if (pwl.empty())\n> > +             return -EINVAL;\n> > +\n> > +     constexpr int step = 1024;\n> > +     for (std::size_t i = 0; i < lut.size(); ++i) {\n> > +             int x = i * step;\n> > +\n> > +             int y = pwl.eval(x);\n> > +             if (y < 0)\n> > +                     return -1;\n> > +\n> > +             lut[i] = static_cast<uint16_t>(std::min(y, 65535));\n> > +     }\n> > +\n> > +     return 0;\n> > +}\n> > +\n> >  void packLscLut(uint32_t packed[NumLscVertexes][NumLscVertexes],\n> >               double const rgb[3][NumLscVertexes][NumLscVertexes])\n> >  {\n> > @@ -236,6 +256,7 @@ private:\n> >       void applyLensShading(const AlscStatus *alscStatus,\n> >                             pisp_be_global_config &global);\n> >       void applyDPC(const DpcStatus *dpcStatus, pisp_be_global_config\n> &global);\n> > +     void applyDecompand(const DecompandStatus *decompandStatus);\n> >       void applySdn(const SdnStatus *sdnStatus, pisp_be_global_config\n> &global);\n> >       void applyTdn(const TdnStatus *tdnStatus, const DeviceStatus\n> *deviceStatus,\n> >                     pisp_be_global_config &global);\n> > @@ -351,6 +372,11 @@ void IpaPiSP::platformPrepareIsp([[maybe_unused]]\n> const PrepareParams &params,\n> >               if (noiseStatus)\n> >                       applyFocusStats(noiseStatus);\n> >\n> > +             DecompandStatus *decompandStatus =\n> > +\n>  rpiMetadata.getLocked<DecompandStatus>(\"decompand.status\");\n> > +             if (decompandStatus)\n> > +                     applyDecompand(decompandStatus);\n> > +\n> >               BlackLevelStatus *blackLevelStatus =\n> >\n>  rpiMetadata.getLocked<BlackLevelStatus>(\"black_level.status\");\n> >               if (blackLevelStatus)\n> > @@ -702,6 +728,18 @@ void IpaPiSP::applyDPC(const DpcStatus *dpcStatus,\n> pisp_be_global_config &global\n> >       be_->SetDpc(dpc);\n> >  }\n> >\n> > +void IpaPiSP::applyDecompand(const DecompandStatus *decompandStatus)\n> > +{\n> > +     pisp_fe_global_config feGlobal;\n> > +     pisp_fe_decompand_config decompand = {};\n> > +\n> > +     if (!generateDecompandLut(decompandStatus->decompandCurve,\n> decompand.lut)) {\n> > +             fe_->SetDecompand(decompand);\n> > +             feGlobal.enables |= PISP_FE_ENABLE_DECOMPAND;\n> > +             fe_->SetGlobal(feGlobal);\n> > +     }\n> > +}\n> > +\n> >  void IpaPiSP::applySdn(const SdnStatus *sdnStatus,\n> pisp_be_global_config &global)\n> >  {\n> >       pisp_be_sdn_config sdn = {};\n>\n> --\n> Regards,\n>\n> Laurent Pinchart\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 C332FBE080\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 14 Oct 2025 07:27:13 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 88DD76052F;\n\tTue, 14 Oct 2025 09:27:12 +0200 (CEST)","from mail-ua1-x930.google.com (mail-ua1-x930.google.com\n\t[IPv6:2607:f8b0:4864:20::930])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 5A6BF60316\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 14 Oct 2025 09:27:10 +0200 (CEST)","by mail-ua1-x930.google.com with SMTP id\n\ta1e0cc1a2514c-8f2cbfba18aso80250241.0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 14 Oct 2025 00:27:10 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=raspberrypi.com header.i=@raspberrypi.com\n\theader.b=\"gDzAHhsW\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google; t=1760426829; x=1761031629;\n\tdarn=lists.libcamera.org; \n\th=cc:to:subject:message-id:date:from:in-reply-to:references\n\t:mime-version:from:to:cc:subject:date:message-id:reply-to;\n\tbh=+O7wUXG9FfuNq8Q2mwI+GQ8W8Vl5hTRc16yX6+FCWFQ=;\n\tb=gDzAHhsWUvx6AyzZ7cL1I3mUZ/6VW5vIdtXtmsOujpu4wX0RiHmiutPnrvhGeNfqgT\n\txp3Q8CpsX1j+vepV+poAczUf2z18v/jFAXGo/ntifyKNX7UfwgGn7rRib/syLnHUpH7M\n\tOXVA3m2QTxrezemf0YJGC5PIxzkczkaXdf689lGZ3qNTiRu0I7whvlq3sl8eNbEeZSLs\n\ttVttPPmAr7e+C849XfkFb3M9wQ0uGQ+aMgMO84r50492ULjaAOTXtS7OkaPXtskQskPb\n\txaAmrw6x26cmO7SiP9vh2AvDvzmBPHSWpFcUFoMnqU3cxjm8V5VozScDORQCT6xbLHHn\n\tIq/g==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1760426829; x=1761031629;\n\th=cc:to:subject:message-id:date:from:in-reply-to:references\n\t:mime-version:x-gm-message-state:from:to:cc:subject:date:message-id\n\t:reply-to;\n\tbh=+O7wUXG9FfuNq8Q2mwI+GQ8W8Vl5hTRc16yX6+FCWFQ=;\n\tb=rJ8e/QbgkoFer8OvjBi1FdIB2fVg/A3ATngZYMWia4UJ79cd7vRTM+A0yGdEs7Pmxu\n\tHLeLChwiHpimDEz/Vz1zlOvpL14COa4uJkmhPMWLpd83i34/I1F7bQW+BJyOjfQAzB85\n\tamJkKNo+1z/LXUm9t/B5iSLfwdRUERJkzqhnVi0PpEbZ+kHDx/lx5d1MtMTg8he6MR4O\n\t8xFlQHck/owpgPi3HuwIb786Ncyus39uoZ+hPxmLYLwMJ+XSsxwsYuqM13tpg2cKCgYJ\n\tkS5jsKro6ebRx8DM30yM4QD26iI9xybdjlnrHKaEYQsehUW1WSbkKpYFLT+sNh07uEaD\n\txULw==","X-Gm-Message-State":"AOJu0Yyqx2vplOwcTv7f7PY4k+ZRLG4RIng3zw+qE7cRaTt4fg5E1DKr\n\tg9+EC5foHq29KopfE/+USF3WBK4w2XQknVpvUDnBZO1tkyWrVUZeWhub40VfJDagQQyELUBf987\n\tpBJ42yL5V7zAhUaqObjF5xqGdK574y72daiTloFZjZA==","X-Gm-Gg":"ASbGncv3FBsHLHf51pbGAkz5Qt/At+k36UQku45NLYDm7gORLbyyqUPg4zZpbCZGTGs\n\tvb4FC2JUp1401dxD9OAz0X7yMPh96rA0UMj4JguXJ6stStzIDCmKGHhgtaJD0Lr2XMd1MVID4Ie\n\trsiYHOItejDyF1D3ZuyF42HjvCvxZZzIZVONZVR42B89Zz5m/2pZgy8+v4WbEudT1oYTJ5OBvP9\n\t3Sbh1qslf1zuAWSDfboYFOzpA==","X-Google-Smtp-Source":"AGHT+IHpUn4XxPogQWG7VaJTRnyu+bWqNRoLERPMeqpE+FUf2P3A28YAECJ9T0NjX8kEX1b7hcQQ4jaQ7rBMvpdXexo=","X-Received":"by 2002:a05:6102:41a3:b0:5a3:82bf:c133 with SMTP id\n\tada2fe7eead31-5d5e236d048mr4334522137.6.1760426828824;\n\tTue, 14 Oct 2025 00:27:08 -0700 (PDT)","MIME-Version":"1.0","References":"<20251003121821.659081-1-naush@raspberrypi.com>\n\t<20251003121821.659081-2-naush@raspberrypi.com>\n\t<20251013145001.GK16422@pendragon.ideasonboard.com>","In-Reply-To":"<20251013145001.GK16422@pendragon.ideasonboard.com>","From":"Naushir Patuck <naush@raspberrypi.com>","Date":"Tue, 14 Oct 2025 08:26:33 +0100","X-Gm-Features":"AS18NWD4duAPVRm20PkW3PwciDVngrb2F1bz21xZwxiFJnns7_aQUnRsHN_9o_0","Message-ID":"<CAEmqJPoP+khFqwN3mOo+=jNFTTKOZaHRnyOEjFj1mUMVSpz-AQ@mail.gmail.com>","Subject":"Re: [PATCH v2 1/4] ipa: rpi: pisp: Add decompand support using PiSP\n\thardware block","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org, \n\tDavid Plowman <david.plowman@raspberrypi.com>, \n\tNick Hollinghurst <nick.hollinghurst@raspberrypi.com>,\n\tSena Asotani <aso.fam429@gmail.com>","Content-Type":"multipart/alternative; boundary=\"000000000000c918660641194f31\"","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":36233,"web_url":"https://patchwork.libcamera.org/comment/36233/","msgid":"<20251014075958.GA30747@pendragon.ideasonboard.com>","date":"2025-10-14T07:59:58","subject":"Re: [PATCH v2 1/4] ipa: rpi: pisp: Add decompand support using PiSP\n\thardware block","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Naush,\n\nOn Tue, Oct 14, 2025 at 08:26:33AM +0100, Naushir Patuck wrote:\n> On Mon, 13 Oct 2025 at 15:50, Laurent Pinchart wrote:\n> > On Fri, Oct 03, 2025 at 01:15:52PM +0100, Naushir Patuck wrote:\n> > > From: Sena Asotani <aso.fam429@gmail.com>\n> > >\n> > > This patch integrates a new decompand algorithm that utilizes the PiSP\n> > > FE hardware block available on Raspberry Pi 5. The implementation\n> > > enables conversion of companded sensor data into linear format prior to\n> > > ISP processing.\n> > >\n> > > Changes include:\n> > > - Implementation of decompand logic for controller and pipe interfaces\n> > > - Enabling decompand block by \"rpi.decompand\" in tuning.json\n> >\n> > I've worked on something similar for i.MX8MP, with a different approach.\n> >\n> > The companding curve is an intrinsic property of the sensor. Depending\n> > on the sensor, it can be\n> >\n> > - hardcoded or configurable\n> > - when configurable, specified in different ways (e.g. piecewise linear\n> >   function, parametric formula or selectable from presets)\n> > - always enabled or controllable\n> >\n> > This creates a relatively large problem space. libcamera needs to know\n> > when a compression curve is applied by the sensor, and what curve is\n> > being applied. Additionally, it may require the ability to\n> > enable/disable compression, as well as the ability to configure the\n> > curve.\n> >\n> > Specifying the curve in a tuning file doesn't seem to be a good\n> > solution. I've opted to support hardcoded curves only to start with (in\n> > order to simplify the problem), and report the curve from the sensor\n> > helper. I've also added a V4L2 control ([1]) to enable and disable\n> > compression, with support in the AR0144 driver([2]).\n> \n> This work for implementing decompanding was done by Sena (cc'ed) for the\n> IMX585 which is not yet upstreamed.  I've not worked on any sensors myself\n> that use this feature, so I can't really tell if a hard-coded curve vs a\n> user programmable one is the best approach.\n\nI've seen both cases implemented in sensors, so we need to support\nhardcoded curves, and may want to support configurable curves.\n\n> Having said that, I would\n> agree that a V4L2 control to enable/disable companding (+ a libcamera\n> control of course) on the sensor is the right approach!\n\nOn the camera side I expect it would be a SensorConfiguration parameter\nrather than a control.\n\n> > Do you plan to implement proper companding support for the RPi pipeline\n> > handler and IPA module ?\n> \n> Do you mean adding the relevant libcamera controls for use by an\n> application?  Apart from that, and having a user programmable curve, this\n> patch set does include everything else required for the IPA/PH to enable\n> the \"decomand\" feature in the frontend.  It seems to do the right thing for\n> the IMX585 as reported by Sena.\n\nI meant\n\n- Making companding dynamically selectable by the user\n- Optionally supporting user-specific curves\n- Moving the curve from tuning files to sensor helpers\n\n> > [1] https://lore.kernel.org/linux-media/20240905225308.11267-9-laurent.pinchart@ideasonboard.com/\n> > [2] https://lore.kernel.org/linux-media/20240905225308.11267-10-laurent.pinchart@ideasonboard.com/\n> >\n> > > Signed-off-by: Sena Asotani <aso.fam429@gmail.com>\n> > > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>\n> > > Tested-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>\n> > > ---\n> > >  src/ipa/rpi/controller/decompand_status.h |  8 ++++\n> > >  src/ipa/rpi/controller/meson.build        |  1 +\n> > >  src/ipa/rpi/controller/rpi/decompand.cpp  | 58 +++++++++++++++++++++++\n> > >  src/ipa/rpi/controller/rpi/decompand.h    | 31 ++++++++++++\n> > >  src/ipa/rpi/pisp/pisp.cpp                 | 38 +++++++++++++++\n> > >  5 files changed, 136 insertions(+)\n> > >  create mode 100644 src/ipa/rpi/controller/decompand_status.h\n> > >  create mode 100644 src/ipa/rpi/controller/rpi/decompand.cpp\n> > >  create mode 100644 src/ipa/rpi/controller/rpi/decompand.h\n> > >\n> > > diff --git a/src/ipa/rpi/controller/decompand_status.h\n> > b/src/ipa/rpi/controller/decompand_status.h\n> > > new file mode 100644\n> > > index 000000000000..2d9888dca4f3\n> > > --- /dev/null\n> > > +++ b/src/ipa/rpi/controller/decompand_status.h\n> > > @@ -0,0 +1,8 @@\n> > > +#pragma once\n> > > +\n> > > +#include \"libipa/pwl.h\"\n> > > +\n> > > +struct DecompandStatus {\n> > > +     uint32_t bitdepth;\n> > > +     libcamera::ipa::Pwl decompandCurve;\n> > > +};\n> > > diff --git a/src/ipa/rpi/controller/meson.build\n> > b/src/ipa/rpi/controller/meson.build\n> > > index 74b74888bbff..c13c48539d10 100644\n> > > --- a/src/ipa/rpi/controller/meson.build\n> > > +++ b/src/ipa/rpi/controller/meson.build\n> > > @@ -14,6 +14,7 @@ rpi_ipa_controller_sources = files([\n> > >      'rpi/cac.cpp',\n> > >      'rpi/ccm.cpp',\n> > >      'rpi/contrast.cpp',\n> > > +    'rpi/decompand.cpp',\n> > >      'rpi/denoise.cpp',\n> > >      'rpi/dpc.cpp',\n> > >      'rpi/geq.cpp',\n> > > diff --git a/src/ipa/rpi/controller/rpi/decompand.cpp\n> > b/src/ipa/rpi/controller/rpi/decompand.cpp\n> > > new file mode 100644\n> > > index 000000000000..2036750f82f4\n> > > --- /dev/null\n> > > +++ b/src/ipa/rpi/controller/rpi/decompand.cpp\n> > > @@ -0,0 +1,58 @@\n> > > +#include \"decompand.h\"\n> > > +\n> > > +#include <libcamera/base/log.h>\n> > > +\n> > > +#include \"../decompand_status.h\"\n> > > +#include \"../histogram.h\"\n> > > +\n> > > +using namespace RPiController;\n> > > +using namespace libcamera;\n> > > +\n> > > +LOG_DEFINE_CATEGORY(RPiDecompand)\n> > > +\n> > > +#define NAME \"rpi.decompand\"\n> > > +\n> > > +Decompand::Decompand(Controller *controller)\n> > > +     : Algorithm(controller)\n> > > +{\n> > > +}\n> > > +\n> > > +char const *Decompand::name() const\n> > > +{\n> > > +     return NAME;\n> > > +}\n> > > +\n> > > +int Decompand::read(const libcamera::YamlObject &params)\n> > > +{\n> > > +     config_.bitdepth = params[\"bitdepth\"].get<uint32_t>(0);\n> > > +     config_.decompandCurve =\n> > params[\"decompand_curve\"].get<ipa::Pwl>(ipa::Pwl{});\n> > > +     return config_.decompandCurve.empty() ? -EINVAL : 0;\n> > > +}\n> > > +\n> > > +void Decompand::initialise()\n> > > +{\n> > > +}\n> > > +\n> > > +void Decompand::switchMode(CameraMode const &cameraMode,\n> > > +                        [[maybe_unused]] Metadata *metadata)\n> > > +{\n> > > +     mode_ = cameraMode;\n> > > +}\n> > > +\n> > > +void Decompand::prepare(Metadata *imageMetadata)\n> > > +{\n> > > +     DecompandStatus decompandStatus;\n> > > +\n> > > +     if (config_.bitdepth == 0 || mode_.bitdepth == config_.bitdepth) {\n> > > +             decompandStatus.decompandCurve = config_.decompandCurve;\n> > > +             imageMetadata->set(\"decompand.status\", decompandStatus);\n> > > +     }\n> > > +}\n> > > +\n> > > +/* Register algorithm with the system. */\n> > > +static Algorithm *create(Controller *controller)\n> > > +{\n> > > +     return new Decompand(controller);\n> > > +}\n> > > +\n> > > +static RegisterAlgorithm reg(NAME, &create);\n> > > diff --git a/src/ipa/rpi/controller/rpi/decompand.h\n> > b/src/ipa/rpi/controller/rpi/decompand.h\n> > > new file mode 100644\n> > > index 000000000000..38b26a21e6d5\n> > > --- /dev/null\n> > > +++ b/src/ipa/rpi/controller/rpi/decompand.h\n> > > @@ -0,0 +1,31 @@\n> > > +#pragma once\n> > > +\n> > > +#include <libipa/pwl.h>\n> > > +\n> > > +#include \"../decompand_status.h\"\n> > > +\n> > > +#include \"algorithm.h\"\n> > > +\n> > > +namespace RPiController {\n> > > +\n> > > +struct DecompandConfig {\n> > > +     uint32_t bitdepth;\n> > > +     libcamera::ipa::Pwl decompandCurve;\n> > > +};\n> > > +\n> > > +class Decompand : public Algorithm\n> > > +{\n> > > +public:\n> > > +     Decompand(Controller *controller = nullptr);\n> > > +     char const *name() const override;\n> > > +     int read(const libcamera::YamlObject &params) override;\n> > > +     void initialise() override;\n> > > +     void switchMode(CameraMode const &cameraMode, Metadata *metadata)\n> > override;\n> > > +     void prepare(Metadata *imageMetadata) override;\n> > > +\n> > > +private:\n> > > +     CameraMode mode_;\n> > > +     DecompandConfig config_;\n> > > +};\n> > > +\n> > > +} /* namespace RPiController */\n> > > diff --git a/src/ipa/rpi/pisp/pisp.cpp b/src/ipa/rpi/pisp/pisp.cpp\n> > > index 829b91258522..14ece12b0895 100644\n> > > --- a/src/ipa/rpi/pisp/pisp.cpp\n> > > +++ b/src/ipa/rpi/pisp/pisp.cpp\n> > > @@ -32,6 +32,7 @@\n> > >  #include \"controller/cac_status.h\"\n> > >  #include \"controller/ccm_status.h\"\n> > >  #include \"controller/contrast_status.h\"\n> > > +#include \"controller/decompand_status.h\"\n> > >  #include \"controller/denoise_algorithm.h\"\n> > >  #include \"controller/denoise_status.h\"\n> > >  #include \"controller/dpc_status.h\"\n> > > @@ -113,6 +114,25 @@ int generateLut(const ipa::Pwl &pwl, uint32_t *lut,\n> > std::size_t lutSize,\n> > >       return 0;\n> > >  }\n> > >\n> > > +int generateDecompandLut(const ipa::Pwl &pwl, Span<uint16_t> lut)\n> > > +{\n> > > +     if (pwl.empty())\n> > > +             return -EINVAL;\n> > > +\n> > > +     constexpr int step = 1024;\n> > > +     for (std::size_t i = 0; i < lut.size(); ++i) {\n> > > +             int x = i * step;\n> > > +\n> > > +             int y = pwl.eval(x);\n> > > +             if (y < 0)\n> > > +                     return -1;\n> > > +\n> > > +             lut[i] = static_cast<uint16_t>(std::min(y, 65535));\n> > > +     }\n> > > +\n> > > +     return 0;\n> > > +}\n> > > +\n> > >  void packLscLut(uint32_t packed[NumLscVertexes][NumLscVertexes],\n> > >               double const rgb[3][NumLscVertexes][NumLscVertexes])\n> > >  {\n> > > @@ -236,6 +256,7 @@ private:\n> > >       void applyLensShading(const AlscStatus *alscStatus,\n> > >                             pisp_be_global_config &global);\n> > >       void applyDPC(const DpcStatus *dpcStatus, pisp_be_global_config\n> > &global);\n> > > +     void applyDecompand(const DecompandStatus *decompandStatus);\n> > >       void applySdn(const SdnStatus *sdnStatus, pisp_be_global_config\n> > &global);\n> > >       void applyTdn(const TdnStatus *tdnStatus, const DeviceStatus\n> > *deviceStatus,\n> > >                     pisp_be_global_config &global);\n> > > @@ -351,6 +372,11 @@ void IpaPiSP::platformPrepareIsp([[maybe_unused]]\n> > const PrepareParams &params,\n> > >               if (noiseStatus)\n> > >                       applyFocusStats(noiseStatus);\n> > >\n> > > +             DecompandStatus *decompandStatus =\n> > > +\n> >  rpiMetadata.getLocked<DecompandStatus>(\"decompand.status\");\n> > > +             if (decompandStatus)\n> > > +                     applyDecompand(decompandStatus);\n> > > +\n> > >               BlackLevelStatus *blackLevelStatus =\n> > >\n> >  rpiMetadata.getLocked<BlackLevelStatus>(\"black_level.status\");\n> > >               if (blackLevelStatus)\n> > > @@ -702,6 +728,18 @@ void IpaPiSP::applyDPC(const DpcStatus *dpcStatus,\n> > pisp_be_global_config &global\n> > >       be_->SetDpc(dpc);\n> > >  }\n> > >\n> > > +void IpaPiSP::applyDecompand(const DecompandStatus *decompandStatus)\n> > > +{\n> > > +     pisp_fe_global_config feGlobal;\n> > > +     pisp_fe_decompand_config decompand = {};\n> > > +\n> > > +     if (!generateDecompandLut(decompandStatus->decompandCurve,\n> > decompand.lut)) {\n> > > +             fe_->SetDecompand(decompand);\n> > > +             feGlobal.enables |= PISP_FE_ENABLE_DECOMPAND;\n> > > +             fe_->SetGlobal(feGlobal);\n> > > +     }\n> > > +}\n> > > +\n> > >  void IpaPiSP::applySdn(const SdnStatus *sdnStatus,\n> > pisp_be_global_config &global)\n> > >  {\n> > >       pisp_be_sdn_config sdn = {};","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 39D17BE080\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 14 Oct 2025 08:00:09 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4598660580;\n\tTue, 14 Oct 2025 10:00:08 +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 58DF660316\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 14 Oct 2025 10:00:06 +0200 (CEST)","from pendragon.ideasonboard.com (82-203-166-19.bb.dnainternet.fi\n\t[82.203.166.19])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id C9D20741;\n\tTue, 14 Oct 2025 09:58:27 +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=\"TL15YgbG\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1760428708;\n\tbh=4fNppnI0bbnXD9KalR88E6O/dGXPYSB4jq1Tv603Yfo=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=TL15YgbGIcD+bwoQPJKS5fQsknH7RYIB8n7hgF3Za0pFiH+NZZZmXyF3RUsOvDQTU\n\tFVmeUe7vynE/MKtocK1s3khReYyNugIjtz+V8eZsjEQkuwc1zWjRemwZIiTRUowe0j\n\tdDW6wC/pPJtUDaQc23XxCOry8ptD7Jf5nb03b9AY=","Date":"Tue, 14 Oct 2025 10:59:58 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Naushir Patuck <naush@raspberrypi.com>","Cc":"libcamera-devel@lists.libcamera.org,\n\tDavid Plowman <david.plowman@raspberrypi.com>,\n\tNick Hollinghurst <nick.hollinghurst@raspberrypi.com>,\n\tSena Asotani <aso.fam429@gmail.com>","Subject":"Re: [PATCH v2 1/4] ipa: rpi: pisp: Add decompand support using PiSP\n\thardware block","Message-ID":"<20251014075958.GA30747@pendragon.ideasonboard.com>","References":"<20251003121821.659081-1-naush@raspberrypi.com>\n\t<20251003121821.659081-2-naush@raspberrypi.com>\n\t<20251013145001.GK16422@pendragon.ideasonboard.com>\n\t<CAEmqJPoP+khFqwN3mOo+=jNFTTKOZaHRnyOEjFj1mUMVSpz-AQ@mail.gmail.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<CAEmqJPoP+khFqwN3mOo+=jNFTTKOZaHRnyOEjFj1mUMVSpz-AQ@mail.gmail.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":36292,"web_url":"https://patchwork.libcamera.org/comment/36292/","msgid":"<CAEmqJPrZNkaNcou5GmmubgfpxkBCH=WEmmXhkT2qNbnVeV7+hg@mail.gmail.com>","date":"2025-10-16T07:33:42","subject":"Re: [PATCH v2 1/4] ipa: rpi: pisp: Add decompand support using PiSP\n\thardware block","submitter":{"id":34,"url":"https://patchwork.libcamera.org/api/people/34/","name":"Naushir Patuck","email":"naush@raspberrypi.com"},"content":"Hi Laurent,\n\nOn Tue, 14 Oct 2025 at 09:00, Laurent Pinchart <\nlaurent.pinchart@ideasonboard.com> wrote:\n\n> Hi Naush,\n>\n> On Tue, Oct 14, 2025 at 08:26:33AM +0100, Naushir Patuck wrote:\n> > On Mon, 13 Oct 2025 at 15:50, Laurent Pinchart wrote:\n> > > On Fri, Oct 03, 2025 at 01:15:52PM +0100, Naushir Patuck wrote:\n> > > > From: Sena Asotani <aso.fam429@gmail.com>\n> > > >\n> > > > This patch integrates a new decompand algorithm that utilizes the\n> PiSP\n> > > > FE hardware block available on Raspberry Pi 5. The implementation\n> > > > enables conversion of companded sensor data into linear format prior\n> to\n> > > > ISP processing.\n> > > >\n> > > > Changes include:\n> > > > - Implementation of decompand logic for controller and pipe\n> interfaces\n> > > > - Enabling decompand block by \"rpi.decompand\" in tuning.json\n> > >\n> > > I've worked on something similar for i.MX8MP, with a different\n> approach.\n> > >\n> > > The companding curve is an intrinsic property of the sensor. Depending\n> > > on the sensor, it can be\n> > >\n> > > - hardcoded or configurable\n> > > - when configurable, specified in different ways (e.g. piecewise linear\n> > >   function, parametric formula or selectable from presets)\n> > > - always enabled or controllable\n> > >\n> > > This creates a relatively large problem space. libcamera needs to know\n> > > when a compression curve is applied by the sensor, and what curve is\n> > > being applied. Additionally, it may require the ability to\n> > > enable/disable compression, as well as the ability to configure the\n> > > curve.\n> > >\n> > > Specifying the curve in a tuning file doesn't seem to be a good\n> > > solution. I've opted to support hardcoded curves only to start with (in\n> > > order to simplify the problem), and report the curve from the sensor\n> > > helper. I've also added a V4L2 control ([1]) to enable and disable\n> > > compression, with support in the AR0144 driver([2]).\n> >\n> > This work for implementing decompanding was done by Sena (cc'ed) for the\n> > IMX585 which is not yet upstreamed.  I've not worked on any sensors\n> myself\n> > that use this feature, so I can't really tell if a hard-coded curve vs a\n> > user programmable one is the best approach.\n>\n> I've seen both cases implemented in sensors, so we need to support\n> hardcoded curves, and may want to support configurable curves.\n>\n> > Having said that, I would\n> > agree that a V4L2 control to enable/disable companding (+ a libcamera\n> > control of course) on the sensor is the right approach!\n>\n> On the camera side I expect it would be a SensorConfiguration parameter\n> rather than a control.\n>\n> > > Do you plan to implement proper companding support for the RPi pipeline\n> > > handler and IPA module ?\n> >\n> > Do you mean adding the relevant libcamera controls for use by an\n> > application?  Apart from that, and having a user programmable curve, this\n> > patch set does include everything else required for the IPA/PH to enable\n> > the \"decomand\" feature in the frontend.  It seems to do the right thing\n> for\n> > the IMX585 as reported by Sena.\n>\n> I meant\n>\n> - Making companding dynamically selectable by the user\n> - Optionally supporting user-specific curves\n> - Moving the curve from tuning files to sensor helpers\n>\n\nI don't have any experience with using companding in sensors.  I don't even\nhave access to the IMX585 that this feature is developed for.  So a few\nbasic questions to help my understanding :)\n\n- Should this be a user accessible control(s)?  Do you see a user needing\nto enable/disable this?  Perhaps this should be a decision made only by the\npipeline handler.\n- Should the curve (if adjustable) be perhaps defined in the sensor driver\nand extracted to userland via the sensor helper?\n- I'm struggling to see why a sensor device would allow adjustable\ncompanding curves, is there a use-case you know about where this is needed?\n\nRegards,\nNaush\n\n\n>\n> > > [1]\n> https://lore.kernel.org/linux-media/20240905225308.11267-9-laurent.pinchart@ideasonboard.com/\n> > > [2]\n> https://lore.kernel.org/linux-media/20240905225308.11267-10-laurent.pinchart@ideasonboard.com/\n> > >\n> > > > Signed-off-by: Sena Asotani <aso.fam429@gmail.com>\n> > > > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>\n> > > > Tested-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>\n> > > > ---\n> > > >  src/ipa/rpi/controller/decompand_status.h |  8 ++++\n> > > >  src/ipa/rpi/controller/meson.build        |  1 +\n> > > >  src/ipa/rpi/controller/rpi/decompand.cpp  | 58\n> +++++++++++++++++++++++\n> > > >  src/ipa/rpi/controller/rpi/decompand.h    | 31 ++++++++++++\n> > > >  src/ipa/rpi/pisp/pisp.cpp                 | 38 +++++++++++++++\n> > > >  5 files changed, 136 insertions(+)\n> > > >  create mode 100644 src/ipa/rpi/controller/decompand_status.h\n> > > >  create mode 100644 src/ipa/rpi/controller/rpi/decompand.cpp\n> > > >  create mode 100644 src/ipa/rpi/controller/rpi/decompand.h\n> > > >\n> > > > diff --git a/src/ipa/rpi/controller/decompand_status.h\n> > > b/src/ipa/rpi/controller/decompand_status.h\n> > > > new file mode 100644\n> > > > index 000000000000..2d9888dca4f3\n> > > > --- /dev/null\n> > > > +++ b/src/ipa/rpi/controller/decompand_status.h\n> > > > @@ -0,0 +1,8 @@\n> > > > +#pragma once\n> > > > +\n> > > > +#include \"libipa/pwl.h\"\n> > > > +\n> > > > +struct DecompandStatus {\n> > > > +     uint32_t bitdepth;\n> > > > +     libcamera::ipa::Pwl decompandCurve;\n> > > > +};\n> > > > diff --git a/src/ipa/rpi/controller/meson.build\n> > > b/src/ipa/rpi/controller/meson.build\n> > > > index 74b74888bbff..c13c48539d10 100644\n> > > > --- a/src/ipa/rpi/controller/meson.build\n> > > > +++ b/src/ipa/rpi/controller/meson.build\n> > > > @@ -14,6 +14,7 @@ rpi_ipa_controller_sources = files([\n> > > >      'rpi/cac.cpp',\n> > > >      'rpi/ccm.cpp',\n> > > >      'rpi/contrast.cpp',\n> > > > +    'rpi/decompand.cpp',\n> > > >      'rpi/denoise.cpp',\n> > > >      'rpi/dpc.cpp',\n> > > >      'rpi/geq.cpp',\n> > > > diff --git a/src/ipa/rpi/controller/rpi/decompand.cpp\n> > > b/src/ipa/rpi/controller/rpi/decompand.cpp\n> > > > new file mode 100644\n> > > > index 000000000000..2036750f82f4\n> > > > --- /dev/null\n> > > > +++ b/src/ipa/rpi/controller/rpi/decompand.cpp\n> > > > @@ -0,0 +1,58 @@\n> > > > +#include \"decompand.h\"\n> > > > +\n> > > > +#include <libcamera/base/log.h>\n> > > > +\n> > > > +#include \"../decompand_status.h\"\n> > > > +#include \"../histogram.h\"\n> > > > +\n> > > > +using namespace RPiController;\n> > > > +using namespace libcamera;\n> > > > +\n> > > > +LOG_DEFINE_CATEGORY(RPiDecompand)\n> > > > +\n> > > > +#define NAME \"rpi.decompand\"\n> > > > +\n> > > > +Decompand::Decompand(Controller *controller)\n> > > > +     : Algorithm(controller)\n> > > > +{\n> > > > +}\n> > > > +\n> > > > +char const *Decompand::name() const\n> > > > +{\n> > > > +     return NAME;\n> > > > +}\n> > > > +\n> > > > +int Decompand::read(const libcamera::YamlObject &params)\n> > > > +{\n> > > > +     config_.bitdepth = params[\"bitdepth\"].get<uint32_t>(0);\n> > > > +     config_.decompandCurve =\n> > > params[\"decompand_curve\"].get<ipa::Pwl>(ipa::Pwl{});\n> > > > +     return config_.decompandCurve.empty() ? -EINVAL : 0;\n> > > > +}\n> > > > +\n> > > > +void Decompand::initialise()\n> > > > +{\n> > > > +}\n> > > > +\n> > > > +void Decompand::switchMode(CameraMode const &cameraMode,\n> > > > +                        [[maybe_unused]] Metadata *metadata)\n> > > > +{\n> > > > +     mode_ = cameraMode;\n> > > > +}\n> > > > +\n> > > > +void Decompand::prepare(Metadata *imageMetadata)\n> > > > +{\n> > > > +     DecompandStatus decompandStatus;\n> > > > +\n> > > > +     if (config_.bitdepth == 0 || mode_.bitdepth ==\n> config_.bitdepth) {\n> > > > +             decompandStatus.decompandCurve =\n> config_.decompandCurve;\n> > > > +             imageMetadata->set(\"decompand.status\",\n> decompandStatus);\n> > > > +     }\n> > > > +}\n> > > > +\n> > > > +/* Register algorithm with the system. */\n> > > > +static Algorithm *create(Controller *controller)\n> > > > +{\n> > > > +     return new Decompand(controller);\n> > > > +}\n> > > > +\n> > > > +static RegisterAlgorithm reg(NAME, &create);\n> > > > diff --git a/src/ipa/rpi/controller/rpi/decompand.h\n> > > b/src/ipa/rpi/controller/rpi/decompand.h\n> > > > new file mode 100644\n> > > > index 000000000000..38b26a21e6d5\n> > > > --- /dev/null\n> > > > +++ b/src/ipa/rpi/controller/rpi/decompand.h\n> > > > @@ -0,0 +1,31 @@\n> > > > +#pragma once\n> > > > +\n> > > > +#include <libipa/pwl.h>\n> > > > +\n> > > > +#include \"../decompand_status.h\"\n> > > > +\n> > > > +#include \"algorithm.h\"\n> > > > +\n> > > > +namespace RPiController {\n> > > > +\n> > > > +struct DecompandConfig {\n> > > > +     uint32_t bitdepth;\n> > > > +     libcamera::ipa::Pwl decompandCurve;\n> > > > +};\n> > > > +\n> > > > +class Decompand : public Algorithm\n> > > > +{\n> > > > +public:\n> > > > +     Decompand(Controller *controller = nullptr);\n> > > > +     char const *name() const override;\n> > > > +     int read(const libcamera::YamlObject &params) override;\n> > > > +     void initialise() override;\n> > > > +     void switchMode(CameraMode const &cameraMode, Metadata\n> *metadata)\n> > > override;\n> > > > +     void prepare(Metadata *imageMetadata) override;\n> > > > +\n> > > > +private:\n> > > > +     CameraMode mode_;\n> > > > +     DecompandConfig config_;\n> > > > +};\n> > > > +\n> > > > +} /* namespace RPiController */\n> > > > diff --git a/src/ipa/rpi/pisp/pisp.cpp b/src/ipa/rpi/pisp/pisp.cpp\n> > > > index 829b91258522..14ece12b0895 100644\n> > > > --- a/src/ipa/rpi/pisp/pisp.cpp\n> > > > +++ b/src/ipa/rpi/pisp/pisp.cpp\n> > > > @@ -32,6 +32,7 @@\n> > > >  #include \"controller/cac_status.h\"\n> > > >  #include \"controller/ccm_status.h\"\n> > > >  #include \"controller/contrast_status.h\"\n> > > > +#include \"controller/decompand_status.h\"\n> > > >  #include \"controller/denoise_algorithm.h\"\n> > > >  #include \"controller/denoise_status.h\"\n> > > >  #include \"controller/dpc_status.h\"\n> > > > @@ -113,6 +114,25 @@ int generateLut(const ipa::Pwl &pwl, uint32_t\n> *lut,\n> > > std::size_t lutSize,\n> > > >       return 0;\n> > > >  }\n> > > >\n> > > > +int generateDecompandLut(const ipa::Pwl &pwl, Span<uint16_t> lut)\n> > > > +{\n> > > > +     if (pwl.empty())\n> > > > +             return -EINVAL;\n> > > > +\n> > > > +     constexpr int step = 1024;\n> > > > +     for (std::size_t i = 0; i < lut.size(); ++i) {\n> > > > +             int x = i * step;\n> > > > +\n> > > > +             int y = pwl.eval(x);\n> > > > +             if (y < 0)\n> > > > +                     return -1;\n> > > > +\n> > > > +             lut[i] = static_cast<uint16_t>(std::min(y, 65535));\n> > > > +     }\n> > > > +\n> > > > +     return 0;\n> > > > +}\n> > > > +\n> > > >  void packLscLut(uint32_t packed[NumLscVertexes][NumLscVertexes],\n> > > >               double const rgb[3][NumLscVertexes][NumLscVertexes])\n> > > >  {\n> > > > @@ -236,6 +256,7 @@ private:\n> > > >       void applyLensShading(const AlscStatus *alscStatus,\n> > > >                             pisp_be_global_config &global);\n> > > >       void applyDPC(const DpcStatus *dpcStatus, pisp_be_global_config\n> > > &global);\n> > > > +     void applyDecompand(const DecompandStatus *decompandStatus);\n> > > >       void applySdn(const SdnStatus *sdnStatus, pisp_be_global_config\n> > > &global);\n> > > >       void applyTdn(const TdnStatus *tdnStatus, const DeviceStatus\n> > > *deviceStatus,\n> > > >                     pisp_be_global_config &global);\n> > > > @@ -351,6 +372,11 @@ void\n> IpaPiSP::platformPrepareIsp([[maybe_unused]]\n> > > const PrepareParams &params,\n> > > >               if (noiseStatus)\n> > > >                       applyFocusStats(noiseStatus);\n> > > >\n> > > > +             DecompandStatus *decompandStatus =\n> > > > +\n> > >  rpiMetadata.getLocked<DecompandStatus>(\"decompand.status\");\n> > > > +             if (decompandStatus)\n> > > > +                     applyDecompand(decompandStatus);\n> > > > +\n> > > >               BlackLevelStatus *blackLevelStatus =\n> > > >\n> > >  rpiMetadata.getLocked<BlackLevelStatus>(\"black_level.status\");\n> > > >               if (blackLevelStatus)\n> > > > @@ -702,6 +728,18 @@ void IpaPiSP::applyDPC(const DpcStatus\n> *dpcStatus,\n> > > pisp_be_global_config &global\n> > > >       be_->SetDpc(dpc);\n> > > >  }\n> > > >\n> > > > +void IpaPiSP::applyDecompand(const DecompandStatus *decompandStatus)\n> > > > +{\n> > > > +     pisp_fe_global_config feGlobal;\n> > > > +     pisp_fe_decompand_config decompand = {};\n> > > > +\n> > > > +     if (!generateDecompandLut(decompandStatus->decompandCurve,\n> > > decompand.lut)) {\n> > > > +             fe_->SetDecompand(decompand);\n> > > > +             feGlobal.enables |= PISP_FE_ENABLE_DECOMPAND;\n> > > > +             fe_->SetGlobal(feGlobal);\n> > > > +     }\n> > > > +}\n> > > > +\n> > > >  void IpaPiSP::applySdn(const SdnStatus *sdnStatus,\n> > > pisp_be_global_config &global)\n> > > >  {\n> > > >       pisp_be_sdn_config sdn = {};\n>\n> --\n> Regards,\n>\n> Laurent Pinchart\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 56ECCC3259\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 16 Oct 2025 07:34:19 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4E9D460663;\n\tThu, 16 Oct 2025 09:34:18 +0200 (CEST)","from mail-vk1-xa2a.google.com (mail-vk1-xa2a.google.com\n\t[IPv6:2607:f8b0:4864:20::a2a])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id C7FFE600CC\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 16 Oct 2025 09:34:15 +0200 (CEST)","by mail-vk1-xa2a.google.com with SMTP id\n\t71dfb90a1353d-54a81d135f2so9946e0c.3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 16 Oct 2025 00:34:15 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=raspberrypi.com header.i=@raspberrypi.com\n\theader.b=\"mkXHmtLk\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google; t=1760600054; x=1761204854;\n\tdarn=lists.libcamera.org; \n\th=cc:to:subject:message-id:date:from:in-reply-to:references\n\t:mime-version:from:to:cc:subject:date:message-id:reply-to;\n\tbh=llMiM4nXjDtFCFVPYHz6AKxQpN51Hmo1LkxwxrSD+H0=;\n\tb=mkXHmtLk+4zmv3cI8HFi1wcNsLnvH1XfCzHQhSRBfHY/6fp+bOMFKgVjjQYyj2eEU5\n\tRaQzERlTCwFNCSv470F9xi0G50wF6OvqQGXsaaxnHKtRfkinvAi+sooAmV107j20mKt1\n\tlgKLvfNgdnX6x8duy/qKMixxaHz12pJx4RmSrlP5xaeXD06Rw7LetOm9WwBpnDgVz0Iy\n\tN6fhAY1AT6EOcQ0gmEHGlStiHAlu1rtZYToCjUVxs6U1ZuHfuPWzGkiLU41au7JyUyVu\n\td2AKsGUwHuTzhpKKyZ1WdvenKMqvSB11Sys0nPP3e8NWFzXgjFtu2vwIitPZwxgrfWZ4\n\t+o8A==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1760600054; x=1761204854;\n\th=cc:to:subject:message-id:date:from:in-reply-to:references\n\t:mime-version:x-gm-message-state:from:to:cc:subject:date:message-id\n\t:reply-to;\n\tbh=llMiM4nXjDtFCFVPYHz6AKxQpN51Hmo1LkxwxrSD+H0=;\n\tb=NpShdNynQ7yLU100tL4GWOyt8qJKh+GoWSepsUr6PhLhXrm5ow2+W/HQPo2oH7Uqg3\n\tJm3unvEUnNiwFFowYYxO/Cir4XAqw1seYxyvpmgO1YREqWHWI1xUKTRyg+tX6nNDxBbi\n\tIa5nQzK0D2Jz4Tj5aFXanRVKqJSZMeoEdlvCvgmTQYyov9L2V9typiYtfZhILA5cU4W7\n\taCLd6dS8KzlGkq94zZE5i7Bh/4+lzNM1AP83KeJtPWis1kh6A9YR9e0rgCBJ1y6E2pEA\n\tdiezXO0H3o1+EUrrrI0Q7LOJZNP81Ika6fTFRUZY9/uZIsMbQlDjThCly2AUBD2yHCc4\n\tM2uA==","X-Gm-Message-State":"AOJu0YxnFf57FWBvfD41fOmHJu3lW/Uu9JjyjmTgfmGMtNv245tMQh6s\n\tW4HtUzYH4U63F6WRWI5TXhd5whitt1y9i1giXUIMWfuq8Cy0HrlizrJzYx1MyggjwOMyEk8pCHi\n\tWL7rrTVWElavOtCxrBXk1fj7jlkDc0XQpJMbQWF8EcA==","X-Gm-Gg":"ASbGncuKsNX2awSnA8ZHJEwiO59o/0zSsSkar5qRK27dQL653+J094nabmcpnN00q48\n\tVMXYygvei8kUAIsIwdZUewzYkFpYWD7X+bQIHlSJp12wN6ycpTC3CkJiD/1PcEUP1bghdrvG4QL\n\t3drtwpGMES4cCMy/CvrG4BJYffT3e7dTZmNNYG61NS+9D9qIzPZPJ+WMNG89mumaaPxjexMijYG\n\tvDVepKRF0JOElknDsxoHa9hgcC8HDH7vbdkS5HQ9aHudt4VaAStfHNhxSxd7yx63BNGtV8BAUfj\n\tRLPJ2BboKadmEwo=","X-Google-Smtp-Source":"AGHT+IE8d5eLsAxEtjcDibOA7hpDHDXWUIm8g7mnhyI55rsyetlf3DxZyQFYi64WunWo7+NQyOHyuQ9dk775sS4MOMo=","X-Received":"by 2002:a05:6122:169c:b0:544:6d56:eef1 with SMTP id\n\t71dfb90a1353d-556345a4f9emr965704e0c.2.1760600054422; Thu, 16 Oct 2025\n\t00:34:14 -0700 (PDT)","MIME-Version":"1.0","References":"<20251003121821.659081-1-naush@raspberrypi.com>\n\t<20251003121821.659081-2-naush@raspberrypi.com>\n\t<20251013145001.GK16422@pendragon.ideasonboard.com>\n\t<CAEmqJPoP+khFqwN3mOo+=jNFTTKOZaHRnyOEjFj1mUMVSpz-AQ@mail.gmail.com>\n\t<20251014075958.GA30747@pendragon.ideasonboard.com>","In-Reply-To":"<20251014075958.GA30747@pendragon.ideasonboard.com>","From":"Naushir Patuck <naush@raspberrypi.com>","Date":"Thu, 16 Oct 2025 08:33:42 +0100","X-Gm-Features":"AS18NWDmyuoxg_szarplIn3p7NZHB0SLEMm2B3FoeT-DjFyALaw7B3KBvw1SXNg","Message-ID":"<CAEmqJPrZNkaNcou5GmmubgfpxkBCH=WEmmXhkT2qNbnVeV7+hg@mail.gmail.com>","Subject":"Re: [PATCH v2 1/4] ipa: rpi: pisp: Add decompand support using PiSP\n\thardware block","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org, \n\tDavid Plowman <david.plowman@raspberrypi.com>, \n\tNick Hollinghurst <nick.hollinghurst@raspberrypi.com>,\n\tSena Asotani <aso.fam429@gmail.com>","Content-Type":"multipart/alternative; boundary=\"000000000000d5f2ae064141a4df\"","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>"}}]