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) {