From patchwork Sat Oct 17 15:38:28 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Qianhui Xu X-Patchwork-Id: 28498 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 EF7FBC324C for ; Sat, 17 Oct 2026 15:38:35 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6412A68E72; Sat, 17 Oct 2026 17:38:34 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=mail.ustc.edu.cn header.i=@mail.ustc.edu.cn header.b="C+qgsqtB"; dkim-atps=neutral Received: from ustc.edu.cn (smtp.ustc.edu.cn [202.38.64.46]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 54D03689D0 for ; Sat, 17 Oct 2026 17:38:31 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mail.ustc.edu.cn; s=dkim; h=Received:From:To:Cc:Subject:Date: Message-ID:In-Reply-To:References:MIME-Version: Content-Transfer-Encoding; bh=Jdw9fDy3ksHOJIGiecNOvMLIp5oJqVr8FU nd4hu4HJE=; b=C+qgsqtB5r/6rMU+HfsiAkgRIXm7HA2jqfrBme3ZMWLVzlnBGV L1OZtdwC/3Fd0Y3m+LEb0Qg/YB31KO1WTdoMufX+Ww9N8hTSYNFUzaZVpPyC4K9X kLfGp2zpAzLKu9aosBN7mlNbs5cGuvPZlrOQ218LddmfpX1NZmfd2LaI0= Received: from xuqianhui.ustc.edu.cn (unknown [114.214.230.12]) by mailimap2024 (Coremail) with SMTP id 3pYKCgCXGD11ltNqUG0EAA--.1829S3; Sat, 17 Oct 2026 23:38:29 +0800 (CST) From: Qianhui Xu To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Hans de Goede , Kieran Bingham , Laurent Pinchart Subject: [PATCH 1/2] ipa: libipa: add camera sensor helpers for GC08A8 and S5KJNS Date: Sat, 17 Oct 2026 23:38:28 +0800 Message-ID: <20261017153829.442320-2-xiaqinghuan@mail.ustc.edu.cn> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20261017153829.442320-1-xiaqinghuan@mail.ustc.edu.cn> References: <20261017153829.442320-1-xiaqinghuan@mail.ustc.edu.cn> MIME-Version: 1.0 X-CM-TRANSID: 3pYKCgCXGD11ltNqUG0EAA--.1829S3 X-Coremail-Antispam: 1UD129KBjvJXoW7tF15Wr18Gry5ZrWrAr1xAFb_yoW8tF4UpF nrCr4UKrykG3WfAasxJw10gw1rua93Xa1UKrsxAw4fZws3Gr97Wr4Skr1UW3WUArn5Xr4r ZF1qvFy5uF4kXFDanT9S1TB71UUUUUDqnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUBab7Iv0xC_tr1lb4IE77IF4wAFF20E14v26r4j6ryUM7CY07I2 0VC2zVCF04k26cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI 8067AKxVWUGwA2048vs2IY020Ec7CjxVAFwI0_Jrv_JF4l8cAvFVAK0II2c7xJM28CjxkF 64kEwVA0rcxSw2x7M28EF7xvwVC0I7IYx2IY67AKxVW7JVWDJwA2z4x0Y4vE2Ix0cI8IcV CY1x0267AKxVWxJVW8Jr1l84ACjcxK6I8E87Iv67AKxVW0oVCq3wA2z4x0Y4vEx4A2jsIE c7CjxVAFwI0_GcCE3s1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I 8CrVC2j2WlYx0E2Ix0cI8IcVAFwI0_Jrv_JF1lYx0Ex4A2jsIE14v26r1j6r4UMcvjeVCF s4IE7xkEbVWUJVW8JwACjcxG0xvY0x0EwIxGrwCY1x0262kKe7AKxVWUtVW8ZwCF04k20x vY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02F40E14v26r1j6r18MI8I 3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_JF0_Jw1lIxkGc2Ij64vIr41lIx AIcVC0I7IYx2IY67AKxVWUCVW8JwCI42IY6xIIjxv20xvEc7CjxVAFwI0_Gr0_Cr1lIxAI cVCF04k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14v26r4j6F4UMIIF0xvEx4A2js IEc7CjxVAFwI0_Gr0_Gr1UYxBIdaVFxhVjvjDU0xZFpf9x07j1iihUUUUU= X-CM-SenderInfo: 50ld1x5qjk3t3q6ptxnoox23vfohv3gofq/1tbiAREDB2rSe1QyUQBCsi 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" Add gain models and black levels for the two image sensors used by the Lenovo Legion Y700 Gen4 (TB322FC, SM8750): - gc08a8 (GalaxyCore, front): the V4L2 analogue gain control is the raw sensor gain code in 1/1024 steps, pedestal is 64 at 10 bits. - s5kjns (Samsung, rear): the V4L2 analogue gain control is the raw sensor gain code in 1/32 steps, pedestal is 64 at 10 bits. Without these helpers the software ISP interprets the V4L2 analogue gain code as a multiplier (for instance gain code 32 as 32x) and leaves the black level at zero, so the AGC converges to an almost black image. Keeping the raw gain code in the kernel drivers and describing it in libipa preserves the sensors' natural V4L2 control semantics. Signed-off-by: Qianhui Xu --- src/ipa/libipa/camera_sensor_helper.cpp | 32 +++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/ipa/libipa/camera_sensor_helper.cpp b/src/ipa/libipa/camera_sensor_helper.cpp index e3e3e53..0013d89 100644 --- a/src/ipa/libipa/camera_sensor_helper.cpp +++ b/src/ipa/libipa/camera_sensor_helper.cpp @@ -789,6 +789,38 @@ public: }; REGISTER_CAMERA_SENSOR_HELPER("ov13858", CameraSensorHelperOv13858) +class CameraSensorHelperGc08a8 : public CameraSensorHelper +{ +public: + CameraSensorHelperGc08a8() + { + /* + * GalaxyCore GC08A8: the V4L2 analogue gain control is the raw + * sensor gain code in 1/1024 steps (0x0400 == 1.0x). + * Pedestal is 64 at 10 bits (see vendor register defaults). + */ + blackLevel_ = 4096; + gain_ = AnalogueGainLinear{ 1, 0, 0, 1024 }; + } +}; +REGISTER_CAMERA_SENSOR_HELPER("gc08a8", CameraSensorHelperGc08a8) + +class CameraSensorHelperS5kjns : public CameraSensorHelper +{ +public: + CameraSensorHelperS5kjns() + { + /* + * Samsung S5KJNS: the V4L2 analogue gain control is the raw + * sensor gain code in 1/32 steps (0x0020 == 1.0x). + * Pedestal is 64 at 10 bits (see vendor register defaults). + */ + blackLevel_ = 4096; + gain_ = AnalogueGainLinear{ 1, 0, 0, 32 }; + } +}; +REGISTER_CAMERA_SENSOR_HELPER("s5kjns", CameraSensorHelperS5kjns) + class CameraSensorHelperVd55g1 : public CameraSensorHelper { public: From patchwork Sat Oct 17 15:38:29 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Qianhui Xu X-Patchwork-Id: 28499 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 BC47BC3305 for ; Sat, 17 Oct 2026 15:38:37 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 3ADE568E5A; Sat, 17 Oct 2026 17:38:35 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=mail.ustc.edu.cn header.i=@mail.ustc.edu.cn header.b="GIr1OhwQ"; dkim-atps=neutral Received: from ustc.edu.cn (smtp.ustc.edu.cn [202.38.64.46]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A191968E43 for ; Sat, 17 Oct 2026 17:38:31 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mail.ustc.edu.cn; s=dkim; h=Received:From:To:Cc:Subject:Date: Message-ID:In-Reply-To:References:MIME-Version: Content-Transfer-Encoding; bh=5qjyqHwQ0/XrT4hAgX6Rs/w7r0YgFLAkpr 7woY0qr3k=; b=GIr1OhwQyA4woWtcJIs09ZdarTKMKQOQ4hr6NFtnvxq+1X4kfv JwpwpWpy686jWJIQ/8qvK1tKoAVdyr+gv4C92vXI9IMJZ+yUV4LKHLyJ2KqRGf9m Cj5Ik0tBn+zzRTunkIuh2kkhDWq4Jb0O9VQYw1q8SHNeBK+TlwJB1h+ps= Received: from xuqianhui.ustc.edu.cn (unknown [114.214.230.12]) by mailimap2024 (Coremail) with SMTP id 3pYKCgCXGD11ltNqUG0EAA--.1829S4; Sat, 17 Oct 2026 23:38:29 +0800 (CST) From: Qianhui Xu To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Hans de Goede , Kieran Bingham , Laurent Pinchart Subject: [PATCH 2/2] ipa: simple: agc: make the exposure target tunable Date: Sat, 17 Oct 2026 23:38:29 +0800 Message-ID: <20261017153829.442320-3-xiaqinghuan@mail.ustc.edu.cn> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20261017153829.442320-1-xiaqinghuan@mail.ustc.edu.cn> References: <20261017153829.442320-1-xiaqinghuan@mail.ustc.edu.cn> MIME-Version: 1.0 X-CM-TRANSID: 3pYKCgCXGD11ltNqUG0EAA--.1829S4 X-Coremail-Antispam: 1UD129KBjvJXoWxGr1DWr48XFWxCr1rGr18AFb_yoWrXFykpr 4kAr98Ar48GFy2yr95ta97WF45Ja48Gr1SkwsYk39Yva9xXr1qkw42yrs09Fyaqr15AF47 ZF1DtFWUAr4DCFJanT9S1TB71UUUUUDqnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUBab7Iv0xC_tr1lb4IE77IF4wAFF20E14v26ryj6rWUM7CY07I2 0VC2zVCF04k26cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI 8067AKxVWUXwA2048vs2IY020Ec7CjxVAFwI0_JFI_Gr1l8cAvFVAK0II2c7xJM28CjxkF 64kEwVA0rcxSw2x7M28EF7xvwVC0I7IYx2IY67AKxVW7JVWDJwA2z4x0Y4vE2Ix0cI8IcV CY1x0267AKxVWxJVW8Jr1l84ACjcxK6I8E87Iv67AKxVW0oVCq3wA2z4x0Y4vEx4A2jsIE c7CjxVAFwI0_GcCE3s1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I 8CrVC2j2WlYx0E2Ix0cI8IcVAFwI0_Jrv_JF1lYx0Ex4A2jsIE14v26r1j6r4UMcvjeVCF s4IE7xkEbVWUJVW8JwACjcxG0xvY0x0EwIxGrwCY1x0262kKe7AKxVWUtVW8ZwCF04k20x vY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02F40E14v26r1j6r18MI8I 3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_JF0_Jw1lIxkGc2Ij64vIr41lIx AIcVC0I7IYx2IY67AKxVWUCVW8JwCI42IY6xIIjxv20xvEc7CjxVAFwI0_Gr0_Cr1lIxAI cVCF04k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14v26r4j6F4UMIIF0xvEx4A2js IEc7CjxVAFwI0_Gr0_Gr1UYxBIdaVFxhVjvjDU0xZFpf9x07jY38nUUUUU= X-CM-SenderInfo: 50ld1x5qjk3t3q6ptxnoox23vfohv3gofq/1tbiAREDB2rSe1QyUQBDsj 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 simple IPA AGC targets the middle of the histogram range, i.e. a mean sample value of 0.5. As the debayer step gamma-encodes its output (the default gamma is 2.2), such a target maps to roughly 73% of the full code range on output, which looks washed out and clips highlights in scenes with a high dynamic range. Allow platforms to override the target from the tuning file with a new "exposureTarget" parameter, expressed as a fraction of the histogram range. The default keeps the existing behaviour, so existing tuning files keep their meaning. Signed-off-by: Qianhui Xu --- src/ipa/simple/algorithms/agc.cpp | 24 +++++++++++++++++++----- src/ipa/simple/algorithms/agc.h | 4 ++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/ipa/simple/algorithms/agc.cpp b/src/ipa/simple/algorithms/agc.cpp index 2f7e040..b6e9d30 100644 --- a/src/ipa/simple/algorithms/agc.cpp +++ b/src/ipa/simple/algorithms/agc.cpp @@ -25,10 +25,11 @@ namespace ipa::soft::algorithms { static constexpr unsigned int kExposureBinsCount = 5; /* - * The exposure is optimal when the mean sample value of the histogram is - * in the middle of the range. + * The exposure is optimal when the mean sample value of the histogram matches + * the configured target. 0.5 (the middle of the range) is a bright default; + * sensors tuned for photographic output usually target a lower code value. */ -static constexpr float kExposureOptimal = kExposureBinsCount / 2.0; +static constexpr double kDefaultExposureTarget = 0.5; /* * This implements the hysteresis for the exposure adjustment. @@ -38,9 +39,21 @@ static constexpr float kExposureOptimal = kExposureBinsCount / 2.0; static constexpr float kExposureSatisfactory = 0.2; Agc::Agc() + : exposureTarget_(kDefaultExposureTarget) { } +int Agc::init([[maybe_unused]] IPAContext &context, const ValueNode &tuningData) +{ + const ValueNode &target = tuningData["exposureTarget"]; + + exposureTarget_ = target.get(kDefaultExposureTarget); + LOG(IPASoftExposure, Debug) + << "Exposure target " << exposureTarget_; + + return 0; +} + void Agc::updateExposure(IPAContext &context, IPAFrameContext &frameContext, double exposureMSV) { /* @@ -53,8 +66,9 @@ void Agc::updateExposure(IPAContext &context, IPAFrameContext &frameContext, dou int32_t &exposure = frameContext.sensor.exposure; double &again = frameContext.sensor.gain; + const double optimal = exposureTarget_ * kExposureBinsCount; - if (exposureMSV < kExposureOptimal - kExposureSatisfactory) { + if (exposureMSV < optimal - kExposureSatisfactory) { if (exposure < context.configuration.agc.exposureMax) { int32_t next = exposure * kExpNumeratorUp / kExpDenominator; if (next - exposure < 1) @@ -70,7 +84,7 @@ void Agc::updateExposure(IPAContext &context, IPAFrameContext &frameContext, dou } } - if (exposureMSV > kExposureOptimal + kExposureSatisfactory) { + if (exposureMSV > optimal + kExposureSatisfactory) { if (again > context.configuration.agc.again10) { double next = again * kExpNumeratorDown / kExpDenominator; if (again - next < context.configuration.agc.againMinStep) diff --git a/src/ipa/simple/algorithms/agc.h b/src/ipa/simple/algorithms/agc.h index 112d9f5..8d3d2f6 100644 --- a/src/ipa/simple/algorithms/agc.h +++ b/src/ipa/simple/algorithms/agc.h @@ -19,6 +19,8 @@ public: Agc(); ~Agc() = default; + int init(IPAContext &context, const ValueNode &tuningData) override; + void process(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, const SwIspStats *stats, @@ -26,6 +28,8 @@ public: private: void updateExposure(IPAContext &context, IPAFrameContext &frameContext, double exposureMSV); + + double exposureTarget_; }; } /* namespace ipa::soft::algorithms */