From patchwork Wed Mar 25 15:13:48 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 26358 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 CF490C3301 for ; Wed, 25 Mar 2026 15:15:27 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5188162BDE; Wed, 25 Mar 2026 16:15:27 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="M0/DvBoK"; 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 165C462B91 for ; Wed, 25 Mar 2026 16:15:26 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:b16a:5ed9:4ada:a95a]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 22B271AFB; Wed, 25 Mar 2026 16:14:08 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1774451648; bh=oAi/9LLTASwPFAIPya7rkzLto5JItlOEGT7r+u/Ulgk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=M0/DvBoKzdTZnsG9wTYfejBBrjN3UuzRjviN/QyW8BePmzd+bA2o5l7W0/folNx/8 462bhuRcmgXIKfwogqR23/eKI51hky4CUFzjZccZ5sU54j5FPHJ2HV2fzMe1FI0yaE ZpOq2cx+eOuVIEY1vNyFtsMaE8g859yTsPxhe7rs= From: Stefan Klug To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug , Paul Elder Subject: [PATCH v2 16/32] ipa: rkisp1: agc: Process frame duration at the right time Date: Wed, 25 Mar 2026 16:13:48 +0100 Message-ID: <20260325151416.2114564-17-stefan.klug@ideasonboard.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260325151416.2114564-1-stefan.klug@ideasonboard.com> References: <20260325151416.2114564-1-stefan.klug@ideasonboard.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 frame duration and vblank should not be calculated during process() but within prepare(), where the data for that frame get's computed. In raw mode, process is not called, so also update it in queueRequest(). Signed-off-by: Stefan Klug Reviewed-by: Paul Elder --- Changes in v2: - Squashed with next patch - Collected tag --- src/ipa/rkisp1/algorithms/agc.cpp | 23 +++++++++++++---------- src/ipa/rkisp1/algorithms/agc.h | 3 +-- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp index fd227e2129ed..4a7b8988221d 100644 --- a/src/ipa/rkisp1/algorithms/agc.cpp +++ b/src/ipa/rkisp1/algorithms/agc.cpp @@ -340,6 +340,9 @@ void Agc::queueRequest(IPAContext &context, } frameContext.agc.minFrameDuration = agc.minFrameDuration; frameContext.agc.maxFrameDuration = agc.maxFrameDuration; + + /* V-blank needs to be valid for the start controls handling. Update it. */ + processFrameDuration(context, frameContext); } /** @@ -383,6 +386,12 @@ void Agc::prepare(IPAContext &context, const uint32_t frame, frameContext.agc.yTarget = context.activeState.agc.automatic.yTarget; + /* + * Expand the target frame duration so that we do not run faster than + * the minimum frame duration when we have short exposures. + */ + processFrameDuration(context, frameContext); + if (frame > 0 && !frameContext.agc.updateMetering) return; @@ -511,11 +520,13 @@ double Agc::estimateLuminance(double gain) const * Compute and populate vblank from the target frame duration. */ void Agc::processFrameDuration(IPAContext &context, - IPAFrameContext &frameContext, - utils::Duration frameDuration) + IPAFrameContext &frameContext) { IPACameraSensorInfo &sensorInfo = context.sensorInfo; utils::Duration lineDuration = context.configuration.sensor.lineDuration; + utils::Duration frameDuration = frameContext.agc.exposure * lineDuration; + + frameDuration = std::max(frameDuration, frameContext.agc.minFrameDuration); frameContext.agc.vblank = (frameDuration / lineDuration) - sensorInfo.outputSize.height; @@ -539,8 +550,6 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame, ControlList &metadata) { if (!stats) { - processFrameDuration(context, frameContext, - frameContext.agc.minFrameDuration); fillMetadata(context, frameContext, metadata); return; } @@ -642,12 +651,6 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame, activeState.agc.automatic.gain = aGain; activeState.agc.automatic.quantizationGain = qGain; activeState.agc.automatic.yTarget = effectiveYTarget(); - /* - * Expand the target frame duration so that we do not run faster than - * the minimum frame duration when we have short exposures. - */ - processFrameDuration(context, frameContext, - std::max(frameContext.agc.minFrameDuration, newExposureTime)); fillMetadata(context, frameContext, metadata); expMeans_ = {}; diff --git a/src/ipa/rkisp1/algorithms/agc.h b/src/ipa/rkisp1/algorithms/agc.h index 7867eed9c4e3..4432711f43af 100644 --- a/src/ipa/rkisp1/algorithms/agc.h +++ b/src/ipa/rkisp1/algorithms/agc.h @@ -51,8 +51,7 @@ private: ControlList &metadata); double estimateLuminance(double gain) const override; void processFrameDuration(IPAContext &context, - IPAFrameContext &frameContext, - utils::Duration frameDuration); + IPAFrameContext &frameContext); Span expMeans_; Span weights_;