{"id":26048,"url":"https://patchwork.libcamera.org/api/1.1/patches/26048/?format=json","web_url":"https://patchwork.libcamera.org/patch/26048/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20260130054028.2043443-1-paul.elder@ideasonboard.com>","date":"2026-01-30T05:40:28","name":"libcamera: layer_manager: Add support for global configuration","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"a36482a4531a3bbf390d03c90df458ba20988134","submitter":{"id":17,"url":"https://patchwork.libcamera.org/api/1.1/people/17/?format=json","name":"Paul Elder","email":"paul.elder@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/26048/mbox/","series":[{"id":5758,"url":"https://patchwork.libcamera.org/api/1.1/series/5758/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=5758","date":"2026-01-30T05:40:28","name":"libcamera: layer_manager: Add support for global configuration","version":1,"mbox":"https://patchwork.libcamera.org/series/5758/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/26048/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/26048/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 6AD97BD78E\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 30 Jan 2026 05:40:42 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 91C5961FD2;\n\tFri, 30 Jan 2026 06:40:41 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 0C04D61FC4\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 30 Jan 2026 06:40:40 +0100 (CET)","from neptunite.hamster-moth.ts.net (unknown\n\t[IPv6:2404:7a81:160:2100:2eea:f891:1bd7:2691])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id BA7DF55C;\n\tFri, 30 Jan 2026 06:40:00 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"uo9gUWxw\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1769751601;\n\tbh=DKB34jNVeWqWl8GRUDmIO174O3Ib4vwd2wQIzFlq0UA=;\n\th=From:To:Cc:Subject:Date:From;\n\tb=uo9gUWxwL+JWlwNTAQ++enDpc+F9xSVMt3rP85YyjP2CWEllU+og1HTEx1jbNvdOV\n\tFc7G3IiMD1CwyumEAKYRh3PH68sX2Wd3h5/GD9SKoSfgsV+N82eBwX2/TMhW76zJlM\n\t8PxtYnXRX0WHpc8Xbon4khwxFQbvap9HC5zC+JC0=","From":"Paul Elder <paul.elder@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Cc":"Paul Elder <paul.elder@ideasonboard.com>","Subject":"[PATCH] libcamera: layer_manager: Add support for global\n\tconfiguration","Date":"Fri, 30 Jan 2026 14:40:28 +0900","Message-ID":"<20260130054028.2043443-1-paul.elder@ideasonboard.com>","X-Mailer":"git-send-email 2.47.2","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","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":"Enable configuring the layer system with the global configuration file,\nwhile retaining the ability to overwrite the global configuration via\nenvironment variables. This allows users to more easily retain layer\nsetups without having to always set environment variables.\n\nTo achieve this, the CameraManager needs to manually construct the\nLayerManager to feed it the global configuration.\n\nWhile at it, add documentation for the layer configuration options\n\nSigned-off-by: Paul Elder <paul.elder@ideasonboard.com>\n---\nThis patch is on top of v6 of \"Add Layers support\" [0]\n\n[0] https://patchwork.libcamera.org/project/libcamera/list/?series=5753\n\n Documentation/runtime_configuration.rst     | 13 +++++\n include/libcamera/internal/camera_manager.h |  4 +-\n include/libcamera/internal/layer_manager.h  | 10 +++-\n src/libcamera/camera_manager.cpp            |  1 +\n src/libcamera/layer_manager.cpp             | 61 ++++++++++-----------\n 5 files changed, 53 insertions(+), 36 deletions(-)","diff":"diff --git a/Documentation/runtime_configuration.rst b/Documentation/runtime_configuration.rst\nindex e99ef2fb9561..a74a738803d6 100644\n--- a/Documentation/runtime_configuration.rst\n+++ b/Documentation/runtime_configuration.rst\n@@ -139,6 +139,19 @@ LIBCAMERA_<NAME>_TUNING_FILE\n \n    Example value: ``/usr/local/share/libcamera/ipa/rpi/vc4/custom_sensor.json``\n \n+LIBCAMERA_LAYER_PATH, layer.path\n+   Define custom search locations for Layer implementations.\n+\n+   Example value: ``${HOME}/.libcamera/share/layer:/opt/libcamera/vendor/share/layer``\n+\n+LIBCAMERA_LAYERS_ENABLE, layer.layers\n+  Define an ordered list of Layers to load. The layer names are declared in the\n+  'name' field of their repsective LayerInfo structs. The layers declared first\n+  are closer to the application, and the layers declared later are closer to\n+  libcamera.\n+\n+  Example value: ``inject_controls,sync``\n+\n pipelines.simple.supported_devices.driver, pipelines.simple.supported_devices.software_isp\n    Override whether software ISP is enabled for the given driver.\n \ndiff --git a/include/libcamera/internal/camera_manager.h b/include/libcamera/internal/camera_manager.h\nindex cc3ede02507f..00afcd2177e7 100644\n--- a/include/libcamera/internal/camera_manager.h\n+++ b/include/libcamera/internal/camera_manager.h\n@@ -46,7 +46,7 @@ public:\n \t}\n \n \tIPAManager *ipaManager() const { return ipaManager_.get(); }\n-\tconst LayerManager *layerManager() const { return &layerManager_; }\n+\tconst LayerManager *layerManager() const { return layerManager_.get(); }\n \n protected:\n \tvoid run() override;\n@@ -73,7 +73,7 @@ private:\n \tstd::unique_ptr<DeviceEnumerator> enumerator_;\n \n \tstd::unique_ptr<IPAManager> ipaManager_;\n-\tLayerManager layerManager_;\n+\tstd::unique_ptr<LayerManager> layerManager_;\n \n \tconst GlobalConfiguration configuration_;\n };\ndiff --git a/include/libcamera/internal/layer_manager.h b/include/libcamera/internal/layer_manager.h\nindex 8427ec3eb5d9..82a6a1d82461 100644\n--- a/include/libcamera/internal/layer_manager.h\n+++ b/include/libcamera/internal/layer_manager.h\n@@ -26,6 +26,8 @@\n #include <libcamera/request.h>\n #include <libcamera/stream.h>\n \n+#include \"libcamera/internal/global_configuration.h\"\n+\n namespace libcamera {\n \n LOG_DECLARE_CATEGORY(LayerLoaded)\n@@ -150,7 +152,9 @@ struct LayerInstance {\n class LayerController\n {\n public:\n-\tLayerController(const Camera *camera, const ControlList &properties,\n+\tLayerController(const Camera *camera,\n+\t\t\tconst GlobalConfiguration &configuration,\n+\t\t\tconst ControlList &properties,\n \t\t\tconst ControlInfoMap &controlInfoMap,\n \t\t\tconst std::map<std::string, std::shared_ptr<LayerLoaded>> &layers);\n \t~LayerController();\n@@ -190,7 +194,7 @@ private:\n class LayerManager\n {\n public:\n-\tLayerManager();\n+\tLayerManager(const GlobalConfiguration &configuration);\n \t~LayerManager() = default;\n \n \tstd::unique_ptr<LayerController>\n@@ -200,6 +204,8 @@ public:\n \n private:\n \tstd::map<std::string, std::shared_ptr<LayerLoaded>> layers_;\n+\n+\tconst GlobalConfiguration &configuration_;\n };\n \n } /* namespace libcamera */\ndiff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp\nindex 554cd935339a..a8e7cfe9daff 100644\n--- a/src/libcamera/camera_manager.cpp\n+++ b/src/libcamera/camera_manager.cpp\n@@ -43,6 +43,7 @@ CameraManager::Private::Private()\n \t: Thread(\"CameraManager\"), initialized_(false)\n {\n \tipaManager_ = std::make_unique<IPAManager>(this->configuration());\n+\tlayerManager_ = std::make_unique<LayerManager>(this->configuration());\n }\n \n int CameraManager::Private::start()\ndiff --git a/src/libcamera/layer_manager.cpp b/src/libcamera/layer_manager.cpp\nindex bef69f6bd04b..445e26234b23 100644\n--- a/src/libcamera/layer_manager.cpp\n+++ b/src/libcamera/layer_manager.cpp\n@@ -25,6 +25,7 @@\n #include <libcamera/control_ids.h>\n #include <libcamera/layer.h>\n \n+#include \"libcamera/internal/global_configuration.h\"\n #include \"libcamera/internal/utils.h\"\n \n /**\n@@ -276,6 +277,7 @@ LayerLoaded::LayerLoaded(const std::string &filename)\n /**\n  * \\brief Initialize the Layers\n  * \\param[in] camera The Camera for whom to initialize layers\n+ * \\param[in] configuration The global configuration\n  * \\param[in] properties The Camera properties\n  * \\param[in] controlInfoMap The Camera controls\n  * \\param[in] layers Map of available layers\n@@ -290,29 +292,26 @@ LayerLoaded::LayerLoaded(const std::string &filename)\n  * efficiently returned at properties() and controls(), respectively.\n  */\n LayerController::LayerController(const Camera *camera,\n+\t\t\t\t const GlobalConfiguration &configuration,\n \t\t\t\t const ControlList &properties,\n \t\t\t\t const ControlInfoMap &controlInfoMap,\n \t\t\t\t const std::map<std::string, std::shared_ptr<LayerLoaded>> &layers)\n {\n \t/* Order the layers */\n-\t/* \\todo Document this. First is closer to application, last is closer to libcamera */\n-\t/* \\todo Get this from configuration file */\n-\tconst char *layerList = utils::secure_getenv(\"LIBCAMERA_LAYERS_ENABLE\");\n-\tif (layerList) {\n-\t\tfor (const auto &layerName : utils::split(layerList, \",\")) {\n-\t\t\tif (layerName.empty())\n-\t\t\t\tcontinue;\n-\n-\t\t\tconst auto &it = layers.find(layerName);\n-\t\t\tif (it == layers.end()) {\n-\t\t\t\tLOG(LayerController, Warning)\n-\t\t\t\t\t<< \"Requested layer '\" << layerName\n-\t\t\t\t\t<< \"' not found\";\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\n-\t\t\texecutionQueue_.emplace_back(std::make_unique<LayerInstance>(it->second));\n+\tstd::vector<std::string> configLayers =\n+\t\tconfiguration.envListOption(\"LIBCAMERA_LAYERS_ENABLE\", { \"layer\", \"layers\" }, \",\")\n+\t\t\t     .value_or(std::vector<std::string>());\n+\n+\tfor (const std::string &layerName : configLayers) {\n+\t\tconst auto &it = layers.find(layerName);\n+\t\tif (it == layers.end()) {\n+\t\t\tLOG(LayerController, Warning)\n+\t\t\t\t<< \"Requested layer '\" << layerName\n+\t\t\t\t<< \"' not found\";\n+\t\t\tcontinue;\n \t\t}\n+\n+\t\texecutionQueue_.emplace_back(std::make_unique<LayerInstance>(it->second));\n \t}\n \n \tfor (std::unique_ptr<LayerInstance> &layer : executionQueue_)\n@@ -532,7 +531,8 @@ void LayerController::stop()\n  * LayerController is responsible for organizing them into queues to be\n  * executed, and for managing closures for each Camera that they belong to.\n  */\n-LayerManager::LayerManager()\n+LayerManager::LayerManager(const GlobalConfiguration &configuration)\n+\t: configuration_(configuration)\n {\n \t/* This is so that we can capture it in the lambda below */\n \tstd::map<std::string, std::shared_ptr<LayerLoaded>> &layers = layers_;\n@@ -560,19 +560,15 @@ LayerManager::LayerManager()\n \t};\n \n \t/* User-specified paths take precedence. */\n-\t/* \\todo Document this */\n-\tconst char *layerPaths = utils::secure_getenv(\"LIBCAMERA_LAYER_PATH\");\n-\tif (layerPaths) {\n-\t\tfor (const auto &dir : utils::split(layerPaths, \":\")) {\n-\t\t\tif (dir.empty())\n-\t\t\t\tcontinue;\n-\n-\t\t\t/*\n-\t\t\t * \\todo Move the shared objects into one directory\n-\t\t\t * instead of each in their own subdir\n-\t\t\t */\n-\t\t\tutils::findSharedObjects(dir.c_str(), 1, soHandler);\n-\t\t}\n+\tstd::vector<std::string> layerPaths =\n+\t\tconfiguration.envListOption(\"LIBCAMERA_LAYER_PATH\", { \"layer\", \"path\" })\n+\t\t\t     .value_or(std::vector<std::string>());\n+\tfor (const auto &dir : layerPaths) {\n+\t\t/*\n+\t\t * \\todo Move the shared objects into one directory\n+\t\t * instead of each in their own subdir\n+\t\t */\n+\t\tutils::findSharedObjects(dir.c_str(), 1, soHandler);\n \t}\n \n \t/*\n@@ -606,7 +602,8 @@ LayerManager::createController(const Camera *camera,\n \t\t\t       const ControlList &properties,\n \t\t\t       const ControlInfoMap &controlInfoMap) const\n {\n-\treturn std::make_unique<LayerController>(camera, properties, controlInfoMap, layers_);\n+\treturn std::make_unique<LayerController>(camera, configuration_,\n+\t\t\t\t\t\t properties, controlInfoMap, layers_);\n }\n \n } /* namespace libcamera */\n","prefixes":[]}