From patchwork Thu Oct 2 13:26:04 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 24549 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 6438CC328C for ; Thu, 2 Oct 2025 13:35:37 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B6B1E6B5F3; Thu, 2 Oct 2025 15:35:33 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="RRoSG21L"; dkim-atps=neutral Received: from mail-wm1-x32d.google.com (mail-wm1-x32d.google.com [IPv6:2a00:1450:4864:20::32d]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1559D6B5A2 for ; Thu, 2 Oct 2025 15:35:31 +0200 (CEST) Received: by mail-wm1-x32d.google.com with SMTP id 5b1f17b1804b1-46e509368caso1392925e9.1 for ; Thu, 02 Oct 2025 06:35:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1759412130; x=1760016930; 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=IVoMSQ9NqKSYjvVxbeL+oHW0AnGWWAyEI8GVF0//jK4=; b=RRoSG21LX0whvvVzC1mDANWqmxen6YnFVx2cIL2dkZYV9o/h5/YvAz4Xu9ko9rvKVW rVtjxcd4gkl4TqKx2nIM/MNrXqrXjitwvOEf4cs8QKom142vXF2SApF78JC35Nj/fEYz N2L8VZNXT+11Qk6SC80C+3O5XK9o5DZru6pc9b4wV9RNjyA67dw+5O7IKpBTWvrOorsW PUGCycZGujEWMQSlIUz/gujYokCLy/f4nHXZp4f92FTqB6X1aqkgui/re9rHSxAqbG+8 ryMkdwhSkkioJXGQs53/AniTpXRyFe4Q8QOMUeR/NIdmyJUYEHUEhRLCyLoGGIJHisr4 xCxg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1759412130; x=1760016930; 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=IVoMSQ9NqKSYjvVxbeL+oHW0AnGWWAyEI8GVF0//jK4=; b=i4J+mHfn+ftxgWk5F0IR8B++pbVJQmQZsQwoHkzDrJ4Ofnsg/gSUrzcGhxvti/2xq8 2po/+yLfTGKJSBbE+48ElFXlBwJveE+1DLwvXV0njWSJGaRW9wBIsjwrKy9yI68K28S4 kyAokL+auQrDusOrMaCgidsKBkbVr3aP5s4Simr+AMBv9CUy+MdhZwJW5pFO9hIIZ633 6QpXquYKgVNxzF64tJ4bJ5FqKnCbp9/FVpSaA/zFzrUnmdtSDDfCeJiXoDqWQUhuMOUP vwVe+myWBjpVNYq4PQuOqSgy0NXAc7SL4HbcvFcRSYRJee1+pnYK+RsY8MMYJ4Xkr1yP QlHA== X-Gm-Message-State: AOJu0YzvSEfFu/LvUKLxqSrWeOgyn3IrgFeAxiZgqpk7e2Ucj/dCNJso 3VzUvKJG+kzzq1TyFUoOtI6wP4JycswRP/O8nMzdISR4ygk7GOMPuI554bObRNQJZ30osXVJgmh g1HiD X-Gm-Gg: ASbGnctQKuTqMDweSpPH8zr6yrSG6FDL9WUjGOxJC4PR49uq6HZovBaA4VVrOetRFVI u2VmbjxrhYY0vY9MvBw/dakpcFMrLd4AXE02m6jXuy0M+mh2LLYTXVHwaYL9zhwAbubF+swiuKm YLxHU+Nf32NReyFRbxHLLmJECiZGTnxHu1toSpyJgT0CYpB7japgkW0sfhkNLF+fAg4vt8Jfb/8 CqSS3/zRtAADS5FJIuZoDKJSOE3m7nyCCErrNERLom0avbxFJXAZ5WNDYTd+U1VYAHF0qvIio4T nhWmEpJElaTXo28C/quUaAjOi8nyghv+WmI5UZ6szTl5FOHaZWvuKcOVk3CjNHLJ/n1DhnixPGb sftbp2yb/rWbPbyEDALJJmmoMa6p5r45JO7+LtKL4R5q8ygqUwPWYZ6v9JcIQMzoe/g== X-Google-Smtp-Source: AGHT+IEirLTYWf1LNe1EuyRVEnD7RJ/VXbyO11sbdUCcv7VOTLLa7bfZDk1dQsoah1YWoWMHQOxd1g== X-Received: by 2002:a05:600c:1d19:b0:46e:3c73:2f9d with SMTP id 5b1f17b1804b1-46e612c9809mr32447265e9.6.1759412130276; Thu, 02 Oct 2025 06:35:30 -0700 (PDT) Received: from NAUSH-P-DELL.pitowers.org ([93.93.133.154]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-46e6918bdebsm40396015e9.9.2025.10.02.06.35.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 02 Oct 2025 06:35:29 -0700 (PDT) From: Naushir Patuck To: libcamera-devel@lists.libcamera.org Cc: David Plowman , Nick Hollinghurst , Sena Asotani , Naushir Patuck Subject: [PATCH v1 1/4] ipa: rpi: pisp: Add decompand support using PiSP hardware block Date: Thu, 2 Oct 2025 14:26:04 +0100 Message-ID: <20251002133523.293413-2-naush@raspberrypi.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251002133523.293413-1-naush@raspberrypi.com> References: <20251002133523.293413-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 --- 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 | 40 ++++++++++++++++ 5 files changed, 138 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..911b04bc0da0 --- /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([[maybe_unused]] 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 (Algorithm *)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..5ef35946efa5 --- /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 = NULL); + 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..e75c87df1924 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, uint16_t *lut, std::size_t lutSize = 65) +{ + if (pwl.empty()) + return -EINVAL; + + constexpr int step = 1024; + for (std::size_t i = 0; i < lutSize; ++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,20 @@ 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 = {}; + + fe_->GetGlobal(feGlobal); + + if (!generateDecompandLut(decompandStatus->decompandCurve, decompand.lut, PISP_FE_DECOMPAND_LUT_SIZE)) { + 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 = {};