From patchwork Fri Oct 3 12:15:52 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 24558 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 5480AC324C for ; Fri, 3 Oct 2025 12:18:37 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 297666B5F3; Fri, 3 Oct 2025 14:18:33 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="BAbJ8hZz"; dkim-atps=neutral Received: from mail-wr1-x431.google.com (mail-wr1-x431.google.com [IPv6:2a00:1450:4864:20::431]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8322169318 for ; Fri, 3 Oct 2025 14:18:31 +0200 (CEST) Received: by mail-wr1-x431.google.com with SMTP id ffacd0b85a97d-3ee0fd0c5c4so198816f8f.3 for ; Fri, 03 Oct 2025 05:18:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1759493911; x=1760098711; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=UbalvF77R6m7kRGcNwpXf4C99U24C/faJvy6AO/sdII=; b=BAbJ8hZzCnAkgLeNUgtnIuR3HF1angcdN0dnj0I1kcWPaXfevphwRWZD1P2LyaezZG 6pnfMhbE51LxOm9rOuEytw37PKqzTXzSkf8AG5bx6c0r1UYBt/8ZDACXylAIDebCBCKB hjaBNWwuOArKqG1SXWA+o7XKtUs94RzNLJbw785oMUW9GwwFbtzAvMspvlVyjsdvD/FI lVTuBSV5F7D99MtkJxJRKxy4sAtRElajj/vlRDoQ/N1thogC43mc8ef7AXv5klPUw9KI gsKG6+5e2spNwOaT47sYxqjMQsezV/xwLPLP2NY2bKXk3hZAOSXTI5kdnE2QoNFFPV1K 7OSg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1759493911; x=1760098711; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=UbalvF77R6m7kRGcNwpXf4C99U24C/faJvy6AO/sdII=; b=RxFAvWvyzvz4aG7wfvNu93Bu26nadEjWo2mK1miAgAy1uQUR3eCI0EcVGkMJY4Ac0g 4cZgPGqotMj1cHaidJgZeXtmjVv1wFtKLk21I3fqsztzmYoWDNQKdJvcGnHyZfApVSHp C3kYTHtXjG0M+HPG4BYwFik4lZ75zQ6yQPSK8YqoMMrJFPv9WIYNHGUSe3XDq5AoR3Nk 54XKwFP8KtZG0Q7+WE8FT7US7CEmi8KZI4GpYpXN+pVvF14T4diESapFGwe3kAZqWKkR P0ne+bsAragGaqUvPlXhxCeAc6ZHm+quBoxYEuTTUi+486kcwj+5MK5yXd54q0IMy35h rRJQ== X-Gm-Message-State: AOJu0YyBGXLEg073jP/N/yFAz+82O7ZHJGeyC5za/Ikr4tB7Zo9mM/cg Z0q9due1gZ7H3MvPoY8m1YbOOsRCQYuhXZSgB5iyd8EzC2YlSwKJ3zI34DiyNZ5wriAeJ7OGXiP WgWxF X-Gm-Gg: ASbGncvmGg2HhjWpfa9BT8FLwPdATvB+Svb8E7QANjDcdYkjK1leVxlhv4fzC/o+f3M MZDGLDj/1SjBudbeuN/OREdzANuaOu78In6c/Bo6PjOKgYOs0oq72ZTC/DcnGWTMZYUajFqmyoe qYzi/CQAoerg9FCgac3zfUPgzk261dJstkrIH/eWXbAP/PYLg7pCkFbCrqDCP6AJIBNyiiXLUov FkRXYpPyfUZ3bAOGSvTAR+NLNytHzn0Jyz/q3q9c4uCXhnT02+ZqyrSyR5kEOWCz4X5xdau19Sa reCaTCZmkeAhCCQOq2N0q6nBnVpWncPn35vDnAdgxiOzyYcBNP8T0c4p+fET9ClIcE1xQ9FvBbe 9hcGSXZYgC7nL56VavLuB1VZQ4LxFK24rgc3mbu+0RemSvkbNK7zdwpTy1dZp8HGl4N1VZA6+ok Gm X-Google-Smtp-Source: AGHT+IH2yG60LIZeoGDumTCkWBhQExH1DkuBbUGJMMhylzEyaHO+s+8XJCUN6IlUXmwKz7ldzfRJYg== X-Received: by 2002:a05:6000:2282:b0:3f3:1be5:ecbf with SMTP id ffacd0b85a97d-425671a06aemr903770f8f.7.1759493910694; Fri, 03 Oct 2025 05:18:30 -0700 (PDT) Received: from NAUSH-P-DELL.pitowers.org ([93.93.133.154]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4255d8f02a8sm7812529f8f.39.2025.10.03.05.18.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 03 Oct 2025 05:18:30 -0700 (PDT) From: Naushir Patuck To: libcamera-devel@lists.libcamera.org Cc: David Plowman , Nick Hollinghurst , Sena Asotani , Naushir Patuck Subject: [PATCH v2 1/4] ipa: rpi: pisp: Add decompand support using PiSP hardware block Date: Fri, 3 Oct 2025 13:15:52 +0100 Message-ID: <20251003121821.659081-2-naush@raspberrypi.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251003121821.659081-1-naush@raspberrypi.com> References: <20251003121821.659081-1-naush@raspberrypi.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" From: Sena Asotani This patch integrates a new decompand algorithm that utilizes the PiSP FE hardware block available on Raspberry Pi 5. The implementation enables conversion of companded sensor data into linear format prior to ISP processing. Changes include: - Implementation of decompand logic for controller and pipe interfaces - Enabling decompand block by "rpi.decompand" in tuning.json Signed-off-by: Sena Asotani Signed-off-by: Naushir Patuck Tested-by: Nick Hollinghurst Reviewed-by: David Plowman --- src/ipa/rpi/controller/decompand_status.h | 8 ++++ src/ipa/rpi/controller/meson.build | 1 + src/ipa/rpi/controller/rpi/decompand.cpp | 58 +++++++++++++++++++++++ src/ipa/rpi/controller/rpi/decompand.h | 31 ++++++++++++ src/ipa/rpi/pisp/pisp.cpp | 38 +++++++++++++++ 5 files changed, 136 insertions(+) create mode 100644 src/ipa/rpi/controller/decompand_status.h create mode 100644 src/ipa/rpi/controller/rpi/decompand.cpp create mode 100644 src/ipa/rpi/controller/rpi/decompand.h diff --git a/src/ipa/rpi/controller/decompand_status.h b/src/ipa/rpi/controller/decompand_status.h new file mode 100644 index 000000000000..2d9888dca4f3 --- /dev/null +++ b/src/ipa/rpi/controller/decompand_status.h @@ -0,0 +1,8 @@ +#pragma once + +#include "libipa/pwl.h" + +struct DecompandStatus { + uint32_t bitdepth; + libcamera::ipa::Pwl decompandCurve; +}; diff --git a/src/ipa/rpi/controller/meson.build b/src/ipa/rpi/controller/meson.build index 74b74888bbff..c13c48539d10 100644 --- a/src/ipa/rpi/controller/meson.build +++ b/src/ipa/rpi/controller/meson.build @@ -14,6 +14,7 @@ rpi_ipa_controller_sources = files([ 'rpi/cac.cpp', 'rpi/ccm.cpp', 'rpi/contrast.cpp', + 'rpi/decompand.cpp', 'rpi/denoise.cpp', 'rpi/dpc.cpp', 'rpi/geq.cpp', diff --git a/src/ipa/rpi/controller/rpi/decompand.cpp b/src/ipa/rpi/controller/rpi/decompand.cpp new file mode 100644 index 000000000000..2036750f82f4 --- /dev/null +++ b/src/ipa/rpi/controller/rpi/decompand.cpp @@ -0,0 +1,58 @@ +#include "decompand.h" + +#include + +#include "../decompand_status.h" +#include "../histogram.h" + +using namespace RPiController; +using namespace libcamera; + +LOG_DEFINE_CATEGORY(RPiDecompand) + +#define NAME "rpi.decompand" + +Decompand::Decompand(Controller *controller) + : Algorithm(controller) +{ +} + +char const *Decompand::name() const +{ + return NAME; +} + +int Decompand::read(const libcamera::YamlObject ¶ms) +{ + config_.bitdepth = params["bitdepth"].get(0); + config_.decompandCurve = params["decompand_curve"].get(ipa::Pwl{}); + return config_.decompandCurve.empty() ? -EINVAL : 0; +} + +void Decompand::initialise() +{ +} + +void Decompand::switchMode(CameraMode const &cameraMode, + [[maybe_unused]] Metadata *metadata) +{ + mode_ = cameraMode; +} + +void Decompand::prepare(Metadata *imageMetadata) +{ + DecompandStatus decompandStatus; + + if (config_.bitdepth == 0 || mode_.bitdepth == config_.bitdepth) { + decompandStatus.decompandCurve = config_.decompandCurve; + imageMetadata->set("decompand.status", decompandStatus); + } +} + +/* Register algorithm with the system. */ +static Algorithm *create(Controller *controller) +{ + return new Decompand(controller); +} + +static RegisterAlgorithm reg(NAME, &create); diff --git a/src/ipa/rpi/controller/rpi/decompand.h b/src/ipa/rpi/controller/rpi/decompand.h new file mode 100644 index 000000000000..38b26a21e6d5 --- /dev/null +++ b/src/ipa/rpi/controller/rpi/decompand.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +#include "../decompand_status.h" + +#include "algorithm.h" + +namespace RPiController { + +struct DecompandConfig { + uint32_t bitdepth; + libcamera::ipa::Pwl decompandCurve; +}; + +class Decompand : public Algorithm +{ +public: + Decompand(Controller *controller = nullptr); + char const *name() const override; + int read(const libcamera::YamlObject ¶ms) override; + void initialise() override; + void switchMode(CameraMode const &cameraMode, Metadata *metadata) override; + void prepare(Metadata *imageMetadata) override; + +private: + CameraMode mode_; + DecompandConfig config_; +}; + +} /* namespace RPiController */ diff --git a/src/ipa/rpi/pisp/pisp.cpp b/src/ipa/rpi/pisp/pisp.cpp index 829b91258522..14ece12b0895 100644 --- a/src/ipa/rpi/pisp/pisp.cpp +++ b/src/ipa/rpi/pisp/pisp.cpp @@ -32,6 +32,7 @@ #include "controller/cac_status.h" #include "controller/ccm_status.h" #include "controller/contrast_status.h" +#include "controller/decompand_status.h" #include "controller/denoise_algorithm.h" #include "controller/denoise_status.h" #include "controller/dpc_status.h" @@ -113,6 +114,25 @@ int generateLut(const ipa::Pwl &pwl, uint32_t *lut, std::size_t lutSize, return 0; } +int generateDecompandLut(const ipa::Pwl &pwl, Span lut) +{ + if (pwl.empty()) + return -EINVAL; + + constexpr int step = 1024; + for (std::size_t i = 0; i < lut.size(); ++i) { + int x = i * step; + + int y = pwl.eval(x); + if (y < 0) + return -1; + + lut[i] = static_cast(std::min(y, 65535)); + } + + return 0; +} + void packLscLut(uint32_t packed[NumLscVertexes][NumLscVertexes], double const rgb[3][NumLscVertexes][NumLscVertexes]) { @@ -236,6 +256,7 @@ private: void applyLensShading(const AlscStatus *alscStatus, pisp_be_global_config &global); void applyDPC(const DpcStatus *dpcStatus, pisp_be_global_config &global); + void applyDecompand(const DecompandStatus *decompandStatus); void applySdn(const SdnStatus *sdnStatus, pisp_be_global_config &global); void applyTdn(const TdnStatus *tdnStatus, const DeviceStatus *deviceStatus, pisp_be_global_config &global); @@ -351,6 +372,11 @@ void IpaPiSP::platformPrepareIsp([[maybe_unused]] const PrepareParams ¶ms, if (noiseStatus) applyFocusStats(noiseStatus); + DecompandStatus *decompandStatus = + rpiMetadata.getLocked("decompand.status"); + if (decompandStatus) + applyDecompand(decompandStatus); + BlackLevelStatus *blackLevelStatus = rpiMetadata.getLocked("black_level.status"); if (blackLevelStatus) @@ -702,6 +728,18 @@ void IpaPiSP::applyDPC(const DpcStatus *dpcStatus, pisp_be_global_config &global be_->SetDpc(dpc); } +void IpaPiSP::applyDecompand(const DecompandStatus *decompandStatus) +{ + pisp_fe_global_config feGlobal; + pisp_fe_decompand_config decompand = {}; + + if (!generateDecompandLut(decompandStatus->decompandCurve, decompand.lut)) { + fe_->SetDecompand(decompand); + feGlobal.enables |= PISP_FE_ENABLE_DECOMPAND; + fe_->SetGlobal(feGlobal); + } +} + void IpaPiSP::applySdn(const SdnStatus *sdnStatus, pisp_be_global_config &global) { pisp_be_sdn_config sdn = {};