From patchwork Fri Mar 6 18:46:40 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Javier Tia X-Patchwork-Id: 26267 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 121D2BE086 for ; Fri, 6 Mar 2026 18:47:24 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id BE40C62635; Fri, 6 Mar 2026 19:47:23 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=jetm.me header.i=@jetm.me header.b="qHKdYu8N"; dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="okr94qrS"; dkim-atps=neutral Received: from fhigh-b6-smtp.messagingengine.com (fhigh-b6-smtp.messagingengine.com [202.12.124.157]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BFB4562620 for ; Fri, 6 Mar 2026 19:47:21 +0100 (CET) Received: from phl-compute-02.internal (phl-compute-02.internal [10.202.2.42]) by mailfhigh.stl.internal (Postfix) with ESMTP id CD8F57A0155; Fri, 6 Mar 2026 13:47:20 -0500 (EST) Received: from phl-imap-07 ([10.202.2.97]) by phl-compute-02.internal (MEProxy); Fri, 06 Mar 2026 13:47:20 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=jetm.me; h=cc:cc :content-transfer-encoding:content-type:content-type:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm3; t=1772822840; x=1772909240; bh=h+BuvakQdxEZJo6r5m3X1LJOae1UMzkzzyG/TIjsqxo=; b= qHKdYu8N/vH4pnnS9qnO5IS+fO18gtvFPHHEVcgTq+hAB9YxealTQomaA0ihZzVH gHi604oark/cxYSwkvRJ3I19wYTnfPXVwmq14LYdGdgxqZufYGMRVL1tRbz6XqtK thEOE3Lf779mERRuRdIKxSI97UTPJKsCv2BCapKU5veCygsR5uLiY11U50NPcZlA USPGjOp0VmtVQ2etQ434iW3t4OlGKSWMzI7HBTP5/UvGY5SZH/Q8Z7GHDDHCvtzD uetXFD+kI8Fj65OxFtSj7UKOTVRFs3lvjxGRgYEOK5zgwro4DJFKuWjkLKFzyh1E 1I6Yk3tu6j2L+gCOcZQMIg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1772822840; x= 1772909240; bh=h+BuvakQdxEZJo6r5m3X1LJOae1UMzkzzyG/TIjsqxo=; b=o kr94qrSn/ukFusm0xJjMLu1ycxVqC24Rh2LAQDQNOOpEJvdfbZP/vBrEl0SxErXb Y9Ff4vg0v96uVBjHmX7K44GyZEu18HruazOHRTgaV2NLxrh4d2zxD7ZbhA43L8d/ PzcOq5z7JQorao+BVAxU4jI7MTIV33lG3jF15YH/O4Zq1KlrhI5BtEAAHT9d560i iOdXDvWbbwEmN+CprAWiv8CRInmD8LN106z1idEBrb4GN7eVG2YzlZW5GZ5zRJqB v+/5mYm/GWVijvSPWLhlRdCK945gka5wWDxrevk+F0gU8IZWL7/1mutFMeNuhNW0 rq+faJO2POhwK34u0guXw== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefgedrtddtgddvjedttdegucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmnecujf gurhepoffhfffugggtgffkvfevofgjfhesthekredtredtjeenucfhrhhomheplfgrvhhi vghrucfvihgruceofhhlohhsshesjhgvthhmrdhmvgeqnecuggftrfgrthhtvghrnhepve ektdfhffevuddtgfetieevtddvheduhfeggfekveejlefhleefieevueefiefhnecuvehl uhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepfhhlohhsshesjh gvthhmrdhmvgdpnhgspghrtghpthhtohepgedpmhhouggvpehsmhhtphhouhhtpdhrtghp thhtohepsggrrhhnrggsrghsrdhpohgtiigvsehiuggvrghsohhnsghorghrugdrtghomh dprhgtphhtthhopehflhhoshhssehjvghtmhdrmhgvpdhrtghpthhtoheplhhisggtrghm vghrrgdquggvvhgvlheslhhishhtshdrlhhisggtrghmvghrrgdrohhrghdprhgtphhtth hopehmiigrmhgriigrlhesrhgvughhrghtrdgtohhm X-ME-Proxy: Feedback-ID: i9dde48b3:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id 8B0911EA006B; Fri, 6 Mar 2026 13:47:20 -0500 (EST) X-Mailer: MessagingEngine.com Webmail Interface From: Javier Tia Date: Fri, 06 Mar 2026 12:46:40 -0600 Subject: [PATCH v4 1/3] ipa: simple: agc: Replace bang-bang controller with proportional MIME-Version: 1.0 Message-Id: <20260306-agc-proportional-v4-1-e87c7e0d837a@jetm.me> To: libcamera-devel@lists.libcamera.org Cc: Javier Tia , Milan Zamazal , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=4996; i=floss@jetm.me; h=from:subject:message-id; bh=SV7Gcbd6KVxn2JTosswI0D9gL6WG/lCrexuHvmEVNEY=; b=owEB7QES/pANAwAKAbXuwwuoZ3cfAcsmYgBpqyEPA8AURRa+CBXFQq47ccTyPZN4PlUZOKtSJ kYBB4wIO+CJAbMEAAEKAB0WIQSbE7ILzw7eI0VKk8m17sMLqGd3HwUCaashDwAKCRC17sMLqGd3 H+/0DAC+haXU0rvymThx+t7rGyihSlVZW7DFrgdq2XRqhbbfbIn/QG/af6eMUKfKGD0GPLpsvsP +nxosfHz2rCoDfmHSeJSE4ZypVob+zZpl9Nw1Iqoqp78AaDyAaKlSuddAILz2luCaOD4mxGvk6W mJbDBHidoPY7z650JAcUcBiKYa/V0DzegOFc9BQ6yQhMpNhE8jnv69dEHEZ/PxIsMlbsLPDJjhQ RSiU9IuzMK9wPx1HdgoFFNML5sY0kHGt2LJ5Uj43jBVWOHYmlVfRy0wp/yQbEsv19853Me/3sO/ ddFL+NANLC6zuCEqP5w90PYBx1fBhN5Xe6cjD/SlO9LPfu0NVRIgeHzf+5/LfPlZZr1FqCdZFB8 cPW++/zIonaD1NVfFvxrw4UaKgFDeRhJHjvvaQ+QNwOesUUuY/jVG0F55AcNFcYZgQRluSAmCJy sT/1fZbJPLQHOO226T52Rm/nGTmbD3o5d7yeWbdyU3gwTBZgjSV1m6K5bon2J6iDA2y4A= X-Developer-Key: i=floss@jetm.me; a=openpgp; fpr=9B13B20BCF0EDE23454A93C9B5EEC30BA867771F In-Reply-To: <20260306-agc-proportional-v4-0-e87c7e0d837a@jetm.me> References: <20260306-agc-proportional-v4-0-e87c7e0d837a@jetm.me> 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 AGC's updateExposure() uses a fixed ~10% step per frame regardless of how far the current exposure is from optimal. With a hysteresis dead band of only +/-4%, the controller overshoots when the correct value falls within one step, causing visible brightness oscillation (flicker). Replace the fixed-step bang-bang controller with a proportional one where the correction factor scales linearly with the MSV error: factor = 1.0 + error * 0.04 At maximum error (~2.5), this gives the same ~10% step as before. Near the target, steps shrink to <1%, eliminating overshoot. The existing hysteresis (kExposureSatisfactory) still prevents hunting on noise. Tested on OV2740 behind Intel IPU6 ISYS (ThinkPad X1 Carbon Gen 10) where the old controller produced continuous brightness flicker. The proportional controller converges in ~3 seconds from cold start with no visible oscillation. Signed-off-by: Javier Tia Reviewed-by: Milan Zamazal Tested-by: Barnabás Pőcze --- src/ipa/simple/algorithms/agc.cpp | 65 ++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/src/ipa/simple/algorithms/agc.cpp b/src/ipa/simple/algorithms/agc.cpp index 2f7e040c..ac977d5f 100644 --- a/src/ipa/simple/algorithms/agc.cpp +++ b/src/ipa/simple/algorithms/agc.cpp @@ -7,6 +7,8 @@ #include "agc.h" +#include +#include #include #include @@ -37,52 +39,66 @@ static constexpr float kExposureOptimal = kExposureBinsCount / 2.0; */ static constexpr float kExposureSatisfactory = 0.2; +/* + * Proportional gain for exposure/gain adjustment. Maps the MSV error to a + * multiplicative correction factor: + * + * factor = 1.0 + kExpProportionalGain * error + * + * With kExpProportionalGain = 0.04: + * - max error ~2.5 -> factor 1.10 (~10% step, same as before) + * - error 1.0 -> factor 1.04 (~4% step) + * - error 0.3 -> factor 1.012 (~1.2% step) + * + * This replaces the fixed 10% bang-bang step with a proportional correction + * that converges smoothly and avoids overshooting near the target. + */ +static constexpr float kExpProportionalGain = 0.04; + Agc::Agc() { } void Agc::updateExposure(IPAContext &context, IPAFrameContext &frameContext, double exposureMSV) { - /* - * kExpDenominator of 10 gives ~10% increment/decrement; - * kExpDenominator of 5 - about ~20% - */ - static constexpr uint8_t kExpDenominator = 10; - static constexpr uint8_t kExpNumeratorUp = kExpDenominator + 1; - static constexpr uint8_t kExpNumeratorDown = kExpDenominator - 1; - int32_t &exposure = frameContext.sensor.exposure; double &again = frameContext.sensor.gain; - if (exposureMSV < kExposureOptimal - kExposureSatisfactory) { + double error = kExposureOptimal - exposureMSV; + + if (std::abs(error) <= kExposureSatisfactory) + return; + + /* + * Compute a proportional correction factor. The sign of the error + * determines the direction: positive error means too dark (increase), + * negative means too bright (decrease). + */ + float factor = 1.0f + static_cast(error) * kExpProportionalGain; + + if (factor > 1.0f) { + /* Scene too dark: increase exposure first, then gain. */ if (exposure < context.configuration.agc.exposureMax) { - int32_t next = exposure * kExpNumeratorUp / kExpDenominator; - if (next - exposure < 1) - exposure += 1; - else - exposure = next; + int32_t next = static_cast(exposure * factor); + exposure = std::max(next, exposure + 1); } else { - double next = again * kExpNumeratorUp / kExpDenominator; + double next = again * factor; if (next - again < context.configuration.agc.againMinStep) again += context.configuration.agc.againMinStep; else again = next; } - } - - if (exposureMSV > kExposureOptimal + kExposureSatisfactory) { + } else { + /* Scene too bright: decrease gain first, then exposure. */ if (again > context.configuration.agc.again10) { - double next = again * kExpNumeratorDown / kExpDenominator; + double next = again * factor; if (again - next < context.configuration.agc.againMinStep) again -= context.configuration.agc.againMinStep; else again = next; } else { - int32_t next = exposure * kExpNumeratorDown / kExpDenominator; - if (exposure - next < 1) - exposure -= 1; - else - exposure = next; + int32_t next = static_cast(exposure * factor); + exposure = std::min(next, exposure - 1); } } @@ -96,6 +112,7 @@ void Agc::updateExposure(IPAContext &context, IPAFrameContext &frameContext, dou LOG(IPASoftExposure, Debug) << "exposureMSV " << exposureMSV + << " error " << error << " factor " << factor << " exp " << exposure << " again " << again; } From patchwork Fri Mar 6 18:46:41 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Javier Tia X-Patchwork-Id: 26268 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 C9E49BE086 for ; Fri, 6 Mar 2026 18:47:26 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7ED6162633; Fri, 6 Mar 2026 19:47:26 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=jetm.me header.i=@jetm.me header.b="qOKeJDgj"; dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="bOVksbR2"; dkim-atps=neutral Received: from fout-b3-smtp.messagingengine.com (fout-b3-smtp.messagingengine.com [202.12.124.146]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 815686261B for ; Fri, 6 Mar 2026 19:47:25 +0100 (CET) Received: from phl-compute-02.internal (phl-compute-02.internal [10.202.2.42]) by mailfout.stl.internal (Postfix) with ESMTP id 8EC401D00128; Fri, 6 Mar 2026 13:47:24 -0500 (EST) Received: from phl-imap-07 ([10.202.2.97]) by phl-compute-02.internal (MEProxy); Fri, 06 Mar 2026 13:47:24 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=jetm.me; h=cc:cc :content-transfer-encoding:content-type:content-type:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm3; t=1772822844; x=1772909244; bh=fFQMfRVX4SXJwh9RbOEBdeIDJ6/usq4wS8mkK6iJZ/4=; b= qOKeJDgjFyeXmQxKn+HXG57pp9CnvSjhVY7uW9tTsGQPSqRHjY64PvtaLAI9x5Et MqTpVImSye4CeA1hiJeB7zw1QStbpP4rf/q0kbobrzM6+oORUkaEETGFZRJ1bVfa 76RLcZQfFlJ95gEqGeUSFAEN0fnN/AwvL62VMjU/sReWcDB/j/TCqmR0OxjJUP53 nIi7gxRlO34x4u6CLxLfdyZ0xZE/RY2qdtUEFcxbYY65u8svdPG49rfFypx7CpDU b3wQQaw1XHRb9lhThEpoc9N14fU5RmSlfP5GUapeSbVWwYty6q8gz0X7J2s7MGng KfQtLR2raO8HyQOilrGoMA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1772822844; x= 1772909244; bh=fFQMfRVX4SXJwh9RbOEBdeIDJ6/usq4wS8mkK6iJZ/4=; b=b OVksbR2c2ujL1cim2h1R2XJR2of872s2Qwgt1O3QJYAkba0F20zX07wzidS1mHYK cBgw/8vfrap8cwU0u1ZWsGk9x+niIle4QIxvwSj1WAtK4IRAjbyveDH9hej/ldNI 38eABC0l/CVqFbnYT+gtKJz7jrC37ZVnyrLBpnaKdR4yA8j1Uj9b6Y1W9GhvmClq ivqXhtLZNjCOGN98HUbl2HL+oTenu+xb+AW+cy+AzXaJbEMPQqvZiRKScnTv8CKp Zrh9uyA9Gh91i6B2DxegCEfBB50/DlOa8sFeuWvtZVc2LHdqQsMSfS1TVznQ1m1+ 4HTgf8gprtMa7oJjyOs7w== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefgedrtddtgddvjedttdegucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmnecujf gurhepoffhfffugggtgffkvfevofgjfhesthekredtredtjeenucfhrhhomheplfgrvhhi vghrucfvihgruceofhhlohhsshesjhgvthhmrdhmvgeqnecuggftrfgrthhtvghrnhepve ektdfhffevuddtgfetieevtddvheduhfeggfekveejlefhleefieevueefiefhnecuvehl uhhsthgvrhfuihiivgepudenucfrrghrrghmpehmrghilhhfrhhomhepfhhlohhsshesjh gvthhmrdhmvgdpnhgspghrtghpthhtohepgedpmhhouggvpehsmhhtphhouhhtpdhrtghp thhtohepsggrrhhnrggsrghsrdhpohgtiigvsehiuggvrghsohhnsghorghrugdrtghomh dprhgtphhtthhopehflhhoshhssehjvghtmhdrmhgvpdhrtghpthhtoheplhhisggtrghm vghrrgdquggvvhgvlheslhhishhtshdrlhhisggtrghmvghrrgdrohhrghdprhgtphhtth hopehmiigrmhgriigrlhesrhgvughhrghtrdgtohhm X-ME-Proxy: Feedback-ID: i9dde48b3:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id 4CD991EA006B; Fri, 6 Mar 2026 13:47:24 -0500 (EST) X-Mailer: MessagingEngine.com Webmail Interface From: Javier Tia Date: Fri, 06 Mar 2026 12:46:41 -0600 Subject: [PATCH v4 2/3] libcamera: software_isp: Normalize statistics sums to 8-bit MIME-Version: 1.0 Message-Id: <20260306-agc-proportional-v4-2-e87c7e0d837a@jetm.me> To: libcamera-devel@lists.libcamera.org Cc: Javier Tia , Milan Zamazal , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=3262; i=floss@jetm.me; h=from:subject:message-id; bh=LPdCiSDd3MA8NAdHMsUrfV6hJzO9wW24ssL+LcTrfSg=; b=owEB7QES/pANAwAKAbXuwwuoZ3cfAcsmYgBpqyEPM0DYOvoMGOjeah2y0sdaHWmcMOG/wzKEq OmSLOmMOZyJAbMEAAEKAB0WIQSbE7ILzw7eI0VKk8m17sMLqGd3HwUCaashDwAKCRC17sMLqGd3 HyFDDACbwlLXhgrHH3oYsJfyvDmsJhZH9uK8XpvVjFAK7LDYGWHy+2v9Or3k574Cut7XRAmIV3L dvE8W1DH2nQmIUlFL9xdGzaGbyjtXss2xcpZvw1DL4mT4QYyZxhXVCHWXGfTv98AsgfFIWgLAT3 1m0yd5Y+DDzsvVGafZl2JOMm1Kjzd/RGCN1OTSPdSTUGLLoAg++SfBIpQ6ogMeIfSKcA5kX3nGy v3sg31YLf5kEZHPPwLHGqFG5fCx//x6qyM9/JrLXDmg0qruRaEm95wAFefMTvgGzU0JFC78HEVZ sfJl+i6cQpVH8VCY0YTTatqLQ1tJxjjyCTBNMRnX5QSGa/UA4sM6OvBwwl1goolYdJAlpS65331 ITMcTliQJJtSxVY5VyAPZH7g5xTV0RldRgCnjYwCOQVIDx20eB7M2Ml3C6Q3YZ5P8Me4z1Dx7No GZ5wWqvDi2jt0M+Ph1ybCZZxcfSZlCxcw4+13OSm944/EIgq0GXlrxanOuy5rQmKOYjng= X-Developer-Key: i=floss@jetm.me; a=openpgp; fpr=9B13B20BCF0EDE23454A93C9B5EEC30BA867771F In-Reply-To: <20260306-agc-proportional-v4-0-e87c7e0d837a@jetm.me> References: <20260306-agc-proportional-v4-0-e87c7e0d837a@jetm.me> 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 SWSTATS_ACCUMULATE_LINE_STATS() macro divides the luminance value for the histogram to normalize it to 8-bit range, but does not apply the same normalization to the RGB sums. For 10-bit and 12-bit unpacked Bayer formats this means the sums are accumulated at native bit depth (0-1023 or 0-4095 per pixel) while the AWB algorithm subtracts an 8-bit black level from them, under-correcting by 4x or 16x respectively. This mismatch between the AWB's gain calculation (using incorrectly BLC-subtracted sums) and the debayer's correct normalized BLC subtraction produces a visible color cast. For example, with the OV2740 sensor (10-bit, BLC=16), the under-subtraction skews R/G gain by ~9%. Fix this by right-shifting the RGB sums in finishFrame() to normalize them to 8-bit scale, matching the histogram and the 8-bit black level used by AWB. A per-format sumShift_ value is set in configure(): 0 for 8-bit and CSI-2 packed formats (already 8-bit), 2 for 10-bit, and 4 for 12-bit unpacked formats. Signed-off-by: Javier Tia Reviewed-by: Milan Zamazal Tested-by: Milan Zamazal Reviewed-by: Barnabás Pőcze Tested-by: Barnabás Pőcze --- include/libcamera/internal/software_isp/swstats_cpu.h | 1 + src/libcamera/software_isp/swstats_cpu.cpp | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/include/libcamera/internal/software_isp/swstats_cpu.h b/include/libcamera/internal/software_isp/swstats_cpu.h index 64b3e23f..37bfde53 100644 --- a/include/libcamera/internal/software_isp/swstats_cpu.h +++ b/include/libcamera/internal/software_isp/swstats_cpu.h @@ -115,6 +115,7 @@ private: unsigned int xShift_; unsigned int stride_; + unsigned int sumShift_; SharedMemObject sharedStats_; SwIspStats stats_; diff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp index 1cedcfbc..744a7560 100644 --- a/src/libcamera/software_isp/swstats_cpu.cpp +++ b/src/libcamera/software_isp/swstats_cpu.cpp @@ -346,6 +346,11 @@ void SwStatsCpu::startFrame(uint32_t frame) void SwStatsCpu::finishFrame(uint32_t frame, uint32_t bufferId) { stats_.valid = frame % kStatPerNumFrames == 0; + if (stats_.valid && sumShift_) { + stats_.sum_.r() >>= sumShift_; + stats_.sum_.g() >>= sumShift_; + stats_.sum_.b() >>= sumShift_; + } *sharedStats_ = stats_; statsReady.emit(frame, bufferId); } @@ -402,6 +407,7 @@ int SwStatsCpu::configure(const StreamConfiguration &inputCfg) if (bayerFormat.packing == BayerFormat::Packing::None && setupStandardBayerOrder(bayerFormat.order) == 0) { processFrame_ = &SwStatsCpu::processBayerFrame2; + sumShift_ = bayerFormat.bitDepth - 8; switch (bayerFormat.bitDepth) { case 8: stats0_ = &SwStatsCpu::statsBGGR8Line0; @@ -422,6 +428,7 @@ int SwStatsCpu::configure(const StreamConfiguration &inputCfg) /* Skip every 3th and 4th line, sample every other 2x2 block */ ySkipMask_ = 0x02; xShift_ = 0; + sumShift_ = 0; processFrame_ = &SwStatsCpu::processBayerFrame2; switch (bayerFormat.order) { From patchwork Fri Mar 6 18:46:42 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Javier Tia X-Patchwork-Id: 26269 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 4ED13BE086 for ; Fri, 6 Mar 2026 18:47:31 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 040D06262B; Fri, 6 Mar 2026 19:47:31 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=jetm.me header.i=@jetm.me header.b="pmNB6ydX"; dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="auylUig1"; dkim-atps=neutral Received: from fout-b3-smtp.messagingengine.com (fout-b3-smtp.messagingengine.com [202.12.124.146]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 16EB26262B for ; Fri, 6 Mar 2026 19:47:29 +0100 (CET) Received: from phl-compute-02.internal (phl-compute-02.internal [10.202.2.42]) by mailfout.stl.internal (Postfix) with ESMTP id 1E1E41D001EF; Fri, 6 Mar 2026 13:47:28 -0500 (EST) Received: from phl-imap-07 ([10.202.2.97]) by phl-compute-02.internal (MEProxy); Fri, 06 Mar 2026 13:47:28 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=jetm.me; h=cc:cc :content-transfer-encoding:content-type:content-type:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm3; t=1772822847; x=1772909247; bh=CHN1xniAfXlwQmhfXAgCskP+NfdleaM3Yb9Adg8Ets4=; b= pmNB6ydXRNTtclbQNeoodsvW7c/7plZ6g1V/xSB/9oPr7DSaFDncqd2D2eggsE47 1XgGgrBAi4xERBQJamW2T6gkGRmHZ95xzrxOzQY7EXM0cM9CqepOI07O1eSB7uI1 PfH8SKKSCYKJ1QTvO+lPTVVJ05AibI3RGIUlZormgIZ0ESd7uxfGkForuAy3pbmk /tQM2urt5Ikq/SK0WyNfABoQ465syPHylKZaBJa1BVYWdXVdC110ZZqNkiKt5FBf QLG+mtXpQp3uuVVAnCCW+/XRBO8MHpQQ7KnuOXLJV9Vs7PsyXTezhNpBW1gVWmCO cRUkuQdTouwb8h04QNxE5A== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1772822847; x= 1772909247; bh=CHN1xniAfXlwQmhfXAgCskP+NfdleaM3Yb9Adg8Ets4=; b=a uylUig1/T/LiMaJYy4Sb0iSidhtVztgCfPY1TV1/uv/DKeqaM8e1gLk1BbjcXb22 hByPeG+8/zO1NJRXua+ZCJgOc3a9LSS+cLA5nPeIzp2sreQKLeZg4YYjIx59OLzi DVFHw6MBVpawKY3ojdokGsMYmxxZYXdUHr3bnxu/o16ROgL9Ct9CRI5bAAxW1pib JKF2EPILvCBPP8ZjcjaWqrYBR0R4sSIpTgtZr8tUgOH8BowYoemGgjJ4I+Uk2L+/ o3+seUDyrn1XC3mtRsFIq0N8RgCxBB8T7izyrzbLv11cgTyXW0BtwhjrBg/TWMjL lpD60Gk69C2VdUweefvEQ== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefgedrtddtgddvjedttdegucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmnecujf gurhepoffhfffugggtgffkvfevofgjfhesthejredtredtjeenucfhrhhomheplfgrvhhi vghrucfvihgruceofhhlohhsshesjhgvthhmrdhmvgeqnecuggftrfgrthhtvghrnhepvd dtjeeiheeijedtveeujeevvdekjeeuveekleeijeekfeejhfefveeiffffvdeinecuvehl uhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepfhhlohhsshesjh gvthhmrdhmvgdpnhgspghrtghpthhtohephedpmhhouggvpehsmhhtphhouhhtpdhrtghp thhtoheprhhosggvrhhtrdhmrgguvghrsegtohhllhgrsghorhgrrdgtohhmpdhrtghpth htohepkhhivghrrghnrdgsihhnghhhrghmsehiuggvrghsohhnsghorghrugdrtghomhdp rhgtphhtthhopehflhhoshhssehjvghtmhdrmhgvpdhrtghpthhtoheplhhisggtrghmvg hrrgdquggvvhgvlheslhhishhtshdrlhhisggtrghmvghrrgdrohhrghdprhgtphhtthho pehmiigrmhgriigrlhesrhgvughhrghtrdgtohhm X-ME-Proxy: Feedback-ID: i9dde48b3:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id D0D6B1EA006B; Fri, 6 Mar 2026 13:47:27 -0500 (EST) X-Mailer: MessagingEngine.com Webmail Interface From: Javier Tia Date: Fri, 06 Mar 2026 12:46:42 -0600 Subject: [PATCH v4 3/3] ipa: libipa: camera_sensor_helper: Add OV2740 black level MIME-Version: 1.0 Message-Id: <20260306-agc-proportional-v4-3-e87c7e0d837a@jetm.me> To: libcamera-devel@lists.libcamera.org Cc: Javier Tia , Robert Mader , Milan Zamazal , Kieran Bingham X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=1395; i=floss@jetm.me; h=from:subject:message-id; bh=CVayJSTkmCsf3E9vSV+wy3VZe+4o2pIj1TTFoqLh3u4=; b=owEB7QES/pANAwAKAbXuwwuoZ3cfAcsmYgBpqyEP1N2etlf4hTxq8on0NTxpNs3AChasz/vmZ zNwj/Eop2OJAbMEAAEKAB0WIQSbE7ILzw7eI0VKk8m17sMLqGd3HwUCaashDwAKCRC17sMLqGd3 H8LqC/9CLvtNbv/tp2eCP2K96dyZq62hLhKNle6Bp4odNM+Cm8Cwv1FW2IPyVUTFO3bSFEnaavp FDd+GIhf16pXxf8HxP2knf0fH5M9UhkwChLFSttPGXx1Vd22cWPoMgkX2/E91UTYmm2hzq/tTJu Se9FVRKNOenDMQ/4G9ZMqAMa75LwWc2x/XyTfzXnwC+laGN+gHdZbm9nJSz8KRbBm3DvOkm3q74 xsrtcql1wts2eaJFiHcc9UoJERnhSzF+ygo66lWqy21DYoHXd5fRfWEbjdIpYRuFW6KaFk339ZQ TxvdErmdEwymK41kVvxL7X7IdLcY8aql13p5ObZEp7nOGJfkSwTdq8GnIQ0NfUbZ73rZ2i1Z/37 NbeTFDeH7D3KBBSQkKiVQuH1nMmNCXG41pmnc93QKQkQuWqG5NUoF94QlGOQ2kdpBIJFa4kyrA8 Bd8kZW6IYrXqczkQOpqCGz+/G5Xep6FPdn8hx1RPua+EMAHWWhHxw6E//Lj6gXppCVyhs= X-Developer-Key: i=floss@jetm.me; a=openpgp; fpr=9B13B20BCF0EDE23454A93C9B5EEC30BA867771F In-Reply-To: <20260306-agc-proportional-v4-0-e87c7e0d837a@jetm.me> References: <20260306-agc-proportional-v4-0-e87c7e0d837a@jetm.me> 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" Set blackLevel_ = 4096 (0x40 at 10-bit) in CameraSensorHelperOv2740. The OV2740 kernel driver programs BLC target register 0x4003 with 0x40 for the 180 MHz link frequency mode. This matches the same pattern used by OV5675 and other OmniVision sensors with a 10-bit black level of 64. Without this, the Simple pipeline falls back to auto-guessing the black level, which happens to arrive at the same value but isn't documented. More importantly, the CameraSensorHelper is the canonical location for sensor calibration data and is used across all pipeline handlers, not just Simple. Suggested-by: Robert Mader Signed-off-by: Javier Tia Reviewed-by: Milan Zamazal Reviewed-by: Kieran Bingham --- src/ipa/libipa/camera_sensor_helper.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ipa/libipa/camera_sensor_helper.cpp b/src/ipa/libipa/camera_sensor_helper.cpp index e3e3e535..3028197e 100644 --- a/src/ipa/libipa/camera_sensor_helper.cpp +++ b/src/ipa/libipa/camera_sensor_helper.cpp @@ -672,6 +672,8 @@ class CameraSensorHelperOv2740 : public CameraSensorHelper public: CameraSensorHelperOv2740() { + /* From Linux kernel driver: 0x40 at 10bits. */ + blackLevel_ = 4096; gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; } };