From patchwork Tue Aug 25 12:06:30 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Emilio Miranda X-Patchwork-Id: 28081 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 43F22C333E for ; Tue, 25 Aug 2026 12:06:41 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5343D683F2; Tue, 25 Aug 2026 14:06:40 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="az+EWjAb"; dkim-atps=neutral Received: from mail-wr1-x42e.google.com (mail-wr1-x42e.google.com [IPv6:2a00:1450:4864:20::42e]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A300D6834C for ; Tue, 25 Aug 2026 14:06:38 +0200 (CEST) Received: by mail-wr1-x42e.google.com with SMTP id ffacd0b85a97d-47fe89fb333so2143264f8f.3 for ; Tue, 25 Aug 2026 05:06:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787659598; x=1788264398; darn=lists.libcamera.org; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to:content-type; bh=Va4JLibvCW8YwkdMVZxYeNP7yYzg4WFg6P10y6MeKq4=; b=az+EWjAb0zJ/Bl/fC7U/Z3feF1go8vFUKQSrdJu1DsBdVotB5ORdWD7Kza9pbPKcZL swWl/K8uMhQDPBJQ7ojFn36lD8zkxX95y1BIKN4cJX3PcP1WF3OGOzu4r1VLifRIXKsB Zy1+D2M/FGidGNpmBFGTCfQSVA/R6Somg7DiLbLORG/Ko71h3h7WmUYZIumiut/KhC8f CvUS7y6msE6ZfBmidXVIwSF/WA0xfuerIBJthaFl0At2hMZBOAtgdrlAixt4vHdmLBQ5 x7tQxAFrlPp9ARzZkTgfJUf8+W6dcvKtpLVgBzuv90gNQVM5BqR4dMhKVp845V72cJjg Fcag== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787659598; x=1788264398; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to: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=Va4JLibvCW8YwkdMVZxYeNP7yYzg4WFg6P10y6MeKq4=; b=oMleab1jbkuk9kL6TLEGAMi9EQ3PtreknlReS4jLX+Hb12+gDG08j2eYyRev+FIZVa VXWtBxa7lxwaixNkAqecHePFa3zBE6YMde30nbqfTsscmwWKt5/IpoAqnk9FdEWVweSL X0m2xQgkqNLYts20XlGJiT+LD4wl/Z75TfOPBT/sR+I2FmUVqK/JVyRtVxOiEkeCIpWW LJW5PAKyhVqmU1KS5z9AwWcAJ6V8KqBk+SK08RDUtJD72QodrbEdelgT95gT0YgUMFqe yLnS3aB+uitUEcHp/YxDZXY2lTgPO1RnG90vm0N5IsqahztXvHW2SsaWad3o7uCdU3ws zl9A== X-Gm-Message-State: AFuF++mxPS/M/1trpsyvX0gG2ur5vRalOv+0lp98VcMPZL/b+7SDIyef 9iySeRU9DugWEZg36x7/rAWWit+IaYg52DPJ0x7NvjZW9nWRyVmrHtqLX7eNLQ== X-Gm-Gg: AR+sD11Re2c1pS5V0kL8ohmWZN/4DE6rBj+AcmzBCslWe0ArMIm3uu9t3pdxj9dxefi 2WCkTVyosb0UBlmkzFubQC+F7qSTpeJyYjX5D/ytNuU7qYsfV3iA3giWj48fiGOLusLDfjb7Vz9 birVPuVjKtcfK/UEKEpTb4i8kggSzFAO2JWgXbjUJt/6WYPACSla3FHZqx93VQz+Usi4CjP4m/u RImcHaypji77VSdrH1RO/BnwqWBoHwf82bRGKEK2aldoDvnfZlZI65o6diBMy0PcO18r0X7ktzH 7oxpBcnKwGtAohDQ0sl+WQNELsavO7oT6IN1kAWChoyUnhIAAgT7Yz+rV90wFGueMPSUYfV4g3/ 12yO6KsjP7SmpFO8+QQr4vu5exPoLEr4p98YiYXQs2QIJafOx3cipmspy+Bm/ZGdtp9zPFzN57f 7sfrjVMAsIbDIejeKgVfb+igFU7AAmBznpGMrRGMrmuh3LmnjFYcbB3Fas+yT/IhHX54q1ABB3l JB1bIa6iYW0XA/oWik= X-Received: by 2002:a05:6000:2412:b0:47f:9ac6:ca60 with SMTP id ffacd0b85a97d-482c0b05a84mr44418960f8f.0.1787659597814; Tue, 25 Aug 2026 05:06:37 -0700 (PDT) Received: from xps9315.home ([90.165.155.167]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-482c9c086fbsm11324366f8f.26.2026.08.25.05.06.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 25 Aug 2026 05:06:37 -0700 (PDT) From: Emilio Miranda To: libcamera-devel@lists.libcamera.org Cc: barnabas.pocze@ideasonboard.com, robert.mader@collabora.com, devve.3@gmail.com, mzamazal@redhat.com, kieran.bingham@ideasonboard.com, sjm@opendigital.cc Subject: [PATCH v2] ipa: simple: Derive AGC minimum gain step from sensor granularity Date: Tue, 25 Aug 2026 14:06:30 +0200 Message-ID: <20260825120632.167143-1-gemilio@gmail.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260825110209.125104-2-gemilio@gmail.com> References: <20260825110209.125104-2-gemilio@gmail.com> MIME-Version: 1.0 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 minimum gain step is computed as 1% of the sensor's gain range. For a sensor with a wide gain range that is far larger than the hardware can resolve: the OV01A10 spans 1-63.9961, giving a step of 0.629961, which is 63% at unity gain where the sensor resolves 1/256 = 0.0039. updateExposure() substitutes againMinStep whenever the proportional correction is smaller than it. Once the exposure saturates and gain is the only remaining control, the AGC therefore applies a 63% change every time it computes a 2% one, and never settles: again 1.00000 exposureMSV 1.99 error +0.51 factor 1.020 -> 1.62996 again 1.62996 exposureMSV 2.90 error -0.41 factor 0.984 -> 1.00000 That is 0.7 EV of brightness flicker at frame rate, observed on a Dell XPS 13 9315 (IPU6, simple pipeline and software ISP). This is not specific to one sensor. Without a CameraSensorHelper the gain values are raw register codes, where a step of 1.0 is by definition the smallest possible change in gain; adding a helper switches the units to real multipliers, and 1% of the range then bears no relation to what the sensor can resolve. Any sensor with a wide gain range is exposed to this once it gains a helper. Sample the step at both ends of the gain range and take the smaller one, so that non-uniform gain models are covered as well. This yields 0.00390625 for the OV01A10, and the gain then tracks continuously instead of alternating between two values. Link: https://bugzilla.redhat.com/show_bug.cgi?id=2483190 Suggested-by: Barnabás Pőcze Signed-off-by: Emilio Miranda --- Changes since v1: - use std::abs, and reflow the expression as suggested - reword the "is harmless" sentence; drop "most of a stop" - Link: trailer instead of the inline URL Base and testing unchanged from v1: v0.7.2, tested on the OV01A10 at 1280x720 against an unpatched build in the same scene. Disclosure: I investigated this with an AI assistant (Claude). The measurements are from my own hardware and I have verified them myself. src/ipa/simple/soft_simple.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) base-commit: 191e202178f02430b5942397c70d215cdd2056fa diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp index 629e1a32d..8bffd2a44 100644 --- a/src/ipa/simple/soft_simple.cpp +++ b/src/ipa/simple/soft_simple.cpp @@ -6,6 +6,7 @@ */ #include +#include #include #include @@ -228,10 +229,21 @@ int IPASoftSimple::configure(const IPAConfigInfo &configInfo) context_.configuration.agc.againMin = camHelper_->gain(againMin); context_.configuration.agc.againMax = camHelper_->gain(againMax); context_.configuration.agc.again10 = std::max(context_.configuration.agc.againMin, 1.0); - context_.configuration.agc.againMinStep = - (context_.configuration.agc.againMax - - context_.configuration.agc.againMin) / - 100.0; + /* + * The minimum gain step must reflect what the sensor can + * actually resolve. Deriving it from a fraction of the gain + * range yields a huge step for sensors with a wide range: the + * OV01A10 spans 1-63.9961, giving 0.63 at unity gain where the + * hardware resolves 1/256. The AGC can then make no correction + * smaller than 63%, and oscillates around the target once the + * exposure saturates and gain is the only remaining control. + * + * Sample the step at both ends of the range and take the + * smaller one, so that non-uniform gain models are covered. + */ + context_.configuration.agc.againMinStep = std::min( + std::abs(camHelper_->gain(againMin + 1) - camHelper_->gain(againMin)), + std::abs(camHelper_->gain(againMax) - camHelper_->gain(againMax - 1))); if (camHelper_->blackLevel().has_value()) { /* * The black level from camHelper_ is a 16 bit value, software ISP