From patchwork Mon Sep 14 14:02:31 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 28262 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 8BFDCC3200 for ; Mon, 14 Sep 2026 14:04:18 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 358EC686D4; Mon, 14 Sep 2026 16:04:18 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="AkJscySh"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6960D686A1 for ; Mon, 14 Sep 2026 16:04:16 +0200 (CEST) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:a279:75fa:1f6c:7f40]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 6DFEA512; Mon, 14 Sep 2026 16:02:36 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1789394556; bh=lP52oR/pts54AJEJyGnL8kjz8nhrdRXCt4NL3sfE++k=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=AkJscyShW15lseSw/yFIcdUXI64i3nddTzjO2VJ/s01KJkdv5HBaijvZLSG/OAxcV emYizOiiWM/pwwEYcSIW/He6mJGacCxwAl5YUiuM4wJZgzEXXxdjzQB9rffzhcJgmv V2xvexcooieEF/4/+n/uqTEi/t3s0+azHRyU3Ync= From: Stefan Klug To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug , Paul Elder Subject: [PATCH v3 18/41] libipa: agc: Process frame duration at the right time Date: Mon, 14 Sep 2026 16:02:31 +0200 Message-ID: <20260914140309.3354666-19-stefan.klug@ideasonboard.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260914140309.3354666-1-stefan.klug@ideasonboard.com> References: <20260914140309.3354666-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 v3: - Rebased on top of libipa agc rework Changes in v2: - Squashed with next patch - Collected tag --- src/ipa/libipa/agc.cpp | 25 ++++++++++++++----------- src/ipa/libipa/agc.h | 3 +-- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/ipa/libipa/agc.cpp b/src/ipa/libipa/agc.cpp index 77e5f1370e9c..9016e5f68ab7 100644 --- a/src/ipa/libipa/agc.cpp +++ b/src/ipa/libipa/agc.cpp @@ -646,6 +646,9 @@ void AgcAlgorithm::queueRequest(const agc::Session &session, agc::ActiveState &s } frameContext.minFrameDuration = state.minFrameDuration; frameContext.maxFrameDuration = state.maxFrameDuration; + + /* V-blank needs to be valid for the start controls handling. Update it. */ + processFrameDuration(session, frameContext); } /** @@ -664,7 +667,7 @@ void AgcAlgorithm::queueRequest(const agc::Session &session, agc::ActiveState &s * * \sa Algorithm::prepare() */ -void AgcAlgorithm::prepare([[maybe_unused]] const agc::Session &session, agc::ActiveState &state, +void AgcAlgorithm::prepare(const agc::Session &session, agc::ActiveState &state, agc::FrameContext &frameContext) { uint32_t activeAutoExposure = state.automatic.exposure; @@ -696,6 +699,12 @@ void AgcAlgorithm::prepare([[maybe_unused]] const agc::Session &session, agc::Ac } frameContext.yTarget = state.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(session, frameContext); } /** @@ -726,7 +735,6 @@ void AgcAlgorithm::process(const agc::Session &session, agc::ActiveState &state, ControlList &metadata) { if (!params) { - processFrameDuration(session, frameContext, frameContext.minFrameDuration); fillMetadata(session, frameContext, metadata); return; } @@ -830,13 +838,6 @@ void AgcAlgorithm::process(const agc::Session &session, agc::ActiveState &state, << "quantization-gain: " << state.automatic.quantizationGain << ", " << "digital-gain: " << state.automatic.digitalGain; - /* - * Expand the target frame duration so that we do not run faster than - * the minimum frame duration when we have short exposures. - */ - processFrameDuration(session, frameContext, - std::max(frameContext.minFrameDuration, newExposureTime)); - fillMetadata(session, frameContext, metadata); } @@ -849,10 +850,12 @@ void AgcAlgorithm::process(const agc::Session &session, agc::ActiveState &state, * Compute and populate vblank from the target frame duration. */ void AgcAlgorithm::processFrameDuration(const agc::Session &session, - agc::FrameContext &frameContext, - utils::Duration frameDuration) + agc::FrameContext &frameContext) { const utils::Duration &lineDuration = session.lineDuration; + utils::Duration frameDuration = frameContext.exposure * lineDuration; + + frameDuration = std::max(frameDuration, frameContext.minFrameDuration); frameContext.vblank = (frameDuration / lineDuration) - session.sensor.outputSize.height; diff --git a/src/ipa/libipa/agc.h b/src/ipa/libipa/agc.h index 9bdda8c72213..4914c9cee24b 100644 --- a/src/ipa/libipa/agc.h +++ b/src/ipa/libipa/agc.h @@ -155,8 +155,7 @@ public: private: void processFrameDuration(const agc::Session &session, - agc::FrameContext &frameContext, - utils::Duration frameDuration); + agc::FrameContext &frameContext); void fillMetadata(const agc::Session &session, const agc::FrameContext &frameContext, ControlList &metadata);