From patchwork Thu Sep 11 09:29:31 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24308 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 E05E8C324E for ; Thu, 11 Sep 2025 09:30:04 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8BE576935A; Thu, 11 Sep 2025 11:30:04 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="f3iBzXim"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 94BE96935A for ; Thu, 11 Sep 2025 11:30:02 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1757583001; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=j+X5tn2xzLx2KA0yaWDVXXROwL+Jr44errMqmeZ7J1Q=; b=f3iBzXimTe8TYnSGpumNR+Wd8SKuEuDbvNfK+vpOhJnN1aQt3fEDBG9wjo6W771pjy8sTv YvNe8gFM7wiBfU1p2Q63pFq4VRiwQOgHGX5O3/wiSjA9P7nIQU+02w/JQT6VIqC5PIQv0Z FSRW6OXyT26+3CvsHkywhoAktPc9D0o= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-584-H9Wda-WfPT-jk7lXgAdzRg-1; Thu, 11 Sep 2025 05:29:58 -0400 X-MC-Unique: H9Wda-WfPT-jk7lXgAdzRg-1 X-Mimecast-MFC-AGG-ID: H9Wda-WfPT-jk7lXgAdzRg_1757582997 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 7E6781800350; Thu, 11 Sep 2025 09:29:56 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.34.98]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 3D8A519560B1; Thu, 11 Sep 2025 09:29:53 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Kieran Bingham , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Laurent Pinchart , Paul Elder Subject: [PATCH v17 01/12] config: Introduce global runtime configuration Date: Thu, 11 Sep 2025 11:29:31 +0200 Message-ID: <20250911092945.16517-2-mzamazal@redhat.com> In-Reply-To: <20250911092945.16517-1-mzamazal@redhat.com> References: <20250911092945.16517-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: oVWXXSyos8RL0C0PgCuz28aEWoVf5Xvjo2ROJHfBzUM_1757582997 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" Currently, libcamera can be configured in runtime using several environment variables. With introducing more and more variables, this mechanism reaches its limits. It would be simpler and more flexible if it was possible to configure libcamera in a single file. For example, there was a request to define pipeline precedence in runtime. We want to compile in multiple pipelines, in order to have them accessible within single packages in distributions. And then being able to select among the pipelines manually as needed based on the particular hardware or operating system environment. Having the configuration file then allows easy switching between hardware, GPU or CPU IPAs. The configuration file can also be used to enable or disable experimental features and avoid the need to track local patches changing configuration options hard-wired in the code when working on new features. This patch introduces basic support for configuration files. GlobalConfiguration class reads and stores the configuration. Its instance can be used by other libcamera objects to access the configuration. A GlobalConfiguration instance is supposed to be stored in a well-defined place, e.g. a CameraManager instance. It is possible to have multiple GlobalConfiguration instances, which may or may not make sense. libcamera configuration can be specified using a system-wide configuration file or a user configuration file. The user configuration file takes precedence if present. There is currently no way to merge multiple configuration files, the one found is used as the only configuration file. If no configuration file is present, nothing changes to the current libcamera behavior (except for some log messages related to configuration file lookup). The configuration file is a YAML file. We already have a mechanism for handling YAML configuration files in libcamera and the given infrastructure can be reused for the purpose. However, the configuration type is abstracted to make contingent future change of the underlying class easier while retaining (most of) the original API. The configuration is versioned. This has currently no particular meaning but is likely to have its purpose in future, especially once configuration validation is introduced. The configuration YAML file looks as follows: --- version: 1 configuration: WHATEVER CONFIGURATION NEEDED This patch introduces just the basic idea. Actually using the configuration in the corresponding places (everything what is currently configurable via environment variables should be configurable in the file configuration) and other enhancements are implemented in the followup patches. Signed-off-by: Milan Zamazal Reviewed-by: Paul Elder --- .../libcamera/internal/global_configuration.h | 34 ++++ include/libcamera/internal/meson.build | 1 + src/libcamera/global_configuration.cpp | 148 ++++++++++++++++++ src/libcamera/meson.build | 1 + 4 files changed, 184 insertions(+) create mode 100644 include/libcamera/internal/global_configuration.h create mode 100644 src/libcamera/global_configuration.cpp diff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h new file mode 100644 index 000000000..f695498c4 --- /dev/null +++ b/include/libcamera/internal/global_configuration.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024-2025 Red Hat, inc. + * + * Global configuration handling + */ + +#pragma once + +#include + +#include "libcamera/internal/yaml_parser.h" + +namespace libcamera { + +class GlobalConfiguration +{ +public: + using Configuration = const YamlObject &; + + GlobalConfiguration(); + + unsigned int version() const; + Configuration configuration() const; + +private: + bool loadFile(const std::filesystem::path &fileName); + void load(); + + std::unique_ptr yamlConfiguration_ = + std::make_unique(); +}; + +} /* namespace libcamera */ diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build index 5c80a28c4..45c299f6a 100644 --- a/include/libcamera/internal/meson.build +++ b/include/libcamera/internal/meson.build @@ -23,6 +23,7 @@ libcamera_internal_headers = files([ 'dma_buf_allocator.h', 'formats.h', 'framebuffer.h', + 'global_configuration.h', 'ipa_data_serializer.h', 'ipa_manager.h', 'ipa_module.h', diff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp new file mode 100644 index 000000000..d02668111 --- /dev/null +++ b/src/libcamera/global_configuration.cpp @@ -0,0 +1,148 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024-2025 Red Hat, inc. + * + * Global configuration handling + */ + +#include "libcamera/internal/global_configuration.h" + +#include +#include +#include + +#include +#include +#include + +#include "libcamera/internal/yaml_parser.h" + +namespace libcamera { + +namespace { +const std::vector globalConfigurationFiles = { + std::filesystem::path(LIBCAMERA_SYSCONF_DIR) / "configuration.yaml", + std::filesystem::path(LIBCAMERA_DATA_DIR) / "configuration.yaml", +}; +} + +LOG_DEFINE_CATEGORY(Configuration) + +/** + * \class GlobalConfiguration + * \brief Support for global libcamera configuration + * + * The configuration file is a YAML file and the configuration itself is stored + * under `configuration' top-level item. + * + * The configuration file is looked up in user's home directory first and if it + * is not found then in system-wide configuration directories. If multiple + * configuration files exist then only the first one found is used and no + * configuration merging is performed. + * + * If the first found configuration file cannot be opened or parsed, an error is + * reported and no configuration file is used. This is to prevent libcamera from + * using an unintended configuration file. + */ + +bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName) +{ + File file(fileName); + if (!file.open(File::OpenModeFlag::ReadOnly)) { + if (file.error() == -ENOENT) + return false; + + LOG(Configuration, Error) + << "Failed to open configuration file " << fileName; + return true; + } + + std::unique_ptr configuration = YamlParser::parse(file); + if (!configuration) { + LOG(Configuration, Error) + << "Failed to parse configuration file " << fileName; + return true; + } + + yamlConfiguration_ = std::move(configuration); + return true; +} + +void GlobalConfiguration::load() +{ + std::filesystem::path userConfigurationDirectory; + const char *xdgConfigHome = utils::secure_getenv("XDG_CONFIG_HOME"); + if (xdgConfigHome) { + userConfigurationDirectory = xdgConfigHome; + } else { + const char *home = utils::secure_getenv("HOME"); + if (home) + userConfigurationDirectory = + std::filesystem::path(home) / ".config"; + } + + if (!userConfigurationDirectory.empty()) { + std::filesystem::path user_configuration_file = + userConfigurationDirectory / "libcamera" / "configuration.yaml"; + if (loadFile(user_configuration_file)) + return; + } + + for (const auto &path : globalConfigurationFiles) { + if (loadFile(path)) + return; + } +} + +/** + * \brief Initialize the global configuration + */ +GlobalConfiguration::GlobalConfiguration() +{ + load(); +} + +/** + * \typedef GlobalConfiguration::Configuration + * \brief Type representing global libcamera configuration + * + * All code outside GlobalConfiguration must use this type declaration and not + * the underlying type. + */ + +/** + * \brief Return configuration version + * + * The version is (optionally) declared in the configuration file in the + * top-level section `version', alongside `configuration'. This has currently no + * real use but may be needed in future if configuration incompatibilities + * occur. + * + * \return Configuration version as declared in the configuration file or 0 if + * no version is declared there + */ +unsigned int GlobalConfiguration::version() const +{ + return (*yamlConfiguration_)["version"].get().value_or(0); +} + +/** + * \brief Return libcamera global configuration + * + * This returns the whole configuration stored in the top-level section + * `configuration' of the YAML configuration file. + * + * The requested part of the configuration can be accessed using \a YamlObject + * methods. + * + * \note \a YamlObject type itself shouldn't be used in type declarations to + * avoid trouble if we decide to change the underlying data objects in future. + * + * \return The whole configuration section + */ +GlobalConfiguration::Configuration GlobalConfiguration::configuration() const +{ + return (*yamlConfiguration_)["configuration"]; +} + +} /* namespace libcamera */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index b3ca27f21..5b9b86f21 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -31,6 +31,7 @@ libcamera_internal_sources = files([ 'device_enumerator_sysfs.cpp', 'dma_buf_allocator.cpp', 'formats.cpp', + 'global_configuration.cpp', 'ipa_controls.cpp', 'ipa_data_serializer.cpp', 'ipa_interface.cpp', From patchwork Thu Sep 11 09:29:32 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24309 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 C674BC328C for ; Thu, 11 Sep 2025 09:30:06 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id AD6CB69371; Thu, 11 Sep 2025 11:30:05 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="OEfu8IBe"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 57BD769369 for ; Thu, 11 Sep 2025 11:30:03 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1757583002; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=GBHXZPfFtSB+MH/uAL2AtkFIccHTCqbrnpNQFVW5BM4=; b=OEfu8IBetjURDv+WWjcUDU6oSJZ2C0s7hZVSFKNEqWKLsKNP+yfX0zoJKQ4XjunDQlzou/ /+QY70p5zFelL1fAhK9uP8NiMw36apw9QfnUsG0sN0+utcgx42rv+kFY8oj44HFyP+JgWW Usl0l7AsjpUWxHeeEbKmW/H1VwSbjM8= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-594-DrG9k2cUM8efsj9GLmXNQA-1; Thu, 11 Sep 2025 05:30:00 -0400 X-MC-Unique: DrG9k2cUM8efsj9GLmXNQA-1 X-Mimecast-MFC-AGG-ID: DrG9k2cUM8efsj9GLmXNQA_1757582999 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id A98DA1800343; Thu, 11 Sep 2025 09:29:59 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.34.98]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 2229119560B1; Thu, 11 Sep 2025 09:29:56 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Kieran Bingham , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Laurent Pinchart , Paul Elder Subject: [PATCH v17 02/12] libcamera: camera_manager: Construct GlobalConfiguration instance Date: Thu, 11 Sep 2025 11:29:32 +0200 Message-ID: <20250911092945.16517-3-mzamazal@redhat.com> In-Reply-To: <20250911092945.16517-1-mzamazal@redhat.com> References: <20250911092945.16517-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: JvOwDGARvPLlSKE3VEvChTb9CGGBQMprMh4HbRawkNM_1757582999 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" Global configuration is accessed via a GlobalConfiguration instance. The instance is conceptually a singleton, but singletons are not welcome in libcamera so we must store the (preferably single) instance somewhere. This patch creates a GlobalConfiguration instance in CameraManager and defines the corresponding access method. CameraManager is typically instantiated only once or a few times, it is accessible in many places in libcamera and the configuration can be retrieved from it and passed to other places if needed (it's read-only once created). Using CameraManager for the purpose is still suboptimal and we use it only due to lack of better options. An alternative could be Logger, which is still a singleton and it's accessible from everywhere. But with Logger, we have a chicken and egg problem -- GlobalConfiguration should log contingent problems with the configuration when it's loaded but if it is created in the logger then there are mutual infinite recursive calls. One possible way to deal with this is to look at the environment variables only during logging initialisation and apply the logging configuration when a CameraManager is constructed. Considering there are intentions to remove the Logger singleton, let's omit logging configuration for now. If there are multiple CameraManager instances, there are also multiple GlobalConfiguration instances, each CameraManager instance is meant to be fully independent, including configuration. They may or may not contain the same data, depending on whether the global configuration file in the file system was changed in the meantime. The configuration is stored in the private CameraManager. It's accessible within libcamera (via CameraManager) but it's not meant to be accessed by applications. Signed-off-by: Milan Zamazal Reviewed-by: Paul Elder Signed-off-by: Milan Zamazal --- include/libcamera/internal/camera_manager.h | 12 ++++++++++-- src/libcamera/camera_manager.cpp | 8 ++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/include/libcamera/internal/camera_manager.h b/include/libcamera/internal/camera_manager.h index 5dfbe1f65..b8b2966b5 100644 --- a/include/libcamera/internal/camera_manager.h +++ b/include/libcamera/internal/camera_manager.h @@ -7,8 +7,6 @@ #pragma once -#include - #include #include #include @@ -18,6 +16,9 @@ #include #include +#include + +#include "libcamera/internal/global_configuration.h" #include "libcamera/internal/process.h" namespace libcamera { @@ -38,6 +39,11 @@ public: void addCamera(std::shared_ptr camera) LIBCAMERA_TSA_EXCLUDES(mutex_); void removeCamera(std::shared_ptr camera) LIBCAMERA_TSA_EXCLUDES(mutex_); + const GlobalConfiguration &configuration() const + { + return configuration_; + } + IPAManager *ipaManager() const { return ipaManager_.get(); } protected: @@ -65,6 +71,8 @@ private: std::unique_ptr enumerator_; std::unique_ptr ipaManager_; + + const GlobalConfiguration configuration_; }; } /* namespace libcamera */ diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp index f81794bfd..dca3d9a83 100644 --- a/src/libcamera/camera_manager.cpp +++ b/src/libcamera/camera_manager.cpp @@ -15,6 +15,7 @@ #include "libcamera/internal/camera.h" #include "libcamera/internal/device_enumerator.h" +#include "libcamera/internal/global_configuration.h" #include "libcamera/internal/ipa_manager.h" #include "libcamera/internal/pipeline_handler.h" @@ -258,6 +259,13 @@ void CameraManager::Private::removeCamera(std::shared_ptr camera) o->cameraRemoved.emit(camera); } +/** + * \fn const GlobalConfiguration &CameraManager::Private::configuration() const + * \brief Get global configuration bound to the camera manager + * + * \return Reference to the configuration + */ + /** * \fn CameraManager::Private::ipaManager() const * \brief Retrieve the IPAManager From patchwork Thu Sep 11 09:29:33 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24310 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 E0600C324E for ; Thu, 11 Sep 2025 09:30:11 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 9317B69376; Thu, 11 Sep 2025 11:30:11 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="O7muSoGA"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1B0616935A for ; Thu, 11 Sep 2025 11:30:10 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1757583009; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Bw52UuO45FOFbwiN3BUPbA2UWTY2YDEcEO8Nrj9Nmi4=; b=O7muSoGApASjhCtnVxJvWrI+splWzAcBmA+FvfQs1XFZ+3GfkjShb/57W7sZceEeF0jr+i uKkT2LpG9uLtYwiZhxL2DthqtIQIkmg5IcqPO5ND3wWALvgg6HFNJrCP/2LlvYM0uVQwkK /jgQM393q3LqfyilsSbaz9HiFqt2a3Y= Received: from mx-prod-mc-04.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-223-VYKxYmA5Ni2maVBAwqA23Q-1; Thu, 11 Sep 2025 05:30:03 -0400 X-MC-Unique: VYKxYmA5Ni2maVBAwqA23Q-1 X-Mimecast-MFC-AGG-ID: VYKxYmA5Ni2maVBAwqA23Q_1757583002 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id A19BA1977538; Thu, 11 Sep 2025 09:30:02 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.34.98]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 44C8119560B1; Thu, 11 Sep 2025 09:29:59 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Kieran Bingham , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Laurent Pinchart , Paul Elder Subject: [PATCH v17 03/12] config: Add configuration retrieval helpers Date: Thu, 11 Sep 2025 11:29:33 +0200 Message-ID: <20250911092945.16517-4-mzamazal@redhat.com> In-Reply-To: <20250911092945.16517-1-mzamazal@redhat.com> References: <20250911092945.16517-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 82JVeA8pAu4Kd0pUHMrke0WZoU-2ZBDkZaheAqjZnRs_1757583002 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" Let's add some helpers to make accessing simple configuration values simpler. The helpers are used in the followup patches. GlobalConfiguration::option ensures that no value is returned rather than a value of YamlObject::empty. Signed-off-by: Milan Zamazal Reviewed-by: Paul Elder --- .../libcamera/internal/global_configuration.h | 28 ++++++ src/libcamera/global_configuration.cpp | 99 +++++++++++++++++++ 2 files changed, 127 insertions(+) diff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h index f695498c4..8d09517ed 100644 --- a/include/libcamera/internal/global_configuration.h +++ b/include/libcamera/internal/global_configuration.h @@ -8,6 +8,11 @@ #pragma once #include +#include +#include +#include + +#include #include "libcamera/internal/yaml_parser.h" @@ -23,6 +28,29 @@ public: unsigned int version() const; Configuration configuration() const; + template + std::optional option( + const std::initializer_list confPath) const + { + const YamlObject *c = &configuration(); + for (auto part : confPath) { + c = &(*c)[part]; + if (!*c) + return {}; + } + return c->get(); + } + + std::optional> listOption( + const std::initializer_list confPath) const; + std::optional envOption( + const char *const envVariable, + const std::initializer_list confPath) const; + std::optional> envListOption( + const char *const envVariable, + const std::initializer_list confPath, + const std::string delimiter = ":") const; + private: bool loadFile(const std::filesystem::path &fileName); void load(); diff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp index d02668111..592edcf30 100644 --- a/src/libcamera/global_configuration.cpp +++ b/src/libcamera/global_configuration.cpp @@ -8,8 +8,12 @@ #include "libcamera/internal/global_configuration.h" #include +#include +#include +#include #include #include +#include #include #include @@ -43,6 +47,12 @@ LOG_DEFINE_CATEGORY(Configuration) * If the first found configuration file cannot be opened or parsed, an error is * reported and no configuration file is used. This is to prevent libcamera from * using an unintended configuration file. + * + * The configuration can be accessed using the provided helpers. Namely + * GlobalConfiguration::option(), GlobalConfiguration::envOption(), + * GlobalConfiguration::listOption(), and GlobalConfiguration::envListOption() + * to access individual options, or GlobalConfiguration::configuration() to + * access the whole configuration. */ bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName) @@ -110,6 +120,95 @@ GlobalConfiguration::GlobalConfiguration() * the underlying type. */ +/** + * \fn std::optional GlobalConfiguration::option(const std::initializer_list &confPath) const + * \brief Return value of the configuration option identified by \a confPath + * \param[in] confPath Sequence of the YAML section names (excluding + * `configuration') leading to the requested option + * \return The value of the configuration item corresponding to \a confPath if + * it exists in the configuration file, or no value otherwise + */ + +/** + * \brief Return values of the configuration option identified by \a confPath + * \tparam T The type of the retrieved configuration value + * \param[in] confPath Sequence of the YAML section names (excluding + * `configuration') leading to the requested list option, separated by dots + * \return A vector of strings or no value if not found + */ +std::optional> GlobalConfiguration::listOption( + const std::initializer_list confPath) const +{ + const YamlObject *c = &configuration(); + for (auto part : confPath) { + c = &(*c)[part]; + if (!*c) + return {}; + } + return c->getList(); +} + +/** + * \brief Return value of environment variable with a fallback on the configuration file + * \param[in] envVariable Environment variable to get the value from + * \param[in] confPath The sequence of YAML section names to fall back on when + * \a envVariable is unavailable + * + * This helper looks first at the given environment variable and if it is + * defined then it returns its value (even if it is empty). Otherwise it looks + * for \a confPath the same way as in GlobalConfiguration::option. Only string + * values are supported. + * + * \note Support for using environment variables to configure libcamera behavior + * is provided here mostly for backward compatibility reasons. Introducing new + * configuration environment variables is discouraged. + * + * \return The value retrieved from the given environment if it is set, + * otherwise the value from the configuration file if it exists, or no value if + * it does not + */ +std::optional GlobalConfiguration::envOption( + const char *envVariable, + const std::initializer_list confPath) const +{ + const char *envValue = utils::secure_getenv(envVariable); + if (envValue) + return std::optional{ std::string{ envValue } }; + return option(confPath); +} + +/** + * \brief Return values of the configuration option from a file or environment + * \param[in] envVariable Environment variable to get the value from + * \param[in] confPath The same as in GlobalConfiguration::option + * \param[in] delimiter Items separator in the environment variable + * + * This helper looks first at the given environment variable and if it is + * defined (even if it is empty) then it splits its value by semicolons and + * returns the resulting list of strings. Otherwise it looks for \a confPath the + * same way as in GlobalConfiguration::option, value of which must be a list of + * strings. + * + * \note Support for using environment variables to configure libcamera behavior + * is provided here mostly for backward compatibility reasons. Introducing new + * configuration environment variables is discouraged. + * + * \return A vector of strings retrieved from the given environment option or + * configuration file or no value if not found; the vector may be empty + */ +std::optional> GlobalConfiguration::envListOption( + const char *const envVariable, + const std::initializer_list confPath, + const std::string delimiter) const +{ + const char *envValue = utils::secure_getenv(envVariable); + if (envValue) { + auto items = utils::split(envValue, delimiter); + return std::vector(items.begin(), items.end()); + } + return listOption(confPath); +} + /** * \brief Return configuration version * From patchwork Thu Sep 11 09:29:34 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24311 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 897ACC324E for ; Thu, 11 Sep 2025 09:30:15 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4AB0E69367; Thu, 11 Sep 2025 11:30:15 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="DCbzIpex"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 154F56935A for ; Thu, 11 Sep 2025 11:30:11 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1757583010; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=fo1jQO0iVdo6uMpU/eheH1m+fzefT0v95Feof2WkKm4=; b=DCbzIpexxBOdenKmeCHvcjnQHi+PspihN9FbsbUTsS3fOPiQlC2T9o5PURLUkgfhgl3ooj r4FMnLSf+m7DvcxX4hfgwr7tBDbokOgZiS2uCc0+YSlJsJuvMV91fhrCTTrJ9ZIqMzjsqj A5r0JrMEJD8G4yJmBzh1sp1KLAzU6iA= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-529-8Ut1NG0bNKak4Uf_5aCC7Q-1; Thu, 11 Sep 2025 05:30:06 -0400 X-MC-Unique: 8Ut1NG0bNKak4Uf_5aCC7Q-1 X-Mimecast-MFC-AGG-ID: 8Ut1NG0bNKak4Uf_5aCC7Q_1757583005 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 815641955E88; Thu, 11 Sep 2025 09:30:05 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.34.98]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 3D3D319560BE; Thu, 11 Sep 2025 09:30:02 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Kieran Bingham , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Laurent Pinchart , Paul Elder Subject: [PATCH v17 04/12] pipeline: rpi: Look up rpi configuration in the configuration file Date: Thu, 11 Sep 2025 11:29:34 +0200 Message-ID: <20250911092945.16517-5-mzamazal@redhat.com> In-Reply-To: <20250911092945.16517-1-mzamazal@redhat.com> References: <20250911092945.16517-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: _S1Gx-i7meslKFCYD9rpxFslrAJgmjRpeRo0hqlcyy0_1757583005 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" Let's make rpi configuration available in the global configuration file. It may be arguable whether pipeline specific configurations belong to the global configuration file. But: - Having a single configuration file is generally easier for the user. - The original configuration via environment variables can be already considered global. - This option points to other configuration files and it makes little sense to add another configuration file to the chain. The rpi configuration is currently placed in a separate file, specified by LIBCAMERA_RPI_CONFIG_FILE environment variable. Let's support the content of the file in the global configuration file. `version' field is omitted as the global configuration file has its own version and the required version in the original file has been 1.0 anyway. The configuration snippet: configuration: pipelines: rpi: bcm2835: pipeline_handler: ... pisp: pipeline_handler: ... To not break current user setups, LIBCAMERA_RPI_CONFIG_FILE environment variable is still supported and works as before, pointing to a separate configuration file. Just the duplicate check for the configuration file version in platformPipelineConfigure methods is removed. Signed-off-by: Milan Zamazal Reviewed-by: Paul Elder --- .../pipeline/rpi/common/pipeline_base.cpp | 59 +++++++++++-------- .../pipeline/rpi/common/pipeline_base.h | 3 +- src/libcamera/pipeline/rpi/pisp/pisp.cpp | 26 +++----- src/libcamera/pipeline/rpi/vc4/vc4.cpp | 26 +++----- 4 files changed, 56 insertions(+), 58 deletions(-) diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp index c209aa596..a4a018268 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp @@ -20,8 +20,10 @@ #include #include "libcamera/internal/camera_lens.h" +#include "libcamera/internal/global_configuration.h" #include "libcamera/internal/ipa_manager.h" #include "libcamera/internal/v4l2_subdevice.h" +#include "libcamera/internal/yaml_parser.h" using namespace std::chrono_literals; @@ -1093,35 +1095,46 @@ int CameraData::loadPipelineConfiguration() /* Initial configuration of the platform, in case no config file is present */ platformPipelineConfigure({}); + std::unique_ptr root; char const *configFromEnv = utils::secure_getenv("LIBCAMERA_RPI_CONFIG_FILE"); - if (!configFromEnv || *configFromEnv == '\0') - return 0; - - std::string filename = std::string(configFromEnv); - File file(filename); + if (configFromEnv && *configFromEnv != '\0') { + std::string filename = std::string(configFromEnv); + File file(filename); + + if (!file.open(File::OpenModeFlag::ReadOnly)) { + LOG(RPI, Warning) << "Failed to open configuration file '" << filename << "'" + << ", using defaults"; + return 0; + } - if (!file.open(File::OpenModeFlag::ReadOnly)) { - LOG(RPI, Warning) << "Failed to open configuration file '" << filename << "'" - << ", using defaults"; - return 0; - } + LOG(RPI, Info) << "Using configuration file '" << filename << "'"; - LOG(RPI, Info) << "Using configuration file '" << filename << "'"; + root = YamlParser::parse(file); + if (!root) { + LOG(RPI, Warning) << "Failed to parse configuration file, using defaults"; + return 0; + } - std::unique_ptr root = YamlParser::parse(file); - if (!root) { - LOG(RPI, Warning) << "Failed to parse configuration file, using defaults"; - return 0; - } + std::optional ver = (*root)["version"].get(); + if (!ver || *ver != 1.0) { + LOG(RPI, Warning) << "Unexpected configuration file version reported: " + << *ver; + return 0; + } - std::optional ver = (*root)["version"].get(); - if (!ver || *ver != 1.0) { - LOG(RPI, Warning) << "Unexpected configuration file version reported: " - << *ver; - return 0; + std::optional t = (*root)["target"].get(); + if (t != target()) { + LOG(RPI, Error) << "Unexpected target reported: expected \"" + << target() << "\", got " << (t ? t->c_str() : "(unknown)"); + return -EINVAL; + } } - const YamlObject &phConfig = (*root)["pipeline_handler"]; + GlobalConfiguration::Configuration config = + pipe()->cameraManager()->_d()->configuration().configuration()["pipelines"]["rpi"]; + const YamlObject &phConfig = (root + ? (*root)["pipeline_handler"] + : config[target()]["pipeline_handler"]); if (phConfig.contains("disable_startup_frame_drops")) LOG(RPI, Warning) @@ -1137,7 +1150,7 @@ int CameraData::loadPipelineConfiguration() frontendDevice()->setDequeueTimeout(config_.cameraTimeoutValue * 1ms); } - return platformPipelineConfigure(root); + return platformPipelineConfigure(phConfig); } int CameraData::loadIPA(ipa::RPi::InitResult *result) diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.h b/src/libcamera/pipeline/rpi/common/pipeline_base.h index 4bce4ec4f..ffbede798 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.h +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h @@ -95,8 +95,9 @@ public: virtual V4L2VideoDevice::Formats ispFormats() const = 0; virtual V4L2VideoDevice::Formats rawFormats() const = 0; virtual V4L2VideoDevice *frontendDevice() = 0; + virtual const std::string &target() const = 0; - virtual int platformPipelineConfigure(const std::unique_ptr &root) = 0; + virtual int platformPipelineConfigure(const YamlObject &phConfig) = 0; std::unique_ptr ipa_; diff --git a/src/libcamera/pipeline/rpi/pisp/pisp.cpp b/src/libcamera/pipeline/rpi/pisp/pisp.cpp index 082724c5a..0fb7c3fe8 100644 --- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp +++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp @@ -740,10 +740,16 @@ public: return cfe_[Cfe::Output0].dev(); } + const std::string &target() const override + { + static const std::string target = "pisp"; + return target; + } + CameraConfiguration::Status platformValidate(RPi::RPiCameraConfiguration *rpiConfig) const override; - int platformPipelineConfigure(const std::unique_ptr &root) override; + int platformPipelineConfigure(const YamlObject &phConfig) override; void platformStart() override; void platformStop() override; @@ -1331,7 +1337,7 @@ PiSPCameraData::platformValidate(RPi::RPiCameraConfiguration *rpiConfig) const return status; } -int PiSPCameraData::platformPipelineConfigure(const std::unique_ptr &root) +int PiSPCameraData::platformPipelineConfigure(const YamlObject &phConfig) { config_ = { .numCfeConfigStatsBuffers = 12, @@ -1340,23 +1346,9 @@ int PiSPCameraData::platformPipelineConfigure(const std::unique_ptr .disableHdr = false, }; - if (!root) + if (!phConfig) return 0; - std::optional ver = (*root)["version"].get(); - if (!ver || *ver != 1.0) { - LOG(RPI, Error) << "Unexpected configuration file version reported"; - return -EINVAL; - } - - std::optional target = (*root)["target"].get(); - if (target != "pisp") { - LOG(RPI, Error) << "Unexpected target reported: expected \"pisp\", got " - << (target ? target->c_str() : "(unknown)"); - return -EINVAL; - } - - const YamlObject &phConfig = (*root)["pipeline_handler"]; config_.numCfeConfigStatsBuffers = phConfig["num_cfe_config_stats_buffers"].get(config_.numCfeConfigStatsBuffers); config_.numCfeConfigQueue = diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp index 99d43bd0a..71c425373 100644 --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp @@ -61,13 +61,19 @@ public: return unicam_[Unicam::Image].dev(); } + const std::string &target() const override + { + static const std::string target = "bcm2835"; + return target; + } + void platformFreeBuffers() override { } CameraConfiguration::Status platformValidate(RPi::RPiCameraConfiguration *rpiConfig) const override; - int platformPipelineConfigure(const std::unique_ptr &root) override; + int platformPipelineConfigure(const YamlObject &phConfig) override; void platformStart() override; void platformStop() override; @@ -493,30 +499,16 @@ CameraConfiguration::Status Vc4CameraData::platformValidate(RPi::RPiCameraConfig return status; } -int Vc4CameraData::platformPipelineConfigure(const std::unique_ptr &root) +int Vc4CameraData::platformPipelineConfigure(const YamlObject &phConfig) { config_ = { .minUnicamBuffers = 2, .minTotalUnicamBuffers = 4, }; - if (!root) + if (!phConfig) return 0; - std::optional ver = (*root)["version"].get(); - if (!ver || *ver != 1.0) { - LOG(RPI, Error) << "Unexpected configuration file version reported"; - return -EINVAL; - } - - std::optional target = (*root)["target"].get(); - if (target != "bcm2835") { - LOG(RPI, Error) << "Unexpected target reported: expected \"bcm2835\", got " - << (target ? target->c_str() : "(unknown)"); - return -EINVAL; - } - - const YamlObject &phConfig = (*root)["pipeline_handler"]; config_.minUnicamBuffers = phConfig["min_unicam_buffers"].get(config_.minUnicamBuffers); config_.minTotalUnicamBuffers = From patchwork Thu Sep 11 09:29:35 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24312 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 22A8EC328C for ; Thu, 11 Sep 2025 09:30:17 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 32B456937A; Thu, 11 Sep 2025 11:30:16 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="DTwdt3Bf"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id CEA936935A for ; Thu, 11 Sep 2025 11:30:13 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1757583012; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6LMVQ+nq8t/v6uElAGgjnybmofVcM3zUkbFRTVX7dzg=; b=DTwdt3BfmaJ6v7URAyaLfNnvp67uzzMcbHv9knUcjLeuu4zcTXgnsKI6W5Obbc0GIMxEYt s6scRHWYuNPX6MDgvHwm+Hbj7H0YP5KvG4LneH7gcBZ0qOtj4NUzS49vlkSjEeTNu3ryGa LLheFbJa9TXNp7TwMwkp4z4P8QwFhr4= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-635-ooD5nlpnPy6XDLCqM5inZQ-1; Thu, 11 Sep 2025 05:30:09 -0400 X-MC-Unique: ooD5nlpnPy6XDLCqM5inZQ-1 X-Mimecast-MFC-AGG-ID: ooD5nlpnPy6XDLCqM5inZQ_1757583008 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 7A2C21800447; Thu, 11 Sep 2025 09:30:08 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.34.98]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 0429119560B1; Thu, 11 Sep 2025 09:30:05 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Kieran Bingham , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Laurent Pinchart , Paul Elder Subject: [PATCH v17 05/12] config: Look up IPA configurables in configuration file Date: Thu, 11 Sep 2025 11:29:35 +0200 Message-ID: <20250911092945.16517-6-mzamazal@redhat.com> In-Reply-To: <20250911092945.16517-1-mzamazal@redhat.com> References: <20250911092945.16517-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 6Wc6DoVkD1f6zZ3FkI2R_ujxDsQYYxmDsDXpb_651ZY_1757583008 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" This patch adds configuration options for environment variables used in the IPA proxy. The configuration snippet: configuration: ipa: config_paths: - config path 1 - config path 2 - ... module_paths: - module path 1 - module path 2 - ... proxy_paths: - proxy path 1 - proxy path 2 - ... force_isolation: BOOL LIBCAMERA__TUNING_FILE remains configurable only via the environment variable; this is supposed to be used only for testing and debugging and it's not clear what to do about IPA names like "rpi/vc4" and "rpi/pisp" exactly. There are two ways to pass the configuration to the places where it is needed: Either to pass it as an argument to the method calls that need it, or to pass it to the class constructors and extract the needed configuration from there. This patch uses the second method as it is less polluting the code. Signed-off-by: Milan Zamazal Reviewed-by: Paul Elder --- include/libcamera/internal/ipa_manager.h | 7 ++- include/libcamera/internal/ipa_proxy.h | 8 ++- src/libcamera/camera_manager.cpp | 2 +- src/libcamera/ipa_manager.cpp | 39 ++++++++----- src/libcamera/ipa_proxy.cpp | 58 +++++++++---------- .../module_ipa_proxy.cpp.tmpl | 4 +- .../module_ipa_proxy.h.tmpl | 2 +- 7 files changed, 68 insertions(+), 52 deletions(-) diff --git a/include/libcamera/internal/ipa_manager.h b/include/libcamera/internal/ipa_manager.h index a0d448cf9..b0b44c74a 100644 --- a/include/libcamera/internal/ipa_manager.h +++ b/include/libcamera/internal/ipa_manager.h @@ -17,6 +17,7 @@ #include #include "libcamera/internal/camera_manager.h" +#include "libcamera/internal/global_configuration.h" #include "libcamera/internal/ipa_module.h" #include "libcamera/internal/pipeline_handler.h" #include "libcamera/internal/pub_key.h" @@ -28,7 +29,7 @@ LOG_DECLARE_CATEGORY(IPAManager) class IPAManager { public: - IPAManager(); + IPAManager(const GlobalConfiguration &configuration); ~IPAManager(); template @@ -42,7 +43,8 @@ public: if (!m) return nullptr; - std::unique_ptr proxy = std::make_unique(m, !self->isSignatureValid(m)); + const GlobalConfiguration &configuration = cm->_d()->configuration(); + std::unique_ptr proxy = std::make_unique(m, !self->isSignatureValid(m), configuration); if (!proxy->isValid()) { LOG(IPAManager, Error) << "Failed to load proxy"; return nullptr; @@ -73,6 +75,7 @@ private: #if HAVE_IPA_PUBKEY static const uint8_t publicKeyData_[]; static const PubKey pubKey_; + bool forceIsolation_; #endif }; diff --git a/include/libcamera/internal/ipa_proxy.h b/include/libcamera/internal/ipa_proxy.h index 983bcc5fa..f1865d67e 100644 --- a/include/libcamera/internal/ipa_proxy.h +++ b/include/libcamera/internal/ipa_proxy.h @@ -7,10 +7,14 @@ #pragma once +#include #include +#include #include +#include "libcamera/internal/global_configuration.h" + namespace libcamera { class IPAModule; @@ -24,7 +28,7 @@ public: ProxyRunning, }; - IPAProxy(IPAModule *ipam); + IPAProxy(IPAModule *ipam, const GlobalConfiguration &configuration); ~IPAProxy(); bool isValid() const { return valid_; } @@ -40,6 +44,8 @@ protected: private: IPAModule *ipam_; + std::vector configPaths_; + std::vector execPaths_; }; } /* namespace libcamera */ diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp index dca3d9a83..64df62444 100644 --- a/src/libcamera/camera_manager.cpp +++ b/src/libcamera/camera_manager.cpp @@ -41,7 +41,7 @@ LOG_DEFINE_CATEGORY(Camera) CameraManager::Private::Private() : initialized_(false) { - ipaManager_ = std::make_unique(); + ipaManager_ = std::make_unique(this->configuration()); } int CameraManager::Private::start() diff --git a/src/libcamera/ipa_manager.cpp b/src/libcamera/ipa_manager.cpp index 830750dcc..000d56efa 100644 --- a/src/libcamera/ipa_manager.cpp +++ b/src/libcamera/ipa_manager.cpp @@ -9,13 +9,17 @@ #include #include +#include #include +#include #include +#include #include #include #include +#include "libcamera/internal/global_configuration.h" #include "libcamera/internal/ipa_module.h" #include "libcamera/internal/ipa_proxy.h" #include "libcamera/internal/pipeline_handler.h" @@ -101,30 +105,36 @@ LOG_DEFINE_CATEGORY(IPAManager) * The IPAManager class is meant to only be instantiated once, by the * CameraManager. */ -IPAManager::IPAManager() +IPAManager::IPAManager(const GlobalConfiguration &configuration) { #if HAVE_IPA_PUBKEY if (!pubKey_.isValid()) LOG(IPAManager, Warning) << "Public key not valid"; + + char *force = utils::secure_getenv("LIBCAMERA_IPA_FORCE_ISOLATION"); + forceIsolation_ = (force && force[0] != '\0') || + (!force && configuration.option({ "ipa", "force_isolation" }) + .value_or(false)); #endif unsigned int ipaCount = 0; /* User-specified paths take precedence. */ - const char *modulePaths = utils::secure_getenv("LIBCAMERA_IPA_MODULE_PATH"); - if (modulePaths) { - for (const auto &dir : utils::split(modulePaths, ":")) { - if (dir.empty()) - continue; - - ipaCount += addDir(dir.c_str()); - } + const auto modulePaths = + configuration.envListOption( + "LIBCAMERA_IPA_MODULE_PATH", { "ipa", "module_paths" }); + for (const auto &dir : modulePaths.value_or(std::vector())) { + if (dir.empty()) + continue; - if (!ipaCount) - LOG(IPAManager, Warning) - << "No IPA found in '" << modulePaths << "'"; + ipaCount += addDir(dir.c_str()); } + if (!ipaCount) + LOG(IPAManager, Warning) << "No IPA found in '" + << utils::join(modulePaths.value_or(std::vector()), ":") + << "'"; + /* * When libcamera is used before it is installed, load IPAs from the * same build directory as the libcamera library itself. @@ -279,11 +289,10 @@ IPAModule *IPAManager::module(PipelineHandler *pipe, uint32_t minVersion, bool IPAManager::isSignatureValid([[maybe_unused]] IPAModule *ipa) const { #if HAVE_IPA_PUBKEY - char *force = utils::secure_getenv("LIBCAMERA_IPA_FORCE_ISOLATION"); - if (force && force[0] != '\0') { + if (forceIsolation_) { LOG(IPAManager, Debug) << "Isolation of IPA module " << ipa->path() - << " forced through environment variable"; + << " forced through configuration"; return false; } diff --git a/src/libcamera/ipa_proxy.cpp b/src/libcamera/ipa_proxy.cpp index b5c13a30f..9d2acd716 100644 --- a/src/libcamera/ipa_proxy.cpp +++ b/src/libcamera/ipa_proxy.cpp @@ -7,13 +7,16 @@ #include "libcamera/internal/ipa_proxy.h" +#include #include #include #include +#include #include #include +#include "libcamera/internal/global_configuration.h" #include "libcamera/internal/ipa_module.h" /** @@ -27,7 +30,8 @@ LOG_DEFINE_CATEGORY(IPAProxy) namespace { -std::string ipaConfigurationFile(const std::string &ipaName, const std::string &name) +std::string ipaConfigurationFile(const std::string &ipaName, const std::string &name, + const std::vector &configPaths) { /* * Start with any user override through the module-specific environment @@ -47,20 +51,15 @@ std::string ipaConfigurationFile(const std::string &ipaName, const std::string & int ret; /* - * Check the directory pointed to by the IPA config path environment - * variable next. + * Check the directory pointed to by the IPA config path next. */ - const char *confPaths = utils::secure_getenv("LIBCAMERA_IPA_CONFIG_PATH"); - if (confPaths) { - for (const auto &dir : utils::split(confPaths, ":")) { - if (dir.empty()) - continue; - - std::string confPath = dir + "/" + ipaName + "/" + name; - ret = stat(confPath.c_str(), &statbuf); - if (ret == 0 && (statbuf.st_mode & S_IFMT) == S_IFREG) - return confPath; - } + for (const auto &dir : configPaths) { + if (dir.empty()) + continue; + std::string confPath = dir + "/" + ipaName + "/" + name; + ret = stat(confPath.c_str(), &statbuf); + if (ret == 0 && (statbuf.st_mode & S_IFMT) == S_IFREG) + return confPath; } std::string root = utils::libcameraSourcePath(); @@ -120,9 +119,12 @@ std::string ipaConfigurationFile(const std::string &ipaName, const std::string & /** * \brief Construct an IPAProxy instance * \param[in] ipam The IPA module + * \param[in] configuration The global configuration */ -IPAProxy::IPAProxy(IPAModule *ipam) - : valid_(false), state_(ProxyStopped), ipam_(ipam) +IPAProxy::IPAProxy(IPAModule *ipam, const GlobalConfiguration &configuration) + : valid_(false), state_(ProxyStopped), ipam_(ipam), + configPaths_(configuration.envListOption("LIBCAMERA_IPA_CONFIG_PATH", { "ipa", "config_paths" }).value_or(std::vector())), + execPaths_(configuration.envListOption("LIBCAMERA_IPA_PROXY_PATH", { "ipa", "proxy_paths" }).value_or(std::vector())) { } @@ -175,7 +177,7 @@ std::string IPAProxy::configurationFile(const std::string &name, * has been validated when loading the module. */ const std::string ipaName = ipam_->info().name; - std::string confPath = ipaConfigurationFile(ipaName, name); + std::string confPath = ipaConfigurationFile(ipaName, name, configPaths_); if (!confPath.empty()) { LOG(IPAProxy, Info) << "Using tuning file " << confPath; return confPath; @@ -188,7 +190,7 @@ std::string IPAProxy::configurationFile(const std::string &name, return std::string(); } - confPath = ipaConfigurationFile(ipaName, fallbackName); + confPath = ipaConfigurationFile(ipaName, fallbackName, configPaths_); LOG(IPAProxy, Warning) << "Configuration file '" << name << "' not found for IPA module '" << ipaName @@ -214,18 +216,14 @@ std::string IPAProxy::resolvePath(const std::string &file) const { std::string proxyFile = "/" + file; - /* Check env variable first. */ - const char *execPaths = utils::secure_getenv("LIBCAMERA_IPA_PROXY_PATH"); - if (execPaths) { - for (const auto &dir : utils::split(execPaths, ":")) { - if (dir.empty()) - continue; - - std::string proxyPath = dir; - proxyPath += proxyFile; - if (!access(proxyPath.c_str(), X_OK)) - return proxyPath; - } + /* Check the configuration first. */ + for (const auto &dir : execPaths_) { + if (dir.empty()) + continue; + + std::string proxyPath = dir + proxyFile; + if (!access(proxyPath.c_str(), X_OK)) + return proxyPath; } /* diff --git a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl index beb646e2d..18b4ab5e5 100644 --- a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl +++ b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl @@ -45,8 +45,8 @@ namespace {{ns}} { {% endfor %} {%- endif %} -{{proxy_name}}::{{proxy_name}}(IPAModule *ipam, bool isolate) - : IPAProxy(ipam), isolate_(isolate), +{{proxy_name}}::{{proxy_name}}(IPAModule *ipam, bool isolate, const GlobalConfiguration &configuration) + : IPAProxy(ipam, configuration), isolate_(isolate), controlSerializer_(ControlSerializer::Role::Proxy), seq_(0) { LOG(IPAProxy, Debug) diff --git a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl index a0312a7c1..057c3ab03 100644 --- a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl +++ b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl @@ -37,7 +37,7 @@ namespace {{ns}} { class {{proxy_name}} : public IPAProxy, public {{interface_name}}, public Object { public: - {{proxy_name}}(IPAModule *ipam, bool isolate); + {{proxy_name}}(IPAModule *ipam, bool isolate, const GlobalConfiguration &configuration); ~{{proxy_name}}(); {% for method in interface_main.methods %} From patchwork Thu Sep 11 09:29:36 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24314 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 E6D59C324E for ; Thu, 11 Sep 2025 09:30:23 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4BEA66937F; Thu, 11 Sep 2025 11:30:23 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="bdf2ZNdT"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1F87F69379 for ; Thu, 11 Sep 2025 11:30:17 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1757583016; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=EnzvDmyWfdHzeUttreOPmWNoUapkICh5Gh15E5DU3MI=; b=bdf2ZNdT2WxE+0ATHy7t0ptnqY5a5bsZ1xQtMzYZZzw/CL4w2FtE8Xj45NU20c1sISB4zf uDl0f6aNym3dYFK5AhjvJ/PlKWb9N8WEs2avZevCJiZwHHmXbrEUFFDNXfiAJwRsVuABl1 sHnIWaQavtchB47lkqQt/TjtaGh4CBY= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-160-mEkZMnOfPDqbPS1s8ENRqg-1; Thu, 11 Sep 2025 05:30:12 -0400 X-MC-Unique: mEkZMnOfPDqbPS1s8ENRqg-1 X-Mimecast-MFC-AGG-ID: mEkZMnOfPDqbPS1s8ENRqg_1757583011 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 842DA180057A; Thu, 11 Sep 2025 09:30:11 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.34.98]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 2A0D819560B1; Thu, 11 Sep 2025 09:30:08 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Kieran Bingham , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Laurent Pinchart , Paul Elder Subject: [PATCH v17 06/12] config: Look up pipelines match list in configuration file Date: Thu, 11 Sep 2025 11:29:36 +0200 Message-ID: <20250911092945.16517-7-mzamazal@redhat.com> In-Reply-To: <20250911092945.16517-1-mzamazal@redhat.com> References: <20250911092945.16517-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: kNbSl6ksgLCV2JPrtaSm2Wq7gh1yDhDzxo_1LsyYQXU_1757583011 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" Let's add a configuration file item for the pipelines match list. The configuration snippet: configuration: pipelines_match_list: rkisp1,simple Signed-off-by: Milan Zamazal Reviewed-by: Paul Elder --- src/libcamera/camera_manager.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp index 64df62444..c203b08f7 100644 --- a/src/libcamera/camera_manager.cpp +++ b/src/libcamera/camera_manager.cpp @@ -111,14 +111,16 @@ void CameraManager::Private::createPipelineHandlers() * file and only fallback on environment variable or all handlers, if * there is no configuration file. */ - const char *pipesList = - utils::secure_getenv("LIBCAMERA_PIPELINES_MATCH_LIST"); - if (pipesList) { + const auto pipesList = + configuration().envListOption("LIBCAMERA_PIPELINES_MATCH_LIST", + { "pipelines_match_list" }, + ","); + if (pipesList.has_value()) { /* * When a list of preferred pipelines is defined, iterate * through the ordered list to match the enumerated devices. */ - for (const auto &pipeName : utils::split(pipesList, ",")) { + for (const auto &pipeName : pipesList.value()) { const PipelineHandlerFactoryBase *factory; factory = PipelineHandlerFactoryBase::getFactoryByName(pipeName); if (!factory) From patchwork Thu Sep 11 09:29:37 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24313 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 5F0E6C324E for ; Thu, 11 Sep 2025 09:30:22 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D90F769371; Thu, 11 Sep 2025 11:30:21 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="GVF5TYYi"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C5C0369371 for ; Thu, 11 Sep 2025 11:30:17 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1757583016; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ts5KFGt4ynS2X51Qhwn2JULH3QkHHKSILHcaHyB8bug=; b=GVF5TYYib9NuGZB0yxIPFm55JV/J8lrtMtv7IiAVFP/yMn5jqboCrvxIwagfuxQ/K34h83 BiD8mPPsbJVCzFs/IoqcqkoC5AZGAnh062PHTa3Y+kQAhII4378Ege9AhUHRYFA6sssEsT QRcGPg9n5dlBCIHp+XTtQAkGmLN2m80= Received: from mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-295-vWs_LsXWPGi4JifKJvcohQ-1; Thu, 11 Sep 2025 05:30:15 -0400 X-MC-Unique: vWs_LsXWPGi4JifKJvcohQ-1 X-Mimecast-MFC-AGG-ID: vWs_LsXWPGi4JifKJvcohQ_1757583014 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 401261956086; Thu, 11 Sep 2025 09:30:14 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.34.98]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 17A7919560B1; Thu, 11 Sep 2025 09:30:11 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Kieran Bingham , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Laurent Pinchart , Paul Elder Subject: [PATCH v17 07/12] pipeline: simple: Allow enabling software ISP via config file Date: Thu, 11 Sep 2025 11:29:37 +0200 Message-ID: <20250911092945.16517-8-mzamazal@redhat.com> In-Reply-To: <20250911092945.16517-1-mzamazal@redhat.com> References: <20250911092945.16517-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: nZQzE4o6eCzLR9WcUoFzzGsq43JiLbjdrt4_v-EmC9c_1757583014 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" This patch allows enabling or disabling software ISP via config file in addition to compile time. This can be useful for software ISP testing on various platforms as well as for overriding the defaults in case the defaults don't work well (e.g. hardware ISP may or may not work on i.MX8MP depending on the kernel and libcamera patches present in the given system). The configuration is specified as follows: configuration: pipelines: simple: supported_devices: - driver: DRIVER-NAME software_isp: BOOLEAN - ... For example: configuration: pipelines: simple: supported_devices: - driver: mxc-isi software_isp: true The overall configuration of enabling or disabling software ISP may get dropped in future but this patch is still useful in the meantime. Signed-off-by: Milan Zamazal Reviewed-by: Paul Elder --- src/libcamera/pipeline/simple/simple.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp index 4f914be80..c816cffc9 100644 --- a/src/libcamera/pipeline/simple/simple.cpp +++ b/src/libcamera/pipeline/simple/simple.cpp @@ -30,11 +30,13 @@ #include #include "libcamera/internal/camera.h" +#include "libcamera/internal/camera_manager.h" #include "libcamera/internal/camera_sensor.h" #include "libcamera/internal/camera_sensor_properties.h" #include "libcamera/internal/converter.h" #include "libcamera/internal/delayed_controls.h" #include "libcamera/internal/device_enumerator.h" +#include "libcamera/internal/global_configuration.h" #include "libcamera/internal/media_device.h" #include "libcamera/internal/pipeline_handler.h" #include "libcamera/internal/software_isp/software_isp.h" @@ -1682,6 +1684,19 @@ bool SimplePipelineHandler::matchDevice(MediaDevice *media, } swIspEnabled_ = info.swIspEnabled; + const GlobalConfiguration &configuration = cameraManager()->_d()->configuration(); + for (GlobalConfiguration::Configuration entry : + configuration.configuration()["pipelines"]["simple"]["supported_devices"] + .asList()) { + auto name = entry["driver"].get(); + if (name == info.driver) { + swIspEnabled_ = entry["software_isp"].get().value_or(swIspEnabled_); + LOG(SimplePipeline, Debug) + << "Configuration file overrides software ISP for " + << info.driver << " to " << swIspEnabled_; + break; + } + } /* Locate the sensors. */ std::vector sensors = locateSensors(media); From patchwork Thu Sep 11 09:29:38 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24315 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 D2A0EC324E for ; Thu, 11 Sep 2025 09:30:25 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0AF346937D; Thu, 11 Sep 2025 11:30:25 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="NZtkdZkB"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BA1276937C for ; Thu, 11 Sep 2025 11:30:20 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1757583019; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=la4ROaSw6rwS4EtEUYWAO3IHnyHCQLRIploNsSTrqyA=; b=NZtkdZkBDXasHkhl7MRN14vuuJ1YiZPf7J/Is3dKaEAoKsq9IqvDzOIxH0Thym/w77eyNX aOhGT2DWXlKOBdXqSdmQSJStJLjU1QF25sWtDmEkzcEhIT2oQ/gxvzmTDkGATDWmaqaUpF Xs8JpR0uprLeFDkqRmAsyomqH1XOmfg= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-401-coup7zZpMWGa09QHtHnAgg-1; Thu, 11 Sep 2025 05:30:18 -0400 X-MC-Unique: coup7zZpMWGa09QHtHnAgg-1 X-Mimecast-MFC-AGG-ID: coup7zZpMWGa09QHtHnAgg_1757583017 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id F3B9D1955E88; Thu, 11 Sep 2025 09:30:16 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.34.98]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 9704F19560B1; Thu, 11 Sep 2025 09:30:14 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Kieran Bingham , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Laurent Pinchart , Paul Elder Subject: [PATCH v17 08/12] Documentation: Add global configuration file documentation Date: Thu, 11 Sep 2025 11:29:38 +0200 Message-ID: <20250911092945.16517-9-mzamazal@redhat.com> In-Reply-To: <20250911092945.16517-1-mzamazal@redhat.com> References: <20250911092945.16517-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: tx6-rMUn0h8fwKUCt0QBqNcTE5QJNMVuR16N-doxJDY_1757583017 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" Extend (and rename) the documentation of environment variables with information about the configuration file. Signed-off-by: Milan Zamazal Reviewed-by: Paul Elder --- Documentation/documentation-contents.rst | 2 +- Documentation/index.rst | 2 +- Documentation/meson.build | 2 +- ...ariables.rst => runtime_configuration.rst} | 116 ++++++++++++++++-- 4 files changed, 107 insertions(+), 15 deletions(-) rename Documentation/{environment_variables.rst => runtime_configuration.rst} (65%) diff --git a/Documentation/documentation-contents.rst b/Documentation/documentation-contents.rst index 5c1118493..4be3729cf 100644 --- a/Documentation/documentation-contents.rst +++ b/Documentation/documentation-contents.rst @@ -7,7 +7,7 @@ * :doc:`/feature_requirements` * :doc:`/guides/application-developer` * :doc:`/python-bindings` - * :doc:`/environment_variables` + * :doc:`/runtime_configuration` * :doc:`/api-html/index` * :doc:`/code-of-conduct` * | diff --git a/Documentation/index.rst b/Documentation/index.rst index 251112fbd..200de6f67 100644 --- a/Documentation/index.rst +++ b/Documentation/index.rst @@ -12,13 +12,13 @@ Application Writer's Guide Camera Sensor Model - Environment variables Feature Requirements IPA Writer's guide Lens driver requirements libcamera Architecture Pipeline Handler Writer's Guide Python Bindings + Runtime configuration Sensor driver requirements SoftwareISP Benchmarking Tracing guide diff --git a/Documentation/meson.build b/Documentation/meson.build index a8d4afc01..b47b16e97 100644 --- a/Documentation/meson.build +++ b/Documentation/meson.build @@ -157,7 +157,6 @@ if sphinx.found() 'contributing.rst', 'design/ae.rst', 'documentation-contents.rst', - 'environment_variables.rst', 'feature_requirements.rst', 'guides/application-developer.rst', 'guides/ipa.rst', @@ -169,6 +168,7 @@ if sphinx.found() 'libcamera_architecture.rst', 'mali-c55.dot', 'python-bindings.rst', + 'runtime_configuration.rst', 'sensor_driver_requirements.rst', 'software-isp-benchmarking.rst', '../README.rst', diff --git a/Documentation/environment_variables.rst b/Documentation/runtime_configuration.rst similarity index 65% rename from Documentation/environment_variables.rst rename to Documentation/runtime_configuration.rst index 0cb4e27cd..8792232d7 100644 --- a/Documentation/environment_variables.rst +++ b/Documentation/runtime_configuration.rst @@ -2,14 +2,95 @@ .. include:: documentation-contents.rst -Environment variables +Runtime configuration ===================== -The libcamera behaviour can be tuned through environment variables. This -document lists all the available variables and describes their usage. - -List of variables ------------------ +The libcamera behaviour can be tuned through a configuration file or +environment variables. This document lists all the configuration options +and describes their usage. + +General rules +------------- + +The configuration file is looked up in the following locations, in this +order: + +- $XDG_CONFIG_HOME/libcamera/configuration.yaml +- LIBCAMERA_SYSCONF_DIR/configuration.yaml +- LIBCAMERA_DATA_DIR/libcamera/configuration.yaml + +The first configuration file found wins, configuration files in other +locations are ignored. + +Settings in environment variables take precedence over settings in +configuration files. This allows overriding behaviour temporarily +without the need to modify configuration files. + +Configuration options +--------------------- + +Here is an overview of the available configuration options, in the YAML +file structure: + +:: + + configuration: + ipa: + force_isolation: # true/false + config_paths: + - ... # full path to a directory + module_paths: + - ... # full path to a directory + pipelines_match_list: + - ... # pipeline name + pipelines: + rpi: + bcm2835: + pipeline_handler: + ... + pisp: + pipeline_handler: + ... + simple: + supported_devices: + - driver: # driver name, e.g. `mxc-isi` + software_isp: # true/false + +Configuration file example +-------------------------- + +:: + + --- + version: 1 + configuration: + ipa: + config_paths: + - /home/user/.libcamera/share/ipa + - /opt/libcamera/vendor/share/ipa + module_paths: + - /home/user/.libcamera/lib + - /opt/libcamera/vendor/lib + proxy_paths: + - /home/user/.libcamera/proxy/worker + - /opt/libcamera/vendor/proxy/worker + force_isolation: true + pipelines_match_list: + - rkisp1 + - simple + pipelines: + rpi: + bcm2835: + pipeline_handler: + min_unicam_buffers: 2 + min_total_unicam_buffers: 2 + simple: + supported_devices: + - driver: mxc-isi + software_isp: true + +List of variables and configuration options +------------------------------------------- LIBCAMERA_LOG_FILE The custom destination for log output. @@ -24,27 +105,27 @@ LIBCAMERA_LOG_LEVELS LIBCAMERA_LOG_NO_COLOR Disable coloring of log messages (`more `__). -LIBCAMERA_IPA_CONFIG_PATH +LIBCAMERA_IPA_CONFIG_PATH, ipa.config_paths Define custom search locations for IPA configurations (`more `__). Example value: ``${HOME}/.libcamera/share/ipa:/opt/libcamera/vendor/share/ipa`` -LIBCAMERA_IPA_FORCE_ISOLATION +LIBCAMERA_IPA_FORCE_ISOLATION, ipa.force_isolation When set to a non-empty string, force process isolation of all IPA modules. Example value: ``1`` -LIBCAMERA_IPA_MODULE_PATH +LIBCAMERA_IPA_MODULE_PATH, ipa.module_paths Define custom search locations for IPA modules (`more `__). Example value: ``${HOME}/.libcamera/lib:/opt/libcamera/vendor/lib`` -LIBCAMERA_IPA_PROXY_PATH +LIBCAMERA_IPA_PROXY_PATH, ipa.proxy_paths Define custom full path for a proxy worker for a given executable name. Example value: ``${HOME}/.libcamera/proxy/worker:/opt/libcamera/vendor/proxy/worker`` -LIBCAMERA_PIPELINES_MATCH_LIST +LIBCAMERA_PIPELINES_MATCH_LIST, pipelines_match_list Define an ordered list of pipeline names to be used to match the media devices in the system. The pipeline handler names used to populate the variable are the ones passed to the REGISTER_PIPELINE_HANDLER() macro in the @@ -55,6 +136,10 @@ LIBCAMERA_PIPELINES_MATCH_LIST LIBCAMERA_RPI_CONFIG_FILE Define a custom configuration file to use in the Raspberry Pi pipeline handler. + Instead of using a separate configuration file, the whole + configuration can be put directly into the global configuration file as + outlined above. + Example value: ``/usr/local/share/libcamera/pipeline/rpi/vc4/minimal_mem.yaml`` LIBCAMERA__TUNING_FILE @@ -62,6 +147,13 @@ LIBCAMERA__TUNING_FILE Example value: ``/usr/local/share/libcamera/ipa/rpi/vc4/custom_sensor.json`` +pipelines.simple.supported_devices.driver, pipelines.simple.supported_devices.software_isp + Override whether software ISP is enabled for the given driver. + + Example `driver` value: ``mxc-isi`` + + Example `software_isp` value: ``true`` + Further details --------------- @@ -156,7 +248,7 @@ code. IPA configuration ~~~~~~~~~~~~~~~~~ -IPA modules use configuration files to store parameters. The format and +IPA modules use their own configuration files to store parameters. The format and contents of the configuration files is specific to the IPA module. They usually contain tuning parameters for the algorithms, in JSON format. From patchwork Thu Sep 11 09:29:39 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24316 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 36917C324E for ; Thu, 11 Sep 2025 09:30:30 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id DEACF69384; Thu, 11 Sep 2025 11:30:29 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="LJRRRJ1J"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 404F46937E for ; Thu, 11 Sep 2025 11:30:24 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1757583023; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=G0eB4l70Q/WXFCStedrJL7fziK2jzThhBecL8wx00EU=; b=LJRRRJ1JeRFO4jyB0ajJg2GFyztmuamRXVArPpkJN7py9RWbEYImbYZReQm9q6SvdOz4mV fEfmzx0oo01/3qbHS2JZm2utz+gd9JuwkMsdw2fH2g6AbkpqQQe8gVv8O6Qpg0ay4/7Xd3 xNqMKl0ZYkoFxSxAeGKiyJDkYd/gWBE= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-536-1aWg5vh7O4uPrihG15QxXQ-1; Thu, 11 Sep 2025 05:30:21 -0400 X-MC-Unique: 1aWg5vh7O4uPrihG15QxXQ-1 X-Mimecast-MFC-AGG-ID: 1aWg5vh7O4uPrihG15QxXQ_1757583020 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 15594180045C; Thu, 11 Sep 2025 09:30:20 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.34.98]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 9202D19560B1; Thu, 11 Sep 2025 09:30:17 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Kieran Bingham , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Laurent Pinchart , Paul Elder Subject: [PATCH v17 09/12] libcamera: software_isp: Make input buffer copying configurable Date: Thu, 11 Sep 2025 11:29:39 +0200 Message-ID: <20250911092945.16517-10-mzamazal@redhat.com> In-Reply-To: <20250911092945.16517-1-mzamazal@redhat.com> References: <20250911092945.16517-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 2krkMonIy4OGNPL3BBDsGHKDim2x0PVtmP6nqlVIWos_1757583020 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" On some platforms, working directly on the input buffer is very slow due to disabled caching. This is why we copy the input buffer into standard (cached) memory. This is an unnecessary overhead on platforms with cached buffers. Let's make input buffer copying configurable. The default is still copying, as its overhead is much lower than contingent operations on non-cached memory. Ideally, we should improve this in future to set the default to non-copying if we can be sure under observable circumstances that we are working with cached buffers. Completes software ISP TODO #6. Reviewed-by: Paul Elder Signed-off-by: Milan Zamazal --- Documentation/runtime_configuration.rst | 13 +++++++++++++ src/libcamera/software_isp/TODO | 11 ----------- src/libcamera/software_isp/debayer_cpu.cpp | 7 +++++-- src/libcamera/software_isp/debayer_cpu.h | 3 ++- src/libcamera/software_isp/software_isp.cpp | 3 ++- 5 files changed, 22 insertions(+), 15 deletions(-) diff --git a/Documentation/runtime_configuration.rst b/Documentation/runtime_configuration.rst index 8792232d7..6610e8bec 100644 --- a/Documentation/runtime_configuration.rst +++ b/Documentation/runtime_configuration.rst @@ -55,6 +55,8 @@ file structure: supported_devices: - driver: # driver name, e.g. `mxc-isi` software_isp: # true/false + software_isp: + copy_input_buffer: # true/false Configuration file example -------------------------- @@ -88,6 +90,8 @@ Configuration file example supported_devices: - driver: mxc-isi software_isp: true + software_isp: + copy_input_buffer: false List of variables and configuration options ------------------------------------------- @@ -154,6 +158,15 @@ pipelines.simple.supported_devices.driver, pipelines.simple.supported_devices.so Example `software_isp` value: ``true`` +software_isp.copy_input_buffer + Define whether input buffers should be copied into standard (cached) + memory in software ISP. This is done by default to prevent very slow + processing on platforms with non-cached buffers. It can be set to + false on platforms with cached buffers to avoid an unnecessary + overhead. + + Example value: ``false`` + Further details --------------- diff --git a/src/libcamera/software_isp/TODO b/src/libcamera/software_isp/TODO index a50db668e..2c919f442 100644 --- a/src/libcamera/software_isp/TODO +++ b/src/libcamera/software_isp/TODO @@ -71,17 +71,6 @@ per-frame buffers like we do for hardware ISPs. --- -6. Input buffer copying configuration - -> DebayerCpu::DebayerCpu(std::unique_ptr stats) -> : stats_(std::move(stats)), gammaCorrection_(1.0) -> { -> enableInputMemcpy_ = true; - -Set this appropriately and/or make it configurable. - ---- - 7. Performance measurement configuration > void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams params) diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp index 66f6038c1..cec6cc6be 100644 --- a/src/libcamera/software_isp/debayer_cpu.cpp +++ b/src/libcamera/software_isp/debayer_cpu.cpp @@ -24,6 +24,7 @@ #include "libcamera/internal/bayer_format.h" #include "libcamera/internal/dma_buf_allocator.h" #include "libcamera/internal/framebuffer.h" +#include "libcamera/internal/global_configuration.h" #include "libcamera/internal/mapped_framebuffer.h" namespace libcamera { @@ -38,8 +39,9 @@ namespace libcamera { /** * \brief Constructs a DebayerCpu object * \param[in] stats Pointer to the stats object to use + * \param[in] configuration The global configuration */ -DebayerCpu::DebayerCpu(std::unique_ptr stats) +DebayerCpu::DebayerCpu(std::unique_ptr stats, const GlobalConfiguration &configuration) : stats_(std::move(stats)) { /* @@ -50,7 +52,8 @@ DebayerCpu::DebayerCpu(std::unique_ptr stats) * always set it to true as the safer choice but this should be changed in * future. */ - enableInputMemcpy_ = true; + enableInputMemcpy_ = + configuration.option({ "software_isp", "copy_input_buffer" }).value_or(true); /* Initialize color lookup tables */ for (unsigned int i = 0; i < DebayerParams::kRGBLookupSize; i++) { diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h index 926195e98..2f35aa18b 100644 --- a/src/libcamera/software_isp/debayer_cpu.h +++ b/src/libcamera/software_isp/debayer_cpu.h @@ -18,6 +18,7 @@ #include #include "libcamera/internal/bayer_format.h" +#include "libcamera/internal/global_configuration.h" #include "debayer.h" #include "swstats_cpu.h" @@ -27,7 +28,7 @@ namespace libcamera { class DebayerCpu : public Debayer, public Object { public: - DebayerCpu(std::unique_ptr stats); + DebayerCpu(std::unique_ptr stats, const GlobalConfiguration &configuration); ~DebayerCpu(); int configure(const StreamConfiguration &inputCfg, diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp index 28e2a360e..b7651b7d2 100644 --- a/src/libcamera/software_isp/software_isp.cpp +++ b/src/libcamera/software_isp/software_isp.cpp @@ -114,7 +114,8 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor, } stats->statsReady.connect(this, &SoftwareIsp::statsReady); - debayer_ = std::make_unique(std::move(stats)); + const GlobalConfiguration &configuration = pipe->cameraManager()->_d()->configuration(); + debayer_ = std::make_unique(std::move(stats), configuration); debayer_->inputBufferReady.connect(this, &SoftwareIsp::inputReady); debayer_->outputBufferReady.connect(this, &SoftwareIsp::outputReady); From patchwork Thu Sep 11 09:29:40 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24317 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 4A0C6C324E for ; Thu, 11 Sep 2025 09:30:32 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id DBF5869388; Thu, 11 Sep 2025 11:30:31 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="h3fzCVOu"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4941A6937E for ; Thu, 11 Sep 2025 11:30:28 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1757583027; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=REK1bmCXcN+AyAMxTkPR+sOtE9C95kxMIuCGw0a3MWE=; b=h3fzCVOu7d+6094nSQTtZlq33w7GZ1dLzHZBuSNTwbJnYviSA199cvV2yPJBXfzB5nQVot 5aWEkEYbKac6EITm10+IEUOpHNPgAlcZDYZEO2aKmJTEDxM6Me8noje/mCfpcTc4UviiBw 3D96VCAvdgk+Wscr9F0uicEWx5Nlztc= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-553-LRi1FQmLP1iObRcFkCFlPw-1; Thu, 11 Sep 2025 05:30:24 -0400 X-MC-Unique: LRi1FQmLP1iObRcFkCFlPw-1 X-Mimecast-MFC-AGG-ID: LRi1FQmLP1iObRcFkCFlPw_1757583022 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id D3D821800293; Thu, 11 Sep 2025 09:30:22 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.34.98]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 8817719560B1; Thu, 11 Sep 2025 09:30:20 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Kieran Bingham , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Laurent Pinchart , Paul Elder Subject: [PATCH v17 10/12] libcamera: software_isp: Make measurement configurable Date: Thu, 11 Sep 2025 11:29:40 +0200 Message-ID: <20250911092945.16517-11-mzamazal@redhat.com> In-Reply-To: <20250911092945.16517-1-mzamazal@redhat.com> References: <20250911092945.16517-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: tvDlzborajHjai0ebDC9sveH45HtP2uZRiFoBNXbHhw_1757583022 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" Software ISP performs performance measurement on certain part of initial frames. Let's make this range configurable. For this purpose, this patch introduces new configuration options pipelines.simple.measure.skip and pipelines.simple.measure.number. Setting the latter one to 0 disables the measurement. Instead of the last frame, the class member and its configuration specify the number of frames to measure. This is easier to use for users and doesn't require to adjust two configuration parameters when the number of the initially skipped frames is changed. The patch also changes the names of the class members to make them more accurate. Completes software ISP TODO #7. Reviewed-by: Paul Elder Signed-off-by: Milan Zamazal --- Documentation/runtime_configuration.rst | 18 ++++++++++++++++ src/libcamera/software_isp/TODO | 25 ---------------------- src/libcamera/software_isp/debayer_cpu.cpp | 25 ++++++++++++++-------- src/libcamera/software_isp/debayer_cpu.h | 7 +++--- 4 files changed, 37 insertions(+), 38 deletions(-) diff --git a/Documentation/runtime_configuration.rst b/Documentation/runtime_configuration.rst index 6610e8bec..702139544 100644 --- a/Documentation/runtime_configuration.rst +++ b/Documentation/runtime_configuration.rst @@ -57,6 +57,9 @@ file structure: software_isp: # true/false software_isp: copy_input_buffer: # true/false + measure: + skip: # non-negative integer, frames to skip initially + number: # non-negative integer, frames to measure Configuration file example -------------------------- @@ -92,6 +95,9 @@ Configuration file example software_isp: true software_isp: copy_input_buffer: false + measure: + skip: 50 + number: 30 List of variables and configuration options ------------------------------------------- @@ -167,6 +173,18 @@ software_isp.copy_input_buffer Example value: ``false`` +software_isp.measure.skip, software_isp.measure.number + Define per-frame time measurement parameters in software ISP. `skip` + defines how many initial frames are skipped before starting the + measurement; `number` defines how many frames then participate in the + measurement. + + Set `software_isp.measure.number` to 0 to disable the measurement. + + Example `skip` value: ``50`` + + Example `number` value: ``30`` + Further details --------------- diff --git a/src/libcamera/software_isp/TODO b/src/libcamera/software_isp/TODO index 2c919f442..f19e15ae2 100644 --- a/src/libcamera/software_isp/TODO +++ b/src/libcamera/software_isp/TODO @@ -71,31 +71,6 @@ per-frame buffers like we do for hardware ISPs. --- -7. Performance measurement configuration - -> void DebayerCpu::process(FrameBuffer *input, FrameBuffer *output, DebayerParams params) -> /* Measure before emitting signals */ -> if (measuredFrames_ < DebayerCpu::kLastFrameToMeasure && -> ++measuredFrames_ > DebayerCpu::kFramesToSkip) { -> timespec frameEndTime = {}; -> clock_gettime(CLOCK_MONOTONIC_RAW, &frameEndTime); -> frameProcessTime_ += timeDiff(frameEndTime, frameStartTime); -> if (measuredFrames_ == DebayerCpu::kLastFrameToMeasure) { -> const unsigned int measuredFrames = DebayerCpu::kLastFrameToMeasure - -> DebayerCpu::kFramesToSkip; -> LOG(Debayer, Info) -> << "Processed " << measuredFrames -> << " frames in " << frameProcessTime_ / 1000 << "us, " -> << frameProcessTime_ / (1000 * measuredFrames) -> << " us/frame"; -> } -> } - -I wonder if there would be a way to control at runtime when/how to -perform those measurements. Maybe that's a bit overkill. - ---- - 8. DebayerCpu cleanups > >> class DebayerCpu : public Debayer, public Object diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp index cec6cc6be..2f57857ad 100644 --- a/src/libcamera/software_isp/debayer_cpu.cpp +++ b/src/libcamera/software_isp/debayer_cpu.cpp @@ -55,6 +55,13 @@ DebayerCpu::DebayerCpu(std::unique_ptr stats, const GlobalConfigurat enableInputMemcpy_ = configuration.option({ "software_isp", "copy_input_buffer" }).value_or(true); + skipBeforeMeasure_ = configuration.option( + { "software_isp", "measure", "skip" }) + .value_or(skipBeforeMeasure_); + framesToMeasure_ = configuration.option( + { "software_isp", "measure", "number" }) + .value_or(framesToMeasure_); + /* Initialize color lookup tables */ for (unsigned int i = 0; i < DebayerParams::kRGBLookupSize; i++) { red_[i] = green_[i] = blue_[i] = i; @@ -557,7 +564,7 @@ int DebayerCpu::configure(const StreamConfiguration &inputCfg, lineBuffers_[i].resize(lineBufferLength_); } - measuredFrames_ = 0; + encounteredFrames_ = 0; frameProcessTime_ = 0; return 0; @@ -763,7 +770,10 @@ void DebayerCpu::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output { timespec frameStartTime; - if (measuredFrames_ < DebayerCpu::kLastFrameToMeasure) { + bool measure = framesToMeasure_ > 0 && + encounteredFrames_ < skipBeforeMeasure_ + framesToMeasure_ && + ++encounteredFrames_ > skipBeforeMeasure_; + if (measure) { frameStartTime = {}; clock_gettime(CLOCK_MONOTONIC_RAW, &frameStartTime); } @@ -820,18 +830,15 @@ void DebayerCpu::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output dmaSyncers.clear(); /* Measure before emitting signals */ - if (measuredFrames_ < DebayerCpu::kLastFrameToMeasure && - ++measuredFrames_ > DebayerCpu::kFramesToSkip) { + if (measure) { timespec frameEndTime = {}; clock_gettime(CLOCK_MONOTONIC_RAW, &frameEndTime); frameProcessTime_ += timeDiff(frameEndTime, frameStartTime); - if (measuredFrames_ == DebayerCpu::kLastFrameToMeasure) { - const unsigned int measuredFrames = DebayerCpu::kLastFrameToMeasure - - DebayerCpu::kFramesToSkip; + if (encounteredFrames_ == skipBeforeMeasure_ + framesToMeasure_) { LOG(Debayer, Info) - << "Processed " << measuredFrames + << "Processed " << framesToMeasure_ << " frames in " << frameProcessTime_ / 1000 << "us, " - << frameProcessTime_ / (1000 * measuredFrames) + << frameProcessTime_ / (1000 * framesToMeasure_) << " us/frame"; } } diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h index 2f35aa18b..9d343e464 100644 --- a/src/libcamera/software_isp/debayer_cpu.h +++ b/src/libcamera/software_isp/debayer_cpu.h @@ -161,11 +161,10 @@ private: unsigned int xShift_; /* Offset of 0/1 applied to window_.x */ bool enableInputMemcpy_; bool swapRedBlueGains_; - unsigned int measuredFrames_; + unsigned int encounteredFrames_; int64_t frameProcessTime_; - /* Skip 30 frames for things to stabilize then measure 30 frames */ - static constexpr unsigned int kFramesToSkip = 30; - static constexpr unsigned int kLastFrameToMeasure = 60; + unsigned int skipBeforeMeasure_ = 30; + unsigned int framesToMeasure_ = 30; }; } /* namespace libcamera */ From patchwork Thu Sep 11 09:29:41 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24318 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 A62E8C324E for ; Thu, 11 Sep 2025 09:30:35 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id F2CA16938B; Thu, 11 Sep 2025 11:30:34 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="Odd2w7rG"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5638F69380 for ; Thu, 11 Sep 2025 11:30:31 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1757583030; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=9q8sEDKnDMQ3d/PZmEK+gtSTSaq00JgeZd8D6BfN+/Y=; b=Odd2w7rGx4LUesOvlvFACxQVByqR/pCpH/Fb4tGSyNBj0GdW4/srJelwY5zHL6qH3LezdH X3mt47gac2v7B6MN5RC66GRzBCp1s9/8oOxRvr+CG9tKX+xqmQyAl/8nMEVj80U/XsXYVn ArKof/5u6JbGz6BqkgXSEKoNdpoI/3I= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-97-TbdmpT63N_m2mJneFJb4eA-1; Thu, 11 Sep 2025 05:30:27 -0400 X-MC-Unique: TbdmpT63N_m2mJneFJb4eA-1 X-Mimecast-MFC-AGG-ID: TbdmpT63N_m2mJneFJb4eA_1757583025 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id C4BED180047F; Thu, 11 Sep 2025 09:30:25 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.34.98]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 6799019560BB; Thu, 11 Sep 2025 09:30:23 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Kieran Bingham , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Laurent Pinchart , Paul Elder Subject: [PATCH v17 11/12] config: Make configuration file locations configurable Date: Thu, 11 Sep 2025 11:29:41 +0200 Message-ID: <20250911092945.16517-12-mzamazal@redhat.com> In-Reply-To: <20250911092945.16517-1-mzamazal@redhat.com> References: <20250911092945.16517-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: h5lbCT0GJ8E8bYgZJ72S_JosQZCjMylGUcqvCu8gTdU_1757583025 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" To support easy switching of configurations, let's introduce LIBCAMERA_CONFIG_DIR and LIBCAMERA_CONFIG_NAME environment variables. LIBCAMERA_CONFIG_DIR environment variable specifies a directory or a list of directories separated by colons where to look for the libcamera configuration file before trying the standard locations. This override can be useful in a meson devenv. LIBCAMERA_CONFIG_NAME - specifies the path of the configuration file to load if it is an absolute path (useful to quickly try some configuration); or - prevents any configuration file from loading if it is defined and empty (useful to disable all configuration files); or - specifies the path of the configuration file to load, relative to the configuration directories (useful to quickly select between different configurations). If a configuration file specified by those environment variables doesn't exist, no custom configuration is loaded. Signed-off-by: Milan Zamazal Reviewed-by: Paul Elder --- Documentation/runtime_configuration.rst | 13 +++++++ src/libcamera/global_configuration.cpp | 50 +++++++++++++++++-------- 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/Documentation/runtime_configuration.rst b/Documentation/runtime_configuration.rst index 702139544..5307f3645 100644 --- a/Documentation/runtime_configuration.rst +++ b/Documentation/runtime_configuration.rst @@ -19,6 +19,19 @@ order: - LIBCAMERA_SYSCONF_DIR/configuration.yaml - LIBCAMERA_DATA_DIR/libcamera/configuration.yaml +If LIBCAMERA_CONFIG_DIR environment variable is non-empty then it +specifies additional directories where to look for the configuration +file, before looking at the standard locations. It can be a single +directory or multiple directories separated by colons. + +The default name of the configuration file, configuration.yaml, can be +overridden in LIBCAMERA_CONFIG_NAME environment variable. The variable +can specify just an alternative configuration file name to be looked up +in the locations above, or a whole absolute path. If an absolute path is +specified then it is the only location that is used; if the given file +doesn't exist then no configuration file is read. If the variable is +defined but empty, no configuration is loaded. + The first configuration file found wins, configuration files in other locations are ignored. diff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp index 592edcf30..8c2670e03 100644 --- a/src/libcamera/global_configuration.cpp +++ b/src/libcamera/global_configuration.cpp @@ -23,13 +23,6 @@ namespace libcamera { -namespace { -const std::vector globalConfigurationFiles = { - std::filesystem::path(LIBCAMERA_SYSCONF_DIR) / "configuration.yaml", - std::filesystem::path(LIBCAMERA_DATA_DIR) / "configuration.yaml", -}; -} - LOG_DEFINE_CATEGORY(Configuration) /** @@ -80,6 +73,33 @@ bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName) void GlobalConfiguration::load() { + const char *libcameraConfigName = + utils::secure_getenv("LIBCAMERA_CONFIG_NAME"); + if (libcameraConfigName && libcameraConfigName[0] == '\0') + return; + if (!libcameraConfigName) + libcameraConfigName = ""; + + std::filesystem::path configName(libcameraConfigName); + + if (configName.is_absolute()) { + loadFile(configName); + return; + } + + if (configName.empty()) + configName = std::filesystem::path("configuration.yaml"); + + std::vector configurationDirectories; + + const char *configDir = utils::secure_getenv("LIBCAMERA_CONFIG_DIR"); + if (configDir) { + for (auto const &path : utils::split(configDir, ":")) { + if (!path.empty()) + configurationDirectories.push_back(path); + } + } + std::filesystem::path userConfigurationDirectory; const char *xdgConfigHome = utils::secure_getenv("XDG_CONFIG_HOME"); if (xdgConfigHome) { @@ -90,18 +110,16 @@ void GlobalConfiguration::load() userConfigurationDirectory = std::filesystem::path(home) / ".config"; } + if (!userConfigurationDirectory.empty()) + configurationDirectories.push_back( + userConfigurationDirectory / "libcamera"); - if (!userConfigurationDirectory.empty()) { - std::filesystem::path user_configuration_file = - userConfigurationDirectory / "libcamera" / "configuration.yaml"; - if (loadFile(user_configuration_file)) - return; - } + configurationDirectories.push_back(LIBCAMERA_SYSCONF_DIR); + configurationDirectories.push_back(LIBCAMERA_DATA_DIR); - for (const auto &path : globalConfigurationFiles) { - if (loadFile(path)) + for (const auto &path : configurationDirectories) + if (loadFile(path / configName)) return; - } } /** From patchwork Thu Sep 11 09:29:42 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24319 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 1423FC324E for ; Thu, 11 Sep 2025 09:30:38 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A52C76937E; Thu, 11 Sep 2025 11:30:37 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="IzLlxYjg"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 855D36937E for ; Thu, 11 Sep 2025 11:30:34 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1757583033; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=+QAMHlAPdUbdVXkoxpasqU6UWQCpzXFG9/7BFW452xU=; b=IzLlxYjg0PviGa7SLniIJJMOR2QOcRXF5yTBYDEiRQH/vf9vRJV4U9W3qKrjvfstFn3GPL TITAIjjPZzn/a8QQtCPe8mCjLv7yN6WlP47TOISx4clx04wh5AIe7acA98ktoLhdLbBjq2 slJcmfpNDofYz/PRAU4RjPoDZ0J3yUw= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-624-d6lZwhx8NrixdF7-P8qHeQ-1; Thu, 11 Sep 2025 05:30:29 -0400 X-MC-Unique: d6lZwhx8NrixdF7-P8qHeQ-1 X-Mimecast-MFC-AGG-ID: d6lZwhx8NrixdF7-P8qHeQ_1757583028 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id BD0B11800447; Thu, 11 Sep 2025 09:30:28 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.34.98]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 4237419560BB; Thu, 11 Sep 2025 09:30:26 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Kieran Bingham , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Laurent Pinchart , Paul Elder Subject: [PATCH v17 12/12] config: Check configuration file version Date: Thu, 11 Sep 2025 11:29:42 +0200 Message-ID: <20250911092945.16517-13-mzamazal@redhat.com> In-Reply-To: <20250911092945.16517-1-mzamazal@redhat.com> References: <20250911092945.16517-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: YchZfRz4m1SLOlgzZ2BhBU1vQU4zL_ce1tAzK8u3gCw_1757583028 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true 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" We don't know what the future versions of the configuration file will look like. The current code can process only version 1; let's check that the read configuration is of this version. Signed-off-by: Milan Zamazal Reviewed-by: Paul Elder --- src/libcamera/global_configuration.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp index 8c2670e03..2eec45363 100644 --- a/src/libcamera/global_configuration.cpp +++ b/src/libcamera/global_configuration.cpp @@ -67,6 +67,15 @@ bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName) return true; } + const std::optional version = (*configuration)["version"].get(); + if (version != 1) { + LOG(Configuration, Error) + << "Failed to read configuration file due to unsupported version " + << (version ? std::to_string(version.value()) : "\"unspecified\"") + << ", expected version 1"; + return true; + } + yamlConfiguration_ = std::move(configuration); return true; }