From patchwork Wed Oct 1 09:11:23 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 24540 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 566D7C324C for ; Wed, 1 Oct 2025 09:11:51 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E11446B5F0; Wed, 1 Oct 2025 11:11:49 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="kA5nijiF"; dkim-atps=neutral Received: from mail-wr1-x436.google.com (mail-wr1-x436.google.com [IPv6:2a00:1450:4864:20::436]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7332169318 for ; Wed, 1 Oct 2025 11:11:48 +0200 (CEST) Received: by mail-wr1-x436.google.com with SMTP id ffacd0b85a97d-3fd2dee5c00so189513f8f.0 for ; Wed, 01 Oct 2025 02:11:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1759309907; x=1759914707; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=IVoMSQ9NqKSYjvVxbeL+oHW0AnGWWAyEI8GVF0//jK4=; b=kA5nijiF89taASF02V5UwNdv4SpvyJTp8mDP5eAAr4axIWOUurMBQ1ish09PKfG+MU Kf9SU/0S1Le+A5R5i/PHxmLjIWX/3d6tSgvb0h+dV3bf6KWpVBvvcw+eDB34YVDJrJfV Zr7UTv8uOs+X4Pp1ayCeKHEt2n0HyqpQOajb/nF09JOPKE4Ku70TJNfHjj9Npd+S+SFU Oge8Y5Vb915Z9FqhCIB5hQPnLg4iytGmvX3jtV8VQMsVb2oUzFAZynU4kfaPlQdyrtD2 bqkCkhVzgNUuaspwHIDmqj7zINUvn0fHYi+rxnebLoueqmm7dmk3QWYuNnhrlDFjzRZH fKkQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1759309907; x=1759914707; h=content-transfer-encoding:mime-version: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=VzwZRLSoXKObAVb1zZAP3E49lYQn74QaAx5dWZCWhUFnDpIk/ZTB304dn9RhQG2aHU gwS7LKfZDqyuLxk5bMtidGdYfgytvFzGoAMsPseggJF2B5dtB6Lb2yWZv89nV8EwquMq 9HPQl85Xl0FsvXWw5YPV+Hc4LGpQtiAUPL8YbNpkY8CuAmbJCW2XSw0tlxqqH3+Ii8QC KBP1p//QRma7ck9RAy2bLdAsYeG3W4z8ns7TK9q/iZWLpZl5zjZntg0vTcABQ7r/G1/A 4lQbrJAfAjgryJ5xDeGKDceV6iC+9sHUeLEJgPM5sKqIn+Tn5K1w1n/owK964mIhGlpX 9C+Q== X-Gm-Message-State: AOJu0YxXa03UFBJi9+xSMdX8Fl1OtX0RL7wHfYw625/NrDqbzZ9XNUyr B9V1eynStrbvux5ppdyfEZoXdiTjEZwtEwceCsUIGTzgSZMzN5hwELsaJV6Oo4QnexT18yUkVx9 OzhL2 X-Gm-Gg: ASbGnctyYrqQOUcr/q/aAYuGlwntBxXM838HIVBiE8Me2asFQQvdWSBhu125ORts1WZ VblAKaQrDoF/tCt8gull2tNLTbCk16gDepStU92ZBh3xyanGstck2lAOy5WAwRoh04rte2uvC5L O/MJnxEua8EkYp6waCOlYi5aUeIXNmhTALg4EHKipU3jzxMbCpO6UahEuKEpPduvINcaaNJIBX4 mozr6GjV/HPppeKm/Ed94+LHzTyF60BYoEjYsON/YnD5XIWvppnZ0IoC0PGQ3bQp2WmT25GpGOk TmQwyTTKJrlnK5C50xis52h4f4wR7i4wG0MsHn2Kd4L+GHPmz/hsC+C3tVAYLfruOfeWLUbJ2FP l9dn/+SIjm8gbLK590KI3kG6GHjfiJ8fDArIWUD5UAT+nz8FmsD4nquTw8yNcdBAUEQ== X-Google-Smtp-Source: AGHT+IFUVjg8zXjzWUXL4mXvBFmklEZOK1EUB13ipgaywuZPC9Rk/RxrpY56qX7R6GphuTp7UwQBCQ== X-Received: by 2002:a05:6000:1a8e:b0:3f3:1695:7c49 with SMTP id ffacd0b85a97d-4255780bfa4mr1121731f8f.7.1759309907477; Wed, 01 Oct 2025 02:11:47 -0700 (PDT) Received: from NAUSH-P-DELL.pitowers.org ([93.93.133.154]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-40fb9c32734sm26743332f8f.25.2025.10.01.02.11.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 01 Oct 2025 02:11:47 -0700 (PDT) From: Naushir Patuck To: libcamera-devel@lists.libcamera.org Cc: David Plowman , Nick Hollinghurst , Sena Asotani , Naushir Patuck Subject: [PATCH] ipa: rpi: pisp: Add decompand support using PiSP hardware block Date: Wed, 1 Oct 2025 10:11:23 +0100 Message-ID: <20251001091143.2051905-1-naush@raspberrypi.com> X-Mailer: git-send-email 2.43.0 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 = {};