From patchwork Fri May 8 12:57:41 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Plowman X-Patchwork-Id: 26691 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 D5796BDCBD for ; Fri, 8 May 2026 13:08:11 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 1D26F6301A; Fri, 8 May 2026 15:08:10 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="J/06+Mj+"; dkim-atps=neutral Received: from mail-wm1-x334.google.com (mail-wm1-x334.google.com [IPv6:2a00:1450:4864:20::334]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B67DD62FE1 for ; Fri, 8 May 2026 15:08:07 +0200 (CEST) Received: by mail-wm1-x334.google.com with SMTP id 5b1f17b1804b1-48a7fe4f40bso21547685e9.0 for ; Fri, 08 May 2026 06:08:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1778245687; x=1778850487; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=B/6c4x6aPmSj4hSBbdqWEJNfL9gt9CXnVpTwIUpnx7A=; b=J/06+Mj+lT+FyhgOldADVQqllQW+b3fxVGBvhhfRtMOxm91OOUILYWcMNmG7Y/2vDG NAHizb8RmlXY0k8GALU2ZWiskh2n5/CxAYqxQlY6sPr5n7WDjxfwYhSBuaLi33ih48Zi CHmgV8rJnhWuKRW41Jb0kUdP3/gFbIoKOFTydHj5HrWM7j6T3QM2SPK5JzYJUdTT3km7 TqH/icAW+348EiIu2kaZD3UiXcjYtxQDLA+IAYkSzG72hQ8Up62107jqxxrLcbR+/0pJ QyXqReCD1mrACbDgCalOwBAWVPCS4HRX39UVeBCTHkJOY2BZv5xnCnqWd2I2jS1s1r02 vW7Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778245687; x=1778850487; h=content-transfer-encoding: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; bh=B/6c4x6aPmSj4hSBbdqWEJNfL9gt9CXnVpTwIUpnx7A=; b=QNoBzCAXToqvVCrxoKQwlACRhpRNv17s2elMXfokRtBj03kCvJ+CSGE5FYuc3hCeKO jDVtbm9H0FIladqGICrFsh9nor13cAz4oRc3tDaYIMx3EP5qSrBZCc2Wlk1iy1jKt+k4 c49KbVcKNZ16QnWaEuz/uU+JQtA9uREzxTNZjxL98thNxfR0ocPSdkByFV0ZLS3M77QM XWq5Z8NKxwdPFK+xLGYrzkOKBbee0CSAYHlL+yEhQl62KdFXwgp79lieAIUbecrnyzeG X6ITJ/Eorvt04GE3Yt/0p8LsX4ZeVFJi6eb3lCRfX3PoKtsTTlFCJgsqT1ziVczBI++7 jklw== X-Gm-Message-State: AOJu0YxVR9XKLkbXlrgYK+hT+NJUOIIzTmxF26o6re672lIQVPsAqkJa tQUHZU5LFyiMwA2JBlU0F+My2muUYQNqLNgZZTk6faRWPX2N0S0mIxLpyPTRjikVRJwnThMmKjk lCafR X-Gm-Gg: AeBDiets+FT0lpg2L3U8ukt4bkyNEuWip+9bYdvlRH1YLAOuG0yAPcat8IwaeLfNDTL k99WdDUJnh9eIb1XVxNCSw/Xbup86XVR3wY20KnFgji4zr+GtnlIcMs306SRjY+6llFjy6xFIdq rxUsaoS0m04nrU6u2T8nqDQA0f2px0X+9BO1//P1ayQ52gsHsd9tKG2JKUoYFXN7LnfXJI8/Dxz 21kEJ3qM8LT/lK4yoIJ9ATuNyVzwoW1BEJE816iUmXJd8b0lEM7AvqJYKmBJHw54h9p+52EKQsf tDPMCk3I0gD4MNnWnXNr2cgkeB+K4IcUeHYTl+SX7NYZGlTRCVk1F0+wUrUH7nCmzQdFBYEC/1O UoOmyURzY1M+bo+l1Mm8QyKaMc3IJ2ZBZ0ZUsFAs4WXQeqMGzeH9DXhZcAGZ8jYTAVHFHzzqG28 Z70NqzQLUiU0anNg901b9CFhI3L1nFleEJ9XSiSZKBvfDuxthI9PPLi3CD0hiV1IZOdwMLjEEnr jkpsClSQg9diroKA9oIT661m2HTgbHo/vRjAw== X-Received: by 2002:a05:600d:d:b0:489:1ff5:edda with SMTP id 5b1f17b1804b1-48e51e08240mr169742525e9.6.1778245686903; Fri, 08 May 2026 06:08:06 -0700 (PDT) Received: from localhost.localdomain ([2a06:61c0:f337:0:9c1f:b517:931a:3b19]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-48e68f5d9b5sm34044905e9.15.2026.05.08.06.08.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 08 May 2026 06:08:06 -0700 (PDT) From: David Plowman To: libcamera-devel@lists.libcamera.org Cc: David Plowman , Naushir Patuck , Jacopo Mondi Subject: [PATCH v5 1/3] pipeline: rpi: Simplify delayed controls Date: Fri, 8 May 2026 13:57:41 +0100 Message-ID: <20260508130804.8238-2-david.plowman@raspberrypi.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260508130804.8238-1-david.plowman@raspberrypi.com> References: <20260508130804.8238-1-david.plowman@raspberrypi.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 queueCount_ value is redundant and can be removed. The pipeline handler calls the push and applyControls functions in a an interleaved manner, so queueCount_ was merely tracking writeCount_, and is therefore unnecessary. Signed-off-by: David Plowman Reviewed-by: Naushir Patuck Reviewed-by: Jacopo Mondi --- .../pipeline/rpi/common/delayed_controls.cpp | 62 +++++++++++-------- .../pipeline/rpi/common/delayed_controls.h | 1 - 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/src/libcamera/pipeline/rpi/common/delayed_controls.cpp b/src/libcamera/pipeline/rpi/common/delayed_controls.cpp index 19c71946..b647174f 100644 --- a/src/libcamera/pipeline/rpi/common/delayed_controls.cpp +++ b/src/libcamera/pipeline/rpi/common/delayed_controls.cpp @@ -32,14 +32,15 @@ namespace RPi { * * Some sensor controls take effect with a delay as the sensor needs time to * adjust, for example exposure and analog gain. This is a helper class to deal - * with such controls and the intended users are pipeline handlers. + * with such controls. * - * The idea is to extend the concept of the buffer depth of a pipeline the - * application needs to maintain to also cover controls. Just as with buffer - * depth if the application keeps the number of requests queued above the - * control depth the controls are guaranteed to take effect for the correct - * request. The control depth is determined by the control with the greatest - * delay. + * The idea is to maintain a queue of controls that have been submitted. + * Whenever a new frame starts, we can "peak back" into this queue to send + * controls at the correct number of frames in advance to account for each + * control's delay. + * + * The overall delay for controls becomes the maximum delay of any of the + * controls. */ /** @@ -119,7 +120,6 @@ DelayedControls::DelayedControls(V4L2Device *device, */ void DelayedControls::reset(unsigned int cookie) { - queueCount_ = 1; writeCount_ = 0; cookies_[0] = cookie; @@ -146,18 +146,25 @@ void DelayedControls::reset(unsigned int cookie) * \brief Push a set of controls on the queue * \param[in] controls List of controls to add to the device queue * - * Push a set of controls to the control queue. This increases the control queue - * depth by one. + * Push a set of controls to the control queue. The next call to applyControls + * will advance the slot in the queue where the next call to push will write + * controls. * * \returns true if \a controls are accepted, or false otherwise */ bool DelayedControls::push(const ControlList &controls, const unsigned int cookie) { /* Copy state from previous frame. */ - for (auto &ctrl : values_) { - Info &info = ctrl.second[queueCount_]; - info = values_[ctrl.first][queueCount_ - 1]; - info.updated = false; + if (writeCount_ > 0) { + for (auto &ctrl : values_) { + Info &info = ctrl.second[writeCount_]; + info = values_[ctrl.first][writeCount_ - 1]; + info.updated = false; + } + } else { + /* Although it works, we don't expect this. */ + LOG(RPiDelayedControls, Warning) + << "push called before applyControls"; } /* Update with new controls. */ @@ -175,18 +182,17 @@ bool DelayedControls::push(const ControlList &controls, const unsigned int cooki if (controlParams_.find(id) == controlParams_.end()) return false; - Info &info = values_[id][queueCount_]; + Info &info = values_[id][writeCount_]; info = Info(control.second); LOG(RPiDelayedControls, Debug) << "Queuing " << id->name() << " to " << info.toString() - << " at index " << queueCount_; + << " at index " << writeCount_; } - cookies_[queueCount_] = cookie; - queueCount_++; + cookies_[writeCount_] = cookie; return true; } @@ -200,9 +206,9 @@ bool DelayedControls::push(const ControlList &controls, const unsigned int cooki * the callers responsibility to not read too old sequence numbers that have been * pushed out of the history. * - * Historic values are evicted by pushing new values onto the queue using - * push(). The max history from the current sequence number that yields valid - * values are thus 16 minus number of controls pushed. + * Historic values are evicted by new frames arriving and applyControls + * advancing the head of the queue in the ring buffer. The valid history in + * the queue consists of 16 entries from this head of the queue. * * \return The controls at \a sequence number */ @@ -234,6 +240,10 @@ std::pair DelayedControls::get(uint32_t sequence) * number. Any user of these helpers is responsible to inform the helper about * the start of any frame. This can be connected with ease to the start of a * exposure (SOE) V4L2 event. + * + * Controls will be sent to the device, each staggered by the appropriate + * number of frames for that control, so that they are applied at the same + * time. */ void DelayedControls::applyControls(uint32_t sequence) { @@ -277,12 +287,12 @@ void DelayedControls::applyControls(uint32_t sequence) } } - writeCount_ = sequence + 1; - - while (writeCount_ > queueCount_) { + while (writeCount_ < sequence + 1) { + writeCount_++; LOG(RPiDelayedControls, Debug) - << "Queue is empty, auto queue no-op."; - push({}, cookies_[queueCount_ - 1]); + << "Pushing noop with for index " << writeCount_ + << " with cookie " << cookies_[writeCount_ - 1]; + push({}, cookies_[writeCount_ - 1]); } device_->setControls(&out); diff --git a/src/libcamera/pipeline/rpi/common/delayed_controls.h b/src/libcamera/pipeline/rpi/common/delayed_controls.h index 487b0057..48ad5a0f 100644 --- a/src/libcamera/pipeline/rpi/common/delayed_controls.h +++ b/src/libcamera/pipeline/rpi/common/delayed_controls.h @@ -76,7 +76,6 @@ private: std::unordered_map controlParams_; unsigned int maxDelay_; - uint32_t queueCount_; uint32_t writeCount_; std::unordered_map> values_; RingBuffer cookies_;