From patchwork Thu May 7 12:20:34 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Plowman X-Patchwork-Id: 26672 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 B9592C32F6 for ; Thu, 7 May 2026 12:55:07 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8CFEE63020; Thu, 7 May 2026 14:55:05 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="bWzQLUsp"; dkim-atps=neutral Received: from mail-wr1-x430.google.com (mail-wr1-x430.google.com [IPv6:2a00:1450:4864:20::430]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E2B3D62010 for ; Thu, 7 May 2026 14:55:02 +0200 (CEST) Received: by mail-wr1-x430.google.com with SMTP id ffacd0b85a97d-44e1860558fso600771f8f.0 for ; Thu, 07 May 2026 05:55:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1778158502; x=1778763302; 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=bWzQLUsp53Wgdgey1p+mfNd46z3nO4Md6r3bNmAkU0QC219xdsoWEKCO6d6m/KuuXv 20TpWL4BMyBNnOa2eBPX1K50pZ6a+yR4egBdaNFHaGRlCXrU41ePcRjtZEI2GpZikcrv ipWO+vJCRB2v7rF/z8IMIcME2QmSlPeRqJxfQGeb6jJGwJsy1HrUmiwGKbTgp1vi4HIV x8EOd6LV/iXxJYy414VC4Nea+9ReY6e0zhZ5gNTnJ8zwH9Z7KWYUOk3qMIBc8OLSWRL9 WSF+paLQQsimt20jMmvbjR1VyQ8mG5WLq42151uSDLhQJp4i1KRQnB4r6mn0q0ngvhX+ HSVw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778158502; x=1778763302; 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=k2qoByikWj6UVi2Y2VyIRF93jiBPIpz31/cB4D8wl73rlRcKx9XSXTfABa4aNH0yPy MPZPvxsfj3GlYKZ+N88BuIVchk4GahLoJhvH9IJPNgsUcYgyJZEaznjsqLC22aLk5TGW PolXiSf5q2rZr2khLxIDS50tH+/+zlERIo1G3YrGaVXicSvDnBE5Nh4y6X27wM42cvz9 FImljWqHuljZ1Ym5yWAoDWDt8n+zewL4bFSQZAFJMcfHsNKKaW9SK6sqO6No9ra1nZIR JtOVFQJpMtJvl8+A0AgK9Q8Lz/ac69sT1niPVTKaAV099OAqKqa0YVgmcpfSNtZT7r0Z ++aw== X-Gm-Message-State: AOJu0Yy4PQTL3kPCnZWW7G18EnagUuyVfB3AN5CTG1ObaOl2SxmI9UWM g6CNkeskYLJcDKQuWUJIPujdM0K/ccVsmhs2VSrt3a59SZRhsJUrZWI2clTzCYczsXiExLb6097 Zyc0v X-Gm-Gg: AeBDievDiG9L2gUJbLQWH9cASCFbzVx/xcZf2UFSSJyO0XV5BeVEB8Bfn5lT47unO/6 qYPJ2TzgC5bsoNXGlAoIQN36GB3oKjI21rImag4e+yCy4DJpQ/aUYcLvumYM7vFd862VGe3Ce56 0qTic2HoAU+VewlC8SR9NVa7oKTXSFo1qol8rtiptbVSXXupgY8f9ZryqoaKOA4k5O2YZxRvuk1 UQXsbctollDyJOeQ0DXcRBI7E9KTofXHqDT+eOLqZZbsmKEEmxErF+j+CmZorQ4XDwAvwbeBzvP m1cjmZWqLBQ78XiJNVpfbHPZjdF9mI7yRJrPG9/VWv1ZKvhe0agwICgt/bg+kToqA3Zppqo/pAJ ygSpQ00zfMOjEoTLnLltnxcI1re6UFrtOV07iAT5/KfPGpFHj+XLqG4yE9qIVebAsllNjReeEn0 As4WL3cYveVkjxqts+LaPOyI1loRk2lq7R70zDSD3T0E8KXNdyylPmzCrUaQZXdAsoj0D9eVQDQ fh/kGrvO0ziMwsxJeGCD5AMcsnQQymvoxW6P59q1iJHFemB3qqd X-Received: by 2002:a05:6000:2901:b0:43d:613:4036 with SMTP id ffacd0b85a97d-4515da9535bmr12535111f8f.37.1778158501943; Thu, 07 May 2026 05:55:01 -0700 (PDT) Received: from davidp-pi5.pitowers.org ([2a00:1098:3142:1f:88ea:c658:5b20:5e46]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-450524833e1sm20396324f8f.2.2026.05.07.05.55.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 May 2026 05:55:01 -0700 (PDT) From: David Plowman To: libcamera-devel@lists.libcamera.org Cc: David Plowman , Naushir Patuck , Jacopo Mondi Subject: [PATCH v4 1/3] pipeline: rpi: Simplify delayed controls Date: Thu, 7 May 2026 13:20:34 +0100 Message-ID: <20260507125458.12140-2-david.plowman@raspberrypi.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260507125458.12140-1-david.plowman@raspberrypi.com> References: <20260507125458.12140-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_;