[{"id":36065,"web_url":"https://patchwork.libcamera.org/comment/36065/","msgid":"<CAEmqJPqdbH33me0KJqkBpFYNLyqKcOyk9zYA-R+3FWbA9Yf7Gg@mail.gmail.com>","date":"2025-10-01T11:40:21","subject":"Re: [PATCH] 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 all,\n\nPlease disregard this patch for the time being, we want to add another\nfeature before reviewing and merging.\n\nRegards,\nNaush\n\n\nOn Wed, 1 Oct 2025 at 10:11, 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> ---\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                 | 40 ++++++++++++++++\n>  5 files changed, 138 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..911b04bc0da0\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([[maybe_unused]] 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 (Algorithm *)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..5ef35946efa5\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 = NULL);\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..e75c87df1924 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, uint16_t *lut, std::size_t\n> lutSize = 65)\n> +{\n> +       if (pwl.empty())\n> +               return -EINVAL;\n> +\n> +       constexpr int step = 1024;\n> +       for (std::size_t i = 0; i < lutSize; ++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,20 @@ 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> +       fe_->GetGlobal(feGlobal);\n> +\n> +       if (!generateDecompandLut(decompandStatus->decompandCurve,\n> decompand.lut, PISP_FE_DECOMPAND_LUT_SIZE)) {\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\n> &global)\n>  {\n>         pisp_be_sdn_config sdn = {};\n> --\n> 2.43.0\n>\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 54167C328C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed,  1 Oct 2025 11:41:02 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 1A6D46B5AA;\n\tWed,  1 Oct 2025 13:41:01 +0200 (CEST)","from mail-vs1-xe35.google.com (mail-vs1-xe35.google.com\n\t[IPv6:2607:f8b0:4864:20::e35])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 2F22B6B58E\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  1 Oct 2025 13:40:58 +0200 (CEST)","by mail-vs1-xe35.google.com with SMTP id\n\tada2fe7eead31-57f496e96d6so401652137.0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 01 Oct 2025 04:40:58 -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=\"nM6J5YZr\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google; t=1759318857; x=1759923657;\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=cRhHjqOhLaORyf1kCEOK1c6abbpyAu5ZqgVbOTzFjw4=;\n\tb=nM6J5YZrhcAkQpYG5/AX4lH9RrWFDFP8LKUs90R0qRNi383iLVIGZ7A3xEnNrZeKPT\n\tqh49jb5qGl89/RD3H1UKyjzZnpdXnNkpbKqHJzZuSWpS/1Ky4Wybqs0v2mL1A6rlOGZ8\n\tThUy+O4OAuh48i7oKwn3+1XbL3KnQ58u4zyjxKVPIf6vZuKW/eb8oqZM33SAL0fkYYbp\n\txVkCCEeJb/98HH4Ko+B0uo4DMRfp75YsRR7PvALgfmk+GmrjaoDjAwRCQYcrVKpXhCVg\n\txN+JngxtT3aoSDaH1AI1mtzyTeDUW/+AKE/HCZr48SUEpCDkKbfK4v47cFzl1vQkoLq1\n\tBlmQ==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1759318857; x=1759923657;\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=cRhHjqOhLaORyf1kCEOK1c6abbpyAu5ZqgVbOTzFjw4=;\n\tb=UCvmavFX/2MJWkf1UYjgjaizXKfBXt4vXXr+FTUvUmzc1ek32TqmZ9ZMPY3kOwibFn\n\tYouVNkl7+d9eQ7a6YNmAgqC1lkFjv/8ZlK0ze++yPSLmF75BnP1c9KQIlmyYzyuGcMq3\n\tpzZDLXoR7H9Pn50vVE345suUKx32M7IPLdXYa+mNq7wFYCdtYn5xtHh0kg9lrNNxRN0g\n\thdht2XEwYbs4pv0+MpkyDqxfl30lEumZ27Z832/GKpfXA8hLbb06kGh17IfPlTZrWfmP\n\tpdO+WEQBmrt0j9P14RlHsi//Ure+KHaSWOb7Rj4Wc1e1yCoqUX1KDdhPG51jlAxQj4JD\n\tawwg==","X-Gm-Message-State":"AOJu0YxQnsCUDLpxbXcNigRwDhNl1Sjjo3EqNxYgMH8Vat6QZdDCMIK5\n\tUWliziYnwcZX5Z1EZPZWEXm+OYznWU79+XvcsOZRn99p7uO/vv2FAFI9NLUSnNOl/ziNT/psztd\n\tGmRCPHze7Sj76393zIuJF1xOwLDV8/9wns2jCLSzstWl2j7j89ywn","X-Gm-Gg":"ASbGncsLfmGMdsJYdwW63rmNj1x5zkxN7o44ZP+dMvpkvyrdJvHb1aJRuiM9k8HNd+h\n\t7H5GbEvLG4m56pXYCPHHcdI+5jaNTTC4nTa8dSW4VWyUVKe+SG4N+0b+xfO501Ne7pJmIIf9H+F\n\tafyGFxZcl9KEmLeEIndHnWV1cmXIR7bp6MTb1SzDB32XCjzfuJBOatq2ONO0NitV5+BGH0oFtRO\n\tzgSLevWfhCO2Xqe8Un5qH89wgo+uxvUlcZslYRA+CoTP7k2Fa7OGWr7OmLBaLHW8QtZ5JLX","X-Google-Smtp-Source":"AGHT+IERTFMzN6jiTUyPf/sLpSttFDgtpNpUY5l6ksVjLM52Vawe6W6CPdq4HfPdSBRRc54aTF07VzI5NC4lmyKpAzI=","X-Received":"by 2002:a05:6102:e12:b0:5c8:72bc:95f2 with SMTP id\n\tada2fe7eead31-5d3fe6d9315mr484880137.5.1759318856527; Wed, 01 Oct 2025\n\t04:40:56 -0700 (PDT)","MIME-Version":"1.0","References":"<20251001091143.2051905-1-naush@raspberrypi.com>","In-Reply-To":"<20251001091143.2051905-1-naush@raspberrypi.com>","From":"Naushir Patuck <naush@raspberrypi.com>","Date":"Wed, 1 Oct 2025 12:40:21 +0100","X-Gm-Features":"AS18NWBuwLdozt4xWDs8xhO7LsNqvGY4UDkme2NrXkglQU6XEgwyvNmpiAyqsJQ","Message-ID":"<CAEmqJPqdbH33me0KJqkBpFYNLyqKcOyk9zYA-R+3FWbA9Yf7Gg@mail.gmail.com>","Subject":"Re: [PATCH] ipa: rpi: pisp: Add decompand support using PiSP\n\thardware block","To":"libcamera-devel@lists.libcamera.org","Cc":"David Plowman <david.plowman@raspberrypi.com>, \n\tNick Hollinghurst <nick.hollinghurst@raspberrypi.com>,\n\tSena Asotani <aso.fam429@gmail.com>","Content-Type":"multipart/alternative; boundary=\"0000000000007d85ca0640175762\"","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>"}}]