From patchwork Fri Oct 17 09:00:05 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 24694 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 EE99FBE080 for ; Fri, 17 Oct 2025 09:00:20 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E853F606AD; Fri, 17 Oct 2025 11:00:17 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="dPwWkDM5"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0F4CB6069F for ; Fri, 17 Oct 2025 11:00:16 +0200 (CEST) Received: from [192.168.1.182] (93-46-82-201.ip106.fastwebnet.it [93.46.82.201]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 90C161574; Fri, 17 Oct 2025 10:58:35 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1760691515; bh=ivkONw8MteuR+PHl4uEkAsL1BGyqPJPYtaLN60opCDY=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=dPwWkDM59niwrMM6u1rg46GAkmkvZEnhjvc889blIsnIyjmWWKdDwz64Nxj1ONPVY Nf4vymmuqBgpKBNAIkDfYw2FNaDSERFPfq4T8cTbHAzicxwHFNJC8x8mtaZo+4pZtV Pk99zB/or/z4xi2Zf5wGf4aNz94liFYL3Sbt9DbI= From: Jacopo Mondi Date: Fri, 17 Oct 2025 11:00:05 +0200 Subject: [PATCH 1/3] ipa: rkisp1: Update exposure limits on vblank change MIME-Version: 1.0 Message-Id: <20251017-exposure-limits-v1-1-6288cd86e719@ideasonboard.com> References: <20251017-exposure-limits-v1-0-6288cd86e719@ideasonboard.com> In-Reply-To: <20251017-exposure-limits-v1-0-6288cd86e719@ideasonboard.com> To: =?utf-8?q?Niklas_S=C3=B6derlund?= , libcamera-devel@lists.libcamera.org Cc: Jacopo Mondi X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=4625; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=ivkONw8MteuR+PHl4uEkAsL1BGyqPJPYtaLN60opCDY=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBo8gWefIr52rmMDCzttbcJF4HrjIZPSbvc46TMw 7gOiTgjmvyJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCaPIFngAKCRByNAaPFqFW PCkxD/9yGtj8x8o3TFHCHJyw5E3u76p5X9wmpO4V3fOOWBTKKsdapn/Fhs+0bv7Jq2Lw4HvO3CQ ZbKBuH9YjDLN6IeR9rT71xYQxFiM2exYmcLYT/uFCa/J90LE5BN9sKTm4/1J8fguYgb/+dFl+G0 gnEiWjqgoiyzuaKHo28TQzmpmFm4b7zw+N4KpnUrblb2CgeIHDUvLSc6yQR3Jc6EZCrwuSyJfLA HUaXZk+c8SE78OrqySbHPPztcfqgJLmjxsLRdJBG70t14Y1TcHtQSa+05LSfcg6MOD7s3YsjYEs UwgaatPLVwHMBLHYWdXnv03lfNkJiUSm9YzgzPxDjc7tACdVop7nkpjdtLXuHiqd05EK7TownzJ 4daJ+0PJ4Ig9YV7gx3i4Vi3K2u2Dmj/SnrhMIBxT6L1dGcWMDDrRbeSN62mEaejfUWG3iHiRa9Y vCCKQvnHPvSW9CwdfuHI4spKyZuLri/RkMFZddhSQ81Ro9Can4vO+q04k464g9a2I94B5S7dgdU mUe/dx5BMVxoOPqajaR80ac9eGBayOGdJ/68DnAtTcv36fJiLpEaRwRuyjNUyR4uQ48yf6jJIFR t2PI/4BA6q4rEmGTUR+cCEsb9JJ/KrtdileEYCMhjsSjk4Ts/lU9/ZOUt0+/u0untRPv0pz9Hjb CH45Yfvta/Al9aA== X-Developer-Key: i=jacopo.mondi@ideasonboard.com; a=openpgp; fpr=72392EDC88144A65C701EA9BA5826A2587AD026B 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 AGC algorithm implementation of the RkISP1 IPA is implemented deriving the generic AgcMeanLuminance class, which limits the achievable exposure time using a maxExposureTime parameter provided by the IPA module. The RkISP1 IPA fetches the maxExposureTime value from the IPAContext sensor.maxExposureTime value, which is initialized at IPA init() and configure() time, but never updated later on, effectively limiting the achievable exposure time to the frame duration programmed at startup time. Whenever the frame duration is changed, the maximum exposure time should change accordingly, but in the current implementation this doesn't happen. Fix this by updating the sensor.maxExposureTime value when a new set of controls is sent to the pipeline handler. Store the current VBLANK value in the IPAContext by replacing 'defVBlank' which is never used and use it to detect changes in the blanking value. Whenever the blanking changes, update the maximum exposure limit accordingly. As reported in a comment in the code, even if the new sensor controls will be programmed in the sensor with a delay of a few frames on the pipeline handler side, the limits for the algorithms should be updated immediately. Signed-off-by: Jacopo Mondi --- src/ipa/rkisp1/ipa_context.h | 2 +- src/ipa/rkisp1/rkisp1.cpp | 31 ++++++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h index f85a130d9c23dba7987f388e395239e4b141d776..af66a749052bc82bbbe7fbb0c4626f2422700926 100644 --- a/src/ipa/rkisp1/ipa_context.h +++ b/src/ipa/rkisp1/ipa_context.h @@ -65,7 +65,7 @@ struct IPASessionConfiguration { double minAnalogueGain; double maxAnalogueGain; - int32_t defVBlank; + unsigned int vBlank; utils::Duration lineDuration; Size size; } sensor; diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp index fa22bfc349043002345d275b11a60ac983e329d7..54bd1434e0f4e34834beb1f9e9c39b77590f8b34 100644 --- a/src/ipa/rkisp1/rkisp1.cpp +++ b/src/ipa/rkisp1/rkisp1.cpp @@ -250,7 +250,7 @@ int IPARkISP1::configure(const IPAConfigInfo &ipaConfig, const IPACameraSensorInfo &info = ipaConfig.sensorInfo; const ControlInfo vBlank = sensorControls_.find(V4L2_CID_VBLANK)->second; - context_.configuration.sensor.defVBlank = vBlank.def().get(); + context_.configuration.sensor.vBlank = vBlank.def().get(); context_.configuration.sensor.size = info.outputSize; context_.configuration.sensor.lineDuration = info.minLineLength * 1.0s / info.pixelRate; @@ -261,8 +261,6 @@ int IPARkISP1::configure(const IPAConfigInfo &ipaConfig, * When the AGC computes the new exposure values for a frame, it needs * to know the limits for exposure time and analogue gain. As it depends * on the sensor, update it with the controls. - * - * \todo take VBLANK into account for maximum exposure time */ context_.configuration.sensor.minExposureTime = minExposure * context_.configuration.sensor.lineDuration; @@ -457,6 +455,33 @@ void IPARkISP1::setControls(unsigned int frame) uint32_t gain = context_.camHelper->gainCode(frameContext.agc.gain); uint32_t vblank = frameContext.agc.vblank; + /* + * Update the exposure limits if vblank has changed. Even if the controls + * will actually be applied to the sensor with some frames of latency + * by DelayedControls, all the algorithms calculations from now on should + * use the new limits. + * + * \todo Sensors usually have a margin that limits the max exposure to + * be shorter by the full frame length: + * + * (max_exposure_lines = height + vblank - margin) + * + * As the margin is a sensor-specific parameter either: + * - Ignore the margin and rely on the driver clamping the exposure + * value correctly + * - Defer to the sensor helpers by creating an exposure() function that + * subtract the margin from the frame length + * + * For the time being ignore the margins and rely on the driver doing + * the adjustment. + */ + if (vblank != context_.configuration.sensor.vBlank) { + context_.configuration.sensor.vBlank = vblank; + context_.configuration.sensor.maxExposureTime = + (vblank + context_.configuration.sensor.size.height) * + context_.configuration.sensor.lineDuration; + } + LOG(IPARkISP1, Debug) << "Set controls for frame " << frame << ": exposure " << exposure << ", gain " << frameContext.agc.gain << ", vblank " << vblank;