[PATCH v5 03/15] config: Introduce global runtime configuration
Milan Zamazal
mzamazal at redhat.com
Thu Dec 5 20:17:33 CET 2024
Barnabás Pőcze <pobrn at protonmail.com> writes:
> Hi
>
>
> 2024. december 5., csütörtök 12:33 keltezéssel, Milan Zamazal <mzamazal at redhat.com> írta:
>
>> Hi Barnabás,
>>
>> thank you for review.
>>
>> Barnabás Pőcze <pobrn at protonmail.com> writes:
>>
>> > Hi
>> >
>> >
>> > 2024. október 1., kedd 12:27 keltezéssel, Milan Zamazal <mzamazal at redhat.com> írta:
>> >
>> >> 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 have been a request for defining 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.
>> >> Its instance is stored as a private singleton accessed using a static
>> >> method of the class. There is currently no reason to have more than one
>> >> instance.
>> >>
>> >> libcamera configuration can be specified using a system-wide
>> >> configuration file or a user configuration file. The user configuration
>> >> file takes precedence if present. There is currently no way to merge
>> >> multiple configuration files, the one found is used as the only
>> >> configuration file. If no configuration file is present, nothing
>> >> changes to the current libcamera behavior (except for some log
>> >> messages related to configuration file lookup).
>> >>
>> >> The configuration file is a YAML file. We already have a mechanism for
>> >> handling YAML configuration files in libcamera and the given
>> >> infrastructure can be reused for the purpose. However, the
>> >> configuration type is abstracted to make contingent future change of the
>> >> underlying class easier while retaining (most of) the original API.
>> >>
>> >> The configuration is versioned. This has currently no particular
>> >> meaning but is likely to have its purpose in future, especially once
>> >> configuration validation is introduced.
>> >>
>> >> The configuration YAML file looks as follows:
>> >>
>> >> ---
>> >> version: 1
>> >> configuration:
>> >> WHATEVER CONFIGURATION NEEDED
>> >>
>> >> There is no logging about reading the configuration file and contingent
>> >> errors. This is on purpose because logging will query configuration,
>> >> which can lead to various problems when done during configuration
>> >> initialization. Reporting the errors will be added later.
>> >>
>> >> The global configuration is intended to be used as a hidden singleton,
>> >> with static class methods around it providing the configuration
>> >> information. The constructor must be still public so that unique_ptr
>> >> can be used.
>> >>
>> >> A complication arises from the fact that when the configuration is
>> >> loaded, logging may be called and logging will ask for the
>> >> configuration. This is error-prone and may lead to subtle problems.
>> >> For this reason, the global configuration is instantiated to a pointer,
>> >> with an empty configuration initially. The real configuration will be
>> >> created through initialize() method. It will be clearer how it helps in
>> >> the followup patch introducing logging configuration.
>> >>
>> >> Logging is also the most notable component from base that uses global
>> >> configuration. In order to be able to do it, the global configuration
>> >> must be put to base.
>> >>
>> >> 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 <mzamazal at redhat.com>
>> >> ---
>> >> .../libcamera/internal/global_configuration.h | 41 +++++
>> >> include/libcamera/internal/meson.build | 1 +
>> >> src/libcamera/base/global_configuration.cpp | 154 ++++++++++++++++++
>> >> src/libcamera/base/meson.build | 1 +
>> >> 4 files changed, 197 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..628d85cb8
>> >> --- /dev/null
>> >> +++ b/include/libcamera/internal/global_configuration.h
>> >> @@ -0,0 +1,41 @@
>> >> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
>> >> +/*
>> >> + * Copyright (C) 2024 Red Hat, inc.
>> >> + *
>> >> + * global_configuration.h - Global configuration handling
>> >> + */
>> >> +
>> >> +#pragma once
>> >> +
>> >> +#include <filesystem>
>> >> +#include <vector>
>> >> +
>> >> +#include "libcamera/internal/yaml_parser.h"
>> >> +
>> >> +namespace libcamera {
>> >> +
>> >> +class GlobalConfiguration
>> >> +{
>> >> +public:
>> >> + using Configuration = const YamlObject &;
>> >> +
>> >> + /* The constructor must be public to be able to use unique_ptr. */
>> >
>> > If one does
>> >
>> > std::unique_ptr<T>(new T)
>> >
>> > then the constructor does not need to be public.
>>
>> Ah, cool.
>>
>> >> + GlobalConfiguration();
>> >> + static void initialize();
>> >> +
>> >> + static unsigned int version();
>> >> + static Configuration configuration();
>> >> +
>> >> +private:
>> >> + static const std::vector<std::filesystem::path> globalConfigurationFiles;
>> >> +
>> >> + static std::unique_ptr<GlobalConfiguration> instance_;
>> >> +
>> >> + std::unique_ptr<YamlObject> configuration_;
>> >> +
>> >> + bool loadFile(const std::filesystem::path &fileName);
>> >> + void load();
>> >> + static Configuration get();
>> >> +};
>> >> +
>> >> +} /* namespace libcamera */
>> >> diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build
>> >> index 1c5eef9ca..6fc6406d7 100644
>> >> --- a/include/libcamera/internal/meson.build
>> >> +++ b/include/libcamera/internal/meson.build
>> >> @@ -21,6 +21,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..7dcf97265
>> >> --- /dev/null
>> >> +++ b/src/libcamera/base/global_configuration.cpp
>> >> @@ -0,0 +1,154 @@
>> >> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
>> >> +/*
>> >> + * Copyright (C) 2024 Red Hat, inc.
>> >> + *
>> >> + * global_configuration.cpp - Global configuration handling
>> >> + */
>> >> +
>> >> +#include "libcamera/internal/global_configuration.h"
>> >> +
>> >> +#include <filesystem>
>> >> +#include <memory>
>> >> +#include <sys/types.h>
>> >> +
>> >> +#include <libcamera/base/file.h>
>> >> +#include <libcamera/base/log.h>
>> >> +#include <libcamera/base/utils.h>
>> >> +
>> >> +#include "libcamera/internal/yaml_parser.h"
>> >> +
>> >> +namespace libcamera {
>> >> +
>> >> +std::unique_ptr<GlobalConfiguration> GlobalConfiguration::instance_ =
>> >> + std::make_unique<GlobalConfiguration>();
>> >
>> > Why is a unique_ptr needed here?
>>
>> Most notably to stick with the libcamera policy of avoiding using plain
>> pointers. And for the instance disposal in initialize() below.
>> [...]
>
> I was thinking that there is no need to dynamically allocate a `GlobalConfiguration`
> instance. In fact, now I think `GlobalConfiguration` could simply be a namespace.
> All private members of the current class would go into an anonymous namespace,
> and all public members would just be functions in the namespace.
I see, we can get rid of `instance_' this way and just store the
configuration. OK, this would be probably better.
>
> Regards,
> Barnabás Pőcze
More information about the libcamera-devel
mailing list