From patchwork Tue May 12 12:36:05 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 26724 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 9176DBDB1C for ; Tue, 12 May 2026 12:36:41 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4A3CA63025; Tue, 12 May 2026 14:36:41 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="W/EGYgkU"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0B07A63020 for ; Tue, 12 May 2026 14:36:39 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778589399; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=uWOyb2MOZwVpr4GK1ZgYUmk44uV3Q47RAq6rwm3svaU=; b=W/EGYgkUJcXgMHU/x4Dzru29uNp5yjJWo/WQ1ilqnNQUqjSi9kDyQsbEXDowf9greBG2nT UVZDfUPd0og6Qy3LNunfN1A9JL0KX+j5E/vO+LJIc5VliSLBwYjEUGz0eW/3h0Sd02bHv/ jAK8F9uQZCM6qOwxeVIVxSIfbJUdUPY= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-61-geZz8zHxOeGeCx_acVtcUw-1; Tue, 12 May 2026 08:36:35 -0400 X-MC-Unique: geZz8zHxOeGeCx_acVtcUw-1 X-Mimecast-MFC-AGG-ID: geZz8zHxOeGeCx_acVtcUw_1778589394 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id C4B06195608A; Tue, 12 May 2026 12:36:33 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.50.44]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id BE7B71944B20; Tue, 12 May 2026 12:36:30 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Xander Pronk , Bryan O'Donoghue , Hans de Goede , Laurent Pinchart , Bryan O'Donoghue , Rick ten Wolde , Milan Zamazal Subject: [RFC PATCH v5 01/10] libcamera: software_isp: egl: Add filter parameter to createTexture2D() Date: Tue, 12 May 2026 14:36:05 +0200 Message-ID: <20260512123619.120068-2-mzamazal@redhat.com> In-Reply-To: <20260512123619.120068-1-mzamazal@redhat.com> References: <20260512123619.120068-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: mcDVxL2RC80xgCMmIYZuianYxvHJWRNsl6Bh0rzTlMk_1778589394 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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: Xander Pronk Add `filter' parameter to createTexture2D() to allow overriding the currently hardcoded GL_NEAREST value. This is needed for grid-based lens shading interpolation, which is implemented in followup patches. Reviewed-by: Bryan O'Donoghue Co-developed-by: Rick ten Wolde Signed-off-by: Rick ten Wolde Signed-off-by: Xander Pronk Signed-off-by: Milan Zamazal --- include/libcamera/internal/egl.h | 3 ++- src/libcamera/egl.cpp | 10 ++++++---- src/libcamera/software_isp/debayer_egl.cpp | 4 +++- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/include/libcamera/internal/egl.h b/include/libcamera/internal/egl.h index 0ad2320b1..6402dd5c7 100644 --- a/include/libcamera/internal/egl.h +++ b/include/libcamera/internal/egl.h @@ -103,7 +103,8 @@ public: int createInputDMABufTexture2D(eGLImage &eglImage, int fd); int createOutputDMABufTexture2D(eGLImage &eglImage, int fd); - void createTexture2D(eGLImage &eglImage, GLint format, uint32_t width, uint32_t height, void *data); + void createTexture2D(eGLImage &eglImage, GLint format, uint32_t width, uint32_t height, + const void *data, GLint filter); void pushEnv(std::vector &shaderEnv, const char *str); void makeCurrent(); diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp index 357918711..80d71451f 100644 --- a/src/libcamera/egl.cpp +++ b/src/libcamera/egl.cpp @@ -211,13 +211,15 @@ int eGL::createOutputDMABufTexture2D(eGLImage &eglImage, int fd) * \param[in] width Texture width in pixels * \param[in] height Texture height in pixels * \param[in] data Pointer to pixel data, or nullptr for uninitialised texture + * \param[in] filter GL texture filter setting * * Creates a 2D texture from a CPU-accessible memory buffer. The texture - * is configured with nearest filtering and clamp-to-edge wrapping. This + * is configured the specified filtering and clamp-to-edge wrapping. This * is useful for uploading static data like lookup tables or uniform color * matrices to the GPU. */ -void eGL::createTexture2D(eGLImage &eglImage, GLint format, uint32_t width, uint32_t height, void *data) +void eGL::createTexture2D(eGLImage &eglImage, GLint format, uint32_t width, uint32_t height, + const void *data, GLint filter) { ASSERT(tid_ == Thread::currentId()); @@ -228,8 +230,8 @@ void eGL::createTexture2D(eGLImage &eglImage, GLint format, uint32_t width, uint glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); // Nearest filtering - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); // Wrap to edge to avoid edge artifacts glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp index eae4c57f4..866592547 100644 --- a/src/libcamera/software_isp/debayer_egl.cpp +++ b/src/libcamera/software_isp/debayer_egl.cpp @@ -506,7 +506,9 @@ int DebayerEGL::debayerGPU(MappedFrameBuffer &in, int out_fd, const DebayerParam egl_.makeCurrent(); /* Create a standard texture input */ - egl_.createTexture2D(*eglImageBayerIn_, glFormat_, inputConfig_.stride / bytesPerPixel_, height_, in.planes()[0].data()); + egl_.createTexture2D(*eglImageBayerIn_, glFormat_, + inputConfig_.stride / bytesPerPixel_, height_, + in.planes()[0].data(), GL_NEAREST); /* Generate the output render framebuffer as render to texture */ egl_.createOutputDMABufTexture2D(*eglImageBayerOut_, out_fd); From patchwork Tue May 12 12:36:06 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 26725 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 DF9A2BDB1C for ; Tue, 12 May 2026 12:36:45 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7C5756302D; Tue, 12 May 2026 14:36:45 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="fSoHCKw6"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8CFF363020 for ; Tue, 12 May 2026 14:36:43 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778589402; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=GMpTRJkAeYb5u4p7zVG3zTLovAUt5iXhXpZDwDhZzFI=; b=fSoHCKw6KvhHRie1UYmqlAcJcH+1ZDktZ7FEuFEEonU8RLHhfzChrizTazmeI7T0c2tAI4 qwlrw0qEhSfVOt3yLFrXzwkLqzNttCJVeREY8w1Ku3HgANGfwE/zbTGQOtkru92ZEt4kl7 Dz/MqFpW5EplXbe6uJvoJH+8LnpspPs= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-303-FPWBD2WTPMC9sJGoJWShTA-1; Tue, 12 May 2026 08:36:39 -0400 X-MC-Unique: FPWBD2WTPMC9sJGoJWShTA-1 X-Mimecast-MFC-AGG-ID: FPWBD2WTPMC9sJGoJWShTA_1778589397 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 4C39C18002C9; Tue, 12 May 2026 12:36:37 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.50.44]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 585371955D84; Tue, 12 May 2026 12:36:33 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Xander Pronk , Bryan O'Donoghue , Hans de Goede , Laurent Pinchart , Rick ten Wolde , Milan Zamazal Subject: [RFC PATCH v5 02/10] libcamera: software_isp: Add LSC data to DebayerParams Date: Tue, 12 May 2026 14:36:06 +0200 Message-ID: <20260512123619.120068-3-mzamazal@redhat.com> In-Reply-To: <20260512123619.120068-1-mzamazal@redhat.com> References: <20260512123619.120068-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: lRNMhBgEvZgpthpD5te7WhQcNaZoZYVP2NKSZRIl5f0_1778589397 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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: Xander Pronk Add a lookup table for grid-based lens shading correction to debayer params. The lookup table is in the format of an RGB texture to be passed to debayering. The parameter is filled in by LSC algorithm implemented in a followup patch. If the algorithm is not enabled, the parameter content is arbitrary and the parameter may not be used. The parameter is currently unused, its handling is implemented in a followup patch. There is no special meaning about the selected grid size, it's just one of the smaller common sizes. Co-developed-by: Rick ten Wolde Signed-off-by: Rick ten Wolde Signed-off-by: Xander Pronk Signed-off-by: Milan Zamazal --- .../internal/software_isp/debayer_params.h | 8 ++++++ src/libcamera/software_isp/debayer.cpp | 28 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/include/libcamera/internal/software_isp/debayer_params.h b/include/libcamera/internal/software_isp/debayer_params.h index 6772b43bc..47f2c3ac2 100644 --- a/include/libcamera/internal/software_isp/debayer_params.h +++ b/include/libcamera/internal/software_isp/debayer_params.h @@ -10,6 +10,7 @@ #pragma once +#include #include #include "libcamera/internal/matrix.h" @@ -25,6 +26,13 @@ struct DebayerParams { float gamma = 1.0; float contrastExp = 1.0; RGB gains = RGB({ 1.0, 1.0, 1.0 }); + + static constexpr unsigned int kLscGridSize = 16; + static constexpr unsigned int kLscValuesPerCell = 3; + using LscValueType = float; + using LscLookupTable = + std::array; + LscLookupTable lscLut{}; }; } /* namespace libcamera */ diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp index 2d7abfb83..d91a7aff5 100644 --- a/src/libcamera/software_isp/debayer.cpp +++ b/src/libcamera/software_isp/debayer.cpp @@ -43,6 +43,34 @@ namespace libcamera { * \brief Contrast value to be used as an exponent */ +/** + * \var DebayerParams::kLscGridSize + * \brief Number of lens shading grid areas in one direction + */ + +/** + * \var DebayerParams::kLscValuesPerCell + * \brief Number of pixel values per each of the lens shading grid areas + */ + +/** + * \typedef DebayerParams::LscValueType + * \brief Type of LSC grid values + */ + +/** + * \typedef DebayerParams::LscLookupTable + * \brief Lookup table for lens shading correction + * + * It's an array of values to be later used as a texture. + * The values are in row - column - RGB order. + */ + +/** + * \var DebayerParams::lscLut + * \brief Lens shading lookup table + */ + /** * \class Debayer * \brief Base debayering class From patchwork Tue May 12 12:36:07 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 26726 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 E32CEBDB1C for ; Tue, 12 May 2026 12:36:47 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8685663030; Tue, 12 May 2026 14:36:47 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="clN1yStH"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id EBD3463030 for ; Tue, 12 May 2026 14:36:45 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778589404; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/4SRSFW2CabW6xnK7ScaXSfCdyrKnii9ObIH+MGlG4o=; b=clN1yStHJqtyjjrZkWKglMC04EptXXd5WtsfoumGUk/bmKNANWrac6q/TTzU9+ZlI4TsBl LfrfUnVRhrL07vkQGIPeMpbuMEHPG3/Ihc4oE2ZDvKWRb2slaHbxQJWvAbkkrUwCWfnRCm jCHilL5H3rDDPXk3cGPyfB91zJuiY9w= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-650-knNr2oPJNGC0Tw2cH2DxAQ-1; Tue, 12 May 2026 08:36:41 -0400 X-MC-Unique: knNr2oPJNGC0Tw2cH2DxAQ-1 X-Mimecast-MFC-AGG-ID: knNr2oPJNGC0Tw2cH2DxAQ_1778589400 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 5EA0D195609D; Tue, 12 May 2026 12:36:40 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.50.44]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id DC8B81955D84; Tue, 12 May 2026 12:36:37 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Bryan O'Donoghue , Hans de Goede , Laurent Pinchart Subject: [RFC PATCH v5 03/10] ipa: simple: Introduce default temperature value Date: Tue, 12 May 2026 14:36:07 +0200 Message-ID: <20260512123619.120068-4-mzamazal@redhat.com> In-Reply-To: <20260512123619.120068-1-mzamazal@redhat.com> References: <20260512123619.120068-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 8dqgAjfxNKNJIuzvttsWRofT2381h1EhRmKdq8cl6J4_1778589400 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" Some algorithms use interpolated values based on temperature. Temperature is computed in the AWB algorithm. Technically, the AWB algorithm can be disabled and then no temperature is computed. Let's avoid implicit assumptions and introduce a constant for a default temperature value and make the temperature value optional. This is currently used by the CCM algorithm. It will be used also by the LSC algorithm in the followup patch. The default temperature value of 6500 is just a common value, there is no special reason to use this or another value. Signed-off-by: Milan Zamazal --- src/ipa/simple/algorithms/awb.cpp | 4 ++-- src/ipa/simple/algorithms/awb.h | 4 +++- src/ipa/simple/algorithms/ccm.cpp | 5 ++++- src/ipa/simple/ipa_context.h | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/ipa/simple/algorithms/awb.cpp b/src/ipa/simple/algorithms/awb.cpp index f5c88ea6f..961126c0d 100644 --- a/src/ipa/simple/algorithms/awb.cpp +++ b/src/ipa/simple/algorithms/awb.cpp @@ -96,11 +96,11 @@ void Awb::process(IPAContext &context, RGB rgbGains{ { 1 / gains.r(), 1 / gains.g(), 1 / gains.b() } }; context.activeState.awb.temperatureK = estimateCCT(rgbGains); - metadata.set(controls::ColourTemperature, context.activeState.awb.temperatureK); + metadata.set(controls::ColourTemperature, context.activeState.awb.temperatureK.value_or(0)); LOG(IPASoftAwb, Debug) << "gain R/B: " << gains << "; temperature: " - << context.activeState.awb.temperatureK; + << context.activeState.awb.temperatureK.value_or(0); } REGISTER_IPA_ALGORITHM(Awb, "Awb") diff --git a/src/ipa/simple/algorithms/awb.h b/src/ipa/simple/algorithms/awb.h index ad993f39c..df46baee4 100644 --- a/src/ipa/simple/algorithms/awb.h +++ b/src/ipa/simple/algorithms/awb.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ /* - * Copyright (C) 2024-2025 Red Hat Inc. + * Copyright (C) 2024-2026 Red Hat Inc. * * Auto white balance */ @@ -13,6 +13,8 @@ namespace libcamera { namespace ipa::soft::algorithms { +constexpr unsigned int kDefaultTemperature = 6500; + class Awb : public Algorithm { public: diff --git a/src/ipa/simple/algorithms/ccm.cpp b/src/ipa/simple/algorithms/ccm.cpp index ace9c35dc..6f566ccdc 100644 --- a/src/ipa/simple/algorithms/ccm.cpp +++ b/src/ipa/simple/algorithms/ccm.cpp @@ -15,6 +15,8 @@ #include "libcamera/internal/matrix.h" +#include "awb.h" + namespace { constexpr unsigned int kTemperatureThreshold = 100; @@ -44,7 +46,8 @@ int Ccm::init([[maybe_unused]] IPAContext &context, const ValueNode &tuningData) void Ccm::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, IPAFrameContext &frameContext, [[maybe_unused]] DebayerParams *params) { - const unsigned int ct = context.activeState.awb.temperatureK; + const unsigned int ct = + context.activeState.awb.temperatureK.value_or(kDefaultTemperature); /* Change CCM only on bigger temperature changes. */ if (!currentCcm_ || diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h index 34f7403a4..c4bd91bb0 100644 --- a/src/ipa/simple/ipa_context.h +++ b/src/ipa/simple/ipa_context.h @@ -50,7 +50,7 @@ struct IPAActiveState { struct { RGB gains; - unsigned int temperatureK; + std::optional temperatureK; } awb; Matrix combinedMatrix; From patchwork Tue May 12 12:36:08 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 26727 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 8B12EBDB1C for ; Tue, 12 May 2026 12:36:51 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 398996302A; Tue, 12 May 2026 14:36:51 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="LfBRY+LS"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8B8CA63025 for ; Tue, 12 May 2026 14:36:49 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778589408; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=WUNXChHuHrlFUDYMtTImEq0u+lDAfNwvjPCkXaMNHXY=; b=LfBRY+LS2fZioTlgyayQZQsarfwK9bnGBgcz//b+LBv9PiyerfejkKmkS/z0QnvekTDuUY ZjD9T6IadFk4WDnJy6vDSstPLh9hwJKuxLuMWyNPR7vrHjm9kwKVRTQvAwfDwzNoR3/q5w vPGdTQBiAACtZGMlSoaIpdRR86bmJ6k= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-515-pabwlV_iP6uMUIz2_YJZiQ-1; Tue, 12 May 2026 08:36:45 -0400 X-MC-Unique: pabwlV_iP6uMUIz2_YJZiQ-1 X-Mimecast-MFC-AGG-ID: pabwlV_iP6uMUIz2_YJZiQ_1778589404 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 70AE51800359; Tue, 12 May 2026 12:36:43 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.50.44]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id D98371944B20; Tue, 12 May 2026 12:36:40 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Xander Pronk , Bryan O'Donoghue , Hans de Goede , Laurent Pinchart , Rick ten Wolde , Milan Zamazal Subject: [RFC PATCH v5 04/10] ipa: simple: Add LSC algorithm Date: Tue, 12 May 2026 14:36:08 +0200 Message-ID: <20260512123619.120068-5-mzamazal@redhat.com> In-Reply-To: <20260512123619.120068-1-mzamazal@redhat.com> References: <20260512123619.120068-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: MnKsU66G3yx4yG1DT9kAd2bTJyRl1FuSYnsQHppsB6Q_1778589404 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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: Xander Pronk The lens shading algorithm uses grid-based interpolation. The grid values are specified in a tuning file as multiplication factors for each of the RGB colours. The interpolated grid is transformed to an array to be used as an RGB texture in debayering. Co-developed-by: Rick ten Wolde Signed-off-by: Rick ten Wolde Signed-off-by: Xander Pronk Signed-off-by: Milan Zamazal --- src/ipa/simple/algorithms/lsc.cpp | 63 +++++++++++++++++++++++++++ src/ipa/simple/algorithms/lsc.h | 41 +++++++++++++++++ src/ipa/simple/algorithms/meson.build | 1 + 3 files changed, 105 insertions(+) create mode 100644 src/ipa/simple/algorithms/lsc.cpp create mode 100644 src/ipa/simple/algorithms/lsc.h diff --git a/src/ipa/simple/algorithms/lsc.cpp b/src/ipa/simple/algorithms/lsc.cpp new file mode 100644 index 000000000..fac774481 --- /dev/null +++ b/src/ipa/simple/algorithms/lsc.cpp @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Lens shading correction + */ + +#include "lsc.h" + +#include + +#include "awb.h" + +namespace libcamera { + +namespace ipa::soft::algorithms { + +LOG_DEFINE_CATEGORY(IPASoftLsc) + +int Lsc::init([[maybe_unused]] IPAContext &context, const ValueNode &tuningData) +{ + int retR = lscR_.readYaml(tuningData["sets"], "ct", "r"); + int retG = lscG_.readYaml(tuningData["sets"], "ct", "g"); + int retB = lscB_.readYaml(tuningData["sets"], "ct", "b"); + + if (retR < 0 || retG < 0 || retB < 0) { + LOG(IPASoftLsc, Error) + << "Failed to parse 'lsc' parameter from tuning file."; + return -EINVAL; + } + + return 0; +} + +int Lsc::configure([[maybe_unused]] IPAContext &context, + [[maybe_unused]] const IPAConfigInfo &configInfo) +{ + return 0; +} + +void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, + [[maybe_unused]] IPAFrameContext &frameContext, DebayerParams *params) +{ + unsigned int ct = + context.activeState.awb.temperatureK.value_or(kDefaultTemperature); + + const LscMatrix matrixR = lscR_.getInterpolated(ct); + const LscMatrix matrixG = lscG_.getInterpolated(ct); + const LscMatrix matrixB = lscB_.getInterpolated(ct); + + DebayerParams::LscLookupTable lut; + constexpr unsigned int gridSize = DebayerParams::kLscGridSize; + for (unsigned int i = 0, j = 0; i < gridSize * gridSize; i++) { + lut[j++] = matrixR.data()[i]; + lut[j++] = matrixG.data()[i]; + lut[j++] = matrixB.data()[i]; + } + params->lscLut = lut; +} + +REGISTER_IPA_ALGORITHM(Lsc, "Lsc") + +} /* namespace ipa::soft::algorithms */ + +} /* namespace libcamera */ diff --git a/src/ipa/simple/algorithms/lsc.h b/src/ipa/simple/algorithms/lsc.h new file mode 100644 index 000000000..16950c5af --- /dev/null +++ b/src/ipa/simple/algorithms/lsc.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Lens shading correction + */ + +#pragma once + +#include "libcamera/internal/matrix.h" + +#include + +#include "algorithm.h" + +namespace libcamera { + +namespace ipa::soft::algorithms { + +class Lsc : public Algorithm +{ +public: + Lsc() = default; + ~Lsc() = default; + + int init(IPAContext &context, const ValueNode &tuningData) override; + int configure(IPAContext &context, + const IPAConfigInfo &configInfo) override; + void prepare(IPAContext &context, + const uint32_t frame, + IPAFrameContext &frameContext, + DebayerParams *params) override; + +private: + using LscMatrix = Matrix; + Interpolator lscR_; + Interpolator lscG_; + Interpolator lscB_; +}; + +} /* namespace ipa::soft::algorithms */ + +} /* namespace libcamera */ diff --git a/src/ipa/simple/algorithms/meson.build b/src/ipa/simple/algorithms/meson.build index 73c637220..c9f6e5590 100644 --- a/src/ipa/simple/algorithms/meson.build +++ b/src/ipa/simple/algorithms/meson.build @@ -6,4 +6,5 @@ soft_simple_ipa_algorithms = files([ 'agc.cpp', 'blc.cpp', 'ccm.cpp', + 'lsc.cpp', ]) From patchwork Tue May 12 12:36:09 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 26728 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 381AEBDB1C for ; Tue, 12 May 2026 12:36:55 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id CCA5463033; Tue, 12 May 2026 14:36:54 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="e071FrAB"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id ED99A63024 for ; Tue, 12 May 2026 14:36:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778589411; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ZejWO7eq6zPZKHw9LKkh1s6lR/zsy+h8NR3S8NCIeYg=; b=e071FrABe89jN+g88H3cg0Wz0uhim1GBnZUgjA9/3DENrSTtqeezZuvSx9cWPwJr3UBOUf DTVwhdYRbhPoR/T0YmXcKjbSZt8hE5MyBi/hYSUDTYNo93iHze/k1WlMqalaJdQhL7kTEZ WcLVKPfQRpMVP3ylrlpnT8UpAakgGlk= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-172-fZL0MPDVOYqT1exp0QgSzQ-1; Tue, 12 May 2026 08:36:48 -0400 X-MC-Unique: fZL0MPDVOYqT1exp0QgSzQ-1 X-Mimecast-MFC-AGG-ID: fZL0MPDVOYqT1exp0QgSzQ_1778589406 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 9885D18002C9; Tue, 12 May 2026 12:36:46 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.50.44]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 00A841955D84; Tue, 12 May 2026 12:36:43 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Xander Pronk , Bryan O'Donoghue , Hans de Goede , Laurent Pinchart , Rick ten Wolde , Milan Zamazal Subject: [RFC PATCH v5 05/10] libcamera: shaders: Add LSC support Date: Tue, 12 May 2026 14:36:09 +0200 Message-ID: <20260512123619.120068-6-mzamazal@redhat.com> In-Reply-To: <20260512123619.120068-1-mzamazal@redhat.com> References: <20260512123619.120068-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: MIlTQK2VPiw-BezY40tOJ8sHnqexAbW4_yFXqyP7vTI_1778589406 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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: Xander Pronk Lens shading correction should be applied after black level subtraction (in order to make the computations with meaningful values) and before white balance (especially before white balance stats are computed). Note that lens shading correction depends on temperature, which is computed from the preceding, rather than current, frame (this is due to how white balance is currently computed). The grid is specified in the YAML definition as follows: - Lsc: sets: - ct: temperature-1 r: [ ... 16 x 16 float values ...] g: [ ... 16 x 16 float values ...] b: [ ... 16 x 16 float values ...] - ct: temperature-2 r: [ ... 16 x 16 float values ...] g: [ ... 16 x 16 float values ...] b: [ ... 16 x 16 float values ...] - ... Reviewed-by: Laurent Pinchart Co-developed-by: Rick ten Wolde Signed-off-by: Rick ten Wolde Signed-off-by: Xander Pronk Signed-off-by: Milan Zamazal --- src/libcamera/shaders/bayer_1x_packed.frag | 8 ++++++++ src/libcamera/shaders/bayer_unpacked.frag | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/src/libcamera/shaders/bayer_1x_packed.frag b/src/libcamera/shaders/bayer_1x_packed.frag index 23747f78a..228c72309 100644 --- a/src/libcamera/shaders/bayer_1x_packed.frag +++ b/src/libcamera/shaders/bayer_1x_packed.frag @@ -70,6 +70,10 @@ uniform vec3 blacklevel; uniform float gamma; uniform float contrastExp; +#if defined(APPLY_LSC) +uniform sampler2D lsc_tex; +#endif + float apply_contrast(float value) { // Apply simple S-curve @@ -227,6 +231,10 @@ void main(void) rgb = rgb - blacklevel; +#if defined(APPLY_LSC) + rgb = rgb * texture2D(lsc_tex, textureOut).rgb; +#endif + /* * CCM is a 3x3 in the format * diff --git a/src/libcamera/shaders/bayer_unpacked.frag b/src/libcamera/shaders/bayer_unpacked.frag index 1b85196ae..af87bcc0f 100644 --- a/src/libcamera/shaders/bayer_unpacked.frag +++ b/src/libcamera/shaders/bayer_unpacked.frag @@ -29,6 +29,10 @@ uniform vec3 blacklevel; uniform float gamma; uniform float contrastExp; +#if defined(APPLY_LSC) +uniform sampler2D lsc_tex; +#endif + float apply_contrast(float value) { // Apply simple S-curve @@ -130,6 +134,10 @@ void main(void) { rgb = rgb - blacklevel; +#if defined(APPLY_LSC) + rgb = rgb * texture2D(lsc_tex, center.xy).rgb; +#endif + /* * CCM is a 3x3 in the format * From patchwork Tue May 12 12:36:10 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 26729 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 D3F10BDB1C for ; Tue, 12 May 2026 12:36:58 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5BB5E6303E; Tue, 12 May 2026 14:36:58 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="LSsV1pQI"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A6A6A63025 for ; Tue, 12 May 2026 14:36:54 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778589413; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ZRdwGsrVqJLKipOBXvy9PWGzIQYZpHLKh2ZirRSbtWc=; b=LSsV1pQIGgg3MEHH79njSyVwAJvXYOjEkmtbuHueGkFFdQNIH80KIse7sVGwDya6nXDE60 B8aiBQO2krBhWvksIGpud4JNAX8XKbeUZBBC57gGjZZpUcswHARxaIOyVEYpDIIXQMYZ8q l7dmovRK3eytCRNX+7V+jInqmXbYAHM= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-217-EHmrmKDwNo28G49owUugRA-1; Tue, 12 May 2026 08:36:50 -0400 X-MC-Unique: EHmrmKDwNo28G49owUugRA-1 X-Mimecast-MFC-AGG-ID: EHmrmKDwNo28G49owUugRA_1778589409 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id DB4FB18002E3; Tue, 12 May 2026 12:36:48 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.50.44]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 287901955D84; Tue, 12 May 2026 12:36:46 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Bryan O'Donoghue , Hans de Goede , Laurent Pinchart Subject: [RFC PATCH v5 06/10] libcamera: software_isp: Pass LSC availability to debayering Date: Tue, 12 May 2026 14:36:10 +0200 Message-ID: <20260512123619.120068-7-mzamazal@redhat.com> In-Reply-To: <20260512123619.120068-1-mzamazal@redhat.com> References: <20260512123619.120068-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: BHL4GqvRpOVuM_dEN2_xXRHW7kZJcMjRjMwFW3epGuY_1778589409 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" The lens shading algorithm may or may not be enabled in the tuning file. Debayering configuration needs this information to arrange things accordingly, e.g. to set up shader parameters. Let's add a corresponding flag that is set in the LSC algorithm (if present) and passed to Debayer::configure. This is similar to what we already do with CCM availability. The flag is ignored by CPU ISP, where LSC is not going to be implemented for now. Reviewed-by: Bryan O'Donoghue Signed-off-by: Milan Zamazal --- include/libcamera/internal/software_isp/software_isp.h | 1 + include/libcamera/ipa/soft.mojom | 4 +++- src/ipa/simple/algorithms/lsc.cpp | 4 +++- src/ipa/simple/ipa_context.h | 1 + src/ipa/simple/soft_simple.cpp | 7 +++++-- src/libcamera/software_isp/debayer.cpp | 1 + src/libcamera/software_isp/debayer.h | 3 ++- src/libcamera/software_isp/debayer_cpu.cpp | 3 ++- src/libcamera/software_isp/debayer_cpu.h | 3 ++- src/libcamera/software_isp/debayer_egl.cpp | 5 ++++- src/libcamera/software_isp/debayer_egl.h | 4 +++- src/libcamera/software_isp/software_isp.cpp | 5 +++-- 12 files changed, 30 insertions(+), 11 deletions(-) diff --git a/include/libcamera/internal/software_isp/software_isp.h b/include/libcamera/internal/software_isp/software_isp.h index 86cb8f8de..1e30b2d68 100644 --- a/include/libcamera/internal/software_isp/software_isp.h +++ b/include/libcamera/internal/software_isp/software_isp.h @@ -99,6 +99,7 @@ private: DebayerParams debayerParams_; DmaBufAllocator dmaHeap_; bool ccmEnabled_; + bool lscEnabled_; std::unique_ptr ipa_; std::deque queuedInputBuffers_; diff --git a/include/libcamera/ipa/soft.mojom b/include/libcamera/ipa/soft.mojom index 77328c5fd..aaefd50c4 100644 --- a/include/libcamera/ipa/soft.mojom +++ b/include/libcamera/ipa/soft.mojom @@ -18,7 +18,9 @@ interface IPASoftInterface { libcamera.SharedFD fdParams, libcamera.IPACameraSensorInfo sensorInfo, libcamera.ControlInfoMap sensorControls) - => (int32 ret, libcamera.ControlInfoMap ipaControls, bool ccmEnabled); + => (int32 ret, + libcamera.ControlInfoMap ipaControls, + bool ccmEnabled, bool lscEnabled); start() => (int32 ret); stop(); configure(IPAConfigInfo configInfo) diff --git a/src/ipa/simple/algorithms/lsc.cpp b/src/ipa/simple/algorithms/lsc.cpp index fac774481..4b821005f 100644 --- a/src/ipa/simple/algorithms/lsc.cpp +++ b/src/ipa/simple/algorithms/lsc.cpp @@ -15,7 +15,7 @@ namespace ipa::soft::algorithms { LOG_DEFINE_CATEGORY(IPASoftLsc) -int Lsc::init([[maybe_unused]] IPAContext &context, const ValueNode &tuningData) +int Lsc::init(IPAContext &context, const ValueNode &tuningData) { int retR = lscR_.readYaml(tuningData["sets"], "ct", "r"); int retG = lscG_.readYaml(tuningData["sets"], "ct", "g"); @@ -27,6 +27,8 @@ int Lsc::init([[maybe_unused]] IPAContext &context, const ValueNode &tuningData) return -EINVAL; } + context.lscEnabled = true; + return 0; } diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h index c4bd91bb0..d77bbc280 100644 --- a/src/ipa/simple/ipa_context.h +++ b/src/ipa/simple/ipa_context.h @@ -93,6 +93,7 @@ struct IPAContext { FCQueue frameContexts; ControlInfoMap::Map ctrlMap; bool ccmEnabled = false; + bool lscEnabled = false; }; } /* namespace ipa::soft */ diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp index 629e1a32d..4c724183a 100644 --- a/src/ipa/simple/soft_simple.cpp +++ b/src/ipa/simple/soft_simple.cpp @@ -57,7 +57,8 @@ public: const IPACameraSensorInfo &sensorInfo, const ControlInfoMap &sensorControls, ControlInfoMap *ipaControls, - bool *ccmEnabled) override; + bool *ccmEnabled, + bool *lscEnabled) override; int configure(const IPAConfigInfo &configInfo) override; int start() override; @@ -97,7 +98,8 @@ int IPASoftSimple::init(const IPASettings &settings, const IPACameraSensorInfo &sensorInfo, const ControlInfoMap &sensorControls, ControlInfoMap *ipaControls, - bool *ccmEnabled) + bool *ccmEnabled, + bool *lscEnabled) { camHelper_ = CameraSensorHelperFactoryBase::create(settings.sensorModel); if (!camHelper_) { @@ -136,6 +138,7 @@ int IPASoftSimple::init(const IPASettings &settings, return ret; *ccmEnabled = context_.ccmEnabled; + *lscEnabled = context_.lscEnabled; params_ = nullptr; stats_ = nullptr; diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp index d91a7aff5..76c66e55b 100644 --- a/src/libcamera/software_isp/debayer.cpp +++ b/src/libcamera/software_isp/debayer.cpp @@ -99,6 +99,7 @@ Debayer::~Debayer() * \param[in] inputCfg The input configuration * \param[in] outputCfgs The output configurations * \param[in] ccmEnabled Whether a color correction matrix is applied + * \param[in] lscEnabled Whether lens shading correction grid is provided * * \return 0 on success, a negative errno on failure */ diff --git a/src/libcamera/software_isp/debayer.h b/src/libcamera/software_isp/debayer.h index a2a17ec18..f4e649417 100644 --- a/src/libcamera/software_isp/debayer.h +++ b/src/libcamera/software_isp/debayer.h @@ -40,7 +40,8 @@ public: virtual int configure(const StreamConfiguration &inputCfg, const std::vector> &outputCfgs, - bool ccmEnabled) = 0; + bool ccmEnabled, + bool lscEnabled) = 0; virtual std::vector formats(PixelFormat inputFormat) = 0; diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp index 1f9b24da0..0a410d03d 100644 --- a/src/libcamera/software_isp/debayer_cpu.cpp +++ b/src/libcamera/software_isp/debayer_cpu.cpp @@ -543,7 +543,8 @@ int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat, int DebayerCpu::configure(const StreamConfiguration &inputCfg, const std::vector> &outputCfgs, - bool ccmEnabled) + bool ccmEnabled, + [[maybe_unused]] bool lscEnabled) { if (getInputConfig(inputCfg.pixelFormat, inputConfig_) != 0) return -EINVAL; diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h index 68da95083..6b7d8b677 100644 --- a/src/libcamera/software_isp/debayer_cpu.h +++ b/src/libcamera/software_isp/debayer_cpu.h @@ -37,7 +37,8 @@ public: int configure(const StreamConfiguration &inputCfg, const std::vector> &outputCfgs, - bool ccmEnabled) override; + bool ccmEnabled, + bool lscEnabled) override; Size patternSize(PixelFormat inputFormat) override; std::vector formats(PixelFormat input) override; std::tuple diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp index 866592547..dc77d0ac6 100644 --- a/src/libcamera/software_isp/debayer_egl.cpp +++ b/src/libcamera/software_isp/debayer_egl.cpp @@ -282,7 +282,8 @@ int DebayerEGL::initBayerShaders(PixelFormat inputFormat, PixelFormat outputForm int DebayerEGL::configure(const StreamConfiguration &inputCfg, const std::vector> &outputCfgs, - [[maybe_unused]] bool ccmEnabled) + [[maybe_unused]] bool ccmEnabled, + bool lscEnabled) { if (getInputConfig(inputCfg.pixelFormat, inputConfig_) != 0) return -EINVAL; @@ -299,6 +300,8 @@ int DebayerEGL::configure(const StreamConfiguration &inputCfg, return -EINVAL; } + lscEnabled_ = lscEnabled; + inputConfig_.stride = inputCfg.stride; inputPixelFormat_ = inputCfg.pixelFormat; width_ = inputCfg.size.width; diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h index 141fb288f..3f5db355a 100644 --- a/src/libcamera/software_isp/debayer_egl.h +++ b/src/libcamera/software_isp/debayer_egl.h @@ -44,7 +44,8 @@ public: int configure(const StreamConfiguration &inputCfg, const std::vector> &outputCfgs, - bool ccmEnabled) override; + bool ccmEnabled, + bool lscEnabled) override; Size patternSize(PixelFormat inputFormat) override; @@ -76,6 +77,7 @@ private: std::unique_ptr eglImageBayerIn_; std::unique_ptr eglImageBayerOut_; + bool lscEnabled_; /* Shader parameters */ float firstRed_x_; float firstRed_y_; diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp index 781cf02f8..e35bf10f1 100644 --- a/src/libcamera/software_isp/software_isp.cpp +++ b/src/libcamera/software_isp/software_isp.cpp @@ -157,7 +157,8 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor, sensorInfo, sensor->controls(), ipaControls, - &ccmEnabled_); + &ccmEnabled_, + &lscEnabled_); if (ret) { LOG(SoftwareIsp, Error) << "IPA init failed"; debayer_.reset(); @@ -273,7 +274,7 @@ int SoftwareIsp::configure(const StreamConfiguration &inputCfg, if (ret < 0) return ret; - ret = debayer_->configure(inputCfg, outputCfgs, ccmEnabled_); + ret = debayer_->configure(inputCfg, outputCfgs, ccmEnabled_, lscEnabled_); if (ret < 0) return ret; From patchwork Tue May 12 12:36:11 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 26730 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 AAA73BDB1C for ; Tue, 12 May 2026 12:37:01 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4588F63029; Tue, 12 May 2026 14:37:01 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="Z59OGY/x"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D2AE563029 for ; Tue, 12 May 2026 14:36:57 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778589416; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=izsKLgfMHPEegccl57RXD3w2QSLYKkSASbj7X/F09Lc=; b=Z59OGY/xhV8o2YKJXwH2+ARVX635kPr5zTOxIisuiej+KwWpf9/MwcgxMlsEErReJlPPMV Qp2dp8GZ/WR9R/R6fjRq8qbz5t6OMetuVPSao5eiaZATHOXVDMeLESdPGMg8+1MdqZuNxf LGjgy3/5vfyaGvhixFqSEGZyCzFhYMA= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-10-AkWS2KKOPb-Co3KnkSUEoQ-1; Tue, 12 May 2026 08:36:53 -0400 X-MC-Unique: AkWS2KKOPb-Co3KnkSUEoQ-1 X-Mimecast-MFC-AGG-ID: AkWS2KKOPb-Co3KnkSUEoQ_1778589412 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 0EC1918002DD; Tue, 12 May 2026 12:36:52 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.50.44]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 4B5421955D84; Tue, 12 May 2026 12:36:49 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Xander Pronk , Bryan O'Donoghue , Hans de Goede , Laurent Pinchart , Rick ten Wolde , Milan Zamazal Subject: [RFC PATCH v5 07/10] libcamera: software_isp: debayer_egl: Add LSC support Date: Tue, 12 May 2026 14:36:11 +0200 Message-ID: <20260512123619.120068-8-mzamazal@redhat.com> In-Reply-To: <20260512123619.120068-1-mzamazal@redhat.com> References: <20260512123619.120068-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: eZFbXcWFi1Vw_gQcPIWxrwZcwQTGKlMRYa4w4R7xiIo_1778589412 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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: Xander Pronk Add support for passing the LSC table from debayerParams to the shaders. The LSC table values are floats, we must add `type' parameter to createTexture2D to support this. Moreover, we use 16-bit internal format for the values, primarily because this works for me, unlike 32-bit floats. Co-developed-by: Rick ten Wolde Signed-off-by: Rick ten Wolde Signed-off-by: Xander Pronk Signed-off-by: Milan Zamazal --- include/libcamera/internal/egl.h | 10 +++++-- .../internal/software_isp/debayer_params.h | 2 ++ src/libcamera/egl.cpp | 16 ++++++++--- src/libcamera/software_isp/debayer.cpp | 5 ++++ src/libcamera/software_isp/debayer_egl.cpp | 28 +++++++++++++++++-- src/libcamera/software_isp/debayer_egl.h | 5 ++++ 6 files changed, 58 insertions(+), 8 deletions(-) diff --git a/include/libcamera/internal/egl.h b/include/libcamera/internal/egl.h index 6402dd5c7..3de47d970 100644 --- a/include/libcamera/internal/egl.h +++ b/include/libcamera/internal/egl.h @@ -103,8 +103,14 @@ public: int createInputDMABufTexture2D(eGLImage &eglImage, int fd); int createOutputDMABufTexture2D(eGLImage &eglImage, int fd); - void createTexture2D(eGLImage &eglImage, GLint format, uint32_t width, uint32_t height, - const void *data, GLint filter); + void createTexture2D(eGLImage &eglImage, + GLint internalFormat, + GLint format, + GLenum type, + uint32_t width, + uint32_t height, + const void *data, + GLint filter); void pushEnv(std::vector &shaderEnv, const char *str); void makeCurrent(); diff --git a/include/libcamera/internal/software_isp/debayer_params.h b/include/libcamera/internal/software_isp/debayer_params.h index 47f2c3ac2..5b1c8b508 100644 --- a/include/libcamera/internal/software_isp/debayer_params.h +++ b/include/libcamera/internal/software_isp/debayer_params.h @@ -30,6 +30,8 @@ struct DebayerParams { static constexpr unsigned int kLscGridSize = 16; static constexpr unsigned int kLscValuesPerCell = 3; using LscValueType = float; + static constexpr unsigned int kLscBytesPerCell = + kLscValuesPerCell * sizeof(LscValueType); using LscLookupTable = std::array; LscLookupTable lscLut{}; diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp index 80d71451f..cbd0a0d81 100644 --- a/src/libcamera/egl.cpp +++ b/src/libcamera/egl.cpp @@ -207,7 +207,9 @@ int eGL::createOutputDMABufTexture2D(eGLImage &eglImage, int fd) /** * \brief Create a 2D texture from a memory buffer * \param[in,out] eglImage EGL image to associate with the texture - * \param[in] format OpenGL internal format (e.g., GL_RGB, GL_RGBA) + * \param[in] internalFormat OpenGL internal storage format (e.g., GL_RGB8, GL_RGBA8) + * \param[in] format OpenGL pixel data format (e.g., GL_RGB, GL_RGBA) + * \param[in] type OpenGL pixel data type (e.g., GL_UNSIGNED_BYTE, GL_FLOAT) * \param[in] width Texture width in pixels * \param[in] height Texture height in pixels * \param[in] data Pointer to pixel data, or nullptr for uninitialised texture @@ -218,8 +220,14 @@ int eGL::createOutputDMABufTexture2D(eGLImage &eglImage, int fd) * is useful for uploading static data like lookup tables or uniform color * matrices to the GPU. */ -void eGL::createTexture2D(eGLImage &eglImage, GLint format, uint32_t width, uint32_t height, - const void *data, GLint filter) +void eGL::createTexture2D(eGLImage &eglImage, + GLint internalFormat, + GLint format, + GLenum type, + uint32_t width, + uint32_t height, + const void *data, + GLint filter) { ASSERT(tid_ == Thread::currentId()); @@ -227,7 +235,7 @@ void eGL::createTexture2D(eGLImage &eglImage, GLint format, uint32_t width, uint glBindTexture(GL_TEXTURE_2D, eglImage.texture_); // Generate texture, bind, associate image to texture, configure, unbind - glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); + glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, data); // Nearest filtering glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp index 76c66e55b..cc1dbb2d0 100644 --- a/src/libcamera/software_isp/debayer.cpp +++ b/src/libcamera/software_isp/debayer.cpp @@ -58,6 +58,11 @@ namespace libcamera { * \brief Type of LSC grid values */ +/** + * \var DebayerParams::kLscBytesPerCell + * \brief Number of bytes per each of the lens shading grid areas + */ + /** * \typedef DebayerParams::LscLookupTable * \brief Lookup table for lens shading correction diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp index dc77d0ac6..293ec2499 100644 --- a/src/libcamera/software_isp/debayer_egl.cpp +++ b/src/libcamera/software_isp/debayer_egl.cpp @@ -115,6 +115,8 @@ int DebayerEGL::getShaderVariableLocations(void) textureUniformBayerFirstRed_ = glGetUniformLocation(programId_, "tex_bayer_first_red"); textureUniformProjMatrix_ = glGetUniformLocation(programId_, "proj_matrix"); + textureUniformLsc_ = glGetUniformLocation(programId_, "lsc_tex"); + LOG(Debayer, Debug) << "vertexIn " << attributeVertex_ << " textureIn " << attributeTexture_ << " tex_y " << textureUniformBayerDataIn_ << " ccm " << ccmUniformDataIn_ @@ -125,7 +127,8 @@ int DebayerEGL::getShaderVariableLocations(void) << " tex_size " << textureUniformSize_ << " stride_factor " << textureUniformStrideFactor_ << " tex_bayer_first_red " << textureUniformBayerFirstRed_ - << " proj_matrix " << textureUniformProjMatrix_; + << " proj_matrix " << textureUniformProjMatrix_ + << " lsc " << textureUniformLsc_; return 0; } @@ -144,6 +147,9 @@ int DebayerEGL::initBayerShaders(PixelFormat inputFormat, PixelFormat outputForm /* Specify GL_OES_EGL_image_external */ egl_.pushEnv(shaderEnv, "#extension GL_OES_EGL_image_external: enable"); + if (lscEnabled_) + egl_.pushEnv(shaderEnv, "#define APPLY_LSC"); + /* * Tell shaders how to re-order output taking account of how the pixels * are actually stored by EGL. @@ -343,6 +349,17 @@ int DebayerEGL::configure(const StreamConfiguration &inputCfg, */ stats_->setWindow(Rectangle(window_.size())); + if (lscEnabled_) { + constexpr unsigned int gridSize = DebayerParams::kLscGridSize; + const unsigned int stride = gridSize * DebayerParams::kLscBytesPerCell; + eglImageLscLookup_ = + std::make_unique(gridSize, + gridSize, + stride, + GL_TEXTURE2, + 2); + } + return 0; } @@ -482,6 +499,13 @@ void DebayerEGL::setShaderVariableValues(const DebayerParams ¶ms) glUniformMatrix3fv(ccmUniformDataIn_, 1, GL_FALSE, ccm); LOG(Debayer, Debug) << " ccmUniformDataIn_ " << ccmUniformDataIn_ << " data " << params.combinedMatrix; + if (lscEnabled_) { + egl_.createTexture2D(*eglImageLscLookup_, GL_RGB16F, GL_RGB, GL_FLOAT, + DebayerParams::kLscGridSize, DebayerParams::kLscGridSize, + params.lscLut.data(), GL_LINEAR); + glUniform1i(textureUniformLsc_, eglImageLscLookup_->texture_unit_uniform_id_); + } + /* * 0 = Red, 1 = Green, 2 = Blue */ @@ -509,7 +533,7 @@ int DebayerEGL::debayerGPU(MappedFrameBuffer &in, int out_fd, const DebayerParam egl_.makeCurrent(); /* Create a standard texture input */ - egl_.createTexture2D(*eglImageBayerIn_, glFormat_, + egl_.createTexture2D(*eglImageBayerIn_, glFormat_, glFormat_, GL_UNSIGNED_BYTE, inputConfig_.stride / bytesPerPixel_, height_, in.planes()[0].data(), GL_NEAREST); diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h index 3f5db355a..85f51cf88 100644 --- a/src/libcamera/software_isp/debayer_egl.h +++ b/src/libcamera/software_isp/debayer_egl.h @@ -77,7 +77,10 @@ private: std::unique_ptr eglImageBayerIn_; std::unique_ptr eglImageBayerOut_; + /* LSC lookup table */ + std::unique_ptr eglImageLscLookup_; bool lscEnabled_; + /* Shader parameters */ float firstRed_x_; float firstRed_y_; @@ -91,6 +94,8 @@ private: GLint textureUniformBayerDataIn_; + GLint textureUniformLsc_; + /* Represent per-frame CCM as a uniform vector of floats 3 x 3 */ GLint ccmUniformDataIn_; From patchwork Tue May 12 12:36:12 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 26731 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 67645C32F7 for ; Tue, 12 May 2026 12:37:02 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 03DC563039; Tue, 12 May 2026 14:37:02 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="HJjO03k9"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 331B76303B for ; Tue, 12 May 2026 14:36:58 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778589417; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=t7TccxbaxtRtPBd2f1gcTDUkMwjnJo0KY5oE/XGxSyA=; b=HJjO03k9sIAOU7Ua5CvkxMxk/9EE/A6qnrMorGWyUAUjkw4iLNgF6qPWCKkqotQx9irLR/ LtNSIczw9IFOHGgSIjLzpmzHFxWGevhKnCW7xr9MqTwtqDcVPDXpWPKJW0uxV44IuCjWfv uYZTDMBCSdg+VQXEzJgkjs53W8Zpqk8= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-371-AZ9LaXMJMbmbThGroB-VgA-1; Tue, 12 May 2026 08:36:55 -0400 X-MC-Unique: AZ9LaXMJMbmbThGroB-VgA-1 X-Mimecast-MFC-AGG-ID: AZ9LaXMJMbmbThGroB-VgA_1778589414 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id AA83A19560B4; Tue, 12 May 2026 12:36:54 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.50.44]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 9E6D41955D84; Tue, 12 May 2026 12:36:52 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Bryan O'Donoghue , Hans de Goede , Laurent Pinchart Subject: [RFC PATCH v5 08/10] ipa: simple: Add LSC type Date: Tue, 12 May 2026 14:36:12 +0200 Message-ID: <20260512123619.120068-9-mzamazal@redhat.com> In-Reply-To: <20260512123619.120068-1-mzamazal@redhat.com> References: <20260512123619.120068-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: HTHu721DmnzVgDEoR8RdDnAnaMQirZeIddydKU7GoVk_1778589414 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" Add a `type' YAML item to the lens shading correction algorithm, in order to distinguish between different methods and their parameters. It is the same as in rkisp1 IPA. A corresponding class variable is added to Lsc. The only supported type for the moment is `table', for the grid-based LSC already implemented. The LSC type will be passed through the IPA interface in a followup patch. For this reason, it's defined as an enum based on uint32_t rather than as an `enum class', so that it can be passed through the Mojo interface as a simple integer without further arrangements. The Lsc algorithm YAML definition has now a new required item type: table to indicate the LSC method to be used. Signed-off-by: Milan Zamazal --- .../internal/software_isp/debayer_params.h | 3 +++ src/ipa/simple/algorithms/lsc.cpp | 23 +++++++++++++------ src/ipa/simple/algorithms/lsc.h | 1 + src/libcamera/software_isp/debayer.cpp | 10 ++++++++ 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/include/libcamera/internal/software_isp/debayer_params.h b/include/libcamera/internal/software_isp/debayer_params.h index 5b1c8b508..9e6c9ddb8 100644 --- a/include/libcamera/internal/software_isp/debayer_params.h +++ b/include/libcamera/internal/software_isp/debayer_params.h @@ -34,6 +34,9 @@ struct DebayerParams { kLscValuesPerCell * sizeof(LscValueType); using LscLookupTable = std::array; + enum LscType : uint32_t { + LscTable, + }; LscLookupTable lscLut{}; }; diff --git a/src/ipa/simple/algorithms/lsc.cpp b/src/ipa/simple/algorithms/lsc.cpp index 4b821005f..87023bc9b 100644 --- a/src/ipa/simple/algorithms/lsc.cpp +++ b/src/ipa/simple/algorithms/lsc.cpp @@ -17,13 +17,22 @@ LOG_DEFINE_CATEGORY(IPASoftLsc) int Lsc::init(IPAContext &context, const ValueNode &tuningData) { - int retR = lscR_.readYaml(tuningData["sets"], "ct", "r"); - int retG = lscG_.readYaml(tuningData["sets"], "ct", "g"); - int retB = lscB_.readYaml(tuningData["sets"], "ct", "b"); - - if (retR < 0 || retG < 0 || retB < 0) { - LOG(IPASoftLsc, Error) - << "Failed to parse 'lsc' parameter from tuning file."; + std::string type = tuningData["type"].get("table"); + + if (type == "table") { + int retR = lscR_.readYaml(tuningData["sets"], "ct", "r"); + int retG = lscG_.readYaml(tuningData["sets"], "ct", "g"); + int retB = lscB_.readYaml(tuningData["sets"], "ct", "b"); + + if (retR < 0 || retG < 0 || retB < 0) { + LOG(IPASoftLsc, Error) + << "Failed to parse 'lsc' parameter from tuning file."; + return -EINVAL; + } + + type_ = DebayerParams::LscTable; + } else { + LOG(IPASoftLsc, Error) << "LSC: type " << type << " not supported"; return -EINVAL; } diff --git a/src/ipa/simple/algorithms/lsc.h b/src/ipa/simple/algorithms/lsc.h index 16950c5af..d7d7c9559 100644 --- a/src/ipa/simple/algorithms/lsc.h +++ b/src/ipa/simple/algorithms/lsc.h @@ -31,6 +31,7 @@ public: private: using LscMatrix = Matrix; + DebayerParams::LscType type_; Interpolator lscR_; Interpolator lscG_; Interpolator lscB_; diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp index cc1dbb2d0..12c2ec9fd 100644 --- a/src/libcamera/software_isp/debayer.cpp +++ b/src/libcamera/software_isp/debayer.cpp @@ -53,6 +53,16 @@ namespace libcamera { * \brief Number of pixel values per each of the lens shading grid areas */ +/** + * \enum DebayerParams::LscType + * \brief Type of lens shading correction to apply + */ + +/** + * \var DebayerParams::LscTable + * \brief Lens shading correction using a lookup table + */ + /** * \typedef DebayerParams::LscValueType * \brief Type of LSC grid values From patchwork Tue May 12 12:36:13 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 26732 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 5D3B6BDB1C for ; Tue, 12 May 2026 12:37:04 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 02DFC63035; Tue, 12 May 2026 14:37:04 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="HuQqZDHH"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id ABA6363040 for ; Tue, 12 May 2026 14:37:00 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778589419; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=4lVwO/cOUEnaMm7csGaMuC3ip1vYDO+wof8lFUK287g=; b=HuQqZDHHWC/Un9BMP5GBq+pFvQOp3oiiFPV12QTDEqs3jdq9F4llSugGTrhg3hPkpCBfUr fszWkovrQz7fEuLgbqSh6pV5feOCM9iJSm9QRTVQ8Va3Dbd0Mg0r4DVtGnBYsFg2w3oLNP 3D7/nRObn3kw60qsrwZutBdyd/m7uE4= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-398-qbmrZvBQPYSzSMxMBEKtHA-1; Tue, 12 May 2026 08:36:58 -0400 X-MC-Unique: qbmrZvBQPYSzSMxMBEKtHA-1 X-Mimecast-MFC-AGG-ID: qbmrZvBQPYSzSMxMBEKtHA_1778589417 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 2B6AD1800614; Tue, 12 May 2026 12:36:57 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.50.44]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 1A7C11955D84; Tue, 12 May 2026 12:36:54 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Bryan O'Donoghue , Hans de Goede , Laurent Pinchart Subject: [RFC PATCH v5 09/10] libcamera: software_isp: Use LSC type instead of LSC enabled Date: Tue, 12 May 2026 14:36:13 +0200 Message-ID: <20260512123619.120068-10-mzamazal@redhat.com> In-Reply-To: <20260512123619.120068-1-mzamazal@redhat.com> References: <20260512123619.120068-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: _Wh_x4d2_yrc-mAYdlJ2mS7jjUOo8WK9uZEkO8SC6KE_1778589417 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" With the upcoming introduction of polynomial lens shading correction, let's replace the boolean LSC-enabled flag with an enum / integer indicating the type of the LSC to apply. For the case when LSC is not enabled, LscNone enum value is introduced. The switch passed to the shaders is renamed from APPLY_LSC to APPLY_LSC_TABLE to get ready for other LSC types and other APPLY_LSC_* switches for shaders. Signed-off-by: Milan Zamazal --- .../internal/software_isp/debayer_params.h | 1 + .../internal/software_isp/software_isp.h | 2 +- include/libcamera/ipa/soft.mojom | 2 +- src/ipa/simple/algorithms/lsc.cpp | 2 +- src/ipa/simple/ipa_context.h | 3 ++- src/ipa/simple/soft_simple.cpp | 6 +++--- src/libcamera/shaders/bayer_1x_packed.frag | 4 ++-- src/libcamera/shaders/bayer_unpacked.frag | 4 ++-- src/libcamera/software_isp/debayer.cpp | 2 +- src/libcamera/software_isp/debayer.h | 2 +- src/libcamera/software_isp/debayer_cpu.cpp | 2 +- src/libcamera/software_isp/debayer_cpu.h | 2 +- src/libcamera/software_isp/debayer_egl.cpp | 21 +++++++++++++------ src/libcamera/software_isp/debayer_egl.h | 6 +++--- src/libcamera/software_isp/software_isp.cpp | 4 ++-- 15 files changed, 37 insertions(+), 26 deletions(-) diff --git a/include/libcamera/internal/software_isp/debayer_params.h b/include/libcamera/internal/software_isp/debayer_params.h index 9e6c9ddb8..37fff49a2 100644 --- a/include/libcamera/internal/software_isp/debayer_params.h +++ b/include/libcamera/internal/software_isp/debayer_params.h @@ -35,6 +35,7 @@ struct DebayerParams { using LscLookupTable = std::array; enum LscType : uint32_t { + LscNone, LscTable, }; LscLookupTable lscLut{}; diff --git a/include/libcamera/internal/software_isp/software_isp.h b/include/libcamera/internal/software_isp/software_isp.h index 1e30b2d68..ded0c3917 100644 --- a/include/libcamera/internal/software_isp/software_isp.h +++ b/include/libcamera/internal/software_isp/software_isp.h @@ -99,7 +99,7 @@ private: DebayerParams debayerParams_; DmaBufAllocator dmaHeap_; bool ccmEnabled_; - bool lscEnabled_; + uint32_t lscType_; std::unique_ptr ipa_; std::deque queuedInputBuffers_; diff --git a/include/libcamera/ipa/soft.mojom b/include/libcamera/ipa/soft.mojom index aaefd50c4..e65a6127c 100644 --- a/include/libcamera/ipa/soft.mojom +++ b/include/libcamera/ipa/soft.mojom @@ -20,7 +20,7 @@ interface IPASoftInterface { libcamera.ControlInfoMap sensorControls) => (int32 ret, libcamera.ControlInfoMap ipaControls, - bool ccmEnabled, bool lscEnabled); + bool ccmEnabled, uint32 lscType); start() => (int32 ret); stop(); configure(IPAConfigInfo configInfo) diff --git a/src/ipa/simple/algorithms/lsc.cpp b/src/ipa/simple/algorithms/lsc.cpp index 87023bc9b..ae5179cfc 100644 --- a/src/ipa/simple/algorithms/lsc.cpp +++ b/src/ipa/simple/algorithms/lsc.cpp @@ -36,7 +36,7 @@ int Lsc::init(IPAContext &context, const ValueNode &tuningData) return -EINVAL; } - context.lscEnabled = true; + context.lscType = type_; return 0; } diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h index d77bbc280..9972efa6d 100644 --- a/src/ipa/simple/ipa_context.h +++ b/src/ipa/simple/ipa_context.h @@ -14,6 +14,7 @@ #include #include "libcamera/internal/matrix.h" +#include "libcamera/internal/software_isp/debayer_params.h" #include "libcamera/internal/vector.h" #include @@ -93,7 +94,7 @@ struct IPAContext { FCQueue frameContexts; ControlInfoMap::Map ctrlMap; bool ccmEnabled = false; - bool lscEnabled = false; + DebayerParams::LscType lscType = DebayerParams::LscNone; }; } /* namespace ipa::soft */ diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp index 4c724183a..d3f4a52cc 100644 --- a/src/ipa/simple/soft_simple.cpp +++ b/src/ipa/simple/soft_simple.cpp @@ -58,7 +58,7 @@ public: const ControlInfoMap &sensorControls, ControlInfoMap *ipaControls, bool *ccmEnabled, - bool *lscEnabled) override; + uint32_t *lscType) override; int configure(const IPAConfigInfo &configInfo) override; int start() override; @@ -99,7 +99,7 @@ int IPASoftSimple::init(const IPASettings &settings, const ControlInfoMap &sensorControls, ControlInfoMap *ipaControls, bool *ccmEnabled, - bool *lscEnabled) + uint32_t *lscType) { camHelper_ = CameraSensorHelperFactoryBase::create(settings.sensorModel); if (!camHelper_) { @@ -138,7 +138,7 @@ int IPASoftSimple::init(const IPASettings &settings, return ret; *ccmEnabled = context_.ccmEnabled; - *lscEnabled = context_.lscEnabled; + *lscType = context_.lscType; params_ = nullptr; stats_ = nullptr; diff --git a/src/libcamera/shaders/bayer_1x_packed.frag b/src/libcamera/shaders/bayer_1x_packed.frag index 228c72309..dc2b582f8 100644 --- a/src/libcamera/shaders/bayer_1x_packed.frag +++ b/src/libcamera/shaders/bayer_1x_packed.frag @@ -70,7 +70,7 @@ uniform vec3 blacklevel; uniform float gamma; uniform float contrastExp; -#if defined(APPLY_LSC) +#if defined(APPLY_LSC_TABLE) uniform sampler2D lsc_tex; #endif @@ -231,7 +231,7 @@ void main(void) rgb = rgb - blacklevel; -#if defined(APPLY_LSC) +#if defined(APPLY_LSC_TABLE) rgb = rgb * texture2D(lsc_tex, textureOut).rgb; #endif diff --git a/src/libcamera/shaders/bayer_unpacked.frag b/src/libcamera/shaders/bayer_unpacked.frag index af87bcc0f..df324e6e1 100644 --- a/src/libcamera/shaders/bayer_unpacked.frag +++ b/src/libcamera/shaders/bayer_unpacked.frag @@ -29,7 +29,7 @@ uniform vec3 blacklevel; uniform float gamma; uniform float contrastExp; -#if defined(APPLY_LSC) +#if defined(APPLY_LSC_TABLE) uniform sampler2D lsc_tex; #endif @@ -134,7 +134,7 @@ void main(void) { rgb = rgb - blacklevel; -#if defined(APPLY_LSC) +#if defined(APPLY_LSC_TABLE) rgb = rgb * texture2D(lsc_tex, center.xy).rgb; #endif diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp index 12c2ec9fd..a77b3c9fc 100644 --- a/src/libcamera/software_isp/debayer.cpp +++ b/src/libcamera/software_isp/debayer.cpp @@ -114,7 +114,7 @@ Debayer::~Debayer() * \param[in] inputCfg The input configuration * \param[in] outputCfgs The output configurations * \param[in] ccmEnabled Whether a color correction matrix is applied - * \param[in] lscEnabled Whether lens shading correction grid is provided + * \param[in] lscType Type of lens shading correction * * \return 0 on success, a negative errno on failure */ diff --git a/src/libcamera/software_isp/debayer.h b/src/libcamera/software_isp/debayer.h index f4e649417..eb3fa7609 100644 --- a/src/libcamera/software_isp/debayer.h +++ b/src/libcamera/software_isp/debayer.h @@ -41,7 +41,7 @@ public: virtual int configure(const StreamConfiguration &inputCfg, const std::vector> &outputCfgs, bool ccmEnabled, - bool lscEnabled) = 0; + uint32_t lscType) = 0; virtual std::vector formats(PixelFormat inputFormat) = 0; diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp index 0a410d03d..14019ff41 100644 --- a/src/libcamera/software_isp/debayer_cpu.cpp +++ b/src/libcamera/software_isp/debayer_cpu.cpp @@ -544,7 +544,7 @@ int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat, int DebayerCpu::configure(const StreamConfiguration &inputCfg, const std::vector> &outputCfgs, bool ccmEnabled, - [[maybe_unused]] bool lscEnabled) + [[maybe_unused]] uint32_t lscType) { if (getInputConfig(inputCfg.pixelFormat, inputConfig_) != 0) return -EINVAL; diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h index 6b7d8b677..de8b99b8a 100644 --- a/src/libcamera/software_isp/debayer_cpu.h +++ b/src/libcamera/software_isp/debayer_cpu.h @@ -38,7 +38,7 @@ public: int configure(const StreamConfiguration &inputCfg, const std::vector> &outputCfgs, bool ccmEnabled, - bool lscEnabled) override; + uint32_t lscType) override; Size patternSize(PixelFormat inputFormat) override; std::vector formats(PixelFormat input) override; std::tuple diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp index 293ec2499..03ec5c5da 100644 --- a/src/libcamera/software_isp/debayer_egl.cpp +++ b/src/libcamera/software_isp/debayer_egl.cpp @@ -147,8 +147,13 @@ int DebayerEGL::initBayerShaders(PixelFormat inputFormat, PixelFormat outputForm /* Specify GL_OES_EGL_image_external */ egl_.pushEnv(shaderEnv, "#extension GL_OES_EGL_image_external: enable"); - if (lscEnabled_) - egl_.pushEnv(shaderEnv, "#define APPLY_LSC"); + switch (lscType_) { + case DebayerParams::LscNone: + break; + case DebayerParams::LscTable: + egl_.pushEnv(shaderEnv, "#define APPLY_LSC_TABLE"); + break; + } /* * Tell shaders how to re-order output taking account of how the pixels @@ -289,7 +294,7 @@ int DebayerEGL::initBayerShaders(PixelFormat inputFormat, PixelFormat outputForm int DebayerEGL::configure(const StreamConfiguration &inputCfg, const std::vector> &outputCfgs, [[maybe_unused]] bool ccmEnabled, - bool lscEnabled) + uint32_t lscType) { if (getInputConfig(inputCfg.pixelFormat, inputConfig_) != 0) return -EINVAL; @@ -306,7 +311,7 @@ int DebayerEGL::configure(const StreamConfiguration &inputCfg, return -EINVAL; } - lscEnabled_ = lscEnabled; + lscType_ = lscType; inputConfig_.stride = inputCfg.stride; inputPixelFormat_ = inputCfg.pixelFormat; @@ -349,7 +354,7 @@ int DebayerEGL::configure(const StreamConfiguration &inputCfg, */ stats_->setWindow(Rectangle(window_.size())); - if (lscEnabled_) { + if (lscType_ == DebayerParams::LscTable) { constexpr unsigned int gridSize = DebayerParams::kLscGridSize; const unsigned int stride = gridSize * DebayerParams::kLscBytesPerCell; eglImageLscLookup_ = @@ -499,11 +504,15 @@ void DebayerEGL::setShaderVariableValues(const DebayerParams ¶ms) glUniformMatrix3fv(ccmUniformDataIn_, 1, GL_FALSE, ccm); LOG(Debayer, Debug) << " ccmUniformDataIn_ " << ccmUniformDataIn_ << " data " << params.combinedMatrix; - if (lscEnabled_) { + switch (lscType_) { + case DebayerParams::LscNone: + break; + case DebayerParams::LscTable: egl_.createTexture2D(*eglImageLscLookup_, GL_RGB16F, GL_RGB, GL_FLOAT, DebayerParams::kLscGridSize, DebayerParams::kLscGridSize, params.lscLut.data(), GL_LINEAR); glUniform1i(textureUniformLsc_, eglImageLscLookup_->texture_unit_uniform_id_); + break; } /* diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h index 85f51cf88..d5cfcad1e 100644 --- a/src/libcamera/software_isp/debayer_egl.h +++ b/src/libcamera/software_isp/debayer_egl.h @@ -45,7 +45,7 @@ public: int configure(const StreamConfiguration &inputCfg, const std::vector> &outputCfgs, bool ccmEnabled, - bool lscEnabled) override; + uint32_t lscType) override; Size patternSize(PixelFormat inputFormat) override; @@ -77,9 +77,9 @@ private: std::unique_ptr eglImageBayerIn_; std::unique_ptr eglImageBayerOut_; - /* LSC lookup table */ + /* Lens shading correction */ + uint32_t lscType_; std::unique_ptr eglImageLscLookup_; - bool lscEnabled_; /* Shader parameters */ float firstRed_x_; diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp index e35bf10f1..3e59f262c 100644 --- a/src/libcamera/software_isp/software_isp.cpp +++ b/src/libcamera/software_isp/software_isp.cpp @@ -158,7 +158,7 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor, sensor->controls(), ipaControls, &ccmEnabled_, - &lscEnabled_); + &lscType_); if (ret) { LOG(SoftwareIsp, Error) << "IPA init failed"; debayer_.reset(); @@ -274,7 +274,7 @@ int SoftwareIsp::configure(const StreamConfiguration &inputCfg, if (ret < 0) return ret; - ret = debayer_->configure(inputCfg, outputCfgs, ccmEnabled_, lscEnabled_); + ret = debayer_->configure(inputCfg, outputCfgs, ccmEnabled_, lscType_); if (ret < 0) return ret; From patchwork Tue May 12 12:36:14 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 26733 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 7CB18BDB1C for ; Tue, 12 May 2026 12:37:08 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 1E13E63039; Tue, 12 May 2026 14:37:08 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="XPIlyzmz"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4C75463039 for ; Tue, 12 May 2026 14:37:05 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778589424; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Dy9SKuAzEW9xA5akmA/eiuI7dLFSDoVPtineW4JKjb0=; b=XPIlyzmzwKVjUM4XOxDxvCHRNY59cr1qo8Km4DWdybNzqhPApeDwnBaYI6qTrAns//wDdj YYQ0WfRwg/vFoprA31306B18VgEnEPAa8Y0k4lGq9Gyg8FEdFZmaqO7RXXPUV29jLk58jk 7iyNt5C1t7OPFJPKPIUJHB+D6hF0BpM= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-9-fcP3_nY7NTi4pjLs8V223Q-1; Tue, 12 May 2026 08:37:00 -0400 X-MC-Unique: fcP3_nY7NTi4pjLs8V223Q-1 X-Mimecast-MFC-AGG-ID: fcP3_nY7NTi4pjLs8V223Q_1778589419 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 855981956095; Tue, 12 May 2026 12:36:59 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.50.44]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id BBB4B1955D84; Tue, 12 May 2026 12:36:57 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Bryan O'Donoghue , Hans de Goede , Laurent Pinchart Subject: [RFC PATCH v5 10/10] libcamera: software_isp: Add polynomial LSC Date: Tue, 12 May 2026 14:36:14 +0200 Message-ID: <20260512123619.120068-11-mzamazal@redhat.com> In-Reply-To: <20260512123619.120068-1-mzamazal@redhat.com> References: <20260512123619.120068-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 6at_ebdfqeqeXSjiFvdquvdX6yuUjoMgrFAzh07YtnE_1778589419 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" In addition to the already implemented table based lens shading correction, let's implement polynomial lens shading correction. The primary differences between the two are: - Table based correction is based on a 16x16 grid of values, while polynomial correction uses 3 coefficients for polynomial computation of the scaling factor. - The polynomial correction implemented here is faster (at least in my environment). - Table based correction allows specifying non-symmetric corrections. This patch implements just the simplest form of the polynomial correction, for ease of implementation and speed. It assumes that lens shading is centred and uses only 3-item polynomial: lsc0 + lsc1 * dist^2 + lsc2 * dist^4, where dist is the distance from the centre. The distance is measured in kilopixels, which is definitely debatable, but it makes easy to deal with different vertical and horizontal sizes and with cropping, assuming the pixels have the same horizontal and vertical sizes. Shifted crops are not considered but can be added easily in another patch by specifying the shift as another uniform. The coefficients are specified for each of the RGB colours. The YAML definition looks like: - Lsc: type: polynomial sets: - ct: temperature-1 r: [ lsc0, lsc1, lsc2 ] g: [ ... ] b: [ ... ] - ct: temperature-2 r: [ ... ] g: [ ... ] b: [ ... ] - ... Signed-off-by: Milan Zamazal --- .../internal/software_isp/debayer_params.h | 4 ++ src/ipa/simple/algorithms/lsc.cpp | 69 +++++++++++++------ src/ipa/simple/algorithms/lsc.h | 4 ++ src/libcamera/shaders/bayer_1x_packed.frag | 9 +++ src/libcamera/shaders/bayer_unpacked.frag | 9 +++ src/libcamera/software_isp/debayer.cpp | 15 ++++ src/libcamera/software_isp/debayer_egl.cpp | 28 +++++++- src/libcamera/software_isp/debayer_egl.h | 4 ++ 8 files changed, 121 insertions(+), 21 deletions(-) diff --git a/include/libcamera/internal/software_isp/debayer_params.h b/include/libcamera/internal/software_isp/debayer_params.h index 37fff49a2..bef6820cb 100644 --- a/include/libcamera/internal/software_isp/debayer_params.h +++ b/include/libcamera/internal/software_isp/debayer_params.h @@ -37,8 +37,12 @@ struct DebayerParams { enum LscType : uint32_t { LscNone, LscTable, + LscPolynomial, }; LscLookupTable lscLut{}; + + static constexpr unsigned int kNLscCoefficients = 3; + std::array, kNLscCoefficients> lscCoefficients; }; } /* namespace libcamera */ diff --git a/src/ipa/simple/algorithms/lsc.cpp b/src/ipa/simple/algorithms/lsc.cpp index ae5179cfc..0470b5e76 100644 --- a/src/ipa/simple/algorithms/lsc.cpp +++ b/src/ipa/simple/algorithms/lsc.cpp @@ -18,23 +18,27 @@ LOG_DEFINE_CATEGORY(IPASoftLsc) int Lsc::init(IPAContext &context, const ValueNode &tuningData) { std::string type = tuningData["type"].get("table"); + int retR, retG, retB; if (type == "table") { - int retR = lscR_.readYaml(tuningData["sets"], "ct", "r"); - int retG = lscG_.readYaml(tuningData["sets"], "ct", "g"); - int retB = lscB_.readYaml(tuningData["sets"], "ct", "b"); - - if (retR < 0 || retG < 0 || retB < 0) { - LOG(IPASoftLsc, Error) - << "Failed to parse 'lsc' parameter from tuning file."; - return -EINVAL; - } - + retR = lscR_.readYaml(tuningData["sets"], "ct", "r"); + retG = lscG_.readYaml(tuningData["sets"], "ct", "g"); + retB = lscB_.readYaml(tuningData["sets"], "ct", "b"); type_ = DebayerParams::LscTable; + } else if (type == "polynomial") { + retR = lscCoefR_.readYaml(tuningData["sets"], "ct", "r"); + retG = lscCoefG_.readYaml(tuningData["sets"], "ct", "g"); + retB = lscCoefB_.readYaml(tuningData["sets"], "ct", "b"); + type_ = DebayerParams::LscPolynomial; } else { LOG(IPASoftLsc, Error) << "LSC: type " << type << " not supported"; return -EINVAL; } + if (retR < 0 || retG < 0 || retB < 0) { + LOG(IPASoftLsc, Error) + << "Failed to parse 'lsc' parameter from tuning file."; + return -EINVAL; + } context.lscType = type_; @@ -53,18 +57,43 @@ void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, unsigned int ct = context.activeState.awb.temperatureK.value_or(kDefaultTemperature); - const LscMatrix matrixR = lscR_.getInterpolated(ct); - const LscMatrix matrixG = lscG_.getInterpolated(ct); - const LscMatrix matrixB = lscB_.getInterpolated(ct); + switch (type_) { + case DebayerParams::LscNone: + break; + + case DebayerParams::LscTable: { + const LscMatrix matrixR = lscR_.getInterpolated(ct); + const LscMatrix matrixG = lscG_.getInterpolated(ct); + const LscMatrix matrixB = lscB_.getInterpolated(ct); + + DebayerParams::LscLookupTable lut; + constexpr unsigned int gridSize = DebayerParams::kLscGridSize; + for (unsigned int i = 0, j = 0; i < gridSize * gridSize; i++) { + lut[j++] = matrixR.data()[i]; + lut[j++] = matrixG.data()[i]; + lut[j++] = matrixB.data()[i]; + } + params->lscLut = lut; - DebayerParams::LscLookupTable lut; - constexpr unsigned int gridSize = DebayerParams::kLscGridSize; - for (unsigned int i = 0, j = 0; i < gridSize * gridSize; i++) { - lut[j++] = matrixR.data()[i]; - lut[j++] = matrixG.data()[i]; - lut[j++] = matrixB.data()[i]; + break; + } + + case DebayerParams::LscPolynomial: { + const Vector coefR = + lscCoefR_.getInterpolated(ct); + const Vector coefG = + lscCoefG_.getInterpolated(ct); + const Vector coefB = + lscCoefB_.getInterpolated(ct); + + for (unsigned int i = 0; i < DebayerParams::kNLscCoefficients; i++) { + params->lscCoefficients[i].r() = coefR[i]; + params->lscCoefficients[i].g() = coefG[i]; + params->lscCoefficients[i].b() = coefB[i]; + } + break; + } } - params->lscLut = lut; } REGISTER_IPA_ALGORITHM(Lsc, "Lsc") diff --git a/src/ipa/simple/algorithms/lsc.h b/src/ipa/simple/algorithms/lsc.h index d7d7c9559..e1981dec7 100644 --- a/src/ipa/simple/algorithms/lsc.h +++ b/src/ipa/simple/algorithms/lsc.h @@ -6,6 +6,7 @@ #pragma once #include "libcamera/internal/matrix.h" +#include "libcamera/internal/vector.h" #include @@ -35,6 +36,9 @@ private: Interpolator lscR_; Interpolator lscG_; Interpolator lscB_; + Interpolator> lscCoefR_; + Interpolator> lscCoefG_; + Interpolator> lscCoefB_; }; } /* namespace ipa::soft::algorithms */ diff --git a/src/libcamera/shaders/bayer_1x_packed.frag b/src/libcamera/shaders/bayer_1x_packed.frag index dc2b582f8..bc45c1993 100644 --- a/src/libcamera/shaders/bayer_1x_packed.frag +++ b/src/libcamera/shaders/bayer_1x_packed.frag @@ -72,6 +72,11 @@ uniform float contrastExp; #if defined(APPLY_LSC_TABLE) uniform sampler2D lsc_tex; +#elif defined(APPLY_LSC_POLYNOMIAL) +uniform vec2 lscScale; +uniform vec3 lsc0; +uniform vec3 lsc1; +uniform vec3 lsc2; #endif float apply_contrast(float value) @@ -233,6 +238,10 @@ void main(void) #if defined(APPLY_LSC_TABLE) rgb = rgb * texture2D(lsc_tex, textureOut).rgb; +#elif defined(APPLY_LSC_POLYNOMIAL) + vec2 offCenter = (textureOut - vec2(0.5, 0.5)) * lscScale; + float dist2 = dot(offCenter, offCenter); + rgb = rgb * (lsc0 + lsc1 * dist2 + lsc2 * dist2 * dist2); #endif /* diff --git a/src/libcamera/shaders/bayer_unpacked.frag b/src/libcamera/shaders/bayer_unpacked.frag index df324e6e1..5a1d82325 100644 --- a/src/libcamera/shaders/bayer_unpacked.frag +++ b/src/libcamera/shaders/bayer_unpacked.frag @@ -31,6 +31,11 @@ uniform float contrastExp; #if defined(APPLY_LSC_TABLE) uniform sampler2D lsc_tex; +#elif defined(APPLY_LSC_POLYNOMIAL) +uniform vec2 lscScale; +uniform vec3 lsc0; +uniform vec3 lsc1; +uniform vec3 lsc2; #endif float apply_contrast(float value) @@ -136,6 +141,10 @@ void main(void) { #if defined(APPLY_LSC_TABLE) rgb = rgb * texture2D(lsc_tex, center.xy).rgb; +#elif defined(APPLY_LSC_POLYNOMIAL) + vec2 offCenter = (center.xy - vec2(0.5, 0.5)) * lscScale; + float dist2 = dot(offCenter, offCenter); + rgb = rgb * (lsc0 + lsc1 * dist2 + lsc2 * dist2 * dist2); #endif /* diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp index a77b3c9fc..ec0c618ba 100644 --- a/src/libcamera/software_isp/debayer.cpp +++ b/src/libcamera/software_isp/debayer.cpp @@ -63,6 +63,11 @@ namespace libcamera { * \brief Lens shading correction using a lookup table */ +/** + * \var DebayerParams::LscPolynomial + * \brief Lens shading correction using polynomial coefficients + */ + /** * \typedef DebayerParams::LscValueType * \brief Type of LSC grid values @@ -86,6 +91,16 @@ namespace libcamera { * \brief Lens shading lookup table */ +/** + * \var DebayerParams::kNLscCoefficients + * \brief Number of the lens shading correction polynomial coefficients + */ + +/** + * \var DebayerParams::lscCoefficients + * \brief Polynomial coefficients for lens shading correction, one per colour channel + */ + /** * \class Debayer * \brief Base debayering class diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp index 03ec5c5da..560a87d66 100644 --- a/src/libcamera/software_isp/debayer_egl.cpp +++ b/src/libcamera/software_isp/debayer_egl.cpp @@ -116,6 +116,10 @@ int DebayerEGL::getShaderVariableLocations(void) textureUniformProjMatrix_ = glGetUniformLocation(programId_, "proj_matrix"); textureUniformLsc_ = glGetUniformLocation(programId_, "lsc_tex"); + lscScale_ = glGetUniformLocation(programId_, "lscScale"); + lsc0_ = glGetUniformLocation(programId_, "lsc0"); + lsc1_ = glGetUniformLocation(programId_, "lsc1"); + lsc2_ = glGetUniformLocation(programId_, "lsc2"); LOG(Debayer, Debug) << "vertexIn " << attributeVertex_ << " textureIn " << attributeTexture_ << " tex_y " << textureUniformBayerDataIn_ @@ -128,7 +132,11 @@ int DebayerEGL::getShaderVariableLocations(void) << " stride_factor " << textureUniformStrideFactor_ << " tex_bayer_first_red " << textureUniformBayerFirstRed_ << " proj_matrix " << textureUniformProjMatrix_ - << " lsc " << textureUniformLsc_; + << " lscTexture " << textureUniformLsc_ + << " lscScale " << lscScale_ + << " lsc0 " << lsc0_ + << " lsc1 " << lsc1_ + << " lsc2 " << lsc2_; return 0; } @@ -153,6 +161,9 @@ int DebayerEGL::initBayerShaders(PixelFormat inputFormat, PixelFormat outputForm case DebayerParams::LscTable: egl_.pushEnv(shaderEnv, "#define APPLY_LSC_TABLE"); break; + case DebayerParams::LscPolynomial: + egl_.pushEnv(shaderEnv, "#define APPLY_LSC_POLYNOMIAL"); + break; } /* @@ -513,6 +524,21 @@ void DebayerEGL::setShaderVariableValues(const DebayerParams ¶ms) params.lscLut.data(), GL_LINEAR); glUniform1i(textureUniformLsc_, eglImageLscLookup_->texture_unit_uniform_id_); break; + case DebayerParams::LscPolynomial: + glUniform2f(lscScale_, imgSize[0] / 1000.0, imgSize[1] / 1000.0); + glUniform3f(lsc0_, + params.lscCoefficients[0].r(), + params.lscCoefficients[0].g(), + params.lscCoefficients[0].b()); + glUniform3f(lsc1_, + params.lscCoefficients[1].r(), + params.lscCoefficients[1].g(), + params.lscCoefficients[1].b()); + glUniform3f(lsc2_, + params.lscCoefficients[2].r(), + params.lscCoefficients[2].g(), + params.lscCoefficients[2].b()); + break; } /* diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h index d5cfcad1e..7d1fa31cb 100644 --- a/src/libcamera/software_isp/debayer_egl.h +++ b/src/libcamera/software_isp/debayer_egl.h @@ -95,6 +95,10 @@ private: GLint textureUniformBayerDataIn_; GLint textureUniformLsc_; + GLint lscScale_; + GLint lsc0_; + GLint lsc1_; + GLint lsc2_; /* Represent per-frame CCM as a uniform vector of floats 3 x 3 */ GLint ccmUniformDataIn_;