From patchwork Tue Jul 15 08:19:08 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23807 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 2C3EEC3237 for ; Tue, 15 Jul 2025 08:19:40 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 12A9C68F55; Tue, 15 Jul 2025 10:19:38 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="DkqlhvID"; 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 0697361517 for ; Tue, 15 Jul 2025 10:19:35 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752567574; 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=oAHQ9AhMHt3Z/tGtF43zu2xHzBhpPCT/amkdDyqcj40=; b=DkqlhvIDjXfqmDCtN7a2WVuv9ZZyXvXhTLw+JmpjfDX+K/hd18lZb7YA2pdJgtd/DxjCiE dIRMb/fuu1zQqKvE//dHUaHwDJbZqVmBP9/fOI5r56dv0kqjWNPEafx8p291luEogaeExS 6ybrwXEweGW0QJBOpDW7TMTUVpLzFoM= 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-373-zAVtHbf5NCCoR6sFFt1HPA-1; Tue, 15 Jul 2025 04:19:31 -0400 X-MC-Unique: zAVtHbf5NCCoR6sFFt1HPA-1 X-Mimecast-MFC-AGG-ID: zAVtHbf5NCCoR6sFFt1HPA_1752567570 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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 3B5971809C8A; Tue, 15 Jul 2025 08:19:30 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.43.17.38]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 88D2418002B1; Tue, 15 Jul 2025 08:19: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 v14 01/12] config: Introduce global runtime configuration Date: Tue, 15 Jul 2025 10:19:08 +0200 Message-ID: <20250715081921.5522-2-mzamazal@redhat.com> In-Reply-To: <20250715081921.5522-1-mzamazal@redhat.com> References: <20250715081921.5522-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: FmvXFmpzknoAA85NWV-h8hgwvK6Zmy_dE4RjSWbfJSk_1752567570 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 | 145 ++++++++++++++++++ src/libcamera/meson.build | 1 + 4 files changed, 181 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..3eaf39c94 --- /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); + bool 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..9a798ba63 --- /dev/null +++ b/src/libcamera/global_configuration.cpp @@ -0,0 +1,145 @@ +/* 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.exists()) + return false; + + if (!file.open(File::OpenModeFlag::ReadOnly)) { + LOG(Configuration, Error) + << "Failed to open configuration file " << fileName; + return true; + } + + yamlConfiguration_ = YamlParser::parse(file); + if (!yamlConfiguration_) { + LOG(Configuration, Error) + << "Failed to parse configuration file " << fileName; + return true; + } + + return true; +} + +bool 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 !!yamlConfiguration_; + } + + for (const auto &path : globalConfigurationFiles) { + if (loadFile(path)) + return !!yamlConfiguration_; + } + + return true; +} + +/** + * \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 15 08:19:09 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23809 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 489B1C3237 for ; Tue, 15 Jul 2025 08:19:48 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id BC41B61517; Tue, 15 Jul 2025 10:19:46 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="Eu5Z1Smx"; 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 D6AF861517 for ; Tue, 15 Jul 2025 10:19:37 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752567576; 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=6AXswV8UZT/zmnK5rJVrcWyZhIl/+NS4eY/HLLgKs5U=; b=Eu5Z1Smxowgw3g4VzZ5f2AyAzyr+oRijEpKMKNITwZysL2p/ekjYNtTo/XSOmIn6LNDOvV LhLJ0GaRTwzz939Hti8N5RdimzFIbugN8Mt+QKhCikUQkkJGv5TLfYgbpFbeY1uEGXrT2z Utw1OhRFmVIbJ453j5SSHN3EGQo47dI= 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-471-TrVK0PmdNDeCJcmBqu6oLw-1; Tue, 15 Jul 2025 04:19:33 -0400 X-MC-Unique: TrVK0PmdNDeCJcmBqu6oLw-1 X-Mimecast-MFC-AGG-ID: TrVK0PmdNDeCJcmBqu6oLw_1752567572 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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 576FB195608A; Tue, 15 Jul 2025 08:19:32 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.43.17.38]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id A2B6A180045B; Tue, 15 Jul 2025 08:19: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 v14 02/12] config: Make GlobalConfiguration instance Date: Tue, 15 Jul 2025 10:19:09 +0200 Message-ID: <20250715081921.5522-3-mzamazal@redhat.com> In-Reply-To: <20250715081921.5522-1-mzamazal@redhat.com> References: <20250715081921.5522-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: wh5U1nDhQ5fDIYv5qxpcse8Jl7mpC1ncXxYdqZxnDRY_1752567572 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 e62e7193c..f3b4ec708 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" @@ -254,6 +255,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 15 08:19:10 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23810 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 E521AC3237 for ; Tue, 15 Jul 2025 08:19:52 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 3271568F62; Tue, 15 Jul 2025 10:19:52 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="MOqjnua2"; 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 86B7868F53 for ; Tue, 15 Jul 2025 10:19:41 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752567580; 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=ouQbv2pcbCE2MzfIO37pQwExN3Dc7Q1tLUEjAlu5KFo=; b=MOqjnua2fagjKoHbDdN2HYtF4WlqV6FsSd5s+etfsLqx7QjLSiJ97m+6WbPBoJOKbS/kQV Ho0td1qRqj0tBFiz03oH4kjMbdRFGORdM1lR3reuilBhlaDuzT/Jy9ln4P7NO2qoQ7X4e+ LJ2VzsTJeAGLWm4Jt/ZNluenaSxoJsA= 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-5-Zc1XfwG5Pz6wVS0Ty2kfCg-1; Tue, 15 Jul 2025 04:19:35 -0400 X-MC-Unique: Zc1XfwG5Pz6wVS0Ty2kfCg-1 X-Mimecast-MFC-AGG-ID: Zc1XfwG5Pz6wVS0Ty2kfCg_1752567574 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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 2DDDA19560A7; Tue, 15 Jul 2025 08:19:34 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.43.17.38]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 9B622180045B; Tue, 15 Jul 2025 08:19: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 v14 03/12] config: Add configuration retrieval helpers Date: Tue, 15 Jul 2025 10:19:10 +0200 Message-ID: <20250715081921.5522-4-mzamazal@redhat.com> In-Reply-To: <20250715081921.5522-1-mzamazal@redhat.com> References: <20250715081921.5522-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: YqycepKjXu-GZyKaowpuQGuV3d7iiiZs1zszaErtKZw_1752567574 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 3eaf39c94..4a9b1efd6 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 9a798ba63..f98744200 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) @@ -107,6 +114,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 15 08:19:11 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23811 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 B053EC3237 for ; Tue, 15 Jul 2025 08:19:55 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 3945C68F66; Tue, 15 Jul 2025 10:19:54 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="bVZ1wPfY"; 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 2D8C968F52 for ; Tue, 15 Jul 2025 10:19:42 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752567580; 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=gVBb1G5SJR7EXPqld/x/7MAYzUqwfRiHPe40gGbvgqQ=; b=bVZ1wPfY/6vtveMKVEDLUxjIraggCTa4S4choNfvIKpW7sN3+e+5H79esj+P3srn082w0k ijzITfA67hj9D8KLas+QY6XXqHRxUdBLbdsi1HZ4OthRBZ0T1vRlWu77+txWDKboOii3Fk F5/TRA5o1UjW3I04uurWq2/W4GhxaDw= 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-244-BbM_QWkHOJ69ZYsAUEb6GQ-1; Tue, 15 Jul 2025 04:19:37 -0400 X-MC-Unique: BbM_QWkHOJ69ZYsAUEb6GQ-1 X-Mimecast-MFC-AGG-ID: BbM_QWkHOJ69ZYsAUEb6GQ_1752567576 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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 363CE19560B6; Tue, 15 Jul 2025 08:19:36 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.43.17.38]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 93CE3180035C; Tue, 15 Jul 2025 08:19:34 +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 v14 04/12] config: Look up rpi configuration in the configuration file Date: Tue, 15 Jul 2025 10:19:11 +0200 Message-ID: <20250715081921.5522-5-mzamazal@redhat.com> In-Reply-To: <20250715081921.5522-1-mzamazal@redhat.com> References: <20250715081921.5522-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: BON9lGxriJKTYZVvlMDdO38UCgqjzwNtCbdr926iZsQ_1752567576 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: pipeline: 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 eafe94427..0826654e6 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()["pipeline"]["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 92b9070c1..f66dbd9c1 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 5cadef527..5fde67ac0 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 15 08:19:12 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23812 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 3F0CDC3237 for ; Tue, 15 Jul 2025 08:19:58 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8CCF268F6A; Tue, 15 Jul 2025 10:19:57 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="Kd9KAfy+"; 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 1BCA668F55 for ; Tue, 15 Jul 2025 10:19:44 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752567583; 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=CUahOlko3T3qih7Lz5GWobtfXBJCrWxKEP56LsQIA+E=; b=Kd9KAfy+ud2XkbShrdA9tkwg42c0WMwUROmPdUBaEiiV1Db4+QM8n/u1MYxo0X3TqgYQa1 4RpqoAoXB2hyyfoQVOcxWf13JViCtYHvGFlOImM6FuiOArJ3e9O1J9ypPn7b9WRhkZ0n+R 09LFhfRJmwmr81SG4pBBsrU7+mYMxfI= 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-204-KuOWWADOO3eW1V323ZQ1_w-1; Tue, 15 Jul 2025 04:19:39 -0400 X-MC-Unique: KuOWWADOO3eW1V323ZQ1_w-1 X-Mimecast-MFC-AGG-ID: KuOWWADOO3eW1V323ZQ1_w_1752567578 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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 1DBE518001D6; Tue, 15 Jul 2025 08:19:38 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.43.17.38]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 8CCAA180045B; Tue, 15 Jul 2025 08:19:36 +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 v14 05/12] config: Look up IPA configurables in configuration file Date: Tue, 15 Jul 2025 10:19:12 +0200 Message-ID: <20250715081921.5522-6-mzamazal@redhat.com> In-Reply-To: <20250715081921.5522-1-mzamazal@redhat.com> References: <20250715081921.5522-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: FnNb_aJx8qD3--Y1qZW-O1XSQdCgmeMQEJJDS2pQ6qw_1752567578 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 4a9b1efd6..eb7a4ad98 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 f3b4ec708..c47fd3677 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 f98744200..0eab053b2 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 @@ -115,13 +117,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(); @@ -130,7 +141,7 @@ std::optional GlobalConfiguration::option( if (!*c) return {}; } - return c->get(); + return c->getList(); } /** @@ -157,7 +168,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 15 08:19:13 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23813 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 23D41C3237 for ; Tue, 15 Jul 2025 08:20:02 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 69CAD68F6C; Tue, 15 Jul 2025 10:20:01 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="CBtqX3OF"; 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 9C1E068F5A for ; Tue, 15 Jul 2025 10:19:45 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752567584; 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=F+9W7S0q/VLWsHHozRq4Dht2K5JgFSm8rYfqPXJo+lA=; b=CBtqX3OFzab19FwaWLfGZrysEzb8FPNGZ2kEZsqfTRSq09UY7AJw/N7fEt/rpFkpFIychG 7mqVYWBdJTiSMnqDknejFbMP7c0f2+M6bjpl2EnmfqqKN0iJNjpx6CeRwszAvJOTsFSg3m d6OBNAcbk5RqAWvOeS1p5dqQhP9Q9fc= 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-83-0A5GDgILNVisA7yD3jMYYQ-1; Tue, 15 Jul 2025 04:19:41 -0400 X-MC-Unique: 0A5GDgILNVisA7yD3jMYYQ-1 X-Mimecast-MFC-AGG-ID: 0A5GDgILNVisA7yD3jMYYQ_1752567580 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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 17D43195608F; Tue, 15 Jul 2025 08:19:40 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.43.17.38]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 8554618002B1; Tue, 15 Jul 2025 08:19:38 +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 v14 06/12] config: Look up pipelines match list in configuration file Date: Tue, 15 Jul 2025 10:19:13 +0200 Message-ID: <20250715081921.5522-7-mzamazal@redhat.com> In-Reply-To: <20250715081921.5522-1-mzamazal@redhat.com> References: <20250715081921.5522-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 0BmzQsfP38j9mSfzXik48BUxMiPSTLub8o0IpMTUn_M_1752567580 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 eb7a4ad98..ed620f55f 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 c47fd3677..8123ae9e3 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 0eab053b2..1d447e1e3 100644 --- a/src/libcamera/global_configuration.cpp +++ b/src/libcamera/global_configuration.cpp @@ -175,6 +175,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 @@ -191,11 +192,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 15 08:19:14 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23814 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 44492C32C8 for ; Tue, 15 Jul 2025 08:20:04 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 243A968F6B; Tue, 15 Jul 2025 10:20:03 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="cIoQd+dW"; 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 5CF6068F60 for ; Tue, 15 Jul 2025 10:19:47 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752567586; 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=FGy4nI4n6Y3AjgQjxjF48CLtakzbeZg/n7WACbdx+/8=; b=cIoQd+dWZLcfRJbkBRl3jbhFpOZiPjvt0GA3JJEGLRX75eJjFUhrK/q79PR9vxPnMBv45t zYiaCTFXhpHXSpI1ufGdDvxTcSAKVaKZiN5FbP21zrRKfABVyZCdjMcSVHndvlBDe3iPXm uHYzpgaBljJm8hbSs1Su+TEts6UOYgQ= 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-319-8tBNB2TwMte0cl2eCevCBg-1; Tue, 15 Jul 2025 04:19:43 -0400 X-MC-Unique: 8tBNB2TwMte0cl2eCevCBg-1 X-Mimecast-MFC-AGG-ID: 8tBNB2TwMte0cl2eCevCBg_1752567582 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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 107261956089; Tue, 15 Jul 2025 08:19:42 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.43.17.38]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 7DAA2180045B; Tue, 15 Jul 2025 08:19:40 +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 v14 07/12] config: Allow enabling software ISP in runtime Date: Tue, 15 Jul 2025 10:19:14 +0200 Message-ID: <20250715081921.5522-8-mzamazal@redhat.com> In-Reply-To: <20250715081921.5522-1-mzamazal@redhat.com> References: <20250715081921.5522-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: Z5h5MPyq7nWtVc3wsj0kyFkFE3DlPSj7YNKI9_gKOVE_1752567582 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 efb07051b..45d7a5c4a 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" @@ -1688,6 +1690,17 @@ bool SimplePipelineHandler::match(DeviceEnumerator *enumerator) } 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 15 08:19:15 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23815 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 1D2C1C3237 for ; Tue, 15 Jul 2025 08:20:07 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 2DC1768F68; Tue, 15 Jul 2025 10:20:06 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="IaXmFRXY"; 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 8EDF968F5C for ; Tue, 15 Jul 2025 10:19:49 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752567588; 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=mk+1IEVY/kHYvn3H/unDfGXFHjke2IRru8kNE2ih9n0=; b=IaXmFRXYyN3C8bHHbzaACrS1MhTwPFl62pqOH//pRSDdqgZohMkHsPA+6IFBs5Jwg5FfMy 2hnXT7CDuo3BF4tT6ajC+iwctrHsQd1CYNs/GtBEVgzDEm1eRGWHo0xAI4tt2nhtK7v+mT DUmE2LGFeGu4vJia5QYTe5V8+DfHkRM= 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-36-K18Kk2njPi2a2mT6_cE52Q-1; Tue, 15 Jul 2025 04:19:45 -0400 X-MC-Unique: K18Kk2njPi2a2mT6_cE52Q-1 X-Mimecast-MFC-AGG-ID: K18Kk2njPi2a2mT6_cE52Q_1752567584 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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 08A721956089; Tue, 15 Jul 2025 08:19:44 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.43.17.38]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 7673B180045B; Tue, 15 Jul 2025 08:19:42 +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 v14 08/12] config: Add global configuration file documentation Date: Tue, 15 Jul 2025 10:19:15 +0200 Message-ID: <20250715081921.5522-9-mzamazal@redhat.com> In-Reply-To: <20250715081921.5522-1-mzamazal@redhat.com> References: <20250715081921.5522-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: pACB9vUFSDmPN7lXCQc5jZvhkETuq4uX5IIJuZ3CStA_1752567584 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} | 100 ++++++++++++++++-- 4 files changed, 94 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 0fc5909d0..6d5af0f62 100644 --- a/Documentation/meson.build +++ b/Documentation/meson.build @@ -128,7 +128,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', @@ -140,6 +139,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..aaf158ef4 100644 --- a/Documentation/environment_variables.rst +++ b/Documentation/runtime_configuration.rst @@ -2,15 +2,93 @@ .. 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: + config_paths: # full paths to directories, separated by colons + force_isolation: # true/false + module_paths: # full paths to directories, separated by colons + pipelines_match_list: # pipeline names, separated by commas + 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 +102,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 +133,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 +238,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 15 08:19:16 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23816 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 526D1C3237 for ; Tue, 15 Jul 2025 08:20:09 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D2F9068F69; Tue, 15 Jul 2025 10:20:07 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="TOrHf70n"; 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 6DEDA68F5D for ; Tue, 15 Jul 2025 10:19:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752567589; 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=vkxUbx+QDCvVHRE9hv/2widlkeeq6+n4CrZnMWdpOqk=; b=TOrHf70nAPEO5FAFCe/xwOktG++jjLzFgOMPUhMWYeZ74AqqQB1ISlmECFyLwTehL0cLsa /A5FWKB8711mdhC+JYjzxa9kgMjY8gdLgW8J2b1H9TBEHu2HtTeSNjVSZ/W3Lv2gqbNJ94 QSMRbcFsSe+Dm3SBhm+njI3wQKKI8BA= 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-467-oetVOQmuMbGZCnZxYQscag-1; Tue, 15 Jul 2025 04:19:47 -0400 X-MC-Unique: oetVOQmuMbGZCnZxYQscag-1 X-Mimecast-MFC-AGG-ID: oetVOQmuMbGZCnZxYQscag_1752567586 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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 12ABF180034E; Tue, 15 Jul 2025 08:19:46 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.43.17.38]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 76F5C18002B1; Tue, 15 Jul 2025 08:19:44 +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 v14 09/12] libcamera: software_isp: Make input buffer copying configurable Date: Tue, 15 Jul 2025 10:19:16 +0200 Message-ID: <20250715081921.5522-10-mzamazal@redhat.com> In-Reply-To: <20250715081921.5522-1-mzamazal@redhat.com> References: <20250715081921.5522-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: UTlKZ_Q9mnx4HRs6Pz3VOdmO56VwgJTUl2xtygFgZjY_1752567586 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 aaf158ef4..db8e27b03 100644 --- a/Documentation/runtime_configuration.rst +++ b/Documentation/runtime_configuration.rst @@ -49,6 +49,7 @@ file structure: pipeline_handler: ... simple: + copy_input_buffer: # true/false supported_devices: - driver: # driver name, e.g. `mxc-isi` software_isp: # true/false @@ -80,6 +81,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 15 08:19:17 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23817 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 30867C3237 for ; Tue, 15 Jul 2025 08:20:11 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7294968F74; Tue, 15 Jul 2025 10:20:10 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="PvFNutpI"; 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 7025D68F65 for ; Tue, 15 Jul 2025 10:19:53 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752567592; 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=feSalzXdHFdUZuIVyNDHRDyuZ5PbMXYoPv9BNh5mOiQ=; b=PvFNutpIdgshcV/2QNNknab23quEvRp19YYPin6QQLUCZfBNZvTXERb8yPbLpbubgiHmuw fJl5T2Q9GibTI8B7HbCE4cbuBXSrCs7ypujmCQwG9qA1NNDaAEaJ4i+cMa0zRgseGa7raz Lq8+yDJHbV10P5Oiw83fvoxcfH21cT4= 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-107-hUKuZflnNxq2ND6ZKcp1Bw-1; Tue, 15 Jul 2025 04:19:49 -0400 X-MC-Unique: hUKuZflnNxq2ND6ZKcp1Bw-1 X-Mimecast-MFC-AGG-ID: hUKuZflnNxq2ND6ZKcp1Bw_1752567588 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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 34D2C1956096; Tue, 15 Jul 2025 08:19:48 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.43.17.38]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 869E4180045B; Tue, 15 Jul 2025 08:19:46 +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 v14 10/12] libcamera: software_isp: Make measurement configurable Date: Tue, 15 Jul 2025 10:19:17 +0200 Message-ID: <20250715081921.5522-11-mzamazal@redhat.com> In-Reply-To: <20250715081921.5522-1-mzamazal@redhat.com> References: <20250715081921.5522-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: SPdXNW0P3ml0DK4lNM69VGJR5WibB2YLpk0mD3Nn5L0_1752567588 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 db8e27b03..f3f7adee9 100644 --- a/Documentation/runtime_configuration.rst +++ b/Documentation/runtime_configuration.rst @@ -50,6 +50,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 @@ -82,6 +85,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 15 08:19:18 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23818 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 06509C3237 for ; Tue, 15 Jul 2025 08:20:13 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C4E7C68F78; Tue, 15 Jul 2025 10:20:11 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="OexKo4Nk"; 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 AE01768F5E for ; Tue, 15 Jul 2025 10:19:55 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752567594; 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=8hpkupQYgOnncgnTUWm+HsE6M6OXOVAeqLKx+kfW1xY=; b=OexKo4NkLbPLx3BBmDxErdk7/172YsHTtdFNAmX+Ze8o5FrUWWAXl6YCpUI7g0/MdSYgta DllLRrCn2KbkbHoUi+vHpbyYryifJyKEl8dYw1qqxU1IwQEvqmecedKPhxeKBhkjO8QzqY mzRV1RVPgvcqAfLpgnEQsoUL3PBEVRU= 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-296-0L2IQL_QNF--0DEq0y62nQ-1; Tue, 15 Jul 2025 04:19:51 -0400 X-MC-Unique: 0L2IQL_QNF--0DEq0y62nQ-1 X-Mimecast-MFC-AGG-ID: 0L2IQL_QNF--0DEq0y62nQ_1752567590 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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 10FEF1808993; Tue, 15 Jul 2025 08:19:50 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.43.17.38]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 7F53B180045B; Tue, 15 Jul 2025 08:19:48 +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 v14 11/12] config: Make configuration file configurable Date: Tue, 15 Jul 2025 10:19:18 +0200 Message-ID: <20250715081921.5522-12-mzamazal@redhat.com> In-Reply-To: <20250715081921.5522-1-mzamazal@redhat.com> References: <20250715081921.5522-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: YEe8Lk0uU6D6nOOa8bNl93S5be2eYB-bx4AiyoOV53w_1752567590 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 f3f7adee9..0c3d8a782 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 1d447e1e3..4ae122924 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) /** @@ -74,6 +67,28 @@ bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName) bool 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 false; + if (!libcameraConfigName) + libcameraConfigName = ""; + + std::filesystem::path configName(libcameraConfigName); + + if (configName.is_absolute()) { + loadFile(configName); + return !!yamlConfiguration_; + } + + if (configName.empty()) + configName = std::filesystem::path("configuration.yaml"); + std::filesystem::path userConfigurationDirectory; const char *xdgConfigHome = utils::secure_getenv("XDG_CONFIG_HOME"); if (xdgConfigHome) { @@ -87,15 +102,14 @@ bool GlobalConfiguration::load() if (!userConfigurationDirectory.empty()) { std::filesystem::path user_configuration_file = - userConfigurationDirectory / "libcamera" / "configuration.yaml"; + userConfigurationDirectory / "libcamera" / configName; if (loadFile(user_configuration_file)) return !!yamlConfiguration_; } - for (const auto &path : globalConfigurationFiles) { - if (loadFile(path)) + for (const auto &path : globalConfigurationDirectories) + if (loadFile(path / configName)) return !!yamlConfiguration_; - } return true; } From patchwork Tue Jul 15 08:19:19 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23819 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 CF66EC3237 for ; Tue, 15 Jul 2025 08:20:14 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D101A68F75; Tue, 15 Jul 2025 10:20:13 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="P/9NFvyw"; 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 89CE368F69 for ; Tue, 15 Jul 2025 10:19:57 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752567596; 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=yT/ASlVTTNNoRAopslzNcngJptjB+jMoS736FzRblwY=; b=P/9NFvywT6YE33NynIxAS06rVhtDRJFInqk5ijzje7eJVE87o3mIyZHOafvtvAX0gZZuYu Z1UpAaf/FQB2XG7USUvX5Rpiw+RuPD0ckCQQybS7YIxJQk5BnSvNjfrQLElg3U7cdjSEJD iKGc1b6kgZy7iwtrjLQ86/lHEbhR5AQ= 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-632-P7VafpflNtKPNOtz_fu-eQ-1; Tue, 15 Jul 2025 04:19:53 -0400 X-MC-Unique: P7VafpflNtKPNOtz_fu-eQ-1 X-Mimecast-MFC-AGG-ID: P7VafpflNtKPNOtz_fu-eQ_1752567592 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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 1ACC518089B4; Tue, 15 Jul 2025 08:19:52 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.43.17.38]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 7929F180035C; Tue, 15 Jul 2025 08:19:50 +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 v14 12/12] config: Make configuration directories configurable Date: Tue, 15 Jul 2025 10:19:19 +0200 Message-ID: <20250715081921.5522-13-mzamazal@redhat.com> In-Reply-To: <20250715081921.5522-1-mzamazal@redhat.com> References: <20250715081921.5522-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: DvBXby2hSTGyZDZzGWRzy3vA3JiB8E0QJ55OuNHiIsE_1752567592 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 0c3d8a782..f8608fa23 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 4ae122924..553d5f221 100644 --- a/src/libcamera/global_configuration.cpp +++ b/src/libcamera/global_configuration.cpp @@ -67,11 +67,6 @@ bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName) bool 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') @@ -89,6 +84,16 @@ bool 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) { @@ -99,15 +104,14 @@ bool 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 !!yamlConfiguration_; - } + 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 !!yamlConfiguration_;