From patchwork Thu Mar 5 20:10:37 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Javier Tia X-Patchwork-Id: 26262 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 2AE87BE086 for ; Thu, 5 Mar 2026 20:16:27 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E01E3625E9; Thu, 5 Mar 2026 21:16:26 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=jetm.me header.i=@jetm.me header.b="oiF0YBfG"; dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="Mw27L+Ft"; dkim-atps=neutral Received: from fhigh-b7-smtp.messagingengine.com (fhigh-b7-smtp.messagingengine.com [202.12.124.158]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7DD98625B1 for ; Thu, 5 Mar 2026 21:16:25 +0100 (CET) Received: from phl-compute-02.internal (phl-compute-02.internal [10.202.2.42]) by mailfhigh.stl.internal (Postfix) with ESMTP id 90B107A025D; Thu, 5 Mar 2026 15:16:24 -0500 (EST) Received: from phl-imap-07 ([10.202.2.97]) by phl-compute-02.internal (MEProxy); Thu, 05 Mar 2026 15:16: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=1772741784; x=1772828184; bh=uwVuDgg7KgYswKekDhNokoZrkRSeONGMrLqJjJBs1qs=; b= oiF0YBfGcY4itXOFhnu4NFiI2licclFt/+OER0Ku45RKTkU55WXnJUfYZn4Ewc6m wgFUp7c5p1gbf2jTSzAUh+M5Ecgfpef9t/5ola4tZX8KJjyRpZA+go7P2PsfG3BS iCerGK22w7IclHqAIXHhQnagP1UWdcKSYGLrJHT/KSukevC21GFxYGgymagu5G45 VRu/8gA/TEiAwZY+QNV1ti7Bga5pz+cfYJbkYVrqar+B7kpfJci5shUqn4fT20Gq sKBEUAyUm7soJRcCRjnBCDuVAFpGe9S2+x1JEvDCoPno0hqxRyV14T8PcTwhZ7UE BpV54N0b/1lejhA+d/9g/g== 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=1772741784; x= 1772828184; bh=uwVuDgg7KgYswKekDhNokoZrkRSeONGMrLqJjJBs1qs=; b=M w27L+Ft3ftgVQA3mgymJc0wCqE3p/Z5iERgyJ0r+TB5sdBk4lXkM+VmL6iXC2kTF ONWCYnnOyemJzRipLTcIQSV02KOR+xnZQjwgMw43ZRmK84Gq+72S35U+BaOCkiFu Cwqgc+x9TuL25RPOE8oLigZPAcC8fcTeI7Hm3XDSvvnGUP+Jdc4I/2xPYCzOsag7 mX+s31/wxuLaecbx0Q6wRNbstg0nTre3oCaKErXSuvBVg6aCrOmRi3DmCQ6Ffxl6 eVCa5Yjz4VGGrl1+tUwEctSw2VGGIF4+gnRcuMDh2m4U+0BQJI6Ugqt5/dHVCADr 7FkxYi28OXmKjiMiUq3Pw== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefgedrtddtgddvieejfedvucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmnecujf gurhepoffhfffugggtgffkvfevofgjfhesthejredtredtjeenucfhrhhomheplfgrvhhi vghrucfvihgruceofhhlohhsshesjhgvthhmrdhmvgeqnecuggftrfgrthhtvghrnhepvd dtjeeiheeijedtveeujeevvdekjeeuveekleeijeekfeejhfefveeiffffvdeinecuvehl uhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepfhhlohhsshesjh gvthhmrdhmvgdpnhgspghrtghpthhtohepfedpmhhouggvpehsmhhtphhouhhtpdhrtghp thhtohepfhhlohhsshesjhgvthhmrdhmvgdprhgtphhtthhopehlihgstggrmhgvrhgrqd guvghvvghlsehlihhsthhsrdhlihgstggrmhgvrhgrrdhorhhgpdhrtghpthhtohepmhii rghmrgiirghlsehrvgguhhgrthdrtghomh X-ME-Proxy: Feedback-ID: i9dde48b3:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id 3E18E1EA006B; Thu, 5 Mar 2026 15:16:24 -0500 (EST) X-Mailer: MessagingEngine.com Webmail Interface From: Javier Tia Date: Thu, 05 Mar 2026 14:10:37 -0600 Subject: [PATCH v3 1/3] ipa: simple: agc: Replace bang-bang controller with proportional MIME-Version: 1.0 Message-Id: <20260305-agc-proportional-v3-1-25abc1bfacca@jetm.me> To: libcamera-devel@lists.libcamera.org Cc: Javier Tia , Milan Zamazal X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=5190; i=floss@jetm.me; h=from:subject:message-id; bh=EYZd/7BZtmvDdIVohTa3jmhfVl5Dkcqp/2W+9Tnztlk=; b=owEB7QES/pANAwAKAbXuwwuoZ3cfAcsmYgBpqeM8XJfEdd+Ud6sv3+9/kpCBzHFiZu8oHziGX kZNhvDLVrqJAbMEAAEKAB0WIQSbE7ILzw7eI0VKk8m17sMLqGd3HwUCaanjPAAKCRC17sMLqGd3 HzMTC/9wEzJjsQCPfEHrCwJQ4nZNieDcTIZfntkBl6Y8uniXsUaj36F6UIzS2JkOBido9dA5uC/ Y9YeIOK/TSOG6qYW4Rlnf6S2r/tku9wFFswEW1Zno44ici8a1KYoHlX2X8QReJjSOYXY2ZvBM7Y AknVDgUq4ChwYSxQ1v11V6MMfE4OVwetsNL+ul98pcEoxrTUfe5MZmcZ3JhNZB4kCZTr1FjoSI1 SgaSShnjqv5Vf/VvFGTx9CQWciDgJzUnQcHnyhpU8To/duF4wfu9ptHTNlsOyQFpawjC89xmC5e yRfZADQtbnb1B+EohLGqmXDXqZ0iQzKneWXMmV7eJ4teq8+ZG01cVnWp3elOW5u+lixkAX+4T1D NhUF9MM8aSILlNiF3ExrfmvHB1QlMKw1f9nSaIKBIBoDTjYEIba9On67HdgF/d2UM9dHTumXL0q ls5xLya7e4On9w3/IXmux+LFMj2KWA4DLdEvWEkyiTE10g0Pn9ymK+2S5IkMmn8Jx0jkc= X-Developer-Key: i=floss@jetm.me; a=openpgp; fpr=9B13B20BCF0EDE23454A93C9B5EEC30BA867771F In-Reply-To: <20260305-agc-proportional-v3-0-25abc1bfacca@jetm.me> References: <20260305-agc-proportional-v3-0-25abc1bfacca@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 + clamp(error * 0.04, -0.15, +0.15) 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 --- src/ipa/simple/algorithms/agc.cpp | 73 ++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 24 deletions(-) diff --git a/src/ipa/simple/algorithms/agc.cpp b/src/ipa/simple/algorithms/agc.cpp index 2f7e040c..a13a7552 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,74 @@ 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; + +/* + * Maximum multiplicative step per frame, to bound the correction when the + * scene changes dramatically. + */ +static constexpr float kExpMaxStep = 0.15; + 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 step = std::clamp(static_cast(error) * kExpProportionalGain, + -kExpMaxStep, kExpMaxStep); + float factor = 1.0f + step; + + 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 +120,7 @@ void Agc::updateExposure(IPAContext &context, IPAFrameContext &frameContext, dou LOG(IPASoftExposure, Debug) << "exposureMSV " << exposureMSV + << " error " << error << " factor " << factor << " exp " << exposure << " again " << again; } From patchwork Thu Mar 5 20:10:38 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Javier Tia X-Patchwork-Id: 26263 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 D8289BE086 for ; Thu, 5 Mar 2026 20:16:29 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 869E9625FC; Thu, 5 Mar 2026 21:16:29 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=jetm.me header.i=@jetm.me header.b="i4oqO1+8"; dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="kN2hH9Kx"; dkim-atps=neutral Received: from fhigh-b7-smtp.messagingengine.com (fhigh-b7-smtp.messagingengine.com [202.12.124.158]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1C2EB623B1 for ; Thu, 5 Mar 2026 21:16:28 +0100 (CET) Received: from phl-compute-02.internal (phl-compute-02.internal [10.202.2.42]) by mailfhigh.stl.internal (Postfix) with ESMTP id 1769A7A015B; Thu, 5 Mar 2026 15:16:27 -0500 (EST) Received: from phl-imap-07 ([10.202.2.97]) by phl-compute-02.internal (MEProxy); Thu, 05 Mar 2026 15:16:27 -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=1772741786; x=1772828186; bh=uy0t7nB/HlnYq82HqVt/dgAUvE9Kh6vaam5WKqkGTo4=; b= i4oqO1+8Mo9s2JaqJSswEUbWH6V+iS2aW7DNhtM5c03V2qGcrzZzbW3Xk1aDkknH bPrh+TKmUiGBKTRyUcFgMM0TPB7DgpHv3oP+UUFcfCvQwQBDmUKdEwNsHOrPa8gy y14cHGtqTDW0gOK9BvG/umZmMwx7kRydTojR/ite0kG98LEFmdD1e2D3v4gqPEFr GeE24FM249kUMv7GnlFGqD40sHWy7sFqKLXm6u7gOk+8fp0H9QR/vs2g8gBz57Og AlbYvJfT/MndtUMpVcX053/7QlskdyiOxU+a0B7GtH3nxI0xr+rAiHbiTb+VZ8d2 cwzefPS4xFNIXqD9KsRzZA== 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=1772741786; x= 1772828186; bh=uy0t7nB/HlnYq82HqVt/dgAUvE9Kh6vaam5WKqkGTo4=; b=k N2hH9Kx/ertCsX8wwVU7su2bbood4kxoO74yhmaShL5pZkApjOoEXt3wwKOu5mzb 3AcCB4S091RFxLrhvgi/ISqrF5F9GcsYtY2NmHwTUkJQy6yjD9wDljYN7GhgLrrJ dP4J3rfGpisqm/NShS071eE4k+IFyDH3cXU7Ufr+5IVV6cj1+WWY5cNzIsiP3WIi lnw7xR2nela6kmqVYUZ4vj8Rw0YDaLgIOhA+8vZU+5oNBkBRmWwUXT/24iCqZtwo meWmPAjS872DlfKf6FXPLMeVmW0jO74QUsBJTKpdRIUfbXzU05B+NqRstS9OtSbP q2c2mOlDVYYZZa0ZKg7Cw== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefgedrtddtgddvieejfedvucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmnecujf gurhepoffhfffugggtgffkvfevofgjfhesthejredtredtjeenucfhrhhomheplfgrvhhi vghrucfvihgruceofhhlohhsshesjhgvthhmrdhmvgeqnecuggftrfgrthhtvghrnhepvd dtjeeiheeijedtveeujeevvdekjeeuveekleeijeekfeejhfefveeiffffvdeinecuvehl uhhsthgvrhfuihiivgepudenucfrrghrrghmpehmrghilhhfrhhomhepfhhlohhsshesjh gvthhmrdhmvgdpnhgspghrtghpthhtohepfedpmhhouggvpehsmhhtphhouhhtpdhrtghp thhtohepfhhlohhsshesjhgvthhmrdhmvgdprhgtphhtthhopehlihgstggrmhgvrhgrqd guvghvvghlsehlihhsthhsrdhlihgstggrmhgvrhgrrdhorhhgpdhrtghpthhtohepmhii rghmrgiirghlsehrvgguhhgrthdrtghomh X-ME-Proxy: Feedback-ID: i9dde48b3:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id C9B5F1EA006B; Thu, 5 Mar 2026 15:16:26 -0500 (EST) X-Mailer: MessagingEngine.com Webmail Interface From: Javier Tia Date: Thu, 05 Mar 2026 14:10:38 -0600 Subject: [PATCH v3 2/3] libcamera: software_isp: Normalize statistics sums to 8-bit MIME-Version: 1.0 Message-Id: <20260305-agc-proportional-v3-2-25abc1bfacca@jetm.me> To: libcamera-devel@lists.libcamera.org Cc: Javier Tia , Milan Zamazal X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=3160; i=floss@jetm.me; h=from:subject:message-id; bh=HsgWWVAXwOLxqb3uUWqLxv+Ul62ExD/zovCwpEj+wLw=; b=owEB7QES/pANAwAKAbXuwwuoZ3cfAcsmYgBpqeM8tDwRJaA9ALl2+h5jBF0ZY5tJoAILEdFLW /MEuaOFkGCJAbMEAAEKAB0WIQSbE7ILzw7eI0VKk8m17sMLqGd3HwUCaanjPAAKCRC17sMLqGd3 H/EGC/9FuyP1/PMql7WXSHj1vHl2nC82Vc0PzOlVUFR+aegslcwblSw2lu6xgY3TngpZtMh5umE CFvnsPmL/P2sVLLRGGPyLogCr9NnXxZDtx70hHAejDPOl49SI8gqmZECjoE5jHo3xZTSoOhPAjs 9bNPy2aeM4kulC+oeT/yjP9qfE7oeIjd6/wGPoZ+WKAnIVRZSGa0aYVqeSwLfSXg6IzICitNht9 Jhaqa6260HYakDNiuMGx+6D3Wmm1jz7xPioyYLD5KeM1CY5dDe48AWo3ffuHn4NVRSpJM3jGukw 5YyfIA0lGxNqAm6wV54cJq9T9RTWHathjN3VydSggY9HHe6OJGU0aOQGPLkErrDd3OSQ4VfbpQH HAtPAO3gEdRdqIjsG1rHj9Y+lxs/Wm1CLLhhqxiRZISgpjQTr13NhfPDZeSqZ3NhEVvqWIzgo7g ukCO55x+PVEeYyyORs3N1dIwWKVIeRynz4wjUuYKx3GQS2Pmubv7NfLSrwXPl58WPlVxo= X-Developer-Key: i=floss@jetm.me; a=openpgp; fpr=9B13B20BCF0EDE23454A93C9B5EEC30BA867771F In-Reply-To: <20260305-agc-proportional-v3-0-25abc1bfacca@jetm.me> References: <20260305-agc-proportional-v3-0-25abc1bfacca@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 --- include/libcamera/internal/software_isp/swstats_cpu.h | 1 + src/libcamera/software_isp/swstats_cpu.cpp | 9 +++++++++ 2 files changed, 10 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..6f834207 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); } @@ -405,12 +410,15 @@ int SwStatsCpu::configure(const StreamConfiguration &inputCfg) switch (bayerFormat.bitDepth) { case 8: stats0_ = &SwStatsCpu::statsBGGR8Line0; + sumShift_ = 0; return 0; case 10: stats0_ = &SwStatsCpu::statsBGGR10Line0; + sumShift_ = 2; return 0; case 12: stats0_ = &SwStatsCpu::statsBGGR12Line0; + sumShift_ = 4; return 0; } } @@ -422,6 +430,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 Thu Mar 5 20:10:39 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Javier Tia X-Patchwork-Id: 26264 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 76EB4BE086 for ; Thu, 5 Mar 2026 20:16:32 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 2A6046260B; Thu, 5 Mar 2026 21:16:32 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=jetm.me header.i=@jetm.me header.b="JfJPwlR+"; dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="V8FKOeP8"; dkim-atps=neutral Received: from fhigh-b7-smtp.messagingengine.com (fhigh-b7-smtp.messagingengine.com [202.12.124.158]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A8F96625F7 for ; Thu, 5 Mar 2026 21:16:30 +0100 (CET) Received: from phl-compute-02.internal (phl-compute-02.internal [10.202.2.42]) by mailfhigh.stl.internal (Postfix) with ESMTP id BFB827A00DE; Thu, 5 Mar 2026 15:16:29 -0500 (EST) Received: from phl-imap-07 ([10.202.2.97]) by phl-compute-02.internal (MEProxy); Thu, 05 Mar 2026 15:16:29 -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=1772741789; x=1772828189; bh=/MMD4p8/87sHjSVFrSohUyOWFCUdXyclLWXy62ga1B4=; b= JfJPwlR+8ISSbpmeN4UphHe+6MVYA3dpGa+WjGj1+Qz7hBtrkUCmRLvl7aiLoJCJ GFz2eyeJJpQgi07BBzmp53HCpjnICJWO4aIOE81AOhWsdv3GMpcpj+/WlUVGI44W bEtlZ+g9Mriw+A9yIq9lXZb6uCuOojXbvumqTJmQJADvqSsa1q+w+0bzjX+kHbI3 AjytGUeNARUvYYnYjHnSwz50BwT35DBzLzdO65qojfV0N+f5gHOXmxzUsnS0yuFw z44wyTZOKg6Kb6kn6zkAWdlMVCVFL/pVf3v9A3KkMkIsFI/8nuuouAecHD+MFkLp EaKFI2nSI/+NLT7E5hQd4w== 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=1772741789; x= 1772828189; bh=/MMD4p8/87sHjSVFrSohUyOWFCUdXyclLWXy62ga1B4=; b=V 8FKOeP8B1UBtkgCweOJA+TniEAZo7AleqayaHoE89dyUBLA917htx5SQui9GMr1w p4lk6If70C5SvJBhEzkGtHzcNFoOnVurRTDDt+4L+PxswSw0ik1KeRYRz/YX9ViX 3OQGz6S4qWTjSd+1joyEN4ZkgMdo9YtFGRaA0rN4y4rpzbRDx5iXUp+1hfI7wafX Or/7pzX4D/lgFFTfIioep1d/ViRu3SfZ72RauVYZALFup9B492ycJpKd97164qvV EM04kLJmAJwGuh8ku6Cpz2i2LF2fZyY4WEBSgnjFyyFceJqpnd4maG6jgbnTTyQ+ Hdo9LTEFO/7Nbr0MIgzQw== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefgedrtddtgddvieejfedvucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmnecujf gurhepoffhfffugggtgffkvfevofgjfhesthejredtredtjeenucfhrhhomheplfgrvhhi vghrucfvihgruceofhhlohhsshesjhgvthhmrdhmvgeqnecuggftrfgrthhtvghrnhepvd dtjeeiheeijedtveeujeevvdekjeeuveekleeijeekfeejhfefveeiffffvdeinecuvehl uhhsthgvrhfuihiivgepudenucfrrghrrghmpehmrghilhhfrhhomhepfhhlohhsshesjh gvthhmrdhmvgdpnhgspghrtghpthhtohepgedpmhhouggvpehsmhhtphhouhhtpdhrtghp thhtoheprhhosggvrhhtrdhmrgguvghrsegtohhllhgrsghorhgrrdgtohhmpdhrtghpth htohepfhhlohhsshesjhgvthhmrdhmvgdprhgtphhtthhopehlihgstggrmhgvrhgrqdgu vghvvghlsehlihhsthhsrdhlihgstggrmhgvrhgrrdhorhhgpdhrtghpthhtohepmhiirg hmrgiirghlsehrvgguhhgrthdrtghomh X-ME-Proxy: Feedback-ID: i9dde48b3:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id 6F0691EA006B; Thu, 5 Mar 2026 15:16:29 -0500 (EST) X-Mailer: MessagingEngine.com Webmail Interface From: Javier Tia Date: Thu, 05 Mar 2026 14:10:39 -0600 Subject: [PATCH v3 3/3] ipa: libipa: camera_sensor_helper: Add OV2740 black level MIME-Version: 1.0 Message-Id: <20260305-agc-proportional-v3-3-25abc1bfacca@jetm.me> To: libcamera-devel@lists.libcamera.org Cc: Javier Tia , Robert Mader , Milan Zamazal X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=1332; i=floss@jetm.me; h=from:subject:message-id; bh=BjI3qJt89qf+UUwNl9t5oW7IrXveeNERIFns4lhr1S8=; b=owEB7QES/pANAwAKAbXuwwuoZ3cfAcsmYgBpqeM8gIZp/S6S2NCbFG17ZMt6HJJHpbE13YQoz HN0U0gufIWJAbMEAAEKAB0WIQSbE7ILzw7eI0VKk8m17sMLqGd3HwUCaanjPAAKCRC17sMLqGd3 H/UEC/9cdRzVlJ7eoM7EsydsgW+eUjLjvkxXjO7mQ1XuVFdcNADHZJFMySdMgt0yNDNmr2Bs15H aTKTsgM/34Nfe1yoKAabqmrYUOXGX04Vm0SKafuu/Zwnj0Wnh0pnmCFxQOi/y4KhFtaO9R/LuuN NOj5BsXWlB6KvzO2YN6dP8IHA2uQxtTMXET+gnSJnamhMpa97nViHO95XAdQ0y7gD89UoRKQwzr nW7irigBp/vyFmzXUpHGAWzEhBnmnWGkS0w73QOrSDminBx8H0KS+rMyWpaDh308Xd82h3Z7ApY dHiMPOVrUz5q8Ejmg91Z5tRtb6LQOn/lwTUjsGVI3/yB2c4FQ/4K9AfCtpaYxOZn1ntSRBWW9Ay Dx5G+6BU4KRlR7lupk0inGBqARQ9cPTTQ5HBJVbHOhI9ahR53GrAHIXb9/6rgm5449LfsEryQ9U VkEaf2qckE9dMbD/iRKX/2Mh0hVerQiFyOZZ5PFbUhqLdr9w94uY4j9sBmpioIpeX/DeY= X-Developer-Key: i=floss@jetm.me; a=openpgp; fpr=9B13B20BCF0EDE23454A93C9B5EEC30BA867771F In-Reply-To: <20260305-agc-proportional-v3-0-25abc1bfacca@jetm.me> References: <20260305-agc-proportional-v3-0-25abc1bfacca@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 --- 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 }; } };