From patchwork Wed Sep 24 12:47:06 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= X-Patchwork-Id: 24447 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 BAE78C32A9 for ; Wed, 24 Sep 2025 12:47:30 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C7D366B601; Wed, 24 Sep 2025 14:47:23 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="pMAjPYo/"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id CEE756B58E for ; Wed, 24 Sep 2025 14:47:16 +0200 (CEST) Received: from pb-laptop.local (185.221.140.70.nat.pool.zt.hu [185.221.140.70]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id AFE51EAE; Wed, 24 Sep 2025 14:45:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1758717952; bh=0iPQLkJdCZwQYnyoJnp+NllikG/FJHULtR/rQoKRazE=; h=From:To:Subject:Date:In-Reply-To:References:From; b=pMAjPYo//04nT2uE1tQrElrDYzdHUHSRhR7/OyL+M0RiNKKHBgvSkWWTKSTItS+/k gKn0GbNRP3i1yAujsjk40SrucuGvVEqZSNo84ZRqQZMS9SujsiUHPf9PUr0NOtmlHy BJVUUPH+9NWzDDIcDE//UUv0RxvVCSgFKYDclin4= From: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= To: libcamera-devel@lists.libcamera.org, Kieran Bingham Subject: [RFC PATCH v1 1/7] libcamera: base: bound_method: Strip qualifiers in argument pack Date: Wed, 24 Sep 2025 14:47:06 +0200 Message-ID: <20250924124713.3361707-2-barnabas.pocze@ideasonboard.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20250924124713.3361707-1-barnabas.pocze@ideasonboard.com> References: <20250924124713.3361707-1-barnabas.pocze@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" Having extra qualifiers, especially `const`, simply inhibits optimization opportunities as it prevents e.g. moving values out of pack object. So strip the qualifiers. Signed-off-by: Barnabás Pőcze --- include/libcamera/base/bound_method.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/libcamera/base/bound_method.h b/include/libcamera/base/bound_method.h index 91fe8b8cb..cb642e0a9 100644 --- a/include/libcamera/base/bound_method.h +++ b/include/libcamera/base/bound_method.h @@ -39,7 +39,7 @@ public: { } - std::tuple...> args_; + std::tuple>...> args_; R ret_; }; @@ -53,7 +53,7 @@ public: { } - std::tuple...> args_; + std::tuple>...> args_; }; class BoundMethodBase From patchwork Wed Sep 24 12:47:07 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= X-Patchwork-Id: 24448 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 C8AB7BDB1C for ; Wed, 24 Sep 2025 12:47:33 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A41896B605; Wed, 24 Sep 2025 14:47:25 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="YlHyXQ2P"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 115BC6B5F0 for ; Wed, 24 Sep 2025 14:47:17 +0200 (CEST) Received: from pb-laptop.local (185.221.140.70.nat.pool.zt.hu [185.221.140.70]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 05E1C15E9; Wed, 24 Sep 2025 14:45:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1758717953; bh=vh+fIL4wFVuH2fOBu8NgwwtpBDP/2tf5eRRCK6gsAeA=; h=From:To:Subject:Date:In-Reply-To:References:From; b=YlHyXQ2PF2pRvJdcabAYrsYV6HOXzqpdfM6/BDWuTN21mUI9jppMDuhmhOP9o0jqu bJw0eKrJwX2qjRL3Dgxnl7lezzQh+kVFP5A6vKE1ET2SBMIH+3c3nlSnHQ/9QG6cyn 0Uq323s0BFBG/LFLEPbT90HF0d3qcPmWrceqN+08= From: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= To: libcamera-devel@lists.libcamera.org, Kieran Bingham Subject: [RFC PATCH v1 2/7] libcamera: base: bound_method: Forward when invoking Date: Wed, 24 Sep 2025 14:47:07 +0200 Message-ID: <20250924124713.3361707-3-barnabas.pocze@ideasonboard.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20250924124713.3361707-1-barnabas.pocze@ideasonboard.com> References: <20250924124713.3361707-1-barnabas.pocze@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" At the moment a single argument pack is used just once, hence it is safe to forward the arguments from the pack, allowing moving to take place instead of copying. Signed-off-by: Barnabás Pőcze --- include/libcamera/base/bound_method.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/libcamera/base/bound_method.h b/include/libcamera/base/bound_method.h index cb642e0a9..0552a9f30 100644 --- a/include/libcamera/base/bound_method.h +++ b/include/libcamera/base/bound_method.h @@ -97,9 +97,9 @@ private: [[maybe_unused]] auto *args = static_cast(pack); if constexpr (!std::is_void_v) - args->ret_ = invoke(std::get(args->args_)...); + args->ret_ = invoke(std::forward>(std::get(args->args_))...); else - invoke(std::get(args->args_)...); + invoke(std::forward>(std::get(args->args_))...); } public: From patchwork Wed Sep 24 12:47:08 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= X-Patchwork-Id: 24449 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 959F2C3331 for ; Wed, 24 Sep 2025 12:47:36 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8E2106B5FE; Wed, 24 Sep 2025 14:47:28 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="GmIc45Y+"; 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 41DF26B5F3 for ; Wed, 24 Sep 2025 14:47:17 +0200 (CEST) Received: from pb-laptop.local (185.221.140.70.nat.pool.zt.hu [185.221.140.70]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 513431E30; Wed, 24 Sep 2025 14:45:53 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1758717953; bh=PULD/bhzlEF1pA8U1Nm12ABhT2Gudiv9VA4pjEP6cP8=; h=From:To:Subject:Date:In-Reply-To:References:From; b=GmIc45Y+F7EGcYqzwG03YsfbmUNQJNtjjlWd3mfwCvqQY8T69PUykrHr14oeiRsue sBJ2KxyMx3wMWAcQwvbO+97T5/8bmgagDsfJAgSSsnXEtteKWOmdGqD1av36eq4F5j dm2PmCXpKZpolgHaa5UVtJgwcn2OL0yc3mUeZhcI= From: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= To: libcamera-devel@lists.libcamera.org, Kieran Bingham Subject: [RFC PATCH v1 3/7] libcamera: controls: Add rvalue `ControlList::merge()` Date: Wed, 24 Sep 2025 14:47:08 +0200 Message-ID: <20250924124713.3361707-4-barnabas.pocze@ideasonboard.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20250924124713.3361707-1-barnabas.pocze@ideasonboard.com> References: <20250924124713.3361707-1-barnabas.pocze@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" Add an overload of `ControlList::merge()` that takes the source `ControlList` object via an rvalue. In contrast to the other overload, this one does not make copies, it uses `std::unordered_map::merge()` to move key-value pairs from one map to the other. Signed-off-by: Barnabás Pőcze --- include/libcamera/controls.h | 1 + src/libcamera/controls.cpp | 42 +++++++++++++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/include/libcamera/controls.h b/include/libcamera/controls.h index 32fb31f78..5d4a53c46 100644 --- a/include/libcamera/controls.h +++ b/include/libcamera/controls.h @@ -432,6 +432,7 @@ public: void clear() { controls_.clear(); } void merge(const ControlList &source, MergePolicy policy = MergePolicy::KeepExisting); + void merge(ControlList &&source, MergePolicy policy = MergePolicy::KeepExisting); bool contains(unsigned int id) const; diff --git a/src/libcamera/controls.cpp b/src/libcamera/controls.cpp index 1e1b49e6b..54cd3b703 100644 --- a/src/libcamera/controls.cpp +++ b/src/libcamera/controls.cpp @@ -1005,9 +1005,6 @@ ControlList::ControlList(const ControlInfoMap &infoMap, * * Only control lists created from the same ControlIdMap or ControlInfoMap may * be merged. Attempting to do otherwise results in undefined behaviour. - * - * \todo Reimplement or implement an overloaded version which internally uses - * std::unordered_map::merge() and accepts a non-const argument. */ void ControlList::merge(const ControlList &source, MergePolicy policy) { @@ -1035,6 +1032,45 @@ void ControlList::merge(const ControlList &source, MergePolicy policy) } } +/** + * \brief Merge the \a source into the ControlList + * \param[in] source The ControlList to merge into this object + * \param[in] policy Controls if existing elements in *this shall be + * overwritten + * + * Merging two control lists moves elements from the \a source and inserts + * them in *this. If the \a source contains elements whose key is already + * present in *this, then those elements are only overwritten if + * \a policy is MergePolicy::OverwriteExisting. + * + * Only control lists created from the same ControlIdMap or ControlInfoMap may + * be merged. Attempting to do otherwise results in undefined behaviour. + */ +void ControlList::merge(ControlList &&source, MergePolicy policy) +{ + /** + * \todo ASSERT that the current and source ControlList are derived + * from a compatible ControlIdMap, to prevent undefined behaviour due to + * id collisions. + * + * This can not currently be a direct pointer comparison due to the + * duplication of the ControlIdMaps in the isolated IPA use cases. + * Furthermore, manually checking each entry of the id map is identical + * is expensive. + * See https://bugs.libcamera.org/show_bug.cgi?id=31 for further details + */ + + switch (policy) { + case MergePolicy::KeepExisting: + controls_.merge(source.controls_); + break; + case MergePolicy::OverwriteExisting: + source.controls_.merge(controls_); + controls_.swap(source.controls_); + break; + } +} + /** * \brief Check if the list contains a control with the specified \a id * \param[in] id The control numerical ID From patchwork Wed Sep 24 12:47:09 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= X-Patchwork-Id: 24450 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 07F24C32A9 for ; Wed, 24 Sep 2025 12:47:38 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 210D96B611; Wed, 24 Sep 2025 14:47:31 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="PAaLgTt3"; 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 86FB76B5F8 for ; Wed, 24 Sep 2025 14:47:17 +0200 (CEST) Received: from pb-laptop.local (185.221.140.70.nat.pool.zt.hu [185.221.140.70]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 9B6761E35; Wed, 24 Sep 2025 14:45:53 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1758717953; bh=Tk9V+4Yr8AFkD+oqP8mCtSO86gr9R9B0KISNqioEJRs=; h=From:To:Subject:Date:In-Reply-To:References:From; b=PAaLgTt3nnpTLZKBfescI6ryK+kHOZ2sUuGfdslldFdCev6xiH/yj5y7783YSKDYj DzX1mB0Wr/XdfTimz8QEr6XNhBiujkwU9nvF74vCTwR16CIIIduOne2B21y0Jfa/U0 V+855xQkmboNCuV8nUTt7X0fe64g2w16uQKSH42Y= From: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= To: libcamera-devel@lists.libcamera.org, Kieran Bingham Subject: [RFC PATCH v1 4/7] libcamera: controls: ControlList: Add `erase()` Date: Wed, 24 Sep 2025 14:47:09 +0200 Message-ID: <20250924124713.3361707-5-barnabas.pocze@ideasonboard.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20250924124713.3361707-1-barnabas.pocze@ideasonboard.com> References: <20250924124713.3361707-1-barnabas.pocze@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" Add two `erase()` functions that can be used to remove elements from a `ControlList` instance. Signed-off-by: Barnabás Pőcze --- include/libcamera/controls.h | 3 +++ src/libcamera/controls.cpp | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/include/libcamera/controls.h b/include/libcamera/controls.h index 5d4a53c46..9045caff7 100644 --- a/include/libcamera/controls.h +++ b/include/libcamera/controls.h @@ -470,6 +470,9 @@ public: const ControlValue &get(unsigned int id) const; void set(unsigned int id, const ControlValue &value); + bool erase(unsigned int id); + bool erase(const ControlId &ctrl) { return erase(ctrl.id()); } + const ControlInfoMap *infoMap() const { return infoMap_; } const ControlIdMap *idMap() const { return idmap_; } diff --git a/src/libcamera/controls.cpp b/src/libcamera/controls.cpp index 54cd3b703..83f8bf056 100644 --- a/src/libcamera/controls.cpp +++ b/src/libcamera/controls.cpp @@ -1156,6 +1156,23 @@ void ControlList::set(unsigned int id, const ControlValue &value) *val = value; } +/** + * \brief Remove the value of control \a id + * \param[in] id The control ID + * \return \a true if \a id was present, \a false otherwise + */ +bool ControlList::erase(unsigned int id) +{ + return controls_.erase(id); +} + +/** + * \fn ControlList::erase(const ControlId &ctrl) + * \brief Remove the value of control \a ctrl + * \param[in] ctrl The control + * \return \a true if \a ctrl was present, \a false otherwise + */ + /** * \fn ControlList::infoMap() * \brief Retrieve the ControlInfoMap used to construct the ControlList From patchwork Wed Sep 24 12:47:10 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= X-Patchwork-Id: 24451 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 C2429C3332 for ; Wed, 24 Sep 2025 12:47:40 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C60606B622; Wed, 24 Sep 2025 14:47:32 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="UchqAQcv"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D75EA6B5F9 for ; Wed, 24 Sep 2025 14:47:17 +0200 (CEST) Received: from pb-laptop.local (185.221.140.70.nat.pool.zt.hu [185.221.140.70]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E4A16AD0; Wed, 24 Sep 2025 14:45:53 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1758717954; bh=1NEsdwLlZPPve6Z848Cw15ik7hXlgefsz1S+d8YnDBQ=; h=From:To:Subject:Date:In-Reply-To:References:From; b=UchqAQcvUxUNdGfUlx1KP1gXEZ+g7OG2laZAUgrHG9ppGYUB/IbnpYPkko52LFclw E/mT+yUSf+StenxxrbgoOpARLKmbJyA3guLnkV2rf9pMliK7FZfQCytKHwYNfvMgsz lV5FI7AdzCM/gTQksvQGedngUnCTkLaYbdHf9REc= From: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= To: libcamera-devel@lists.libcamera.org, Kieran Bingham Subject: [RFC PATCH v1 5/7] libcamera: camera: Make `waitingRequests_` an `std::deque` Date: Wed, 24 Sep 2025 14:47:10 +0200 Message-ID: <20250924124713.3361707-6-barnabas.pocze@ideasonboard.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20250924124713.3361707-1-barnabas.pocze@ideasonboard.com> References: <20250924124713.3361707-1-barnabas.pocze@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" Use `std::deque` instead of `std::queue` because an `std::queue` cannot be iterated. Signed-off-by: Barnabás Pőcze --- include/libcamera/internal/camera.h | 2 +- src/libcamera/pipeline_handler.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/libcamera/internal/camera.h b/include/libcamera/internal/camera.h index 8a2e9ed58..0f50c14a5 100644 --- a/include/libcamera/internal/camera.h +++ b/include/libcamera/internal/camera.h @@ -37,7 +37,7 @@ public: const PipelineHandler *pipe() const { return pipe_.get(); } std::list queuedRequests_; - std::queue waitingRequests_; + std::deque waitingRequests_; ControlInfoMap controlInfo_; ControlList properties_; diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index e5f9e55c9..d0d3fbc79 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -370,7 +370,7 @@ void PipelineHandler::stop(Camera *camera) * after the device to keep them in order. */ Camera::Private *data = camera->_d(); - std::queue waitingRequests; + std::deque waitingRequests; waitingRequests.swap(data->waitingRequests_); /* Stop the pipeline handler and let the queued requests complete. */ @@ -379,7 +379,7 @@ void PipelineHandler::stop(Camera *camera) /* Cancel and signal as complete all waiting requests. */ while (!waitingRequests.empty()) { Request *request = waitingRequests.front(); - waitingRequests.pop(); + waitingRequests.pop_front(); cancelRequest(request); } @@ -461,7 +461,7 @@ void PipelineHandler::queueRequest(Request *request) Camera *camera = request->_d()->camera(); Camera::Private *data = camera->_d(); - data->waitingRequests_.push(request); + data->waitingRequests_.push_back(request); request->_d()->prepare(300ms); } @@ -510,7 +510,7 @@ void PipelineHandler::doQueueRequests(Camera *camera) * Pop the request first, in case doQueueRequests() is called * recursively from within doQueueRequest() */ - data->waitingRequests_.pop(); + data->waitingRequests_.pop_front(); doQueueRequest(request); } } From patchwork Wed Sep 24 12:47:11 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= X-Patchwork-Id: 24452 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 3AB5ABDB1C for ; Wed, 24 Sep 2025 12:47:42 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 34EB46B614; Wed, 24 Sep 2025 14:47:36 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="XHyZP5CK"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 307D96B5FB for ; Wed, 24 Sep 2025 14:47:18 +0200 (CEST) Received: from pb-laptop.local (185.221.140.70.nat.pool.zt.hu [185.221.140.70]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 3D26A1E36; Wed, 24 Sep 2025 14:45:54 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1758717954; bh=rRY8KqO5CkXTsdWJUkqirBQf/6DBZyG/gB8dlDWRQKM=; h=From:To:Subject:Date:In-Reply-To:References:From; b=XHyZP5CKunzZsY+Bsj1gOsEP8bKMqQamvZv9Hd3ORuCclchRZ7/x3m1mwTZjMP08a GdrJKs5qqr4Z47d/cBDBIbMNC99QRqQ6hcTjCWeETSJpD68eJbJDOD7dLXHWT5NX2X bpBn5v/av6lJL4//VTyw8Zlpp+g7Th/QnC5YFK8I= From: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= To: libcamera-devel@lists.libcamera.org, Kieran Bingham Subject: [RFC PATCH v1 6/7] libcamera: camera: Add `applyControls()` Date: Wed, 24 Sep 2025 14:47:11 +0200 Message-ID: <20250924124713.3361707-7-barnabas.pocze@ideasonboard.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20250924124713.3361707-1-barnabas.pocze@ideasonboard.com> References: <20250924124713.3361707-1-barnabas.pocze@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" Add `Camera::applyControls()` whose purpose is to apply controls as soon as possible, without going through `Request::controls()`. A new virtual function `PipelineHandler::applyControlsDevice()` is provided for pipeline handler to implement fast-tracked application of controls. If the pipeline handler does not implement that functionality, or it fails, then a fallback mechanism is used. The controls will be saved for later, and they will be merged into the control list of the next request sent to the pipeline handler (`Camera::Private::waitingRequests_`). Signed-off-by: Barnabás Pőcze --- include/libcamera/camera.h | 1 + include/libcamera/internal/camera.h | 1 + include/libcamera/internal/pipeline_handler.h | 7 ++ src/libcamera/camera.cpp | 53 +++++++++ src/libcamera/pipeline_handler.cpp | 110 +++++++++++++++++- 5 files changed, 171 insertions(+), 1 deletion(-) diff --git a/include/libcamera/camera.h b/include/libcamera/camera.h index b24a29740..94f940496 100644 --- a/include/libcamera/camera.h +++ b/include/libcamera/camera.h @@ -147,6 +147,7 @@ public: std::unique_ptr createRequest(uint64_t cookie = 0); int queueRequest(Request *request); + int applyControls(ControlList &&controls); int start(const ControlList *controls = nullptr); int stop(); diff --git a/include/libcamera/internal/camera.h b/include/libcamera/internal/camera.h index 0f50c14a5..5a77298b3 100644 --- a/include/libcamera/internal/camera.h +++ b/include/libcamera/internal/camera.h @@ -38,6 +38,7 @@ public: std::list queuedRequests_; std::deque waitingRequests_; + ControlList pendingControls_; ControlInfoMap controlInfo_; ControlList properties_; diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h index e89d6a33e..16ff54bab 100644 --- a/include/libcamera/internal/pipeline_handler.h +++ b/include/libcamera/internal/pipeline_handler.h @@ -57,6 +57,7 @@ public: void registerRequest(Request *request); void queueRequest(Request *request); + int applyControls(Camera *camera, ControlList &&controls); bool completeBuffer(Request *request, FrameBuffer *buffer); void completeRequest(Request *request); @@ -75,6 +76,12 @@ protected: void hotplugMediaDevice(MediaDevice *media); virtual int queueRequestDevice(Camera *camera, Request *request) = 0; + + virtual int applyControlsDevice([[maybe_unused]] Camera *camera, [[maybe_unused]] const ControlList &controls) + { + return -EOPNOTSUPP; + } + virtual void stopDevice(Camera *camera) = 0; virtual bool acquireDevice(Camera *camera); diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp index 2e1e146a2..778445e36 100644 --- a/src/libcamera/camera.cpp +++ b/src/libcamera/camera.cpp @@ -637,6 +637,14 @@ Camera::Private::~Private() * queued requests was reached. */ +/** + * \var Camera::Private::pendingControls_ + * \brief The list of pending controls + * + * This list tracks the controls that need to be applied to the device with the + * next request going to PipelineHandler::queueRequestDevice(). + */ + /** * \var Camera::Private::controlInfo_ * \brief The set of controls supported by the camera @@ -1374,6 +1382,51 @@ int Camera::queueRequest(Request *request) return 0; } +/** + * \brief Apply controls immediately + * \param[in] controls The list of controls to apply + * + * This function tries to ensure that the controls in \a controls are applied + * to the camera as soon as possible. + * + * The exact guarantees are camera dependent, but it is guaranteed that the + * controls will be applied no later than if they were part of the next \ref Request "request" + * that the application \ref Camera::queueRequest() "queues". + * + * \context This function is \threadsafe. It may only be called when the camera + * is in the Running state as defined in \ref camera_operation. + * + * \return 0 on success or a negative error code otherwise + * \retval -ENODEV The camera has been disconnected from the system + * \retval -EACCES The camera is not running + */ +int Camera::applyControls(ControlList &&controls) +{ + Private *const d = _d(); + + /* + * \todo What to do if not running? Should it be stored and merged into the "start" `ControlList`? + * If yes, should that list of pending controls be overwritten/updated when stopped? + * And should it be cleared in `Camera::release()`? + */ + + int ret = d->isAccessAllowed(Private::CameraRunning); + if (ret < 0) + return ret; + + if (controls.empty()) + return 0; + + patchControlList(controls); + + /* + * \todo Or `ConnectionTypeBlocking` to get the return value? + */ + d->pipe_->invokeMethod(&PipelineHandler::applyControls, ConnectionTypeQueued, this, std::move(controls)); + + return 0; +} + /** * \brief Start capture from camera * \param[in] controls Controls to be applied before starting the Camera diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index d0d3fbc79..99bb2193f 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -387,6 +387,12 @@ void PipelineHandler::stop(Camera *camera) ASSERT(data->queuedRequests_.empty()); ASSERT(data->waitingRequests_.empty()); + /* + * \todo Or not? This probably needs discussions regarding + * the expected state of controls after a stop-start sequence. + */ + data->pendingControls_.clear(); + data->requestSequence_ = 0; } @@ -466,6 +472,54 @@ void PipelineHandler::queueRequest(Request *request) request->_d()->prepare(300ms); } +/** + * \brief Apply controls immediately + * \param[in] camera The camera + * \param[in] controls The controls to apply + * + * This function tries to apply \a controls immediately to the device by + * calling applyControlsDevice(). If that fails, then a fallback mechanism + * is used to ensure that \a controls will be merged into the control list + * of the next request submitted to the pipeline handler. + * + * This function also ensures that requests in Camera::Private::waitingRequests_ + * will not override the fast-tracked controls. + * + * \context This function is called from the CameraManager thread. + */ +int PipelineHandler::applyControls(Camera *camera, ControlList &&controls) +{ + Camera::Private *data = camera->_d(); + int res = applyControlsDevice(camera, controls); + + /* + * Prevent later requests from overriding the fast-tracked controls. + * \todo This is unfortunately slow. + */ + for (const auto &[k, v] : controls) { + for (Request *r : data->waitingRequests_) + r->controls().erase(k); + } + + if (res < 0) { + /* + * \todo Always fall back or only if EOPNOTSUPP is returned? + * Possibly there could be some way for the user to influence + * the fallback logic (e.g. `flags` argument for `Camera::applyControls()`). + */ + if (res != -EOPNOTSUPP) + LOG(Pipeline, Debug) << "Fast tracking controls failed: " << res; + + /* + * Fall back to adding the controls to the next request that enters the + * pipeline handler. See PipelineHandler::doQueueRequest(). + */ + data->pendingControls_.merge(std::move(controls), ControlList::MergePolicy::OverwriteExisting); + } + + return 0; +} + /** * \brief Queue one requests to the device */ @@ -484,9 +538,49 @@ void PipelineHandler::doQueueRequest(Request *request) return; } + if (!data->pendingControls_.empty()) { + /* + * Note that `ControlList::MergePolicy::KeepExisting` is used. This is + * needed to ensure that if `request` is newer than pendingControls_, + * then its controls take precedence. + * + * For older requests, `PipelineHandler::applyControls()` has already removed + * the controls that should be overridden. + * + * \todo How to handle (if at all) conflicting controls? + * \todo How to handle failure of `queueRequestDevice()`? + * After the merge it becomes impossible to retrieve the pending controls + * from `request->controls()`. Making a copy in such a hot-path is not ideal. + */ + request->controls().merge(std::move(data->pendingControls_), ControlList::MergePolicy::KeepExisting); + data->pendingControls_.clear(); + } + int ret = queueRequestDevice(camera, request); - if (ret) + if (ret) { + /* + * \todo What to do now? + * + * The original `pendingControls_` is not easily recoverable. + * + * Initially + * request->controls() = A u B + * pendingControls_ = A' u C + * + * then after the above merge + * request->controls() = A u B u C + * pendingControls_ = A' + * + * so recovering `pendingControls_` without a copy of at least + * `B` or `C` does not appear easy. + * + * But sometimes recovering is not even desirable: assume that the controls + * in `pendingControls_` causes the failure. In that case keeping them around + * will cause every single subsequent request to fail. + */ + cancelRequest(request); + } } /** @@ -532,6 +626,20 @@ void PipelineHandler::doQueueRequests(Camera *camera) * \return 0 on success or a negative error code otherwise */ +/** + * \fn PipelineHandler::applyControlsDevice() + * \brief Apply controls immediately + * \param[in] camera The camera + * \param[in] controls The controls to apply + * + * This function applies \a controls to \a camera immediately. + * + * \context This function is called from the CameraManager thread. + * + * \return 0 on success or a negative error code otherwise + * \return -EOPNOTSUPP if fast-tracking controls is not supported + */ + /** * \brief Complete a buffer for a request * \param[in] request The request the buffer belongs to From patchwork Wed Sep 24 12:47:12 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= X-Patchwork-Id: 24453 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 9FD3DC3333 for ; Wed, 24 Sep 2025 12:47:43 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id F38546B61A; Wed, 24 Sep 2025 14:47:38 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="oc0aFRjK"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 83B9C6B5FE for ; Wed, 24 Sep 2025 14:47:18 +0200 (CEST) Received: from pb-laptop.local (185.221.140.70.nat.pool.zt.hu [185.221.140.70]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 8BD6CEAE; Wed, 24 Sep 2025 14:45:54 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1758717954; bh=1yuf+0Ga7i3WmZm1QBVcrYKwEAHGPGbR7X1KO5XGSXY=; h=From:To:Subject:Date:In-Reply-To:References:From; b=oc0aFRjKwl7MyccnAobYxPpx4x0gH4hI0dhJ/3AO10QeSJmiwTIu7/m64s71yMJsh 1EWk2pNXeyqTfdkzIsfgw4r23X0OKCE8R4OZwpY+R22Nd3gzO3UE3P6mzl4D98xYIE +kIFxZ8bTARTglqFv9nr/m0osCT1LM6N5bJFv0+E= From: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= To: libcamera-devel@lists.libcamera.org, Kieran Bingham Subject: [RFC PATCH v1 7/7] libcamera: pipeline: uvcvideo: Implement `applyControlsDevice()` Date: Wed, 24 Sep 2025 14:47:12 +0200 Message-ID: <20250924124713.3361707-8-barnabas.pocze@ideasonboard.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20250924124713.3361707-1-barnabas.pocze@ideasonboard.com> References: <20250924124713.3361707-1-barnabas.pocze@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" Implement fast-tracked control application in the uvcvideo pipeline handler. Signed-off-by: Barnabás Pőcze --- src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp index 4b5816dfd..17a01daad 100644 --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp @@ -109,6 +109,11 @@ private: { return static_cast(camera->_d()); } + + int applyControlsDevice(Camera *camera, const ControlList &controls) override + { + return processControls(cameraData(camera), controls); + } }; namespace {