From patchwork Fri Jul 11 20:12:20 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23790 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 89976C3237 for ; Fri, 11 Jul 2025 20:12:49 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 3B64D68F27; Fri, 11 Jul 2025 22:12:49 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="JYSJUzML"; 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 21AC068E30 for ; Fri, 11 Jul 2025 22:12:45 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752264764; 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=JYSJUzMLJVrys6+E5MqZxlKPRvJUJ3wEDdNeIehqBEmNjEd8Db/Qg6W/pHPMpgD7BME7A8 rqj7REtPEOFJIYPcXuWHNCjeYn6wVu77nceCTHPaWvQli3hy06AXTOMHzv4SzULvEQT7wT lPDxip2E7kbPsoLx3njpdCvPxUxRFqQ= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-287-wlR9cuehNau1A6kj1Dop6A-1; Fri, 11 Jul 2025 16:12:42 -0400 X-MC-Unique: wlR9cuehNau1A6kj1Dop6A-1 X-Mimecast-MFC-AGG-ID: wlR9cuehNau1A6kj1Dop6A_1752264761 Received: from mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.40]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 90E111800290; Fri, 11 Jul 2025 20:12:41 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.224.49]) by mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 9EA2C19560A3; Fri, 11 Jul 2025 20:12:39 +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 v13 01/12] config: Introduce global runtime configuration Date: Fri, 11 Jul 2025 22:12:20 +0200 Message-ID: <20250711201232.129264-2-mzamazal@redhat.com> In-Reply-To: <20250711201232.129264-1-mzamazal@redhat.com> References: <20250711201232.129264-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.40 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: auPdjtWV0LTGYeAoEApqdtq2ym4HfXD_jNb59un9dGE_1752264761 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 Fri Jul 11 20:12:21 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23791 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 393F2C3237 for ; Fri, 11 Jul 2025 20:12:52 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D16BA68F2D; Fri, 11 Jul 2025 22:12:51 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="Rk2SAXMT"; 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 F1E2D68F1E for ; Fri, 11 Jul 2025 22:12:49 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752264769; 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=Rk2SAXMTw2UH+AAyTyazujOTwjOu49tbJIUlTAyFO/+yc9fQpUDNQM+s6TOYbCGEsfqjeB yFtwCniMood8f7wGZrGBbA+ojHfe3YP5pApHJ/Lr7/iMfVr0Lz3JnlMyfIrRQHvPmyHxoj LZHczCGjsT7yXMUHPiNOnh1kXes9vzI= 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-42-CQHsbd-3OaqMyjD4FDoMNQ-1; Fri, 11 Jul 2025 16:12:45 -0400 X-MC-Unique: CQHsbd-3OaqMyjD4FDoMNQ-1 X-Mimecast-MFC-AGG-ID: CQHsbd-3OaqMyjD4FDoMNQ_1752264764 Received: from mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.40]) (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 5CDAC1956094; Fri, 11 Jul 2025 20:12:44 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.224.49]) by mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 3E46F19560A3; Fri, 11 Jul 2025 20:12:41 +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 v13 02/12] config: Make GlobalConfiguration instance Date: Fri, 11 Jul 2025 22:12:21 +0200 Message-ID: <20250711201232.129264-3-mzamazal@redhat.com> In-Reply-To: <20250711201232.129264-1-mzamazal@redhat.com> References: <20250711201232.129264-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.40 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: BQ_vnjwxOUzXFLdx0mMnJGwoXAbopBVTpZxyJhUtGBo_1752264764 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 Fri Jul 11 20:12:22 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23792 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 4C9A6C3237 for ; Fri, 11 Jul 2025 20:12:53 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id BB97F68F2E; Fri, 11 Jul 2025 22:12:52 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="fyBybspw"; 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 2B4C768F1B for ; Fri, 11 Jul 2025 22:12:51 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752264770; 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=fyBybspw8voFpewYvIp2DnCynFtAek3Kl//xPUIWJBLUE0Z2M67PZ1csMryoQONeWB75qP htd9dijVTD1FX4YR/bcHIK5kZEr8OD9WGzOuQf2jNv1b5D00YgaZbr/4V6EbrmX2YAb74l nZLtNcpaT4ChmJ3aBPuHGKkcVZRGAaY= 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-491-vjajVzWuNHaSOoQnIo2iBg-1; Fri, 11 Jul 2025 16:12:47 -0400 X-MC-Unique: vjajVzWuNHaSOoQnIo2iBg-1 X-Mimecast-MFC-AGG-ID: vjajVzWuNHaSOoQnIo2iBg_1752264766 Received: from mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.40]) (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 B1BCA1956080; Fri, 11 Jul 2025 20:12:46 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.224.49]) by mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id DB41E1955F21; Fri, 11 Jul 2025 20:12: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 v13 03/12] config: Add configuration retrieval helpers Date: Fri, 11 Jul 2025 22:12:22 +0200 Message-ID: <20250711201232.129264-4-mzamazal@redhat.com> In-Reply-To: <20250711201232.129264-1-mzamazal@redhat.com> References: <20250711201232.129264-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.40 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: GQM4pORfUXUEGM7u-RXiLIKQj6UAq87goWoWNEw7QEo_1752264766 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 Fri Jul 11 20:12:23 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23793 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 B12F9C3237 for ; Fri, 11 Jul 2025 20:12:56 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 66CAD68F27; Fri, 11 Jul 2025 22:12:56 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="hY26wKqI"; 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 B889068F27 for ; Fri, 11 Jul 2025 22:12:54 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752264773; 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=+B12Wo+K8hhcOI4WB2SMraUSYqDyvuoc1d8CFqC01mQ=; b=hY26wKqIC6XQB3YqcitB5OzRPA1+V8i/56uI+BH/A9bptLAssUOkvGx1IbPjw9hzJaor3T 5kLabX8654WxQw0bM/t8HJgNUeuCY7+/oRx5B+2CrFwKpzlnEZdCN7rEt2HAcON59CLczU YTVyxZmBgtNqjD7wpVYHBcqN5wEOW7A= 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-49-NIGFFvp7Ov-Y2o97pUk9pg-1; Fri, 11 Jul 2025 16:12:50 -0400 X-MC-Unique: NIGFFvp7Ov-Y2o97pUk9pg-1 X-Mimecast-MFC-AGG-ID: NIGFFvp7Ov-Y2o97pUk9pg_1752264769 Received: from mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.40]) (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 7CD6919560A2; Fri, 11 Jul 2025 20:12:49 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.224.49]) by mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 2DD3C19560A3; Fri, 11 Jul 2025 20:12: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 v13 04/12] config: Look up rpi configuration in the configuration file Date: Fri, 11 Jul 2025 22:12:23 +0200 Message-ID: <20250711201232.129264-5-mzamazal@redhat.com> In-Reply-To: <20250711201232.129264-1-mzamazal@redhat.com> References: <20250711201232.129264-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.40 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: LUvoQck4uFuUnTGy6_8aeu9tpUffSzd_PlCfmXqjp1I_1752264769 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 | 62 ++++++++++++------- .../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, 59 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..0eea242de 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,10 @@ int CameraData::loadPipelineConfiguration() frontendDevice()->setDequeueTimeout(config_.cameraTimeoutValue * 1ms); } - return platformPipelineConfigure(root); + std::optional expectedTarget = (root + ? (*root)["target"].get() + : target()); + 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 Fri Jul 11 20:12:24 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23794 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 3A255C32C8 for ; Fri, 11 Jul 2025 20:12:57 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id DBF2D68F2D; Fri, 11 Jul 2025 22:12:56 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="GvyOQa2r"; 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 6C0D168F27 for ; Fri, 11 Jul 2025 22:12:55 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752264774; 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=csKT2xOe36u+jNvnG+n4rUCOorv8GFRhnX3X0jCzfKU=; b=GvyOQa2rhYv7TtRVYJZQ7GcGcyLxAHrX9itd44TL3rrWPU0w/qF1K4OaPLtOOpFDzs1N0u sLVgaNBMz31Ql64nKvX4L52L86tw+zih9kKwcvrd4utIKY+6eswFGtGP/FrmneL8hQLAbT yvxLM7WswE6P93adrzLBv5ZvitIKDIA= 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-573-jej1DBeDO1eMCMK5-PoaHw-1; Fri, 11 Jul 2025 16:12:53 -0400 X-MC-Unique: jej1DBeDO1eMCMK5-PoaHw-1 X-Mimecast-MFC-AGG-ID: jej1DBeDO1eMCMK5-PoaHw_1752264772 Received: from mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.40]) (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 353551956080; Fri, 11 Jul 2025 20:12:52 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.224.49]) by mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 09BD619560A3; Fri, 11 Jul 2025 20:12:49 +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 v13 05/12] config: Look up IPA configurables in configuration file Date: Fri, 11 Jul 2025 22:12:24 +0200 Message-ID: <20250711201232.129264-6-mzamazal@redhat.com> In-Reply-To: <20250711201232.129264-1-mzamazal@redhat.com> References: <20250711201232.129264-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.40 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: JpeDU8zQL_1cXLSvsGucvzIOWkKcWE8onPMJfjO3hkY_1752264772 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, 129 insertions(+), 52 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..97c22c730 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::optional> configPaths_; + std::optional> 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..468e0ddf8 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,10 +51,15 @@ 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) +IPAProxy::IPAProxy(IPAModule *ipam, const GlobalConfiguration &configuration) : valid_(false), state_(ProxyStopped), ipam_(ipam) { + configPaths_ = configuration.envListOption("LIBCAMERA_IPA_CONFIG_PATH", + { "ipa", "config_paths" }); + execPaths_ = configuration.envListOption( + "LIBCAMERA_IPA_PROXY_PATH", { "ipa", "proxy_paths" }); } IPAProxy::~IPAProxy() @@ -122,20 +130,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_.value_or(std::vector())) { + 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 +202,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_.value_or(std::vector())) { + 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 Fri Jul 11 20:12:25 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23795 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 070EDC3237 for ; Fri, 11 Jul 2025 20:12:59 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B11F368F37; Fri, 11 Jul 2025 22:12:58 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="RkbSL+m+"; 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 AC11D68F2F for ; Fri, 11 Jul 2025 22:12:57 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752264776; 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=RkbSL+m+crMThy9J9vtxNHGIUcMAyBDAOQZj1Up/ydzmt+BOBp81QEl9WgTZT8J3l7ee43 nJu5yX3wt3VszwH1CuOTb5awySsgsFlP+UEFBeHO3v0yVz82E4WgKJOqIDCqEcW36y1W/U 0hEmH7Qw3XOCCgz38mWvyfqdTheduIE= 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-634-G1WxMOh7PES0z9qKxEMlAQ-1; Fri, 11 Jul 2025 16:12:55 -0400 X-MC-Unique: G1WxMOh7PES0z9qKxEMlAQ-1 X-Mimecast-MFC-AGG-ID: G1WxMOh7PES0z9qKxEMlAQ_1752264774 Received: from mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.40]) (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 82C4C195608E; Fri, 11 Jul 2025 20:12:54 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.224.49]) by mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id A697119560A3; Fri, 11 Jul 2025 20:12:52 +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 v13 06/12] config: Look up pipelines match list in configuration file Date: Fri, 11 Jul 2025 22:12:25 +0200 Message-ID: <20250711201232.129264-7-mzamazal@redhat.com> In-Reply-To: <20250711201232.129264-1-mzamazal@redhat.com> References: <20250711201232.129264-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.40 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: pYxF2hPyQH1URaMB5QQYuX1z07A3VBVYM3M9RmCZK_w_1752264774 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 Fri Jul 11 20:12:26 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23796 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 E0F8DC3237 for ; Fri, 11 Jul 2025 20:13:02 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A2B6668F3D; Fri, 11 Jul 2025 22:13:02 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="Zv7VeH+j"; 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 DE77768F27 for ; Fri, 11 Jul 2025 22:13:00 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752264779; 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=Zv7VeH+jOxX6NRpL/7ejqYLd/zYFghJh2ZFAh5dulh3+gvj5tRvsdZf7Y34I/ScZSgXoxL XAwYEJwQIUj79r4kKqOeK8RbRyseqf/iw9zTJSjpwAWZGpbH/gJWATZ1DeP37I5tOxzQEg hiE7ZZIPYd6JpfywPwT6lNSssC6iePQ= 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-330-HqjuyQnZNpyw8eJ1qhAp3g-1; Fri, 11 Jul 2025 16:12:58 -0400 X-MC-Unique: HqjuyQnZNpyw8eJ1qhAp3g-1 X-Mimecast-MFC-AGG-ID: HqjuyQnZNpyw8eJ1qhAp3g_1752264777 Received: from mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.40]) (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 2F80B1956096; Fri, 11 Jul 2025 20:12:57 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.224.49]) by mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 1E18D19560A3; Fri, 11 Jul 2025 20:12:54 +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 v13 07/12] config: Allow enabling software ISP in runtime Date: Fri, 11 Jul 2025 22:12:26 +0200 Message-ID: <20250711201232.129264-8-mzamazal@redhat.com> In-Reply-To: <20250711201232.129264-1-mzamazal@redhat.com> References: <20250711201232.129264-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.40 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: h2iE2fxYW4kvHAL1zo56MdYA1G0Hdh0G94Y4tI6dMbo_1752264777 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 Fri Jul 11 20:12:27 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23797 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 728ABC3237 for ; Fri, 11 Jul 2025 20:13:06 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 2BCBD68F36; Fri, 11 Jul 2025 22:13:06 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="EUKtqDkc"; 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 F177B68F27 for ; Fri, 11 Jul 2025 22:13:04 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752264784; 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=FoPzQuVJWnF3yYTfzYFSLNZNuhRj1AQOlFFl3WEekqo=; b=EUKtqDkcCf4bwr5UPrms5/fN+heyA0/kn/ojJi3Ew+4ZQ7+XXEhBl+o6rypMiaJ1iNJgP7 2PkgxH/RKpEwocgZrxdH2neTusuN67cUPwLfmTbYk5WagD2RxTNGdnbLBKSWMFc3CGgrD4 t4SQSLrNJQUw8adJyspBDX/rbxtaUOc= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-631-OliGVVK3MMChV_v24hhfcw-1; Fri, 11 Jul 2025 16:13:00 -0400 X-MC-Unique: OliGVVK3MMChV_v24hhfcw-1 X-Mimecast-MFC-AGG-ID: OliGVVK3MMChV_v24hhfcw_1752264779 Received: from mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.40]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 6E1F51800290; Fri, 11 Jul 2025 20:12:59 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.224.49]) by mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id B00F019560A3; Fri, 11 Jul 2025 20:12:57 +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 v13 08/12] config: Add global configuration file documentation Date: Fri, 11 Jul 2025 22:12:27 +0200 Message-ID: <20250711201232.129264-9-mzamazal@redhat.com> In-Reply-To: <20250711201232.129264-1-mzamazal@redhat.com> References: <20250711201232.129264-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.40 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: orjOWiwpXk60vxvfVXgy5DCODXj1B80QtKt3Q2O0So4_1752264779 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} | 108 ++++++++++++++++-- 4 files changed, 102 insertions(+), 12 deletions(-) rename Documentation/{environment_variables.rst => runtime_configuration.rst} (66%) 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 66% rename from Documentation/environment_variables.rst rename to Documentation/runtime_configuration.rst index 6f1235587..04289cd16 100644 --- a/Documentation/environment_variables.rst +++ b/Documentation/runtime_configuration.rst @@ -2,15 +2,101 @@ .. 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 + ipas: + rkisp1: + tuning_file: # full path + rpi: + tuning_file: # full path + 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 + ipas: + rpi: + tuning_file: /home/pi/imx283.json + 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 +110,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 +141,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 +246,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 Fri Jul 11 20:12:28 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23798 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 34709C3237 for ; Fri, 11 Jul 2025 20:13:09 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E4E4668F37; Fri, 11 Jul 2025 22:13:08 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="gvLo3YEm"; 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 3D73E68F27 for ; Fri, 11 Jul 2025 22:13:07 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752264786; 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=MZB7n4dHxpN+nDwQIr2GIicjg244quWE26Q0f77zMhI=; b=gvLo3YEmfXjqgDUWd3SrnGRUQOPjhOhWx1XbqFOdwiZaMWH/INwGdOn1H0hhCIEhSsX7vt 34IehwoUvs3hguSqTTZRDHMpwEBb802NrThMu85VJY7KBOMHoov8sawT3rgFrfdsoStrqN Uuf4Bgn6p2rBdSOlJ78343k6eAvpSdE= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-102-q-swKqOdMcisJezVtf1Fig-1; Fri, 11 Jul 2025 16:13:03 -0400 X-MC-Unique: q-swKqOdMcisJezVtf1Fig-1 X-Mimecast-MFC-AGG-ID: q-swKqOdMcisJezVtf1Fig_1752264782 Received: from mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.40]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 0232E180120D; Fri, 11 Jul 2025 20:13:02 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.224.49]) by mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 0946619560A3; Fri, 11 Jul 2025 20:12:59 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Kieran Bingham , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Laurent Pinchart Subject: [PATCH v13 09/12] libcamera: software_isp: Make input buffer copying configurable Date: Fri, 11 Jul 2025 22:12:28 +0200 Message-ID: <20250711201232.129264-10-mzamazal@redhat.com> In-Reply-To: <20250711201232.129264-1-mzamazal@redhat.com> References: <20250711201232.129264-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.40 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: AfLY06KKmwIPqP6b0Nox18d5CMP8wGrzcF2DSFLhFq4_1752264782 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 04289cd16..42f49b686 100644 --- a/Documentation/runtime_configuration.rst +++ b/Documentation/runtime_configuration.rst @@ -54,6 +54,7 @@ file structure: pipeline_handler: ... simple: + copy_input_buffer: # true/false supported_devices: - driver: # driver name, e.g. `mxc-isi` software_isp: # true/false @@ -88,6 +89,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 Fri Jul 11 20:12:29 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23799 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 281D4C3237 for ; Fri, 11 Jul 2025 20:13:12 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id BE58368F45; Fri, 11 Jul 2025 22:13:11 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="OJGw4DTy"; 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 2C3CF68F27 for ; Fri, 11 Jul 2025 22:13:10 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752264789; 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=cbk4esr4ScLuXICUPeHTr2G7bNtOexUC/Q0bd0IArN8=; b=OJGw4DTy9ZtxiaYOefvI37ERQsVyjUqIdunc8uNelj0wiaH3BDUXfORutBeGdA3Ggj/I+C WeX7qifZGvmXqNoET0PErIvrIKA/GYBtcRWMKKRelHeygZssDMa0f+y/fYOLzvcxD8VbSB /Mbiu6DtMGoXIjzyvuwM1SQPhgNOq2g= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-381-NIcMAUR4N_OQsiIKzXEnBg-1; Fri, 11 Jul 2025 16:13:05 -0400 X-MC-Unique: NIcMAUR4N_OQsiIKzXEnBg-1 X-Mimecast-MFC-AGG-ID: NIcMAUR4N_OQsiIKzXEnBg_1752264784 Received: from mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.40]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 80DA419560AA; Fri, 11 Jul 2025 20:13:04 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.224.49]) by mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 921621955F29; Fri, 11 Jul 2025 20:13:02 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Kieran Bingham , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Laurent Pinchart Subject: [PATCH v13 10/12] libcamera: software_isp: Make measurement configurable Date: Fri, 11 Jul 2025 22:12:29 +0200 Message-ID: <20250711201232.129264-11-mzamazal@redhat.com> In-Reply-To: <20250711201232.129264-1-mzamazal@redhat.com> References: <20250711201232.129264-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.40 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: lkq0XB7Ne94DMfQHwqo2HTEBWrfUbbmndy21LWAxliU_1752264784 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 42f49b686..66f4cc913 100644 --- a/Documentation/runtime_configuration.rst +++ b/Documentation/runtime_configuration.rst @@ -55,6 +55,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 @@ -90,6 +93,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 Fri Jul 11 20:12:30 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23800 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 CAFDDC3237 for ; Fri, 11 Jul 2025 20:13:14 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7D79F68F49; Fri, 11 Jul 2025 22:13:14 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="ij+nQ+v8"; 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 2065C68F27 for ; Fri, 11 Jul 2025 22:13:12 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752264791; 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=7kuJ/Xy6vSqEJSbvR3Fg14ElX6uA1fuVFZO8FGT3Z58=; b=ij+nQ+v8yCd2NMFhXLknOgH692F7vDE86DorqEsmXkHsMUERGSDZLavbffuRVpCWmxCVBo DVGOAJQ12OAUXu2Re0AXMOWowu8A49m79f7K4YdeVCe6P0Zts4NbNr4KfTHxL+Nh/YnpqW elwjA02N7E8DDwmeMA+AtLFxrTdXP2Y= 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-408-NU__jG_4P0-t5krYVyrb_w-1; Fri, 11 Jul 2025 16:13:07 -0400 X-MC-Unique: NU__jG_4P0-t5krYVyrb_w-1 X-Mimecast-MFC-AGG-ID: NU__jG_4P0-t5krYVyrb_w_1752264787 Received: from mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.40]) (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 E45221956096; Fri, 11 Jul 2025 20:13:06 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.224.49]) by mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id F17371955F21; Fri, 11 Jul 2025 20:13:04 +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 v13 11/12] config: Make configuration file configurable Date: Fri, 11 Jul 2025 22:12:30 +0200 Message-ID: <20250711201232.129264-12-mzamazal@redhat.com> In-Reply-To: <20250711201232.129264-1-mzamazal@redhat.com> References: <20250711201232.129264-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.40 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 8CmHOqyJx6L_AvTEHDU0HDJjDxMBJpzXx0OEIimRHb4_1752264787 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 66f4cc913..4647ff213 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 Fri Jul 11 20:12:31 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23801 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 58084C3237 for ; Fri, 11 Jul 2025 20:13:17 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 1365868F49; Fri, 11 Jul 2025 22:13:17 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="LS4xZwc+"; 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 63C5C68F27 for ; Fri, 11 Jul 2025 22:13:14 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1752264793; 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=p9KhA9tDjO8XNcK7wC5WyW4xMHUpQqeh9CvBoef+n7U=; b=LS4xZwc+ZxtWFVlIFr/742BvJcTIWPw4JjEMiRQBqRJfULlY0TXvrlmN1xuVzgJNciiAlL JrRFUeFPsg+7RRb+f5BszWUlc6uGsnHQV0EAXdblLi+ASSV6hAJzhQLSIo3s6+Ew2fu5Jd T4IW0DqM79Fu1pxq6ffXQXGEg0bA8ao= 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-423-pndHP6tUO2GgHy3PI_m-3A-1; Fri, 11 Jul 2025 16:13:10 -0400 X-MC-Unique: pndHP6tUO2GgHy3PI_m-3A-1 X-Mimecast-MFC-AGG-ID: pndHP6tUO2GgHy3PI_m-3A_1752264789 Received: from mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.40]) (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 437B81809C89; Fri, 11 Jul 2025 20:13:09 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.224.49]) by mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 53FFD19560A3; Fri, 11 Jul 2025 20:13:07 +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 v13 12/12] config: Make configuration directories configurable Date: Fri, 11 Jul 2025 22:12:31 +0200 Message-ID: <20250711201232.129264-13-mzamazal@redhat.com> In-Reply-To: <20250711201232.129264-1-mzamazal@redhat.com> References: <20250711201232.129264-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.40 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: XjyyRd1_2YPJXQiQiBjUQ196hTwGNHUj-CQGcTVU_JQ_1752264789 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 4647ff213..552dccd41 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_;