From patchwork Tue Jul 29 07:31:49 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24012 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 E13F7BDCC1 for ; Tue, 29 Jul 2025 07:32:31 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0A176691CE; Tue, 29 Jul 2025 09:32:27 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="GHHoLGed"; 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 26846691C7 for ; Tue, 29 Jul 2025 09:32:21 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1753774340; 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=0H4BUC87svpD/bg2VHPgtIpWTDHBmdYdn7oq7DBqhEU=; b=GHHoLGedbCb7K96OJyVoVCvoaDbEX/RHBsVK8b2zI8rTh0eFjRx+13tWCoWkZ7v2BrecRU utFOg7YhLMOyROSGgjld8MfJUJt0qTTJSi1bKKUKb3H9DqAswU6eOa6DPCAf0q+4YrZRFm Cv9TlbW/tNgqY5D5izE1HSWQQbkXSwM= Received: from mx-prod-mc-01.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-177-dPXn-im6Ms2PnikVbTpAdA-1; Tue, 29 Jul 2025 03:32:13 -0400 X-MC-Unique: dPXn-im6Ms2PnikVbTpAdA-1 X-Mimecast-MFC-AGG-ID: dPXn-im6Ms2PnikVbTpAdA_1753774332 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 7B78E19560B6; Tue, 29 Jul 2025 07:32:12 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.43.17.23]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 594C31800242; Tue, 29 Jul 2025 07:32:10 +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 Subject: [PATCH v16 01/12] config: Introduce global runtime configuration Date: Tue, 29 Jul 2025 09:31:49 +0200 Message-ID: <20250729073201.5369-2-mzamazal@redhat.com> In-Reply-To: <20250729073201.5369-1-mzamazal@redhat.com> References: <20250729073201.5369-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: JIUvA17Psim5hTAyMn8POvQAdopsEUSaMCTrPLNdpRU_1753774332 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, stores and accesses the configuration. GlobalConfiguration instances are meant to be stored to and accessed from instances of another class, preferably from a single instance. 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 --- .../libcamera/internal/global_configuration.h | 34 +++++ include/libcamera/internal/meson.build | 1 + src/libcamera/global_configuration.cpp | 144 ++++++++++++++++++ src/libcamera/meson.build | 1 + 4 files changed, 180 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..50756b859 --- /dev/null +++ b/src/libcamera/global_configuration.cpp @@ -0,0 +1,144 @@ +/* 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. + */ + +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 de1eb99b2..275cf5a4b 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 Tue Jul 29 07:31:50 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24011 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 50B91BDCC1 for ; Tue, 29 Jul 2025 07:32:29 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 480E9691D1; Tue, 29 Jul 2025 09:32:25 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="QCsNC9UX"; 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 D4AC7614CD for ; Tue, 29 Jul 2025 09:32:19 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1753774338; 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=YSA6knoGYMYGCeSyvoUioydyEcY+dIW9xKtfVe72zUs=; b=QCsNC9UXviCJ+b4XhIGLlfPLAkUf6ZQlOlcyt5lEEqO7wBDZuinpbQTwIriKy4QsVcYwNk ++A6Lh9Sp/EAw1amXmP5p/7AhZAPBqF/XygLXf2s5U/ZEtqkDlJi97oewxK4GkztSLQUU4 d6SLlilaV2JmJ2lEhEI9FtjP6jdErlI= Received: from mx-prod-mc-03.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-186-2FggCaAKPeCJnj0Ap6UBbw-1; Tue, 29 Jul 2025 03:32:15 -0400 X-MC-Unique: 2FggCaAKPeCJnj0Ap6UBbw-1 X-Mimecast-MFC-AGG-ID: 2FggCaAKPeCJnj0Ap6UBbw_1753774335 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 9285619560AA; Tue, 29 Jul 2025 07:32:14 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.43.17.23]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id D14501800B6C; Tue, 29 Jul 2025 07:32:12 +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 Subject: [PATCH v16 02/12] config: Make GlobalConfiguration instance Date: Tue, 29 Jul 2025 09:31:50 +0200 Message-ID: <20250729073201.5369-3-mzamazal@redhat.com> In-Reply-To: <20250729073201.5369-1-mzamazal@redhat.com> References: <20250729073201.5369-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: msGkTsyGj8WINf_5_R1MDijgnh7l8MDbISm5Zncj3f8_1753774335 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 CameraManager privately, it's not meant to be accessed by applications. Signed-off-by: Milan Zamazal --- include/libcamera/internal/camera_manager.h | 8 ++++++++ src/libcamera/camera_manager.cpp | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/include/libcamera/internal/camera_manager.h b/include/libcamera/internal/camera_manager.h index 0150ca61f..e8082eb34 100644 --- a/include/libcamera/internal/camera_manager.h +++ b/include/libcamera/internal/camera_manager.h @@ -18,6 +18,7 @@ #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: @@ -66,6 +72,8 @@ private: std::unique_ptr ipaManager_; ProcessManager processManager_; + + 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 Tue Jul 29 07:31:51 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24013 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 325A9BDCC1 for ; Tue, 29 Jul 2025 07:32:35 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 92D33691CB; Tue, 29 Jul 2025 09:32:34 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="hKmPVSLT"; 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 7AA87691C7 for ; Tue, 29 Jul 2025 09:32:22 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1753774341; 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=pEz0xlQDB93TD9/9f/OdVhclR+Bn+Mqi0RRDFEVvADM=; b=hKmPVSLT9Z944r+Ie3eyVB/tD4cOuUC+K2uAPvQXH6gNFPBaeEIigl6LNKWWkeD8gGa48x yRIz9OPzPiZAMgUYKaytbeWEsVOzFihG+AiPNkJGCfZucWx/LEjyfurgyTg40qdXnWxBgn z3rvZ3nOn2ZIdtArmuojvrMcYUqoeq8= 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-310-FE1bKyY1MHientwl9YFxKQ-1; Tue, 29 Jul 2025 03:32:17 -0400 X-MC-Unique: FE1bKyY1MHientwl9YFxKQ-1 X-Mimecast-MFC-AGG-ID: FE1bKyY1MHientwl9YFxKQ_1753774336 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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 8D8BA180045C; Tue, 29 Jul 2025 07:32:16 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.43.17.23]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 062261800242; Tue, 29 Jul 2025 07:32: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 Subject: [PATCH v16 03/12] config: Add configuration retrieval helpers Date: Tue, 29 Jul 2025 09:31:51 +0200 Message-ID: <20250729073201.5369-4-mzamazal@redhat.com> In-Reply-To: <20250729073201.5369-1-mzamazal@redhat.com> References: <20250729073201.5369-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: U7fG5HEbK4T-TbIzjyNo6D_r8yJrhj1FZuRdno-cvU8_1753774336 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. GlobalConfiguration::option ensures that no value is returned rather than a value of YamlObject::empty. Signed-off-by: Milan Zamazal --- .../libcamera/internal/global_configuration.h | 8 +++ src/libcamera/global_configuration.cpp | 53 +++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h index f695498c4..78bebff9f 100644 --- a/include/libcamera/internal/global_configuration.h +++ b/include/libcamera/internal/global_configuration.h @@ -8,6 +8,9 @@ #pragma once #include +#include +#include +#include #include "libcamera/internal/yaml_parser.h" @@ -22,6 +25,11 @@ public: unsigned int version() const; Configuration configuration() const; + std::optional option( + const std::initializer_list confPath) const; + std::optional envOption( + const char *const envVariable, + const std::initializer_list confPath) const; private: bool loadFile(const std::filesystem::path &fileName); diff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp index 50756b859..5be0f0701 100644 --- a/src/libcamera/global_configuration.cpp +++ b/src/libcamera/global_configuration.cpp @@ -8,6 +8,8 @@ #include "libcamera/internal/global_configuration.h" #include +#include +#include #include #include @@ -39,6 +41,11 @@ LOG_DEFINE_CATEGORY(Configuration) * 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. + * + * The configuration can be accessed using the provided helpers. Namely + * GlobalConfiguration::option() or GlobalConfiguration::envOption() to access + * individual options or GlobalConfiguration::configuration() to access the + * whole configuration. */ bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName) @@ -106,6 +113,52 @@ GlobalConfiguration::GlobalConfiguration() * the underlying type. */ +/** + * \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 A value if an item corresponding to \a confPath exists in the + * configuration file, no value otherwise + */ +std::optional GlobalConfiguration::option( + const std::initializer_list confPath) const +{ + const YamlObject *c = &configuration(); + for (auto part : confPath) { + c = &(*c)[part]; + if (!*c) + return {}; + } + return c->get(); +} + +/** + * \brief Return value 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 + * + * 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 A value retrieved from the given environment option or configuration + * file or no value if not found + */ +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 configuration version * From patchwork Tue Jul 29 07:31:52 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24014 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 26651BDCC1 for ; Tue, 29 Jul 2025 07:32:38 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6DC16691DC; Tue, 29 Jul 2025 09:32:37 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="FByCPL9+"; 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 19066691CB for ; Tue, 29 Jul 2025 09:32:22 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1753774341; 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=dtcDPiFOhGOoHa31BP64+C+KEhnRhcC5Qu+bPuKHRr0=; b=FByCPL9+3d/6BtVpJTsBiumSCoSB3bNIxdG3baNd+b4byrsK66EhpLzDWe2zag3gHa6rWA Zq0wjSzUgeK0wFJexLTOkbXVZtIFpZbwPg1TMnCpTWEFCQUC8xzCa6fqiA/dqsNn75n5+T PqnVqkSJPmCPQSILJz+RPemhdVAXPZ0= Received: from mx-prod-mc-03.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-408-p6ZYE49FPg20lPO3tA5CnA-1; Tue, 29 Jul 2025 03:32:19 -0400 X-MC-Unique: p6ZYE49FPg20lPO3tA5CnA-1 X-Mimecast-MFC-AGG-ID: p6ZYE49FPg20lPO3tA5CnA_1753774338 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 8963E19560B3; Tue, 29 Jul 2025 07:32:18 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.43.17.23]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 016E118001DD; Tue, 29 Jul 2025 07:32:16 +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 Subject: [PATCH v16 04/12] config: Look up rpi configuration in the configuration file Date: Tue, 29 Jul 2025 09:31:52 +0200 Message-ID: <20250729073201.5369-5-mzamazal@redhat.com> In-Reply-To: <20250729073201.5369-1-mzamazal@redhat.com> References: <20250729073201.5369-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 0VQ1Ut_Azqa1t3mRMhEiTd8YevjUPLYrtuKKvcd2aKI_1753774338 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 --- .../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 563df198e..1effa85cd 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; @@ -1091,35 +1093,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) @@ -1135,7 +1148,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 Tue Jul 29 07:31:53 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24015 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 9EA0BC32B5 for ; Tue, 29 Jul 2025 07:32:40 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 544E5691E1; Tue, 29 Jul 2025 09:32:39 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="hPKoGOX9"; 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 6BBFC691CB for ; Tue, 29 Jul 2025 09:32:26 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1753774345; 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=amtUO3i0DcCI7qpxVj8ejA8x6/ITyfYqV/TmG5CC3rA=; b=hPKoGOX9um3HbXgrNuo332gy8s/D5KvmRxOd0VwZ3UbIYMoD/Y3a7nrT12h+2yyQhYqkyU iepxx6TdtZmX/FqNLJodgtTA2IXCH03oF5IMB/RAGiMIglSajhF6/Kf8XKatA1iHzF+koa P2sjuyfv8w31T9VimbdG1Whtx9Cnt50= 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-458-yx8Y0AnqPS-RtIbmCV1WTA-1; Tue, 29 Jul 2025 03:32:23 -0400 X-MC-Unique: yx8Y0AnqPS-RtIbmCV1WTA-1 X-Mimecast-MFC-AGG-ID: yx8Y0AnqPS-RtIbmCV1WTA_1753774340 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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 833F818001CA; Tue, 29 Jul 2025 07:32:20 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.43.17.23]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id EFF021800242; Tue, 29 Jul 2025 07:32:18 +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 Subject: [PATCH v16 05/12] config: Look up IPA configurables in configuration file Date: Tue, 29 Jul 2025 09:31:53 +0200 Message-ID: <20250729073201.5369-6-mzamazal@redhat.com> In-Reply-To: <20250729073201.5369-1-mzamazal@redhat.com> References: <20250729073201.5369-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: FPKOdM-G6lnWRRe1LWTZacA6jNimHAVLrt9J7vUbYtc_1753774340 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. Two utility functions configuration retrieval functions are added, to retrieve lists of values. 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 --- .../libcamera/internal/global_configuration.h | 21 +++++++- include/libcamera/internal/ipa_manager.h | 7 ++- include/libcamera/internal/ipa_proxy.h | 8 ++- src/libcamera/camera_manager.cpp | 2 +- src/libcamera/global_configuration.cpp | 47 +++++++++++++++-- src/libcamera/ipa_manager.cpp | 39 ++++++++------ src/libcamera/ipa_proxy.cpp | 51 +++++++++---------- .../module_ipa_proxy.cpp.tmpl | 4 +- .../module_ipa_proxy.h.tmpl | 2 +- 9 files changed, 128 insertions(+), 53 deletions(-) diff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h index 78bebff9f..3b500ee29 100644 --- a/include/libcamera/internal/global_configuration.h +++ b/include/libcamera/internal/global_configuration.h @@ -12,6 +12,8 @@ #include #include +#include + #include "libcamera/internal/yaml_parser.h" namespace libcamera { @@ -25,11 +27,28 @@ public: unsigned int version() const; Configuration configuration() const; - std::optional option( + + 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; private: bool loadFile(const std::filesystem::path &fileName); 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/global_configuration.cpp b/src/libcamera/global_configuration.cpp index 5be0f0701..1371392c5 100644 --- a/src/libcamera/global_configuration.cpp +++ b/src/libcamera/global_configuration.cpp @@ -9,9 +9,11 @@ #include #include +#include #include #include #include +#include #include #include @@ -114,13 +116,22 @@ GlobalConfiguration::GlobalConfiguration() */ /** + * \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 A value if an item corresponding to \a confPath exists in the * configuration file, no value otherwise */ -std::optional GlobalConfiguration::option( + +/** + * \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(); @@ -129,7 +140,7 @@ std::optional GlobalConfiguration::option( if (!*c) return {}; } - return c->get(); + return c->getList(); } /** @@ -156,7 +167,37 @@ std::optional GlobalConfiguration::envOption( const char *envValue = utils::secure_getenv(envVariable); if (envValue) return std::optional{ std::string{ envValue } }; - return option(confPath); + 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 + * + * 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 +{ + const char *envValue = utils::secure_getenv(envVariable); + if (envValue) { + auto items = utils::split(envValue, ":"); + return std::vector(items.begin(), items.end()); + } + return listOption(confPath); } /** 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 9907b9615..b845e9086 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" /** @@ -48,9 +51,12 @@ LOG_DEFINE_CATEGORY(IPAProxy) /** * \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())) { } @@ -122,20 +128,15 @@ std::string IPAProxy::configurationFile(const std::string &name, 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(); @@ -199,18 +200,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 9a3aadbd2..0f87e7976 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 Tue Jul 29 07:31:54 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24016 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 BA83DBDCC1 for ; Tue, 29 Jul 2025 07:32:42 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 44007691C9; Tue, 29 Jul 2025 09:32:42 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="Y1GOg8Xx"; 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 EAB48691C9 for ; Tue, 29 Jul 2025 09:32:28 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1753774348; 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=CVJmUDDOdQWEuPbm/ztceMKR1Mham4+L2VrTcWsORts=; b=Y1GOg8XxkV2coZY9w/asO/RSt1LUu31n+w1LNJQHGB4B1xi+6MV9FRE0V26I9wyJ+BDZt6 hfQwkPCQZJKNE6POMcn0995HZTU6mgKl6DcOkGvEOD8m9jt/Us2OPoCyfjYBlKCfR0AHuu ols8NqjqesF1R6Pvmn6kVkkgJzWQqMk= 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-498-3TDEOFoGNmG3ajCK1IdjZg-1; Tue, 29 Jul 2025 03:32:24 -0400 X-MC-Unique: 3TDEOFoGNmG3ajCK1IdjZg-1 X-Mimecast-MFC-AGG-ID: 3TDEOFoGNmG3ajCK1IdjZg_1753774342 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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 7E20319560B5; Tue, 29 Jul 2025 07:32:22 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.43.17.23]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id EA4D61800242; Tue, 29 Jul 2025 07:32: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 Subject: [PATCH v16 06/12] config: Look up pipelines match list in configuration file Date: Tue, 29 Jul 2025 09:31:54 +0200 Message-ID: <20250729073201.5369-7-mzamazal@redhat.com> In-Reply-To: <20250729073201.5369-1-mzamazal@redhat.com> References: <20250729073201.5369-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: OMML0uyAUqdZ7FuiCYoCSCA9VbDjS0txj-P3436owaI_1753774342 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 --- include/libcamera/internal/global_configuration.h | 3 ++- src/libcamera/camera_manager.cpp | 10 ++++++---- src/libcamera/global_configuration.cpp | 6 ++++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h index 3b500ee29..8d09517ed 100644 --- a/include/libcamera/internal/global_configuration.h +++ b/include/libcamera/internal/global_configuration.h @@ -48,7 +48,8 @@ public: const std::initializer_list confPath) const; std::optional> envListOption( const char *const envVariable, - const std::initializer_list confPath) const; + const std::initializer_list confPath, + const std::string delimiter = ":") const; private: bool loadFile(const std::filesystem::path &fileName); 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) diff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp index 1371392c5..b9531fdfb 100644 --- a/src/libcamera/global_configuration.cpp +++ b/src/libcamera/global_configuration.cpp @@ -174,6 +174,7 @@ std::optional GlobalConfiguration::envOption( * \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 @@ -190,11 +191,12 @@ std::optional GlobalConfiguration::envOption( */ std::optional> GlobalConfiguration::envListOption( const char *const envVariable, - const std::initializer_list confPath) const + const std::initializer_list confPath, + const std::string delimiter) const { const char *envValue = utils::secure_getenv(envVariable); if (envValue) { - auto items = utils::split(envValue, ":"); + auto items = utils::split(envValue, delimiter); return std::vector(items.begin(), items.end()); } return listOption(confPath); From patchwork Tue Jul 29 07:31:55 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24017 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 A9E25C32B5 for ; Tue, 29 Jul 2025 07:32:44 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E5BE6691D8; Tue, 29 Jul 2025 09:32:43 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="AATzXgZu"; 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 88411691C4 for ; Tue, 29 Jul 2025 09:32:29 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1753774348; 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=Wlv24hNNHSFMz+Ca9+dxl2NBtE2pvv+Gq7b8gHuo7j4=; b=AATzXgZudEPAHdqbLKUvFYDOgLo6hx0f2HGRrXZiwJfBcnO9tARTTnkzk6vDcnPLI5Bx+a 2kbu5nUQrViSNYWyEVma81KWcJ3sImLcuGjRXFt8TO6T6RvFFrDoXIrBLd4MCu2oSjN+NH l+XPxne+OecXRKI1Xu8+FuULbNTZapI= 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-659-wg7EiVtTOe2jTYLITh-2HQ-1; Tue, 29 Jul 2025 03:32:26 -0400 X-MC-Unique: wg7EiVtTOe2jTYLITh-2HQ-1 X-Mimecast-MFC-AGG-ID: wg7EiVtTOe2jTYLITh-2HQ_1753774344 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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 785031800261; Tue, 29 Jul 2025 07:32:24 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.43.17.23]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id E4DC71800B6C; Tue, 29 Jul 2025 07:32:22 +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 Subject: [PATCH v16 07/12] config: Allow enabling software ISP in runtime Date: Tue, 29 Jul 2025 09:31:55 +0200 Message-ID: <20250729073201.5369-8-mzamazal@redhat.com> In-Reply-To: <20250729073201.5369-1-mzamazal@redhat.com> References: <20250729073201.5369-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: Rv8VvxFfQl14R8_446FIIHUHFn96bI-4GJLCb7NNBbk_1753774344 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 in runtime 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 --- src/libcamera/pipeline/simple/simple.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp index 4323472e1..70c41aed0 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" @@ -1679,6 +1681,17 @@ 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) << "Overriding software ISP to " << swIspEnabled_; + break; + } + } /* Locate the sensors. */ std::vector sensors = locateSensors(media); From patchwork Tue Jul 29 07:31:56 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24018 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 94E4DBDCC1 for ; Tue, 29 Jul 2025 07:32:48 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 38743691E6; Tue, 29 Jul 2025 09:32:48 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="UsWb31HJ"; 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 C5682691D2 for ; Tue, 29 Jul 2025 09:32:33 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1753774352; 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=V17u0rfLz9Cpntt/wWhBD4R8M57WdYopWU9LERr80P0=; b=UsWb31HJTemOQ1fEVZbOTUAy8t8KDDpbicsgPhpR6QMDOlrfmzjVfVjwRRP38k743SQSPL nSILvUeCLWZmrh0LTx6/ccRsoh9ODJ9KM4OXkZEr23Ow50zwNNjBHe/kTu2ICRiqSrXYkF t2ATwCG5X6MPpKA7ImiJW+dtZU9J45o= 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-653-y4tq9qavPjia_9tx5xAS5Q-1; Tue, 29 Jul 2025 03:32:28 -0400 X-MC-Unique: y4tq9qavPjia_9tx5xAS5Q-1 X-Mimecast-MFC-AGG-ID: y4tq9qavPjia_9tx5xAS5Q_1753774346 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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 73B1A195608E; Tue, 29 Jul 2025 07:32:26 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.43.17.23]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id E01531800B6A; Tue, 29 Jul 2025 07:32:24 +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 Subject: [PATCH v16 08/12] config: Add global configuration file documentation Date: Tue, 29 Jul 2025 09:31:56 +0200 Message-ID: <20250729073201.5369-9-mzamazal@redhat.com> In-Reply-To: <20250729073201.5369-1-mzamazal@redhat.com> References: <20250729073201.5369-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: TXWdVF7qOjtmPj9thcGCePi4kOityBXRE5D6uOBcp88_1753774346 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 --- Documentation/documentation-contents.rst | 2 +- Documentation/index.rst | 2 +- Documentation/meson.build | 2 +- ...ariables.rst => runtime_configuration.rst} | 105 ++++++++++++++++-- 4 files changed, 99 insertions(+), 12 deletions(-) rename Documentation/{environment_variables.rst => runtime_configuration.rst} (67%) 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 3afdcc1a8..4e17c41c0 100644 --- a/Documentation/meson.build +++ b/Documentation/meson.build @@ -129,7 +129,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', @@ -141,6 +140,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 67% rename from Documentation/environment_variables.rst rename to Documentation/runtime_configuration.rst index 6f1235587..8fd80c311 100644 --- a/Documentation/environment_variables.rst +++ b/Documentation/runtime_configuration.rst @@ -2,15 +2,98 @@ .. 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. +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 ----------------- +The corresponding configuration file paths, if available, are listed in parentheses. + LIBCAMERA_LOG_FILE The custom destination for log output. @@ -24,27 +107,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 +138,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 to the global configuration file as + outlined above. + Example value: ``/usr/local/share/libcamera/pipeline/rpi/vc4/minimal_mem.yaml`` LIBCAMERA__TUNING_FILE @@ -156,7 +243,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 Tue Jul 29 07:31:57 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24020 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 E34E2C32B5 for ; Tue, 29 Jul 2025 07:32:52 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 54879691DB; Tue, 29 Jul 2025 09:32:52 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="b72qau8Z"; 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 5F1C5691D2 for ; Tue, 29 Jul 2025 09:32:35 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1753774355; 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=3LUr82u9Lybis4WkxZ3NYmMkSbv6PMFm0tCyt/2VICU=; b=b72qau8Z4N+CyFno8tIPu6SQHzbqUglAbAHUirWSnI0k/rd6C0vXTFMlyrFJ/MQMxSapRp lkaNP/h0KweUjrIGh5VqCKOscDAkWyEA1gA9nv6kplEra07zxfIQhPSx7jZWXjGJd2Bt7+ 58z11vq2qt+7a1E3StFzfQuD+Urg5qQ= 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-158-oJqu3_C4NrCjGX-71xlQYQ-1; Tue, 29 Jul 2025 03:32:30 -0400 X-MC-Unique: oJqu3_C4NrCjGX-71xlQYQ-1 X-Mimecast-MFC-AGG-ID: oJqu3_C4NrCjGX-71xlQYQ_1753774348 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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 77F0B1956096; Tue, 29 Jul 2025 07:32:28 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.43.17.23]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id E3F121800242; Tue, 29 Jul 2025 07:32: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 Subject: [PATCH v16 09/12] libcamera: software_isp: Make input buffer copying configurable Date: Tue, 29 Jul 2025 09:31:57 +0200 Message-ID: <20250729073201.5369-10-mzamazal@redhat.com> In-Reply-To: <20250729073201.5369-1-mzamazal@redhat.com> References: <20250729073201.5369-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: OUYIZB27VwZJGtvjAlHPINiu5fVabwwyi-Mt1D25PpA_1753774348 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 it's 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. Signed-off-by: Milan Zamazal --- Documentation/runtime_configuration.rst | 2 ++ 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, 11 insertions(+), 15 deletions(-) diff --git a/Documentation/runtime_configuration.rst b/Documentation/runtime_configuration.rst index 8fd80c311..57285cadb 100644 --- a/Documentation/runtime_configuration.rst +++ b/Documentation/runtime_configuration.rst @@ -52,6 +52,7 @@ file structure: pipeline_handler: ... simple: + copy_input_buffer: # true/false supported_devices: - driver: # driver name, e.g. `mxc-isi` software_isp: # true/false @@ -85,6 +86,7 @@ Configuration file example min_unicam_buffers: 2 min_total_unicam_buffers: 2 simple: + copy_input_buffer: false supported_devices: - driver: mxc-isi software_isp: true 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..704d4e487 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({ "pipelines", "simple", "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 Tue Jul 29 07:31:58 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24019 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 CF5F2BDCC1 for ; Tue, 29 Jul 2025 07:32:50 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4A051691E0; Tue, 29 Jul 2025 09:32:50 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="E7alK/l1"; 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 EC7E6691DC for ; Tue, 29 Jul 2025 09:32:34 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1753774353; 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=N+dWsZEUK+MTlZ2gTleh6YVF5mH6pyV8PLZA2l5iQoo=; b=E7alK/l1xnSn3dPRnLYIz16p3gvXuwjiPNWjNoRhr6VbdN3XYY1PNzLG+iFNH8wzP92XSf kfbWqjdzNMBJU3NFXdGgRmmKjxTHqnu0YvBAQUaS/jTioOQyHD4aF+wd0Yv7p0f81fuq54 B4HY+Bu/RevvOpY19/Q6aL5RpeZz2Go= 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-260-ZzvfHH-8NR2QUQPimI9Nug-1; Tue, 29 Jul 2025 03:32:31 -0400 X-MC-Unique: ZzvfHH-8NR2QUQPimI9Nug-1 X-Mimecast-MFC-AGG-ID: ZzvfHH-8NR2QUQPimI9Nug_1753774350 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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 70345180034C; Tue, 29 Jul 2025 07:32:30 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.43.17.23]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id DE2861800242; Tue, 29 Jul 2025 07:32:28 +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 Subject: [PATCH v16 10/12] libcamera: software_isp: Make measurement configurable Date: Tue, 29 Jul 2025 09:31:58 +0200 Message-ID: <20250729073201.5369-11-mzamazal@redhat.com> In-Reply-To: <20250729073201.5369-1-mzamazal@redhat.com> References: <20250729073201.5369-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: _kLlBwJul8j237seXa4xmwt_t--VbO7IiJbJ38U3jfY_1753774350 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. Signed-off-by: Milan Zamazal --- Documentation/runtime_configuration.rst | 6 ++++++ 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, 25 insertions(+), 38 deletions(-) diff --git a/Documentation/runtime_configuration.rst b/Documentation/runtime_configuration.rst index 57285cadb..0708302d4 100644 --- a/Documentation/runtime_configuration.rst +++ b/Documentation/runtime_configuration.rst @@ -53,6 +53,9 @@ file structure: ... simple: copy_input_buffer: # true/false + measure: + skip: # non-negative integer, frames to skip initially + number: # non-negative integer, frames to measure supported_devices: - driver: # driver name, e.g. `mxc-isi` software_isp: # true/false @@ -87,6 +90,9 @@ Configuration file example min_total_unicam_buffers: 2 simple: copy_input_buffer: false + measure: + skip: 50 + number: 30 supported_devices: - driver: mxc-isi software_isp: true 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 704d4e487..d43687f75 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({ "pipelines", "simple", "copy_input_buffer" }).value_or(true); + skipBeforeMeasure_ = configuration.option( + { "pipelines", "simple", "measure", "skip" }) + .value_or(skipBeforeMeasure_); + framesToMeasure_ = configuration.option( + { "pipelines", "simple", "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 Tue Jul 29 07:31:59 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24021 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 7200BBDCC1 for ; Tue, 29 Jul 2025 07:32:54 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id CA4F8691E1; Tue, 29 Jul 2025 09:32:53 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="ZghNdZFe"; 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 C72F1691C9 for ; Tue, 29 Jul 2025 09:32:38 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1753774357; 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=KZH1M40kN7gRf18w853lx1mvr3ItJz4YX/OeTmQAgZs=; b=ZghNdZFeECFKVBUx6WxXvTRcMDAhJXPUbzKeQmZDEuZ8aO8KTx9QcwQjS5u8uyVYXcXqdM ap6rg2QDXDYxpW6N1ALqYRnW6IAjd0FhUUOk1B+ApZjYW5idbvtPy8pc0RKrfzp9L37j5v v/OS1G5LoRMLt8uj/rMNuI2tq5zTdH4= 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-688-ljt52DLsM22xeD5Z1erURw-1; Tue, 29 Jul 2025 03:32:33 -0400 X-MC-Unique: ljt52DLsM22xeD5Z1erURw-1 X-Mimecast-MFC-AGG-ID: ljt52DLsM22xeD5Z1erURw_1753774352 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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 6C72B1956089; Tue, 29 Jul 2025 07:32:32 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.43.17.23]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id D888418001DD; Tue, 29 Jul 2025 07:32:30 +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 Subject: [PATCH v16 11/12] config: Make configuration file configurable Date: Tue, 29 Jul 2025 09:31:59 +0200 Message-ID: <20250729073201.5369-12-mzamazal@redhat.com> In-Reply-To: <20250729073201.5369-1-mzamazal@redhat.com> References: <20250729073201.5369-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: CXN-f95c99XFULq0vdZzDN2k2D9PW4YBgs5Rjhq7taU_1753774352 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_NAME environment variable, which: - specifies the path of the configuration file to load if it is an absolute path; or - prevents any configuration file from loading if it is defined and empty; or - specifies the path of the configuration file to load, relative to the configuration directories. If such a configuration file doesn't exist, no custom configuration is loaded. Signed-off-by: Milan Zamazal --- Documentation/runtime_configuration.rst | 8 ++++++ src/libcamera/global_configuration.cpp | 36 +++++++++++++++++-------- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/Documentation/runtime_configuration.rst b/Documentation/runtime_configuration.rst index 0708302d4..71a1a175d 100644 --- a/Documentation/runtime_configuration.rst +++ b/Documentation/runtime_configuration.rst @@ -19,6 +19,14 @@ order: - LIBCAMERA_SYSCONF_DIR/configuration.yaml - LIBCAMERA_DATA_DIR/libcamera/configuration.yaml +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 it can contain a whole relative or 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 b9531fdfb..68a4731a1 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) /** @@ -75,6 +68,28 @@ bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName) void GlobalConfiguration::load() { + const std::vector globalConfigurationDirectories = { + std::filesystem::path(LIBCAMERA_SYSCONF_DIR), + std::filesystem::path(LIBCAMERA_DATA_DIR), + }; + + 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::filesystem::path userConfigurationDirectory; const char *xdgConfigHome = utils::secure_getenv("XDG_CONFIG_HOME"); if (xdgConfigHome) { @@ -88,15 +103,14 @@ void GlobalConfiguration::load() if (!userConfigurationDirectory.empty()) { std::filesystem::path user_configuration_file = - userConfigurationDirectory / "libcamera" / "configuration.yaml"; + userConfigurationDirectory / "libcamera" / configName; if (loadFile(user_configuration_file)) return; } - for (const auto &path : globalConfigurationFiles) { - if (loadFile(path)) + for (const auto &path : globalConfigurationDirectories) + if (loadFile(path / configName)) return; - } } /** From patchwork Tue Jul 29 07:32:00 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24022 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 CDA23C332A for ; Tue, 29 Jul 2025 07:32:56 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id CF4F6691E8; Tue, 29 Jul 2025 09:32:55 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="UAIwam9O"; 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 D9011691C9 for ; Tue, 29 Jul 2025 09:32:40 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1753774359; 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=8XG+YDsJXqrg1JhCl2tpo6LbJVvRVk6ur9BvRH8qr/c=; b=UAIwam9Oy4cX5hDnnqd2mrNGpurX0sc6rz4lF4S20BnXQsGhcT75frnwe9zdRdgdTJdhh7 PCG3GVCQzZwFNXt8aF7CFzk8mR8f7pmWPoszXcHZ/GZ3Grua2m/69fl7Je0GXtUe+qHRhC 8+46yAB1Btg4CieyRmHT9DqDPkss/rQ= Received: from mx-prod-mc-01.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-380-zlKo5p9fMKiAp_ApuqPoFg-1; Tue, 29 Jul 2025 03:32:36 -0400 X-MC-Unique: zlKo5p9fMKiAp_ApuqPoFg-1 X-Mimecast-MFC-AGG-ID: zlKo5p9fMKiAp_ApuqPoFg_1753774354 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 6748D19560B4; Tue, 29 Jul 2025 07:32:34 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.43.17.23]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id D2BDB18001DD; Tue, 29 Jul 2025 07:32:32 +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 Subject: [PATCH v16 12/12] config: Make configuration directories configurable Date: Tue, 29 Jul 2025 09:32:00 +0200 Message-ID: <20250729073201.5369-13-mzamazal@redhat.com> In-Reply-To: <20250729073201.5369-1-mzamazal@redhat.com> References: <20250729073201.5369-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: e10aCcmVMFN3_491L-Gtfs09foSml7-ncCfERF6Udpw_1753774354 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" A newly introduced 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. Signed-off-by: Milan Zamazal --- Documentation/runtime_configuration.rst | 5 +++++ src/libcamera/global_configuration.cpp | 28 ++++++++++++++----------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/Documentation/runtime_configuration.rst b/Documentation/runtime_configuration.rst index 71a1a175d..759f6f476 100644 --- a/Documentation/runtime_configuration.rst +++ b/Documentation/runtime_configuration.rst @@ -19,6 +19,11 @@ 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 diff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp index 68a4731a1..d80f5a158 100644 --- a/src/libcamera/global_configuration.cpp +++ b/src/libcamera/global_configuration.cpp @@ -68,11 +68,6 @@ bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName) void GlobalConfiguration::load() { - const std::vector globalConfigurationDirectories = { - std::filesystem::path(LIBCAMERA_SYSCONF_DIR), - std::filesystem::path(LIBCAMERA_DATA_DIR), - }; - const char *libcameraConfigName = utils::secure_getenv("LIBCAMERA_CONFIG_NAME"); if (libcameraConfigName && libcameraConfigName[0] == '\0') @@ -90,6 +85,16 @@ void GlobalConfiguration::load() 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) { @@ -100,15 +105,14 @@ 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" / configName; - if (loadFile(user_configuration_file)) - return; - } + configurationDirectories.push_back(LIBCAMERA_SYSCONF_DIR); + configurationDirectories.push_back(LIBCAMERA_DATA_DIR); - for (const auto &path : globalConfigurationDirectories) + for (const auto &path : configurationDirectories) if (loadFile(path / configName)) return; }