From patchwork Tue Apr 7 22:01:07 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 26487 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 A2C2BC32BB for ; Tue, 7 Apr 2026 22:02:57 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 072C862DDA; Wed, 8 Apr 2026 00:02:49 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="P093AwE+"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9DF0662CEB for ; Wed, 8 Apr 2026 00:02:41 +0200 (CEST) Received: from [192.168.0.204] (ams.linuxembedded.co.uk [209.38.108.23]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E5A371C3F; Wed, 8 Apr 2026 00:01:13 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1775599274; bh=iZAHoQLS2AsifD7XmJAW9+6UedqcEBhtvRK5onvL/+M=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=P093AwE+OoflH4csdp5ywjudXoK++JZFCDLxpzGylT82YcGMqNzFO8vp8q08XIyb7 seAs/mnJzHrBpuHJCysUwkQ8XmQBuctNOvAFTNCcvBFmv+1lyGzu4OgxYDG3mCL8Ik ycB9tHDElUDt6pTTusQxxxubYN/mNgNoiCiQTukk= From: Kieran Bingham Date: Tue, 07 Apr 2026 23:01:07 +0100 Subject: [PATCH 04/13] libcamera: software_isp: Apply gains in CPU ISP MIME-Version: 1.0 Message-Id: <20260407-kbingham-awb-split-v1-4-a39af3f4dc20@ideasonboard.com> References: <20260407-kbingham-awb-split-v1-0-a39af3f4dc20@ideasonboard.com> In-Reply-To: <20260407-kbingham-awb-split-v1-0-a39af3f4dc20@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Kieran Bingham , Milan Zamazal X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1775599359; l=4292; i=kieran.bingham@ideasonboard.com; s=20260204; h=from:subject:message-id; bh=/qHwlJH4HM+aP5KdyZDAbML9TLl/S2aWLr0jTOIFApY=; b=t94QFNq9U/XuWPGm+5FO2FgHBHXHcSlYLGZ4ZRYQezwUA9X1L2Zv56bppl8BVYHmcqFdKq7qu mRaiRoIbEKSATVmR3gCyW2Rrx8zO/fJAnDBXJOHAZeD0fmRh8eRVsTK X-Developer-Key: i=kieran.bingham@ideasonboard.com; a=ed25519; pk=IOxS2C6nWHNjLfkDR71Iesk904i6wJDfEERqV7hDBdY= 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: Milan Zamazal One of the preceding patches removed white balance gains from the combined matrix. Which is correct but the gains are not applied now in CPU ISP when a CCM is used. This patch applies the gains in the CCM table. It also clamps the pixel values if they are out of range after applying the gains. Signed-off-by: Milan Zamazal --- src/libcamera/software_isp/debayer_cpu.cpp | 45 +++++++++++++++--------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp index 5356d6bbec11c30fa0b05659d44a91e69e2b79d0..2dc0df5597938cc19317187f7b1ed8a10b1cc111 100644 --- a/src/libcamera/software_isp/debayer_cpu.cpp +++ b/src/libcamera/software_isp/debayer_cpu.cpp @@ -911,45 +911,46 @@ void DebayerCpu::updateLookupTables(const DebayerParams ¶ms) }; const unsigned int gammaTableSize = gammaTable_.size(); RGB blackIndex = params.blackLevel * kRGBLookupSize; + RGB gains = params.gains; + const RGB div = (RGB(kRGBLookupSize) - blackIndex).max(1.0); if (ccmEnabled_) { if (gammaUpdateNeeded || - matrixChanged(params.combinedMatrix, params_.combinedMatrix)) { + matrixChanged(params.combinedMatrix, params_.combinedMatrix) || + params.gains != params_.gains) { auto &red = swapRedBlueGains_ ? blueCcm_ : redCcm_; auto &green = greenCcm_; auto &blue = swapRedBlueGains_ ? redCcm_ : blueCcm_; - const unsigned int redIndex = swapRedBlueGains_ ? 2 : 0; - const unsigned int greenIndex = 1; - const unsigned int blueIndex = swapRedBlueGains_ ? 0 : 2; - const RGB div = - (RGB(kRGBLookupSize) - blackIndex).max(1.0) / - kRGBLookupSize; for (unsigned int i = 0; i < kRGBLookupSize; i++) { - const RGB rgb = ((RGB(i) - blackIndex) / div).max(0.0); - red[i].r = std::round(rgb.r() * params.combinedMatrix[redIndex][0]); - red[i].g = std::round(rgb.g() * params.combinedMatrix[greenIndex][0]); - red[i].b = std::round(rgb.b() * params.combinedMatrix[blueIndex][0]); - green[i].r = std::round(rgb.r() * params.combinedMatrix[redIndex][1]); - green[i].g = std::round(rgb.g() * params.combinedMatrix[greenIndex][1]); - green[i].b = std::round(rgb.b() * params.combinedMatrix[blueIndex][1]); - blue[i].r = std::round(rgb.r() * params.combinedMatrix[redIndex][2]); - blue[i].g = std::round(rgb.g() * params.combinedMatrix[greenIndex][2]); - blue[i].b = std::round(rgb.b() * params.combinedMatrix[blueIndex][2]); + const RGB rgb = + (gains * (RGB(i) - blackIndex) * kRGBLookupSize / div) + .min(kRGBLookupSize - 1) + .max(0.0); + red[i].r = std::round(rgb.r() * params.combinedMatrix[0][0]); + red[i].g = std::round(rgb.g() * params.combinedMatrix[1][0]); + red[i].b = std::round(rgb.b() * params.combinedMatrix[2][0]); + green[i].r = std::round(rgb.r() * params.combinedMatrix[0][1]); + green[i].g = std::round(rgb.g() * params.combinedMatrix[1][1]); + green[i].b = std::round(rgb.b() * params.combinedMatrix[2][1]); + blue[i].r = std::round(rgb.r() * params.combinedMatrix[0][2]); + blue[i].g = std::round(rgb.g() * params.combinedMatrix[1][2]); + blue[i].b = std::round(rgb.b() * params.combinedMatrix[2][2]); + if (swapRedBlueGains_) { + std::swap(red[i].r, red[i].b); + std::swap(green[i].r, green[i].b); + std::swap(blue[i].r, blue[i].b); + } gammaLut_[i] = gammaTable_[i * gammaTableSize / kRGBLookupSize]; } } } else { if (gammaUpdateNeeded || params.gains != params_.gains) { - auto &gains = params.gains; auto &red = swapRedBlueGains_ ? blue_ : red_; auto &green = green_; auto &blue = swapRedBlueGains_ ? red_ : blue_; - const RGB div = - (RGB(kRGBLookupSize) - blackIndex).max(1.0) / - gammaTableSize; for (unsigned int i = 0; i < kRGBLookupSize; i++) { const RGB lutGains = - (gains * (RGB(i) - blackIndex) / div) + (gains * (RGB(i) - blackIndex) * gammaTableSize / div) .min(gammaTableSize - 1) .max(0.0); red[i] = gammaTable_[lutGains.r()];