From patchwork Wed Aug 26 08:23:21 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?UsOzYmVydCBCb8W+aWs=?= X-Patchwork-Id: 28096 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 81E2AC333C for ; Wed, 26 Aug 2026 08:33:24 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6053E68435; Wed, 26 Aug 2026 10:33:23 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="O17G06BK"; dkim-atps=neutral Received: from mail-ej1-x635.google.com (mail-ej1-x635.google.com [IPv6:2a00:1450:4864:20::635]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D23106829C for ; Wed, 26 Aug 2026 10:23:31 +0200 (CEST) Received: by mail-ej1-x635.google.com with SMTP id a640c23a62f3a-c2529b3139fso30818166b.3 for ; Wed, 26 Aug 2026 01:23:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787732611; x=1788337411; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to:content-type; bh=u2vSYs2q8Fs/3CDo5cRlj1SpZ4/3f1Dy+5ESx5Pg+8U=; b=O17G06BK6+3SkmUe5SSCr01uh5J7OWMk8y6dGepv6RipUnfJSSGlQKWmwTSFWFU4c3 ncciy9f+L0c8+9N+iKFJfiAIZUOqxM4Kqt354S+B27bKYPpWeRBXDe1cWPNisqplgCpQ PMBJ+XWRdjq8ikRtsPX0QSvAiJcBLpNwcilRvuSkRrwboawvzNKQRzrNqsWufl2sKwNa vYZKPfbh+qUrJMR7jz7KGwro3mbo4CiRDkgqBbydWVrP7JJDkVwjlxI/M9DZtbKmwG8q IMlLNLal3AbMlUMIH33XnY/wAXm7wk+qZa6cSjZZG7iIOvTmXYuXIrpopPX+ndkD/jjf AKMQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787732611; x=1788337411; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=u2vSYs2q8Fs/3CDo5cRlj1SpZ4/3f1Dy+5ESx5Pg+8U=; b=SfLDCQ5cbKMDnbhLbK6Wq2rynixYQbwZb5mUVkqJ85Kuix55GPSRElAQEWrCi5tfvl TWaIfmrew2+NNmPz+AOp5tVLRxiUwZ13c/3LvrRRtmt5oI5pm5VpvSTLJPGlCtUk86jD P7HZZGyQ4CLUMfzYuW3MY6HbSG1yYymAfhqHoeAa77j60fLmfEm+OBqYnZA2n515fyzR MmV5KLItCuxyDeV6UXN8tdxdHRhk1HZMPtIUx5oew+LLKRHf98iS4AigpeIvvmNpC4Po RQmjoN81keTECoaNYqqj7diPKQt6jyofeHe3ww89YSJoh7Zbv4EgPIblTw/fTOj4ASWN vlAw== X-Gm-Message-State: AFuF++mvy+Swbs1LZuNTK9T/Ea9k4SCnqsLhDl6E+U54Nr+YmKLsTZB1 aoUmUKubkapwMl6snDFiwdXVV9UEYQsr3F7ytQ2qIRUzDrNYXr4CMp87ZlrywoS09xc= X-Gm-Gg: AR+sD12eI2TXvpLYNzjbLsPkzgQMmzqbcmnTbpxQJl1YoedOctLJD2jD/E/kwUtdLmb 86m8RhvtYNjizCiiprT5rwjjg0ktX1E2/kmS0vjdIBo1xrosYQbIxB5YiKdAOwx3OVwyJUyP2Hv 4jAqRWk8d378x8KQI5zMYJHElpjC/3rqP6qe9qSnQ3aC90TmoYpYQm/W0OG/kde/KcVA0Kkx+Sc 3nOpfn9EbTrBKcMKG6ZZbpkwpkWP6JmedqrCKzDwZaVaJqNXzXvnzz3nuPlpT2yMJCo+5duF3al 7Suhwwl5uS3v2XxQJYaWYMu1W3Vr5uAHHVRJvlF4vW4enrxXXDv+BbHxk5j8aRZ2WvuuMUs30/9 iFor7TF380QyefOu2aRXisCzLkOk75wRUXHYRvSLK6dH4EYUX1/GVBYT+wSX46lotaPqyddMu4p Q9rayi6H2B1JeVg4wWjuuCX/se3ouCj8j+B5v9gOIt4IGr9J4Q0YIpuKUR7mpZLa7FjHQWL5jD4 lN/BMJjEOuUyPEk4bGcB8CkpaKBXdSTpfn1AXmfDRsAGEdBqSLWeHp7CfRrag+J2svCIkwf93pD qsby7d1Tk0WtFcs= X-Received: by 2002:a17:906:ef0e:b0:c12:e178:9e68 with SMTP id a640c23a62f3a-c250c3292a1mr560002366b.19.1787732610929; Wed, 26 Aug 2026 01:23:30 -0700 (PDT) Received: from robert-83cx (static-dsl-191.87-197-115.telecom.sk. [87.197.115.191]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-c250a5d69a7sm554222766b.8.2026.08.26.01.23.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 26 Aug 2026 01:23:30 -0700 (PDT) From: Robert Bozik To: libcamera-devel@lists.libcamera.org Cc: Kieran Bingham , Milan Zamazal , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Hans de Goede , Robert Mader , Bryan O'Donoghue , Laurent Pinchart , Robert Bozik Subject: [PATCH 0/7] Software ISP: OV32C4 support, frame duration control, faster AGC with digital gain, temporal denoise Date: Wed, 26 Aug 2026 10:23:21 +0200 Message-ID: <20260826082328.24176-1-robertbozik@gmail.com> X-Mailer: git-send-email 2.53.0 MIME-Version: 1.0 X-Mailman-Approved-At: Wed, 26 Aug 2026 10:33:21 +0200 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" Hi, this series comes out of bringing up the OmniVision OV32C4 - the under-display camera of the Lenovo Yoga Slim 9 14ILL10, behind an Intel IPU7 - on libcamera's software ISP. The kernel driver is under review on linux-media [1]. The first two patches are specific to that sensor; the other five are software ISP and simple pipeline changes the sensor needed to be usable outside of good light, and they are meant to stand on their own. Patches 1-2 add the sensor to camera_sensor_properties and libipa's CameraSensorHelper. Both numbers in the helper were measured on the sensor rather than copied: the analogue gain is code/256 (ov13b10 and ov08x40 use the same register with /128, which does not hold for this part), and the black level is 4096, i.e. 64 at 10 bits, stable to one LSB across the whole gain range. The unit cell size comes from the vendor's product brief. Patch 3 implements FrameDurationLimits for the software ISP through the sensor's vertical blanking. The AGC lets the exposure grow up to the longest allowed frame and moves V4L2_CID_VBLANK along with it, so the frame rate only drops when the exposure actually needs it; VBLANK is written through DelayedControls ahead of the exposure so the driver can extend the exposure range first. FrameDuration is reported in the metadata. This relies on the driver calling __v4l2_ctrl_modify_range() on the exposure control when VBLANK changes, which is what the in-tree sensor drivers do. Patch 4 passes the controls given to Camera::start() through the simple pipeline handler to the software ISP IPA (they were dropped before), so that libcamerasrc framerate caps and PipeWire can set FrameDurationLimits at all. Patch 5 makes the AGC converge faster when far from its target (a ratio step of at most 2x per iteration, the existing proportional step near the target) and adds digital gain, applied in the ISP colour gains after black level subtraction once exposure and analogue gain are exhausted. It is bounded by a new maxDigitalGain tuning key, off by default, and reported as DigitalGain in the metadata. Patch 6 adds a maxFrameDuration tuning key that bounds the default frame duration for applications that never set FrameDurationLimits (PipeWire 1.6.2 does not), so a sensor with a long VBLANK range does not fall to sub-1 fps in the dark by default. An explicit FrameDurationLimits still allows the full range. Patch 7 adds temporal noise reduction to the GPU debayer: a pass before demosaicing blends the raw frame with the filtered history, with motion detected per 4x4 block against a threshold derived from a sensor noise model (variance = noiseSlope * signal + noiseFloor), configured through a new Denoise algorithm in the tuning file. The CPU debayer ignores the parameters for now. Everything was tested on the machine above against master 35c137c2 with cam, gstreamer and PipeWire: exposure and frame length were verified linear on the raw data up to 306 ms per frame, a 30 -> 15 fps request moves VBLANK from 774 to 3389 lines, and the AGC settles in about a second where it previously did not settle at all. Tooling disclosure: this series was written with the help of an AI coding assistant (Claude, Anthropic; claude-opus-5 and claude-fable-5) in an extended interactive session. The assistant drafted the code and this cover letter from my descriptions and measurements; I ran every test, reviewed all of the code and take responsibility for it. I have not added Assisted-by trailers to the commits because utils/checkstyle.py rejects that key; I am happy to add them if you would rather have them. The sensor's tuning file is deliberately not part of this series: its colour matrices are derived from the vendor's calibration data and I have not established whether they can be redistributed. [1] https://lore.kernel.org/linux-media/20260826072002.14357-1-robertbozik@gmail.com/ Thanks, Robert Robert Bozik (7): libcamera: camera_sensor_properties: Add OV32C4 ipa: libipa: camera_sensor_helper: Add OV32C4 ipa: softisp: Support FrameDurationLimits through vertical blanking pipeline: simple: Pass the startup controls to the software ISP IPA ipa: softisp: Converge faster and add digital gain to the AGC ipa: softisp: Let the tuning file bound the default frame duration libcamera: software_isp: Add temporal noise reduction to the GPU debayer .../internal/software_isp/debayer_params.h | 14 + .../internal/software_isp/software_isp.h | 2 +- include/libcamera/ipa/softisp.mojom | 2 +- src/ipa/libipa/camera_sensor_helper.cpp | 17 + src/ipa/softisp/algorithms/agc.cpp | 295 +++++++++++++++++- src/ipa/softisp/algorithms/agc.h | 18 ++ src/ipa/softisp/algorithms/denoise.cpp | 89 ++++++ src/ipa/softisp/algorithms/denoise.h | 36 +++ src/ipa/softisp/algorithms/meson.build | 1 + src/ipa/softisp/ipa_context.h | 25 ++ src/ipa/softisp/softisp.cpp | 60 +++- src/libcamera/pipeline/simple/simple.cpp | 24 +- .../sensor/camera_sensor_properties.cpp | 5 + src/libcamera/shaders/meson.build | 1 + src/libcamera/shaders/temporal.frag | 131 ++++++++ src/libcamera/software_isp/debayer.cpp | 13 + src/libcamera/software_isp/debayer_egl.cpp | 172 ++++++++++ src/libcamera/software_isp/debayer_egl.h | 23 ++ src/libcamera/software_isp/software_isp.cpp | 5 +- 19 files changed, 907 insertions(+), 26 deletions(-) create mode 100644 src/ipa/softisp/algorithms/denoise.cpp create mode 100644 src/ipa/softisp/algorithms/denoise.h create mode 100644 src/libcamera/shaders/temporal.frag base-commit: 35c137c2f3e7104b96702c649344fafc91d8e233