Patch Detail
Show a patch.
GET /api/patches/19813/?format=api
{ "id": 19813, "url": "https://patchwork.libcamera.org/api/patches/19813/?format=api", "web_url": "https://patchwork.libcamera.org/patch/19813/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/projects/1/?format=api", "name": "libcamera", "link_name": "libcamera", "list_id": "libcamera_core", "list_email": "libcamera-devel@lists.libcamera.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20240326112419.503286-2-mzamazal@redhat.com>", "date": "2024-03-26T11:24:04", "name": "[RFC,01/11] config: Introduce global runtime configuration", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "f09ad9bd0728e915cce7f32291f6336c4c97c855", "submitter": { "id": 177, "url": "https://patchwork.libcamera.org/api/people/177/?format=api", "name": "Milan Zamazal", "email": "mzamazal@redhat.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/19813/mbox/", "series": [ { "id": 4241, "url": "https://patchwork.libcamera.org/api/series/4241/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=4241", "date": "2024-03-26T11:24:03", "name": "Add global configuration file", "version": 1, "mbox": "https://patchwork.libcamera.org/series/4241/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/19813/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/19813/checks/", "tags": {}, "headers": { "Return-Path": "<libcamera-devel-bounces@lists.libcamera.org>", "X-Original-To": "parsemail@patchwork.libcamera.org", "Delivered-To": "parsemail@patchwork.libcamera.org", "Received": [ "from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 10E52C32CA\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 26 Mar 2024 11:26:36 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 7EE7E6336F;\n\tTue, 26 Mar 2024 12:26:35 +0100 (CET)", "from us-smtp-delivery-124.mimecast.com\n\t(us-smtp-delivery-124.mimecast.com [170.10.133.124])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 9845E6331B\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 26 Mar 2024 12:26:29 +0100 (CET)", "from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com\n\t[66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS\n\t(version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n\tus-mta-438-9DbREjoKPSuP5Udupxeqbw-1; Tue, 26 Mar 2024 07:26:18 -0400", "from smtp.corp.redhat.com\n\t(int-mx01.intmail.prod.int.rdu2.redhat.com [10.11.54.1])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\tkey-exchange X25519 server-signature RSA-PSS (2048 bits)\n\tserver-digest SHA256) (No client certificate requested)\n\tby mimecast-mx02.redhat.com (Postfix) with ESMTPS id 9DA01101A526\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 26 Mar 2024 11:26:15 +0000 (UTC)", "from nuthatch.brq.redhat.com (unknown [10.43.17.39])\n\tby smtp.corp.redhat.com (Postfix) with ESMTP id 110003C22;\n\tTue, 26 Mar 2024 11:26:14 +0000 (UTC)" ], "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=redhat.com header.i=@redhat.com\n\theader.b=\"XM257og2\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1711452379;\n\th=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n\tto:to:cc:cc:mime-version:mime-version:content-type:content-type:\n\tcontent-transfer-encoding:content-transfer-encoding:\n\tin-reply-to:in-reply-to:references:references;\n\tbh=ZOpqgvP0/AzliHmux1yBNzHqutaIO8zDnOdJa0JHxP8=;\n\tb=XM257og2xve+NIOw68W0FZLVtUoXumadVI7XGMEG02muqvz550kjEg1nxrp00eXOmeDb92\n\tlJvw6Nj4vKqRQ1exbedlECwBnlfYoveTT8p/87ASzPp5J+af6L744GMVJZ48RkxmCA5qvH\n\tv9twa3Kikl9CUj1bbaV74BVC8HqCEbE=", "X-MC-Unique": "9DbREjoKPSuP5Udupxeqbw-1", "From": "Milan Zamazal <mzamazal@redhat.com>", "To": "libcamera-devel@lists.libcamera.org", "Cc": "Milan Zamazal <mzamazal@redhat.com>", "Subject": "[RFC PATCH 01/11] config: Introduce global runtime configuration", "Date": "Tue, 26 Mar 2024 12:24:04 +0100", "Message-ID": "<20240326112419.503286-2-mzamazal@redhat.com>", "In-Reply-To": "<20240326112419.503286-1-mzamazal@redhat.com>", "References": "<20240326112419.503286-1-mzamazal@redhat.com>", "MIME-Version": "1.0", "X-Scanned-By": "MIMEDefang 3.4.1 on 10.11.54.1", "X-Mimecast-Spam-Score": "0", "X-Mimecast-Originator": "redhat.com", "Content-Transfer-Encoding": "8bit", "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": "<libcamera-devel.lists.libcamera.org>", "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>", "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>", "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>", "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>", "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>", "Errors-To": "libcamera-devel-bounces@lists.libcamera.org", "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>" }, "content": "Currently, libcamera can be configured in runtime using several environment\nvariables. With introducing more and more variables, this mechanism reaches its\nlimits. It would be simpler and more flexible if it was possible to configure\nlibcamera in a single file.\n\nFor example, there have been a request for defining pipeline precedence in\nruntime. We want to have support for multiple pipelines compiled in order to\nhave single packages in distributions. And then being able to select among them\nas needed based on the particular hardware or operating system environment.\nThis can for example allow easy switching between hardware, CPU or GPU IPAs.\nAnother possible use case is tuning image output, especially with software ISP,\nto user liking. For example, some users may prefer higher contrast without the\nneed to use the corresponding knobs, if present at all, in every application.\n\nThis patch introduces basic support for configuration files.\nGlobalConfiguration class reads, stores and adds access to the configuration.\nIts instance is stored as a singleton and be accessed using a static method of\nthe class.\n\nlibcamera configuration can be specified using a system-wide configuration file\nor a user configuration file. The user configuration file take precedence if\npresent. There is currently no way to merge multiple configuration files, the\none found is used as the only configuration file. If no configuration file is\npresent, nothing changes to the current libcamera behavior (except for some log messages).\n\nThe configuration file is a YAML file, we already have a mechanism for handling\nYAML configuration files in libcamera and the given infrastructure can be reused\nfor the purpose. However, the configuration type is abstracted to make\ncontingent future change of the underlying class easier, if retaining (most of)\nits API.\n\nThe configuration is versioned. This has currently no particular meaning but is\nlikely to have its purpose in future, especially once configuration validation\nis introduced.\n\nThe configuration YAML file looks as follows:\n\n ---\n version: 1\n configuration:\n WHATEVER CONFIGURATION NEEDED\n\nThis patch introduces just the basic idea. Actually using the configuration in\nthe corresponding places (everything what is currently configurable via\nenvironment variables should be configurable in the file configuration),\nrefining the mechanism (e.g. configuration file validation to avoid mistakes\ncaused by typos) and other improvements will be addressed in followup patches.\n\nGlobalConfiguration is meant to be used as a globally accessible singleton.\nThere is currently no reason to have more than one instance.\n\nSigned-off-by: Milan Zamazal <mzamazal@redhat.com>\n---\n .../libcamera/internal/global_configuration.h | 44 ++++++\n include/libcamera/internal/meson.build | 1 +\n src/libcamera/global_configuration.cpp | 132 ++++++++++++++++++\n src/libcamera/meson.build | 1 +\n 4 files changed, 178 insertions(+)\n create mode 100644 include/libcamera/internal/global_configuration.h\n create mode 100644 src/libcamera/global_configuration.cpp", "diff": "diff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h\nnew file mode 100644\nindex 00000000..0a4f3c02\n--- /dev/null\n+++ b/include/libcamera/internal/global_configuration.h\n@@ -0,0 +1,44 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2024 Red Hat, inc.\n+ *\n+ * global_configuration.h - Global configuration handling\n+ */\n+\n+#pragma once\n+\n+#include <filesystem>\n+#include <vector>\n+\n+#include \"libcamera/internal/yaml_parser.h\"\n+\n+namespace libcamera {\n+\n+class GlobalConfiguration\n+{\n+public:\n+\t/**\n+\t * \\brief Type representing global libcamera configuration.\n+\t *\n+\t * All code outside GlobalConfiguration must use this type and not the\n+\t * underlying type.\n+\t */\n+\tusing Configuration = const YamlObject &;\n+\n+\tstatic unsigned int version();\n+\tstatic Configuration configuration();\n+\n+private:\n+\tstatic const std::vector<std::filesystem::path> globalConfigurationFiles;\n+\n+\tbool initialized_;\n+\tstd::unique_ptr<YamlObject> configuration_;\n+\n+\tGlobalConfiguration();\n+\tbool loadFile(const std::filesystem::path &fileName);\n+\tvoid load();\n+\tstatic const GlobalConfiguration &instance();\n+\tstatic Configuration get();\n+};\n+\n+} /* namespace libcamera */\ndiff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build\nindex 160fdc37..640a54aa 100644\n--- a/include/libcamera/internal/meson.build\n+++ b/include/libcamera/internal/meson.build\n@@ -28,6 +28,7 @@ libcamera_internal_headers = files([\n 'dma_heaps.h',\n 'formats.h',\n 'framebuffer.h',\n+ 'global_configuration.h',\n 'ipa_manager.h',\n 'ipa_module.h',\n 'ipa_proxy.h',\ndiff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp\nnew file mode 100644\nindex 00000000..72c3ce26\n--- /dev/null\n+++ b/src/libcamera/global_configuration.cpp\n@@ -0,0 +1,132 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2024 Red Hat, inc.\n+ *\n+ * global_configuration.cpp - Global configuration handling\n+ */\n+\n+#include \"libcamera/internal/global_configuration.h\"\n+\n+#include <cstdint>\n+#include <filesystem>\n+#include <memory>\n+#include <sys/types.h>\n+\n+#include <libcamera/base/file.h>\n+#include <libcamera/base/log.h>\n+\n+#include \"libcamera/internal/yaml_parser.h\"\n+\n+#include \"libcamera/base/utils.h\"\n+\n+namespace libcamera {\n+\n+LOG_DEFINE_CATEGORY(Configuration)\n+\n+/**\n+ * \\class GlobalConfiguration\n+ * \\brief Support for global libcamera configuration\n+ *\n+ * ...\n+ */\n+\n+GlobalConfiguration::GlobalConfiguration()\n+\t: initialized_(false), configuration_(std::make_unique<YamlObject>())\n+{\n+}\n+\n+const std::vector<std::filesystem::path>\n+\tGlobalConfiguration::globalConfigurationFiles = {\n+\t\tstd::filesystem::path(LIBCAMERA_SYSCONF_DIR) / \"configuration.yaml\",\n+\t\tstd::filesystem::path(\"/etc/libcamera/configuration.yaml\"),\n+\t};\n+\n+void GlobalConfiguration::load()\n+{\n+\tstd::filesystem::path userConfigurationDirectory;\n+\tchar *xdgConfigHome = utils::secure_getenv(\"XDG_CONFIG_HOME\");\n+\tif (xdgConfigHome) {\n+\t\tuserConfigurationDirectory = xdgConfigHome;\n+\t} else {\n+\t\tconst char *home = utils::secure_getenv(\"HOME\");\n+\t\tif (home)\n+\t\t\tuserConfigurationDirectory =\n+\t\t\t\tstd::filesystem::path(home) / \".config\";\n+\t}\n+\n+\tif (!userConfigurationDirectory.empty()) {\n+\t\tstd::filesystem::path user_configuration_file =\n+\t\t\tuserConfigurationDirectory / \"libcamera\" / \"configuration.yaml\";\n+\t\tif (loadFile(user_configuration_file))\n+\t\t\treturn;\n+\t}\n+\n+\tfor (auto path : globalConfigurationFiles)\n+\t\tif (loadFile(path))\n+\t\t\treturn;\n+\n+\tinitialized_ = true;\n+\tLOG(Configuration, Debug) << \"No configuration file found\";\n+}\n+\n+bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName)\n+{\n+\tFile file(fileName);\n+\tif (!file.exists()) {\n+\t\treturn false;\n+\t}\n+\n+\tif (!file.open(File::OpenModeFlag::ReadOnly)) {\n+\t\tLOG(Configuration, Warning)\n+\t\t\t<< \"Failed to open configuration file '\" << fileName << \"'\";\n+\t\treturn true;\n+\t}\n+\n+\tauto root = YamlParser::parse(file);\n+\tif (!root) {\n+\t\tLOG(Configuration, Warning) << \"Failed to parse configuration file \"\n+\t\t\t\t\t << fileName;\n+\t\treturn true;\n+\t}\n+\tconfiguration_ = std::move(root);\n+\tinitialized_ = true;\n+\tLOG(Configuration, Info) << \"Configuration file \" << fileName << \"loaded\";\n+\n+\treturn true;\n+}\n+\n+const GlobalConfiguration &GlobalConfiguration::instance()\n+{\n+\tstatic GlobalConfiguration configuration;\n+\tif (!configuration.initialized_) {\n+\t\tconfiguration.load();\n+\t}\n+\treturn configuration;\n+}\n+\n+GlobalConfiguration::Configuration GlobalConfiguration::get()\n+{\n+\treturn (*instance().configuration_);\n+}\n+\n+/**\n+ * \\brief Return configuration version.\n+ *\n+ * ...\n+ */\n+unsigned int GlobalConfiguration::version()\n+{\n+\treturn get()[\"version\"].get<unsigned int>().value_or(0);\n+}\n+\n+/**\n+ * \\brief Return libcamera global configuration.\n+ *\n+ * ...\n+ */\n+GlobalConfiguration::Configuration GlobalConfiguration::configuration()\n+{\n+\treturn get()[\"configuration\"];\n+}\n+\n+} /* namespace libcamera */\ndiff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\nindex a3b12bc1..b81c75b8 100644\n--- a/src/libcamera/meson.build\n+++ b/src/libcamera/meson.build\n@@ -21,6 +21,7 @@ libcamera_sources = files([\n 'framebuffer.cpp',\n 'framebuffer_allocator.cpp',\n 'geometry.cpp',\n+ 'global_configuration.cpp',\n 'ipa_controls.cpp',\n 'ipa_data_serializer.cpp',\n 'ipa_interface.cpp',\n", "prefixes": [ "RFC", "01/11" ] }