From patchwork Mon Jun 16 08:47:19 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 23564 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 97B02C3237 for ; Mon, 16 Jun 2025 08:47:52 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 517CD68DC0; Mon, 16 Jun 2025 10:47:52 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="AVV9QP/5"; 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 D9A8468DB4 for ; Mon, 16 Jun 2025 10:47:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750063669; 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=IJLfQVHEXaumvo+gfPnw73YRBbctGrbT7PW9PKMHD48=; b=AVV9QP/5o7SUXn8zeWlP6t5wl29tXeO6HOvEezyQ0cIO6B3cXuUXEAWyBKRb4NynDbOH32 yObRS1Ze8/2nif5DWFhSKAvJEYEIbqpPYpRcjjZks/HQDZvQM7Gjf4fc35PdcOeaLKWy+f XsXWJYR9KJgaBRalSBvFuFYG1MT6HvI= 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-159-9uGdd109OCO-3NHrTfLb1g-1; Mon, 16 Jun 2025 04:47:47 -0400 X-MC-Unique: 9uGdd109OCO-3NHrTfLb1g-1 X-Mimecast-MFC-AGG-ID: 9uGdd109OCO-3NHrTfLb1g_1750063666 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (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 EAA24195608A; Mon, 16 Jun 2025 08:47:45 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.226.135]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 7278B1956094; Mon, 16 Jun 2025 08:47:42 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Kieran Bingham , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Laurent Pinchart Subject: [PATCH v10 01/13] yaml: Move yaml_parser.cpp to base Date: Mon, 16 Jun 2025 10:47:19 +0200 Message-ID: <20250616084733.18707-2-mzamazal@redhat.com> In-Reply-To: <20250616084733.18707-1-mzamazal@redhat.com> References: <20250616084733.18707-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: V0Erwvrco_gsE5mZUqcT2fnGM8gkz3ooEUXpk1BuI6I_1750063666 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, which uses objects from the YAML parser, will be accessed from base. Thus YAML parser must be moved to base too. Indentation is changed in one place of the moved file to make the autoformatter and checkstyle.py happy. Signed-off-by: Milan Zamazal Reviewed-by: Kieran Bingham Signed-off-by: Milan Zamazal --- src/libcamera/base/meson.build | 14 ++++++++++++++ src/libcamera/{ => base}/yaml_parser.cpp | 13 ++++++------- src/libcamera/meson.build | 14 -------------- 3 files changed, 20 insertions(+), 21 deletions(-) rename src/libcamera/{ => base}/yaml_parser.cpp (98%) diff --git a/src/libcamera/base/meson.build b/src/libcamera/base/meson.build index a742dfdfe..94843eb95 100644 --- a/src/libcamera/base/meson.build +++ b/src/libcamera/base/meson.build @@ -24,10 +24,12 @@ libcamera_base_internal_sources = files([ 'thread.cpp', 'timer.cpp', 'utils.cpp', + 'yaml_parser.cpp', ]) libdw = dependency('libdw', required : false) libunwind = dependency('libunwind', required : false) +libyaml = dependency('yaml-0.1', required : false) if cc.has_header_symbol('execinfo.h', 'backtrace') config_h.set('HAVE_BACKTRACE', 1) @@ -41,11 +43,23 @@ if libunwind.found() config_h.set('HAVE_UNWIND', 1) endif +# Fallback to a subproject if libyaml isn't found, as it's not packaged in AOSP. +if not libyaml.found() + cmake = import('cmake') + + libyaml_vars = cmake.subproject_options() + libyaml_vars.add_cmake_defines({'CMAKE_POSITION_INDEPENDENT_CODE': 'ON'}) + libyaml_vars.append_compile_args('c', '-Wno-unused-value') + libyaml_wrap = cmake.subproject('libyaml', options : libyaml_vars) + libyaml = libyaml_wrap.dependency('yaml') +endif + libcamera_base_deps = [ libatomic, libdw, libthreads, libunwind, + libyaml, ] # Internal components must use the libcamera_base_private dependency to enable diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/base/yaml_parser.cpp similarity index 98% rename from src/libcamera/yaml_parser.cpp rename to src/libcamera/base/yaml_parser.cpp index a5e424615..13111faaa 100644 --- a/src/libcamera/yaml_parser.cpp +++ b/src/libcamera/base/yaml_parser.cpp @@ -149,13 +149,12 @@ YamlObject::Getter::get(const YamlObject &obj) const template struct YamlObject::Getter || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v>> -{ + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v>> { std::optional get(const YamlObject &obj) const { if (obj.type_ != Type::Value) diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 202db1efe..24fcfcf57 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -55,7 +55,6 @@ libcamera_internal_sources = files([ 'v4l2_subdevice.cpp', 'v4l2_videodevice.cpp', 'vector.cpp', - 'yaml_parser.cpp', ]) includes = [ @@ -83,7 +82,6 @@ if not cc.has_function('dlopen') libdl = cc.find_library('dl') endif libudev = dependency('libudev', required : get_option('udev')) -libyaml = dependency('yaml-0.1', required : false) # Use one of gnutls or libcrypto (provided by OpenSSL), trying gnutls first. libcrypto = dependency('gnutls', required : false) @@ -119,17 +117,6 @@ if libudev.found() ]) endif -# Fallback to a subproject if libyaml isn't found, as it's not packaged in AOSP. -if not libyaml.found() - cmake = import('cmake') - - libyaml_vars = cmake.subproject_options() - libyaml_vars.add_cmake_defines({'CMAKE_POSITION_INDEPENDENT_CODE': 'ON'}) - libyaml_vars.append_compile_args('c', '-Wno-unused-value') - libyaml_wrap = cmake.subproject('libyaml', options : libyaml_vars) - libyaml = libyaml_wrap.dependency('yaml') -endif - control_sources = [] controls_mode_files = { @@ -190,7 +177,6 @@ libcamera_deps += [ libdl, liblttng, libudev, - libyaml, ] # We add '/' to the build_rpath as a 'safe' path to act as a boolean flag. From patchwork Mon Jun 16 08:47: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: 23565 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 56C42C3237 for ; Mon, 16 Jun 2025 08:47:56 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0D1DA68DD1; Mon, 16 Jun 2025 10:47:56 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="ijNq3fdT"; 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 D132468DB4 for ; Mon, 16 Jun 2025 10:47:54 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750063673; 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=sWxzDKxmqIoIE/yxwI7Jq4K6tNeFFAjUQVv5wOVRoBI=; b=ijNq3fdTIWOobpy7jjUuSc2a04nwz+cXprqAZzJ7G6Y9ti7clojVmxpkbIl468vANM+BY8 /85G0mgbveLAhZyNjcSu2LHhR/waveOaaqX3zLmls/YT/pgAK1NLxb3d86vXU/5Tj23KjK /b4AWUTcNmoaPI4aHb0NsE31WH8uRvc= 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-317--nNdWBXBOMWguPqugn7HsA-1; Mon, 16 Jun 2025 04:47:49 -0400 X-MC-Unique: -nNdWBXBOMWguPqugn7HsA-1 X-Mimecast-MFC-AGG-ID: -nNdWBXBOMWguPqugn7HsA_1750063668 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (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 B3DD6195608A; Mon, 16 Jun 2025 08:47:48 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.226.135]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 89E271956094; Mon, 16 Jun 2025 08:47: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 v10 02/13] config: Introduce global runtime configuration Date: Mon, 16 Jun 2025 10:47:20 +0200 Message-ID: <20250616084733.18707-3-mzamazal@redhat.com> In-Reply-To: <20250616084733.18707-1-mzamazal@redhat.com> References: <20250616084733.18707-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: ofuxZeQ6-zO6zk40nN4rVE7Ws0ojxR5A0HQwaaTemzM_1750063668 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. Another possible use case is tuning image output, especially with software ISP, to user liking. For example, some users may prefer higher contrast without the need to use the corresponding knobs, if present at all, in every application. 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. GlobalConfiguration is defined in base because it will be accessed from code in base, e.g. logging. 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/base/global_configuration.cpp | 150 ++++++++++++++++++ src/libcamera/base/meson.build | 1 + 4 files changed, 186 insertions(+) create mode 100644 include/libcamera/internal/global_configuration.h create mode 100644 src/libcamera/base/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..8d0410ac2 --- /dev/null +++ b/include/libcamera/internal/global_configuration.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024-2025 Red Hat, inc. + * + * Global configuration handling + */ + +#pragma once + +#include + +#include "libcamera/internal/yaml_parser.h" + +namespace libcamera { + +class GlobalConfiguration +{ +public: + using Configuration = const YamlObject &; + + GlobalConfiguration(); + + unsigned int version() const; + Configuration configuration() const; + +private: + bool loadFile(const std::filesystem::path &fileName); + void load(); + Configuration get() const; + + std::unique_ptr yamlConfiguration; +}; + +} /* namespace libcamera */ diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build index 33f318b2b..951bfee49 100644 --- a/include/libcamera/internal/meson.build +++ b/include/libcamera/internal/meson.build @@ -22,6 +22,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/base/global_configuration.cpp b/src/libcamera/base/global_configuration.cpp new file mode 100644 index 000000000..1ddf5bc33 --- /dev/null +++ b/src/libcamera/base/global_configuration.cpp @@ -0,0 +1,150 @@ +/* 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("/etc/libcamera/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, Warning) + << "Failed to open configuration file " << fileName; + return true; + } + + auto root = YamlParser::parse(file); + if (!root) { + LOG(Configuration, Warning) + << "Failed to parse configuration file " << fileName; + return true; + } + yamlConfiguration = std::move(root); + + return true; +} + +void GlobalConfiguration::load() +{ + std::filesystem::path userConfigurationDirectory; + char *xdgConfigHome = utils::secure_getenv("XDG_CONFIG_HOME"); + if (xdgConfigHome) { + userConfigurationDirectory = xdgConfigHome; + } else { + const char *home = utils::secure_getenv("HOME"); + if (home) + userConfigurationDirectory = + std::filesystem::path(home) / ".config"; + } + + if (!userConfigurationDirectory.empty()) { + std::filesystem::path user_configuration_file = + userConfigurationDirectory / "libcamera" / "configuration.yaml"; + if (loadFile(user_configuration_file)) + return; + } + + for (const auto &path : globalConfigurationFiles) + if (loadFile(path)) + return; +} + +GlobalConfiguration::Configuration GlobalConfiguration::get() const +{ + return *yamlConfiguration; +} + +/** + * \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 get()["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 get()["configuration"]; +} + +} /* namespace libcamera */ diff --git a/src/libcamera/base/meson.build b/src/libcamera/base/meson.build index 94843eb95..4c0032845 100644 --- a/src/libcamera/base/meson.build +++ b/src/libcamera/base/meson.build @@ -16,6 +16,7 @@ libcamera_base_internal_sources = files([ 'event_dispatcher_poll.cpp', 'event_notifier.cpp', 'file.cpp', + 'global_configuration.cpp', 'log.cpp', 'memfd.cpp', 'message.cpp', From patchwork Mon Jun 16 08:47: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: 23566 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 2AD25C3237 for ; Mon, 16 Jun 2025 08:48:00 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D5D2268DD1; Mon, 16 Jun 2025 10:47:59 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="D4BMe33y"; 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 146B568DB4 for ; Mon, 16 Jun 2025 10:47:58 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750063677; 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=Tz5GVy7X6bJSyGK+oTefH1l7yTyGVl5UdlTHfmSnG6I=; b=D4BMe33ySd/11kf6x0Nw5flchTfQUz/fGE1OIwIqNVWK0y0Oz9DoP//mlcnBhgTSJerMog ZZ1sy1wz1oNXf5rvwGn2ZQ2Bw6KqvVCEf4imzU4anbwZw4BbFMLgJ/cEjRRS5OiO12nTpG Iw1zsYgtUbYsL46n8eoHajipd9Iyero= 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-627-lqtp30leOIiaxpdNGN-QEQ-1; Mon, 16 Jun 2025 04:47:53 -0400 X-MC-Unique: lqtp30leOIiaxpdNGN-QEQ-1 X-Mimecast-MFC-AGG-ID: lqtp30leOIiaxpdNGN-QEQ_1750063672 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (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 8263B1800343; Mon, 16 Jun 2025 08:47:52 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.226.135]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 5ABC01956094; Mon, 16 Jun 2025 08:47: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 v10 03/13] config: Make GlobalConfiguration instance Date: Mon, 16 Jun 2025 10:47:21 +0200 Message-ID: <20250616084733.18707-4-mzamazal@redhat.com> In-Reply-To: <20250616084733.18707-1-mzamazal@redhat.com> References: <20250616084733.18707-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: nWu5k5-nP9lXZEGPDczMasRSBT-BEppn-CzqeOnBNYs_1750063672 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. Perhaps some acceptable workaround could be found, which would also allow an easier logging configuration. If there are multiple CameraManager instances, there are also multiple GlobalConfiguration instances. 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. This is dirty and a potential source of trouble (although not expected to have much impact in practice) but there is no idea how to do better if we want to avoid having GlobalConfiguration singleton or dealing with the logging problem. 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 Mon Jun 16 08:47: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: 23567 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 AFACAC3237 for ; Mon, 16 Jun 2025 08:48:02 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6A3F568DD6; Mon, 16 Jun 2025 10:48:02 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="U/0tFhio"; 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 4099268DD6 for ; Mon, 16 Jun 2025 10:48:00 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750063679; 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=SN0Ccq5YV1NrfzJKANaIZ8pRYPooZ6g4Mm09kCNtDmI=; b=U/0tFhioNj/SHES4aBWvtaSKYF3f6q9FLJcKqAkJKsMNAvKrOHoohfkDmhIP9ia4DnMbYa m1ZckGAa4YLsDfjl393f8Pkgf4xRFUwSY0E9o81RoJyywT6KTyP2JBcxATju+dUHVI+Bkt m5mxlfO7uthm0c9BSZvaf7Db9fyT7rU= 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-197-gIRYygdnMnCnSbM_wpLCzg-1; Mon, 16 Jun 2025 04:47:56 -0400 X-MC-Unique: gIRYygdnMnCnSbM_wpLCzg-1 X-Mimecast-MFC-AGG-ID: gIRYygdnMnCnSbM_wpLCzg_1750063675 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (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 39DDD18002EC; Mon, 16 Jun 2025 08:47:55 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.226.135]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id F05BB1956096; Mon, 16 Jun 2025 08:47: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 v10 04/13] config: Add configuration retrieval helpers Date: Mon, 16 Jun 2025 10:47:22 +0200 Message-ID: <20250616084733.18707-5-mzamazal@redhat.com> In-Reply-To: <20250616084733.18707-1-mzamazal@redhat.com> References: <20250616084733.18707-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: DLMfD7iZblwPfe3Ze0YEs8_Lif6SN0rlGBNXxAjPQfk_1750063675 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 must check for the key presence before retrieving the value using operator[] because if the key is not present then YamlObject::empty may be returned as a regular value. Signed-off-by: Milan Zamazal --- .../libcamera/internal/global_configuration.h | 5 ++ src/libcamera/base/global_configuration.cpp | 52 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h index 8d0410ac2..5d9531158 100644 --- a/include/libcamera/internal/global_configuration.h +++ b/include/libcamera/internal/global_configuration.h @@ -8,6 +8,8 @@ #pragma once #include +#include +#include #include "libcamera/internal/yaml_parser.h" @@ -22,6 +24,9 @@ public: unsigned int version() const; Configuration configuration() const; + std::optional option(const std::string &confPath) const; + std::optional envOption(const char *const envVariable, + const std::string &confPath) const; private: bool loadFile(const std::filesystem::path &fileName); diff --git a/src/libcamera/base/global_configuration.cpp b/src/libcamera/base/global_configuration.cpp index 1ddf5bc33..1ef63750c 100644 --- a/src/libcamera/base/global_configuration.cpp +++ b/src/libcamera/base/global_configuration.cpp @@ -8,6 +8,8 @@ #include "libcamera/internal/global_configuration.h" #include +#include +#include #include #include @@ -40,6 +42,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) @@ -112,6 +119,51 @@ 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 separated by dots + * \return A value if an item corresponding to \a confPath exists in the + * configuration file, no value otherwise + */ +std::optional GlobalConfiguration::option(const std::string &confPath) const +{ + const YamlObject *c = &configuration(); + for (auto part : utils::split(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 *const envVariable, + const std::string &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 Mon Jun 16 08:47: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: 23568 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 5F9ACC3237 for ; Mon, 16 Jun 2025 08:48:10 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 1069868DD9; Mon, 16 Jun 2025 10:48:10 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="RjJfwbsi"; 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 74AD668DC0 for ; Mon, 16 Jun 2025 10:48:04 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750063683; 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=a1vEno8Te+tpljG/yAhFKI0mbUpdaKxphUuEyfCqPQs=; b=RjJfwbsigZlUiUu1ivi6M/CQb+t2+axhApcyhsMFyDYTWi1Ks/HtFrlvamDjJsygKZ7RPC ml6mFwUN/AFd/WqK1IloW0TLjcKhy7hkr+rrZ9yx4OAwZ7LlCfSCy+BMZPYBxs/mPvZ1FE IiUHLFCZPLwjK8nH/YQCZaLUDUCeUhM= 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-81-G_KT1XinM5CuEcvTCjcslA-1; Mon, 16 Jun 2025 04:47:59 -0400 X-MC-Unique: G_KT1XinM5CuEcvTCjcslA-1 X-Mimecast-MFC-AGG-ID: G_KT1XinM5CuEcvTCjcslA_1750063678 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (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 A461C195609F; Mon, 16 Jun 2025 08:47:58 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.226.135]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id D79B31956094; Mon, 16 Jun 2025 08:47:55 +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 v10 05/13] config: Look up rpi config path in configuration file Date: Mon, 16 Jun 2025 10:47:23 +0200 Message-ID: <20250616084733.18707-6-mzamazal@redhat.com> In-Reply-To: <20250616084733.18707-1-mzamazal@redhat.com> References: <20250616084733.18707-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: Og_iKJ42Gh0_aDImGNVJP-KTQ8YfaKvdXxSNfcILdwI_1750063678 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 introduce a configuration option for rpi configuration file path. 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 configuration snippet: configuration: pipeline: rpi: config_file: FILENAME Signed-off-by: Milan Zamazal --- src/libcamera/pipeline/rpi/common/pipeline_base.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp index d8c7ca935..850a5e31b 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp @@ -20,6 +20,7 @@ #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" @@ -1084,7 +1085,12 @@ int CameraData::loadPipelineConfiguration() /* Initial configuration of the platform, in case no config file is present */ platformPipelineConfigure({}); - char const *configFromEnv = utils::secure_getenv("LIBCAMERA_RPI_CONFIG_FILE"); + const GlobalConfiguration &config = pipe()->cameraManager()->_d()->configuration(); + std::optional configFile = + config.envOption("LIBCAMERA_RPI_CONFIG_FILE", "pipelines.rpi.config_file"); + if (!configFile.has_value()) + return 0; + char const *configFromEnv = configFile.value().c_str(); if (!configFromEnv || *configFromEnv == '\0') return 0; From patchwork Mon Jun 16 08:47: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: 23569 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 B037FC3237 for ; Mon, 16 Jun 2025 08:48:11 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id EBC4A68DDF; Mon, 16 Jun 2025 10:48:10 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="ZuiI4lyK"; 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 1D13F68DD6 for ; Mon, 16 Jun 2025 10:48:07 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750063686; 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=in/GPXpIKRsVBQ9RdLJldHkDsGbpYRnvZIwtvva45FQ=; b=ZuiI4lyKHoQAMUW6JEWtNLqmkb9ODCVbFoA5UILRYB8tHJWAZB4071h4rm89PU4TbiwGBr M762tC8yPTq/Q+EA4YGqm7wfh9YLA8pX96LILzYISBuS2szWS2w0+eyy/Cu+Aau2npo3LB kn5mA5MPzi6+OaXLp6KoE9g//FNtjnA= 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-572-iKDK90a7OLyGYA3TJ7O8vQ-1; Mon, 16 Jun 2025 04:48:03 -0400 X-MC-Unique: iKDK90a7OLyGYA3TJ7O8vQ-1 X-Mimecast-MFC-AGG-ID: iKDK90a7OLyGYA3TJ7O8vQ_1750063682 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (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 715EC180028B; Mon, 16 Jun 2025 08:48:02 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.226.135]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 33BD11956094; Mon, 16 Jun 2025 08:47:58 +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 v10 06/13] config: Look up IPA configurables in configuration file Date: Mon, 16 Jun 2025 10:47:24 +0200 Message-ID: <20250616084733.18707-7-mzamazal@redhat.com> In-Reply-To: <20250616084733.18707-1-mzamazal@redhat.com> References: <20250616084733.18707-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: XVYLBInFOL_J484Z8ulY4lmj1MTD5zOiiMvv3hVaU1A_1750063682 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 ipas: IPA_NAME: tuning_file: TUNING FILE Signed-off-by: Milan Zamazal --- .../libcamera/internal/global_configuration.h | 35 ++++++++- include/libcamera/internal/ipa_manager.h | 8 ++- include/libcamera/internal/ipa_proxy.h | 5 +- src/libcamera/base/global_configuration.cpp | 47 +++++++++++- src/libcamera/camera_manager.cpp | 2 +- src/libcamera/ipa_manager.cpp | 37 ++++++---- src/libcamera/ipa_proxy.cpp | 72 ++++++++++--------- src/libcamera/pipeline/ipu3/ipu3.cpp | 3 +- src/libcamera/pipeline/mali-c55/mali-c55.cpp | 2 + src/libcamera/pipeline/rkisp1/rkisp1.cpp | 4 +- .../pipeline/rpi/common/pipeline_base.cpp | 3 +- src/libcamera/pipeline/vimc/vimc.cpp | 3 +- src/libcamera/software_isp/software_isp.cpp | 4 +- test/ipa/ipa_interface_test.cpp | 3 +- .../module_ipa_proxy.cpp.tmpl | 4 +- .../module_ipa_proxy.h.tmpl | 2 +- 16 files changed, 169 insertions(+), 65 deletions(-) diff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h index 5d9531158..ddf61e021 100644 --- a/include/libcamera/internal/global_configuration.h +++ b/include/libcamera/internal/global_configuration.h @@ -11,6 +11,8 @@ #include #include +#include + #include "libcamera/internal/yaml_parser.h" namespace libcamera { @@ -24,9 +26,40 @@ public: unsigned int version() const; Configuration configuration() const; - std::optional option(const std::string &confPath) const; + +#ifndef __DOXYGEN__ + template || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v> * = nullptr> +#else + template +#endif + std::optional option(const std::string &confPath) const + { + const YamlObject *c = &configuration(); + for (auto part : utils::split(confPath, ".")) { + c = &(*c)[part]; + if (!*c) + return {}; + } + return c->get(); + } + + std::vector listOption(const std::string &confPath) const; std::optional envOption(const char *const envVariable, const std::string &confPath) const; + std::vector envListOption( + const char *const envVariable, + const std::string &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..8ad717919 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), configuration); if (!proxy->isValid()) { LOG(IPAManager, Error) << "Failed to load proxy"; return nullptr; @@ -66,7 +68,7 @@ private: IPAModule *module(PipelineHandler *pipe, uint32_t minVersion, uint32_t maxVersion); - bool isSignatureValid(IPAModule *ipa) const; + bool isSignatureValid(IPAModule *ipa, const GlobalConfiguration &configuration) const; std::vector> modules_; diff --git a/include/libcamera/internal/ipa_proxy.h b/include/libcamera/internal/ipa_proxy.h index 983bcc5fa..01cc5deff 100644 --- a/include/libcamera/internal/ipa_proxy.h +++ b/include/libcamera/internal/ipa_proxy.h @@ -11,6 +11,8 @@ #include +#include "libcamera/internal/global_configuration.h" + namespace libcamera { class IPAModule; @@ -30,10 +32,11 @@ public: bool isValid() const { return valid_; } std::string configurationFile(const std::string &name, + const GlobalConfiguration &configuration, const std::string &fallbackName = std::string()) const; protected: - std::string resolvePath(const std::string &file) const; + std::string resolvePath(const std::string &file, const GlobalConfiguration &configuration) const; bool valid_; ProxyState state_; diff --git a/src/libcamera/base/global_configuration.cpp b/src/libcamera/base/global_configuration.cpp index 1ef63750c..420b46386 100644 --- a/src/libcamera/base/global_configuration.cpp +++ b/src/libcamera/base/global_configuration.cpp @@ -9,9 +9,11 @@ #include #include +#include #include #include #include +#include #include #include @@ -120,13 +122,22 @@ GlobalConfiguration::GlobalConfiguration() */ /** + * \fn std::optional GlobalConfiguration::option(const std::string &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 separated by dots * \return A value if an item corresponding to \a confPath exists in the * configuration file, no value otherwise */ -std::optional GlobalConfiguration::option(const std::string &confPath) const + +/** + * \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 (empty one if the option is not found) + */ +std::vector GlobalConfiguration::listOption(const std::string &confPath) const { const YamlObject *c = &configuration(); for (auto part : utils::split(confPath, ".")) { @@ -134,7 +145,7 @@ std::optional GlobalConfiguration::option(const std::string &confPa if (!*c) return {}; } - return c->get(); + return c->getList().value_or(std::vector()); } /** @@ -161,7 +172,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 (an empty vector is returned if nothing is found) + */ +std::vector GlobalConfiguration::envListOption( + const char *const envVariable, + const std::string &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/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/ipa_manager.cpp b/src/libcamera/ipa_manager.cpp index 830750dcc..c0e069b46 100644 --- a/src/libcamera/ipa_manager.cpp +++ b/src/libcamera/ipa_manager.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -16,6 +17,7 @@ #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,7 +103,7 @@ 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()) @@ -111,18 +113,25 @@ IPAManager::IPAManager() 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; + const auto modulePaths = + configuration.envListOption( + "LIBCAMERA_IPA_MODULE_PATH", "ipa.module_paths"); + for (const auto &dir : modulePaths) { + if (dir.empty()) + continue; - ipaCount += addDir(dir.c_str()); - } + ipaCount += addDir(dir.c_str()); + } - if (!ipaCount) - LOG(IPAManager, Warning) - << "No IPA found in '" << modulePaths << "'"; + if (!ipaCount) { + std::string paths; + if (!modulePaths.empty()) { + paths = std::accumulate(std::next(modulePaths.begin()), + modulePaths.end(), + modulePaths[0], + [](std::string s1, std::string s2) { return s1 + ":" + s2; }); + } + LOG(IPAManager, Warning) << "No IPA found in '" << paths << "'"; } /* @@ -276,11 +285,13 @@ IPAModule *IPAManager::module(PipelineHandler *pipe, uint32_t minVersion, */ #endif -bool IPAManager::isSignatureValid([[maybe_unused]] IPAModule *ipa) const +bool IPAManager::isSignatureValid([[maybe_unused]] IPAModule *ipa, const GlobalConfiguration &configuration) const { #if HAVE_IPA_PUBKEY char *force = utils::secure_getenv("LIBCAMERA_IPA_FORCE_ISOLATION"); - if (force && force[0] != '\0') { + if ((force && force[0] != '\0') || + (!force && configuration.option("ipa.force_isolation") + .value_or(false))) { LOG(IPAManager, Debug) << "Isolation of IPA module " << ipa->path() << " forced through environment variable"; diff --git a/src/libcamera/ipa_proxy.cpp b/src/libcamera/ipa_proxy.cpp index 9907b9615..a00f2ad21 100644 --- a/src/libcamera/ipa_proxy.cpp +++ b/src/libcamera/ipa_proxy.cpp @@ -14,6 +14,7 @@ #include #include +#include "libcamera/internal/global_configuration.h" #include "libcamera/internal/ipa_module.h" /** @@ -71,6 +72,7 @@ IPAProxy::~IPAProxy() /** * \brief Retrieve the absolute path to an IPA configuration file * \param[in] name The configuration file name + * \param[in] configuration The global configuration * \param[in] fallbackName The name of a fallback configuration file * * This function locates the configuration file for an IPA and returns its @@ -96,6 +98,7 @@ IPAProxy::~IPAProxy() * no configuration file can be found */ std::string IPAProxy::configurationFile(const std::string &name, + const GlobalConfiguration &configuration, const std::string &fallbackName) const { /* @@ -105,37 +108,37 @@ std::string IPAProxy::configurationFile(const std::string &name, const std::string ipaName = ipam_->info().name; /* - * Start with any user override through the module-specific environment - * variable. Use the name of the IPA module up to the first '/' to - * construct the variable name. + * Start with any user override through the module-specific configuration or + * environment variable. Use the name of the IPA module up to the first '/' + * to construct the configuration and variable names. */ - std::string ipaEnvName = ipaName.substr(0, ipaName.find('/')); + std::string ipaBaseName = ipaName.substr(0, ipaName.find('/')); + std::string ipaConfigName = "ipa.ipas." + ipaBaseName + ".tuning_file"; + std::string ipaEnvName = ipaBaseName; std::transform(ipaEnvName.begin(), ipaEnvName.end(), ipaEnvName.begin(), [](unsigned char c) { return std::toupper(c); }); ipaEnvName = "LIBCAMERA_" + ipaEnvName + "_TUNING_FILE"; - char const *configFromEnv = utils::secure_getenv(ipaEnvName.c_str()); - if (configFromEnv && *configFromEnv != '\0') - return { configFromEnv }; + auto config = configuration.envOption(ipaEnvName.c_str(), ipaConfigName); + if (config) + return { config.value() }; struct stat statbuf; 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; - } + auto confPaths = + configuration.envListOption( + "LIBCAMERA_IPA_CONFIG_PATH", "ipa.config_paths"); + for (const auto &dir : 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; } std::string root = utils::libcameraSourcePath(); @@ -178,12 +181,13 @@ std::string IPAProxy::configurationFile(const std::string &name, << "Configuration file '" << name << "' not found for IPA module '" << ipaName << "', falling back to '" << fallbackName << "'"; - return configurationFile(fallbackName); + return configurationFile(fallbackName, configuration); } /** * \brief Find a valid full path for a proxy worker for a given executable name * \param[in] file File name of proxy worker executable + * \param[in] configuration The global configuration * * A proxy worker's executable could be found in either the global installation * directory, or in the paths specified by the environment variable @@ -195,22 +199,22 @@ std::string IPAProxy::configurationFile(const std::string &name, * \return The full path to the proxy worker executable, or an empty string if * no valid executable path */ -std::string IPAProxy::resolvePath(const std::string &file) const +std::string IPAProxy::resolvePath(const std::string &file, const GlobalConfiguration &configuration) 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. */ + const auto execPaths = + configuration.envListOption( + "LIBCAMERA_IPA_PROXY_PATH", "ipa.proxy_paths"); + for (const auto &dir : execPaths) { + if (dir.empty()) + continue; + + std::string proxyPath = dir; + proxyPath += proxyFile; + if (!access(proxyPath.c_str(), X_OK)) + return proxyPath; } /* diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index e31e3879d..723f7665b 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -1183,8 +1183,9 @@ int IPU3CameraData::loadIPA() * The API tuning file is made from the sensor name. If the tuning file * isn't found, fall back to the 'uncalibrated' file. */ + const GlobalConfiguration &configuration = pipe()->cameraManager()->_d()->configuration(); std::string ipaTuningFile = - ipa_->configurationFile(sensor->model() + ".yaml", "uncalibrated.yaml"); + ipa_->configurationFile(sensor->model() + ".yaml", configuration, "uncalibrated.yaml"); ret = ipa_->init(IPASettings{ ipaTuningFile, sensor->model() }, sensorInfo, sensor->controls(), &ipaControls_); diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp index 4acc091bd..d346fa25f 100644 --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp @@ -388,7 +388,9 @@ int MaliC55CameraData::loadIPA() ipa_->setSensorControls.connect(this, &MaliC55CameraData::setSensorControls); + const GlobalConfiguration &configuration = pipe()->cameraManager()->_d()->configuration(); std::string ipaTuningFile = ipa_->configurationFile(sensor_->model() + ".yaml", + configuration, "uncalibrated.yaml"); /* We need to inform the IPA of the sensor configuration */ diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp index 675f0a749..aded4cb43 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp @@ -40,6 +40,7 @@ #include "libcamera/internal/delayed_controls.h" #include "libcamera/internal/device_enumerator.h" #include "libcamera/internal/framebuffer.h" +#include "libcamera/internal/global_configuration.h" #include "libcamera/internal/ipa_manager.h" #include "libcamera/internal/media_device.h" #include "libcamera/internal/media_pipeline.h" @@ -383,8 +384,9 @@ int RkISP1CameraData::loadIPA(unsigned int hwRevision) ipa_->metadataReady.connect(this, &RkISP1CameraData::metadataReady); /* The IPA tuning file is made from the sensor name. */ + const GlobalConfiguration &configuration = pipe()->cameraManager()->_d()->configuration(); std::string ipaTuningFile = - ipa_->configurationFile(sensor_->model() + ".yaml", "uncalibrated.yaml"); + ipa_->configurationFile(sensor_->model() + ".yaml", configuration, "uncalibrated.yaml"); IPACameraSensorInfo sensorInfo{}; int ret = sensor_->sensorInfo(&sensorInfo); diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp index 850a5e31b..4ce8035cd 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp @@ -1150,7 +1150,8 @@ int CameraData::loadIPA(ipa::RPi::InitResult *result) std::string model = sensor_->model(); if (isMonoSensor(sensor_)) model += "_mono"; - std::string configurationFile = ipa_->configurationFile(model + ".json"); + const GlobalConfiguration &configuration = pipe()->cameraManager()->_d()->configuration(); + std::string configurationFile = ipa_->configurationFile(model + ".json", configuration); IPASettings settings(configurationFile, sensor_->model()); ipa::RPi::InitParams params; diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp index 07273bd2b..555d51bb6 100644 --- a/src/libcamera/pipeline/vimc/vimc.cpp +++ b/src/libcamera/pipeline/vimc/vimc.cpp @@ -494,7 +494,8 @@ bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator) data->ipa_->paramsComputed.connect(data.get(), &VimcCameraData::paramsComputed); - std::string conf = data->ipa_->configurationFile("vimc.conf"); + const GlobalConfiguration &configuration = manager_->_d()->configuration(); + std::string conf = data->ipa_->configurationFile("vimc.conf", configuration); Flags inFlags = ipa::vimc::TestFlag::Flag2; Flags outFlags; data->ipa_->init(IPASettings{ conf, data->sensor_->model() }, diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp index 28e2a360e..3ce354111 100644 --- a/src/libcamera/software_isp/software_isp.cpp +++ b/src/libcamera/software_isp/software_isp.cpp @@ -21,6 +21,7 @@ #include #include "libcamera/internal/framebuffer.h" +#include "libcamera/internal/global_configuration.h" #include "libcamera/internal/ipa_manager.h" #include "libcamera/internal/software_isp/debayer_params.h" @@ -130,8 +131,9 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor, * The API tuning file is made from the sensor name. If the tuning file * isn't found, fall back to the 'uncalibrated' file. */ + const GlobalConfiguration &configuration = pipe->cameraManager()->_d()->configuration(); std::string ipaTuningFile = - ipa_->configurationFile(sensor->model() + ".yaml", "uncalibrated.yaml"); + ipa_->configurationFile(sensor->model() + ".yaml", configuration, "uncalibrated.yaml"); IPACameraSensorInfo sensorInfo{}; int ret = sensor->sensorInfo(&sensorInfo); diff --git a/test/ipa/ipa_interface_test.cpp b/test/ipa/ipa_interface_test.cpp index b81783664..1afcbf106 100644 --- a/test/ipa/ipa_interface_test.cpp +++ b/test/ipa/ipa_interface_test.cpp @@ -106,7 +106,8 @@ protected: } /* Test initialization of IPA module. */ - std::string conf = ipa_->configurationFile("vimc.conf"); + const GlobalConfiguration configuration; + std::string conf = ipa_->configurationFile("vimc.conf", configuration); Flags inFlags; Flags outFlags; int ret = ipa_->init(IPASettings{ conf, "vimc" }, 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..71e920eb1 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,7 +45,7 @@ namespace {{ns}} { {% endfor %} {%- endif %} -{{proxy_name}}::{{proxy_name}}(IPAModule *ipam, bool isolate) +{{proxy_name}}::{{proxy_name}}(IPAModule *ipam, bool isolate, const GlobalConfiguration &configuration) : IPAProxy(ipam), isolate_(isolate), controlSerializer_(ControlSerializer::Role::Proxy), seq_(0) { @@ -54,7 +54,7 @@ namespace {{ns}} { << ipam->path(); if (isolate_) { - const std::string proxyWorkerPath = resolvePath("{{module_name}}_ipa_proxy"); + const std::string proxyWorkerPath = resolvePath("{{module_name}}_ipa_proxy", configuration); if (proxyWorkerPath.empty()) { LOG(IPAProxy, Error) << "Failed to get proxy worker path"; 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 Mon Jun 16 08:47: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: 23570 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 2DF62C3237 for ; Mon, 16 Jun 2025 08:48:13 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 819F068DD6; Mon, 16 Jun 2025 10:48:12 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="RgXYoySb"; 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 C902068DC6 for ; Mon, 16 Jun 2025 10:48:09 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750063688; 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=r14txaJ0G6tckH0QcLCrdFm1NtoW0hnAPrx2xeh+Ze4=; b=RgXYoySbnb1eLTKd7I4Buopi6cqXtTzXUwD8TubvZvwgtmSed13B+MUW3ntt++Ls5LdaP5 IMMyWqfvarnTbj0Lkjj9OOMvLXKlE4MuYoFvWRxrPwgfAzN/J79J3LM2gJoGUnjYdhI207 Aei99YmyBDpL8tNrVme4vbdnIZFUDGI= 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-593-3_1qHOHQNRWVx7glXNUN7Q-1; Mon, 16 Jun 2025 04:48:06 -0400 X-MC-Unique: 3_1qHOHQNRWVx7glXNUN7Q-1 X-Mimecast-MFC-AGG-ID: 3_1qHOHQNRWVx7glXNUN7Q_1750063685 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (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 67F191801BD8; Mon, 16 Jun 2025 08:48:05 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.226.135]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 3D8B91956094; Mon, 16 Jun 2025 08:48: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 v10 07/13] config: Look up pipelines match list in configuration file Date: Mon, 16 Jun 2025 10:47:25 +0200 Message-ID: <20250616084733.18707-8-mzamazal@redhat.com> In-Reply-To: <20250616084733.18707-1-mzamazal@redhat.com> References: <20250616084733.18707-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: PtOrL737ePEL29EYDIt_4B__vZuYNA8nqjhg8tCLwfQ_1750063685 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 --- src/libcamera/camera_manager.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp index c47fd3677..b4d56c3aa 100644 --- a/src/libcamera/camera_manager.cpp +++ b/src/libcamera/camera_manager.cpp @@ -111,14 +111,15 @@ 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) { + std::optional pipesList = + configuration().envOption("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 : utils::split(pipesList.value(), ",")) { const PipelineHandlerFactoryBase *factory; factory = PipelineHandlerFactoryBase::getFactoryByName(pipeName); if (!factory) From patchwork Mon Jun 16 08:47: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: 23571 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 0BB5DC3237 for ; Mon, 16 Jun 2025 08:48:16 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id BB12368DDF; Mon, 16 Jun 2025 10:48:15 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="FMK7BMXk"; 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 8B0E568DDB for ; Mon, 16 Jun 2025 10:48:13 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750063692; 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=R3Yqr3rE+0gDDz9YJsK0iKtnw8uLDg//mWDjMNi8pQ4=; b=FMK7BMXknUb405HdnfPJCRWia3QhO2kCAWLOXsJgHq2iSjQW8b0vh0ANigAqpbnlosdIyf 10/9L3scsoEBXS6Q8gySjeU34Fw+voM+xnniWWvsYc6aJbcQsNxMRfSTq9vPwvhuV8UjAf ERSCHHvX8wPneAvxSy86Ud8NiPve8BA= 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-288-E8YjKBZINZWki8jegyatqg-1; Mon, 16 Jun 2025 04:48:09 -0400 X-MC-Unique: E8YjKBZINZWki8jegyatqg-1 X-Mimecast-MFC-AGG-ID: E8YjKBZINZWki8jegyatqg_1750063688 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (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 0C18D1956089; Mon, 16 Jun 2025 08:48:08 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.226.135]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 02FAC1956096; Mon, 16 Jun 2025 08:48:05 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Kieran Bingham , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Laurent Pinchart Subject: [PATCH v10 08/13] config: Allow enabling software ISP in runtime Date: Mon, 16 Jun 2025 10:47:26 +0200 Message-ID: <20250616084733.18707-9-mzamazal@redhat.com> In-Reply-To: <20250616084733.18707-1-mzamazal@redhat.com> References: <20250616084733.18707-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: r10-qpV45J2LNnZUeIwRSXUuexd2C9F1b70IsyKPyyI_1750063688 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 Mon Jun 16 08:47: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: 23572 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 AFC7AC3237 for ; Mon, 16 Jun 2025 08:48:16 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 51C4468DE5; Mon, 16 Jun 2025 10:48:16 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="SlyKmkCD"; 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 CD39968DDB for ; Mon, 16 Jun 2025 10:48:14 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750063693; 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=RhQKCOTjaIxG3W5+4R6SVoe0xZkjaZpsqTiyAgrDvaE=; b=SlyKmkCDCliXSLGmEO7Sn5JhAhUWXXoL3UF0odrinIVLzXUn5fEGLi9KWL4heJpYpkDBtK 8l0HaUHyVqOkn3rkYorfgGOS9PUVWXLUgmBfTqUlYo8sPGZ0I9PVkjAR/LZnIAN+bpURCr o1Anhcz2wHmDK8DnRBaRa1uo5rNnSSc= 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-612-aNTepT8_MVadual6JZpQFw-1; Mon, 16 Jun 2025 04:48:12 -0400 X-MC-Unique: aNTepT8_MVadual6JZpQFw-1 X-Mimecast-MFC-AGG-ID: aNTepT8_MVadual6JZpQFw_1750063691 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (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 5352F1956089; Mon, 16 Jun 2025 08:48:11 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.226.135]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 9C4C71956094; Mon, 16 Jun 2025 08:48:08 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Kieran Bingham , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Laurent Pinchart Subject: [PATCH v10 09/13] config: Add global configuration file documentation Date: Mon, 16 Jun 2025 10:47:27 +0200 Message-ID: <20250616084733.18707-10-mzamazal@redhat.com> In-Reply-To: <20250616084733.18707-1-mzamazal@redhat.com> References: <20250616084733.18707-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: -AVMYinr0AEApQk_Fkv_v_RgV7ZyDN0K6LUKdpD5hMo_1750063691 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} | 98 +++++++++++++++++-- 4 files changed, 91 insertions(+), 13 deletions(-) rename Documentation/{environment_variables.rst => runtime_configuration.rst} (67%) diff --git a/Documentation/documentation-contents.rst b/Documentation/documentation-contents.rst index 5c1118493..4be3729cf 100644 --- a/Documentation/documentation-contents.rst +++ b/Documentation/documentation-contents.rst @@ -7,7 +7,7 @@ * :doc:`/feature_requirements` * :doc:`/guides/application-developer` * :doc:`/python-bindings` - * :doc:`/environment_variables` + * :doc:`/runtime_configuration` * :doc:`/api-html/index` * :doc:`/code-of-conduct` * | diff --git a/Documentation/index.rst b/Documentation/index.rst index 251112fbd..200de6f67 100644 --- a/Documentation/index.rst +++ b/Documentation/index.rst @@ -12,13 +12,13 @@ Application Writer's Guide Camera Sensor Model - Environment variables Feature Requirements IPA Writer's guide Lens driver requirements libcamera Architecture Pipeline Handler Writer's Guide Python Bindings + Runtime configuration Sensor driver requirements SoftwareISP Benchmarking Tracing guide diff --git a/Documentation/meson.build b/Documentation/meson.build index 0fc5909d0..6d5af0f62 100644 --- a/Documentation/meson.build +++ b/Documentation/meson.build @@ -128,7 +128,6 @@ if sphinx.found() 'contributing.rst', 'design/ae.rst', 'documentation-contents.rst', - 'environment_variables.rst', 'feature_requirements.rst', 'guides/application-developer.rst', 'guides/ipa.rst', @@ -140,6 +139,7 @@ if sphinx.found() 'libcamera_architecture.rst', 'mali-c55.dot', 'python-bindings.rst', + 'runtime_configuration.rst', 'sensor_driver_requirements.rst', 'software-isp-benchmarking.rst', '../README.rst', diff --git a/Documentation/environment_variables.rst b/Documentation/runtime_configuration.rst similarity index 67% rename from Documentation/environment_variables.rst rename to Documentation/runtime_configuration.rst index 6f1235587..d7b5f35ee 100644 --- a/Documentation/environment_variables.rst +++ b/Documentation/runtime_configuration.rst @@ -2,15 +2,93 @@ .. include:: documentation-contents.rst -Environment variables +Runtime configuration ===================== -The libcamera behaviour can be tuned through environment variables. This -document lists all the available variables and describes their usage. +The libcamera behaviour can be tuned through a configuration file or +environment variables. This document lists all the configuration options +and describes their usage. + +General rules +------------- + +The configuration file is looked up in the following locations, in this +order: + +- $XDG_CONFIG_HOME/libcamera/configuration.yaml +- LIBCAMERA_SYSCONF_DIR/configuration.yaml +- /etc/libcamera/configuration.yaml + +The first configuration file found wins, contingent 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: + config_file: # full path + 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: + config_file: /usr/local/share/libcamera/pipeline/rpi/vc4/minimal_mem.yaml + simple: + supported_devices: + - driver: mxc-isi + software_isp: true List of variables ----------------- +The corresponding configuration file paths, if available, are listed in parentheses. + LIBCAMERA_LOG_FILE The custom destination for log output. @@ -24,27 +102,27 @@ LIBCAMERA_LOG_LEVELS LIBCAMERA_LOG_NO_COLOR Disable coloring of log messages (`more `__). -LIBCAMERA_IPA_CONFIG_PATH +LIBCAMERA_IPA_CONFIG_PATH (ipa.config_paths) Define custom search locations for IPA configurations (`more `__). Example value: ``${HOME}/.libcamera/share/ipa:/opt/libcamera/vendor/share/ipa`` -LIBCAMERA_IPA_FORCE_ISOLATION +LIBCAMERA_IPA_FORCE_ISOLATION (ipa.force_isolation) When set to a non-empty string, force process isolation of all IPA modules. Example value: ``1`` -LIBCAMERA_IPA_MODULE_PATH +LIBCAMERA_IPA_MODULE_PATH (ipa.module_paths) Define custom search locations for IPA modules (`more `__). Example value: ``${HOME}/.libcamera/lib:/opt/libcamera/vendor/lib`` -LIBCAMERA_IPA_PROXY_PATH +LIBCAMERA_IPA_PROXY_PATH (ipa.proxy_paths) Define custom full path for a proxy worker for a given executable name. Example value: ``${HOME}/.libcamera/proxy/worker:/opt/libcamera/vendor/proxy/worker`` -LIBCAMERA_PIPELINES_MATCH_LIST +LIBCAMERA_PIPELINES_MATCH_LIST (pipelines_match_list) Define an ordered list of pipeline names to be used to match the media devices in the system. The pipeline handler names used to populate the variable are the ones passed to the REGISTER_PIPELINE_HANDLER() macro in the @@ -52,7 +130,7 @@ LIBCAMERA_PIPELINES_MATCH_LIST Example value: ``rkisp1,simple`` -LIBCAMERA_RPI_CONFIG_FILE +LIBCAMERA_RPI_CONFIG_FILE (pipelines.rpi.config_file) Define a custom configuration file to use in the Raspberry Pi pipeline handler. Example value: ``/usr/local/share/libcamera/pipeline/rpi/vc4/minimal_mem.yaml`` @@ -156,7 +234,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 Mon Jun 16 08:47: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: 23573 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 CC191C3237 for ; Mon, 16 Jun 2025 08:48:21 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 83C1968DE5; Mon, 16 Jun 2025 10:48:21 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="AV0jJmao"; 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 6311F68DDA for ; Mon, 16 Jun 2025 10:48:19 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750063698; 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=QnrY38GoVIiMKctOGvjeeQJcN9tul6u+eMh5CdYoedk=; b=AV0jJmaoU+n1iJGnkspLkPYp0bf+7DZVhqhPQl/9eZiTrRQB3lwadrBTf50bW6ewiQlLQA DsStQUCoyxvaquTZwa9hElwi++zRZ5fpyjTXO3NCCK0N8DgGWEV/uENfvhDcCSyPGFQYE5 JehLWDTPcgt5Fa0oLieDaiD1J2Kp8DE= 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-678-ZOM7FbHVNCOOSOrViMJ2Kg-1; Mon, 16 Jun 2025 04:48:15 -0400 X-MC-Unique: ZOM7FbHVNCOOSOrViMJ2Kg-1 X-Mimecast-MFC-AGG-ID: ZOM7FbHVNCOOSOrViMJ2Kg_1750063694 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (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 E95501956096; Mon, 16 Jun 2025 08:48:13 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.226.135]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id EF4F11956094; Mon, 16 Jun 2025 08:48:11 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Kieran Bingham , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Laurent Pinchart Subject: [PATCH v10 10/13] libcamera: software_isp: Make input buffer copying configurable Date: Mon, 16 Jun 2025 10:47:28 +0200 Message-ID: <20250616084733.18707-11-mzamazal@redhat.com> In-Reply-To: <20250616084733.18707-1-mzamazal@redhat.com> References: <20250616084733.18707-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: k9-Ivip7mTZIn4BhTr-xS5NIajHTN2SOLpQ7Bgs_ICQ_1750063694 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 | 4 ++-- 5 files changed, 11 insertions(+), 16 deletions(-) diff --git a/Documentation/runtime_configuration.rst b/Documentation/runtime_configuration.rst index d7b5f35ee..9fc5e4548 100644 --- a/Documentation/runtime_configuration.rst +++ b/Documentation/runtime_configuration.rst @@ -49,6 +49,7 @@ file structure: rpi: config_file: # full path simple: + copy_input_buffer: # true/false supported_devices: - driver: # driver name, e.g. `mxc-isi` software_isp: # true/false @@ -80,6 +81,7 @@ Configuration file example rpi: config_file: /usr/local/share/libcamera/pipeline/rpi/vc4/minimal_mem.yaml 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..3b5587164 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 3ce354111..a0ad88cac 100644 --- a/src/libcamera/software_isp/software_isp.cpp +++ b/src/libcamera/software_isp/software_isp.cpp @@ -115,7 +115,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); @@ -131,7 +132,6 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor, * The API tuning file is made from the sensor name. If the tuning file * isn't found, fall back to the 'uncalibrated' file. */ - const GlobalConfiguration &configuration = pipe->cameraManager()->_d()->configuration(); std::string ipaTuningFile = ipa_->configurationFile(sensor->model() + ".yaml", configuration, "uncalibrated.yaml"); From patchwork Mon Jun 16 08:47: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: 23574 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 D38E8C3237 for ; Mon, 16 Jun 2025 08:48:22 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7C23568DE0; Mon, 16 Jun 2025 10:48:22 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="V8SE//aw"; 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 F2CCD68DDA for ; Mon, 16 Jun 2025 10:48:19 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750063699; 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=yDtgGKlVm8xi8RkiRhj3yJWyfeVC2gqzqprVMPRazjE=; b=V8SE//awryxKy6XYLhn2SMVC7zltaesuh+VeQkIFTe7dE99WZygyECzWoP4MUezfZLBtvx vuSpSud0C+3+1GX203HV+F5uYwW85jJOJNk4Qg8dWzdFE7Yb43R5W52rlXxxEm7PMecilL aGIo9qMGiZFGBZ5y5K2zPGNf/pM0STY= 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-681-t-_j76AcM2GxpDKbN8zrcA-1; Mon, 16 Jun 2025 04:48:17 -0400 X-MC-Unique: t-_j76AcM2GxpDKbN8zrcA-1 X-Mimecast-MFC-AGG-ID: t-_j76AcM2GxpDKbN8zrcA_1750063696 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (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 7BF171956086; Mon, 16 Jun 2025 08:48:16 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.226.135]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 711131956096; Mon, 16 Jun 2025 08:48:14 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Kieran Bingham , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Laurent Pinchart Subject: [PATCH v10 11/13] libcamera: software_isp: Make measurement configurable Date: Mon, 16 Jun 2025 10:47:29 +0200 Message-ID: <20250616084733.18707-12-mzamazal@redhat.com> In-Reply-To: <20250616084733.18707-1-mzamazal@redhat.com> References: <20250616084733.18707-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: upYmmBHRIyG3taeLMmrgOqdBVExWGPph4G-xo9GwAJU_1750063696 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 9fc5e4548..b7d1d3288 100644 --- a/Documentation/runtime_configuration.rst +++ b/Documentation/runtime_configuration.rst @@ -50,6 +50,9 @@ file structure: config_file: # full path simple: copy_input_buffer: # true/false + measure: + skip: # non-negative integer, frames to skip initially + number: # non-negative integer, frames to measure supported_devices: - driver: # driver name, e.g. `mxc-isi` software_isp: # true/false @@ -82,6 +85,9 @@ Configuration file example config_file: /usr/local/share/libcamera/pipeline/rpi/vc4/minimal_mem.yaml 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 3b5587164..6eeadcd23 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 Mon Jun 16 08:47: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: 23575 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 71B55C3237 for ; Mon, 16 Jun 2025 08:48:26 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 1E79B68DE5; Mon, 16 Jun 2025 10:48:26 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="hX6GOuAc"; 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 C49AD68DD0 for ; Mon, 16 Jun 2025 10:48:24 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750063703; 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=inaWVlbwo9MvpAcNvhnP2iSzLeECQ1jwH5lu9QdLHmg=; b=hX6GOuAc6engfUkm8upQurVmN9THco4uFUiiykmAl1a0A79Xb+MRNy6xpkSP6Rt9/VToW2 NNuYaT5omxgcaB13jeGI2Cp8keQOyM0r0U4KRthVoE22hKFpnnmUvkD8tFg+SCV1p7Atg3 CNEK4p1zaWr21u81fBNfRqWchORYYJ8= 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-184-b4TwS06IP8-jygfvrhUJ3w-1; Mon, 16 Jun 2025 04:48:20 -0400 X-MC-Unique: b4TwS06IP8-jygfvrhUJ3w-1 X-Mimecast-MFC-AGG-ID: b4TwS06IP8-jygfvrhUJ3w_1750063699 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (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 59E9A18011CD; Mon, 16 Jun 2025 08:48:19 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.226.135]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 2DE351956094; Mon, 16 Jun 2025 08:48:16 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Kieran Bingham , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Laurent Pinchart Subject: [PATCH v10 12/13] config: Make configuration file configurable Date: Mon, 16 Jun 2025 10:47:30 +0200 Message-ID: <20250616084733.18707-13-mzamazal@redhat.com> In-Reply-To: <20250616084733.18707-1-mzamazal@redhat.com> References: <20250616084733.18707-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 7tgKokRfROa6NndZAQ1fQVrsJL4H1Rjolc-2osuhyGU_1750063699 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 denotes: - The path of the configuration file to load if it is an absolute path; or - 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/base/global_configuration.cpp | 26 ++++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/Documentation/runtime_configuration.rst b/Documentation/runtime_configuration.rst index b7d1d3288..9e2650799 100644 --- a/Documentation/runtime_configuration.rst +++ b/Documentation/runtime_configuration.rst @@ -19,6 +19,14 @@ order: - LIBCAMERA_SYSCONF_DIR/configuration.yaml - /etc/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. + The first configuration file found wins, contingent configuration files in other locations are ignored. diff --git a/src/libcamera/base/global_configuration.cpp b/src/libcamera/base/global_configuration.cpp index 420b46386..9c9d1d74e 100644 --- a/src/libcamera/base/global_configuration.cpp +++ b/src/libcamera/base/global_configuration.cpp @@ -75,8 +75,28 @@ bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName) return true; } +const std::vector + globalConfigurationDirectories = { + std::filesystem::path(LIBCAMERA_SYSCONF_DIR), + std::filesystem::path("/etc/libcamera"), + }; + void GlobalConfiguration::load() { + const char *libcameraConfigName = + utils::secure_getenv("LIBCAMERA_CONFIG_NAME"); + if (!libcameraConfigName) + libcameraConfigName = ""; + std::filesystem::path configName(libcameraConfigName); + + if (configName.is_absolute()) { + loadFile(configName); + return; + } + + if (configName.empty()) + configName = std::filesystem::path("configuration.yaml"); + std::filesystem::path userConfigurationDirectory; char *xdgConfigHome = utils::secure_getenv("XDG_CONFIG_HOME"); if (xdgConfigHome) { @@ -90,13 +110,13 @@ void GlobalConfiguration::load() if (!userConfigurationDirectory.empty()) { std::filesystem::path user_configuration_file = - userConfigurationDirectory / "libcamera" / "configuration.yaml"; + userConfigurationDirectory / "libcamera" / configName; if (loadFile(user_configuration_file)) return; } - for (const auto &path : globalConfigurationFiles) - if (loadFile(path)) + for (const auto &path : globalConfigurationDirectories) + if (loadFile(path / configName)) return; } From patchwork Mon Jun 16 08:47: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: 23576 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 AC250C3237 for ; Mon, 16 Jun 2025 08:48:30 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5E8F668DE9; Mon, 16 Jun 2025 10:48:30 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="E4DbLU1y"; 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 DB33768DDF for ; Mon, 16 Jun 2025 10:48:28 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750063708; 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=wwiSUxqZXDImkCgxwsFksKMoP6626Kkdw2/zIDnVmFU=; b=E4DbLU1yBXU7QdH65m9MuXDhCn0h1VU2RvLWZpL7Hg54T8FFte/BmxpoukXaJu4kNgrKW3 +AK4OBiS4pAYIQlW47Ns3cvhEOTOvmoXuRi9iqb4crWHgha6K6k8t5py9ewoqG3E/fUlHx S/1hk13znoKRudswrNPYB0OhLdrqbQ8= 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-153-3uOrQKatNU-Rk4WF2n8LtA-1; Mon, 16 Jun 2025 04:48:23 -0400 X-MC-Unique: 3uOrQKatNU-Rk4WF2n8LtA-1 X-Mimecast-MFC-AGG-ID: 3uOrQKatNU-Rk4WF2n8LtA_1750063702 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (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 3DB4219560AE; Mon, 16 Jun 2025 08:48:22 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.226.135]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 0BA931956094; Mon, 16 Jun 2025 08:48:19 +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 v10 13/13] config: Make configuration directories configurable Date: Mon, 16 Jun 2025 10:47:31 +0200 Message-ID: <20250616084733.18707-14-mzamazal@redhat.com> In-Reply-To: <20250616084733.18707-1-mzamazal@redhat.com> References: <20250616084733.18707-1-mzamazal@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: ERckGpGK53LZZCmgk8lOXOzG-eYDSFd342PtFcb8B-w_1750063702 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/base/global_configuration.cpp | 15 +++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Documentation/runtime_configuration.rst b/Documentation/runtime_configuration.rst index 9e2650799..8f9e6fd75 100644 --- a/Documentation/runtime_configuration.rst +++ b/Documentation/runtime_configuration.rst @@ -19,6 +19,11 @@ order: - LIBCAMERA_SYSCONF_DIR/configuration.yaml - /etc/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/base/global_configuration.cpp b/src/libcamera/base/global_configuration.cpp index 9c9d1d74e..d3e148e91 100644 --- a/src/libcamera/base/global_configuration.cpp +++ b/src/libcamera/base/global_configuration.cpp @@ -75,12 +75,6 @@ bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName) return true; } -const std::vector - globalConfigurationDirectories = { - std::filesystem::path(LIBCAMERA_SYSCONF_DIR), - std::filesystem::path("/etc/libcamera"), - }; - void GlobalConfiguration::load() { const char *libcameraConfigName = @@ -97,6 +91,15 @@ void GlobalConfiguration::load() if (configName.empty()) configName = std::filesystem::path("configuration.yaml"); + const char *const configDir = utils::secure_getenv("LIBCAMERA_CONFIG_DIR"); + std::vector globalConfigurationDirectories; + if (configDir) + for (auto const &path : utils::split(configDir, ":")) + if (!path.empty()) + globalConfigurationDirectories.push_back(path); + globalConfigurationDirectories.push_back(LIBCAMERA_SYSCONF_DIR); + globalConfigurationDirectories.push_back("/etc/libcamera"); + std::filesystem::path userConfigurationDirectory; char *xdgConfigHome = utils::secure_getenv("XDG_CONFIG_HOME"); if (xdgConfigHome) {