From patchwork Wed Aug 26 18:19:51 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 28108 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 3FFC4C333C for ; Wed, 26 Aug 2026 18:20:25 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E52396844A; Wed, 26 Aug 2026 20:20:24 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="NLoAqZQg"; 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 5B9C868446 for ; Wed, 26 Aug 2026 20:20:23 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1787768422; 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=3Wwwq2Drxdga7M7U0uvYncQxQR+MXUFHviaom74aHyM=; b=NLoAqZQgBCphbJ8yS9AW6Yt/VXY3Z9XTVl3TcwarmbGrOf5zZZXNavOMZneH68M25DlVNG 2uDkqoyV8riKoJWgHAiFSikJt2/8Cmu/RC1qq51zuzy0ibk4/ZYS51vVtY2w6DNSP/68It vk17v0u/6M5UcLCJeTR8K1WSei/oKzE= 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-379-vqhXPaslMSyLYtSc5aYX7g-1; Wed, 26 Aug 2026 14:20:17 -0400 X-MC-Unique: vqhXPaslMSyLYtSc5aYX7g-1 X-Mimecast-MFC-AGG-ID: vqhXPaslMSyLYtSc5aYX7g_1787768416 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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 DE2BA19540C2; Wed, 26 Aug 2026 18:20:15 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.redhat.corp (headnet05.pony-001.prod.iad2.dc.redhat.com [10.2.32.117]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 99CE01800577; Wed, 26 Aug 2026 18:20:12 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Xander Pronk , Bryan O'Donoghue , Hans de Goede , Laurent Pinchart , Robert Mader , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Rick ten Wolde , Milan Zamazal , Bryan O'Donoghue Subject: [PATCH v15 4/6] libcamera: shaders: Add LSC support Date: Wed, 26 Aug 2026 20:19:51 +0200 Message-ID: <20260826181953.261754-5-mzamazal@redhat.com> In-Reply-To: <20260826181953.261754-1-mzamazal@redhat.com> References: <20260826181953.261754-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: naYVbDggzwxYKq6F9ZyvnUwv2oSPB62MxK1dvU6lbpk_1787768416 X-Mimecast-Originator: redhat.com 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 shaders are compiled on initialisation, while lens shading correction can be enabled or disabled dynamically, using the corresponding control. The whole correction in the shader is wrapped by a conditional macro to be able to disable it and all the related overheads if Lsc algorithm is not enabled at all. If Lsc algorithm is enabled, the correction is always applied, whether the given control is enabled or not. If it is not, 1.0 multipliers are expected to be provided. This is because lens shading correction is supposed to be rarely switched off using the runtime control when Lsc algorithm is enabled, e.g. only for demoing or debugging purposes. We prefer accepting the performance penalty of applying a no-op correction in such cases rather than disturbing GPU computation in the regular flow by introducing a runtime `if'. lsc_tex texture contains 8-bit UQ<2, 6> quantized data as provided by the IPA algorithm. It is converted to float in the shader by multiplying it by 4.0. Co-developed-by: Rick ten Wolde Signed-off-by: Rick ten Wolde Signed-off-by: Xander Pronk Signed-off-by: Milan Zamazal Reviewed-by: Bryan O'Donoghue Tested-by: Barnabás Pőcze --- src/libcamera/shaders/bayer_1x_packed.frag | 12 ++++++++++++ src/libcamera/shaders/bayer_unpacked.frag | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/src/libcamera/shaders/bayer_1x_packed.frag b/src/libcamera/shaders/bayer_1x_packed.frag index 0b641a5f3..e61334070 100644 --- a/src/libcamera/shaders/bayer_1x_packed.frag +++ b/src/libcamera/shaders/bayer_1x_packed.frag @@ -71,6 +71,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 @@ -232,6 +236,14 @@ void main(void) */ rgb = (rgb - blacklevel) / (1.0 - blacklevel); +#if defined(APPLY_LSC) + /* Multiple by 4.0 for UQ<2, 6> -> float conversion: + * texture2D(...) = original_float * 2^6 (quantization) * 1/2^8 (texture byte to float) + * => original_float = texture2D(...) / 2^6 * 2^8 = texture2D(...) * 2^2 + */ + rgb = rgb * (texture2D(lsc_tex, textureOut).rgb * 4.0); +#endif + /* Apply AWB gains, and saturate each channel at sensor range */ rgb = clamp(rgb * awb, vec3(0.0), vec3(1.0)); diff --git a/src/libcamera/shaders/bayer_unpacked.frag b/src/libcamera/shaders/bayer_unpacked.frag index 10c5e941b..be2f89dd0 100644 --- a/src/libcamera/shaders/bayer_unpacked.frag +++ b/src/libcamera/shaders/bayer_unpacked.frag @@ -30,6 +30,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 @@ -135,6 +139,11 @@ void main(void) { */ rgb = (rgb - blacklevel) / (1.0 - blacklevel); +#if defined(APPLY_LSC) + /* Multiple by 4.0 for UQ<2, 6> -> float conversion */ + rgb = rgb * (texture2D(lsc_tex, center.xy).rgb * 4.0); +#endif + /* Apply AWB gains, and saturate each channel at sensor range */ rgb = clamp(rgb * awb, vec3(0.0), vec3(1.0));