From patchwork Fri Jun 24 00:30:04 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 16361 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 3BB29BD808 for ; Fri, 24 Jun 2022 00:30:26 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4208E65635; Fri, 24 Jun 2022 02:30:25 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1656030625; bh=40pLfsGo7v+rc0VPtPFVqcUAaJsnI0nprqpJGSG5WKM=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=aaDgYZURuQcTWZaSV821R3ylzac96nnVvzQUEZ2a5f8OX9TFkEjm5rhrO2kMyD2G9 4akySgY7ytMuqMILGsEz5/T2nr38oc2TwCaI/xDbSDxlwMljvr4bjiK4YIYjad+XeM Zql7MwIZkiIyw+0BwIPqNVdHv8UA0WItdQRXG0fo5z8HuFQit95Juz4XKCRc2mglBf DuefDnsAOYTCHJptBkcsDS5qExe4XD1YmmMrcd/bhh2r/5i2Xl7PE5fP3pGAJWC5qC yFB+NH6mWj0YYtT7sdKZNXwtKtUQ6LJ9JjQSHP/5Xvyo+xe7w5Oc7B0dK7rWMlyXtu IMrQao/DPppLQ== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D832261FB2 for ; Fri, 24 Jun 2022 02:30:23 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="b8G15sk8"; dkim-atps=neutral Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id F256CDD; Fri, 24 Jun 2022 02:30:22 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1656030623; bh=40pLfsGo7v+rc0VPtPFVqcUAaJsnI0nprqpJGSG5WKM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=b8G15sk8Kw2eX3fRAhZfLZSL5b+LYaavOidBxTTKXcmnYMRWUPRAhvDq8ak8qrg7I iWvT+Qov/SbbXu+SAKkEDuE78V4U0EqDIiIpcyIUQGjHfvDNwpyTQkPepuLLzop4kO 7PvclfQixMES/TPHtEZVOeRbCPcSkWx/++Xa0ucw= To: libcamera-devel@lists.libcamera.org Date: Fri, 24 Jun 2022 03:30:04 +0300 Message-Id: <20220624003004.31600-1-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220620014305.26778-4-laurent.pinchart@ideasonboard.com> References: <20220620014305.26778-4-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4.1 03/12] ipa: libipa: algorithm: Add an algorithm registration mechanism 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: , X-Patchwork-Original-From: Laurent Pinchart via libcamera-devel From: Laurent Pinchart Reply-To: Laurent Pinchart Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" In order to allow dynamic instantiation of algorithms based on tuning data files, add a mechanism to register algorithms with the IPA module. The implementation relies on an AlgorithmFactory class and a registration macro, similar to the pipeline handler registration mechanism. The main difference is that the algorithm registration and instantiation are implemented in the Module class instead of the AlgorithmFactory class, making the factory an internal implementation detail. Signed-off-by: Laurent Pinchart Reviewed-by: Paul Elder --- Changes since v4: - Simplify the REGISTER_IPA_ALGORITHM() macro by making more use of templates - Add name argument to the REGISTER_IPA_ALGORITHM() macro --- The first changed compared to v4 is an implementation detail, and the second change is significant. It decouples the algorithm name from the class name, allowing identifications of algorithms with strings that wouldn't be valid C++ symbol names. For instance, the Raspberry Pi IPA naming scheme ("rpi.${algo}") can now be supported. Documentation/Doxyfile.in | 1 + src/ipa/libipa/algorithm.cpp | 48 ++++++++++++++++++++++++++++++++++++ src/ipa/libipa/algorithm.h | 47 ++++++++++++++++++++++++++++++++++- src/ipa/libipa/module.cpp | 24 ++++++++++++++++++ src/ipa/libipa/module.h | 33 +++++++++++++++++++++++++ 5 files changed, 152 insertions(+), 1 deletion(-) diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in index 3d20e3ca460f..4bb83d50c6c9 100644 --- a/Documentation/Doxyfile.in +++ b/Documentation/Doxyfile.in @@ -886,6 +886,7 @@ EXCLUDE_SYMBOLS = libcamera::BoundMethodArgs \ libcamera::BoundMethodStatic \ libcamera::CameraManager::Private \ libcamera::SignalBase \ + libcamera::ipa::AlgorithmFactoryBase \ *::details \ std::* diff --git a/src/ipa/libipa/algorithm.cpp b/src/ipa/libipa/algorithm.cpp index 2df91e5d8fed..1d0998089044 100644 --- a/src/ipa/libipa/algorithm.cpp +++ b/src/ipa/libipa/algorithm.cpp @@ -32,6 +32,11 @@ namespace ipa { * argument. */ +/** + * \typedef Algorithm::Module + * \brief The IPA module type for this class of algorithms + */ + /** * \fn Algorithm::configure() * \brief Configure the Algorithm given an IPAConfigInfo @@ -94,6 +99,49 @@ namespace ipa { * such that the algorithms use up to date state as required. */ +/** + * \class AlgorithmFactory + * \brief Registration of Algorithm classes and creation of instances + * \tparam _Algorithm The algorithm class type for this factory + * + * To facilitate instantiation of Algorithm classes, the AlgorithmFactory class + * implements auto-registration of algorithms with the IPA Module class. Each + * Algorithm subclass shall register itself using the REGISTER_IPA_ALGORITHM() + * macro, which will create a corresponding instance of an AlgorithmFactory and + * register it with the IPA Module. + */ + +/** + * \fn AlgorithmFactory::AlgorithmFactory() + * \brief Construct an algorithm factory + * \param[in] name Name of the algorithm class + * + * Creating an instance of the factory automatically registers is with the IPA + * Module class, enabling creation of algorithm instances through + * Module::createAlgorithm(). + * + * The factory \a name identifies the algorithm and shall be unique. + */ + +/** + * \fn AlgorithmFactory::create() + * \brief Create an instance of the Algorithm corresponding to the factory + * \return A pointer to a newly constructed instance of the Algorithm subclass + * corresponding to the factory + */ + +/** + * \def REGISTER_IPA_ALGORITHM + * \brief Register an algorithm with the IPA module + * \param[in] algorithm Class name of Algorithm derived class to register + * \param[in] name Name of the algorithm + * + * Register an Algorithm subclass with the IPA module to make it available for + * instantiation through Module::createAlgorithm(). The \a name identifies the + * algorithm and must be unique across all algorithms registered for the IPA + * module. + */ + } /* namespace ipa */ } /* namespace libcamera */ diff --git a/src/ipa/libipa/algorithm.h b/src/ipa/libipa/algorithm.h index fd2ffcfbc900..cfbe4ed8efac 100644 --- a/src/ipa/libipa/algorithm.h +++ b/src/ipa/libipa/algorithm.h @@ -6,14 +6,19 @@ */ #pragma once +#include +#include + namespace libcamera { namespace ipa { -template +template class Algorithm { public: + using Module = _Module; + virtual ~Algorithm() {} virtual int configure([[maybe_unused]] typename Module::Context &context, @@ -34,6 +39,46 @@ public: } }; +template +class AlgorithmFactoryBase +{ +public: + AlgorithmFactoryBase(const char *name) + : name_(name) + { + _Module::registerAlgorithm(this); + } + + virtual ~AlgorithmFactoryBase() = default; + + const std::string &name() const { return name_; } + + virtual std::unique_ptr> create() const = 0; + +private: + std::string name_; +}; + +template +class AlgorithmFactory : public AlgorithmFactoryBase +{ +public: + AlgorithmFactory(const char *name) + : AlgorithmFactoryBase(name) + { + } + + ~AlgorithmFactory() = default; + + std::unique_ptr> create() const override + { + return std::make_unique<_Algorithm>(); + } +}; + +#define REGISTER_IPA_ALGORITHM(algorithm, name) \ +static AlgorithmFactory global_##algorithm##Factory(name); + } /* namespace ipa */ } /* namespace libcamera */ diff --git a/src/ipa/libipa/module.cpp b/src/ipa/libipa/module.cpp index d03cc8ef03ed..451614fd04da 100644 --- a/src/ipa/libipa/module.cpp +++ b/src/ipa/libipa/module.cpp @@ -75,6 +75,30 @@ namespace ipa { * \brief The type of the IPA statistics and ISP results */ +/** + * \fn Module::createAlgorithm() + * \brief Create an instance of an Algorithm by name + * \param[in] name The algorithm name + * + * This function is the entry point to algorithm instantiation for the IPA + * module. It creates and returns an instance of an algorithm identified by its + * \a name. If no such algorithm exists, the function returns nullptr. + * + * To make an algorithm available to the IPA module, it shall be registered with + * the REGISTER_IPA_ALGORITHM() macro. + * + * \return A new instance of the Algorithm subclass corresponding to the \a name + */ + +/** + * \fn Module::registerAlgorithm() + * \brief Add an algorithm factory class to the list of available algorithms + * \param[in] factory Factory to use to construct the algorithm + * + * This function registers an algorithm factory. It is meant to be called by the + * AlgorithmFactory constructor only. + */ + } /* namespace ipa */ } /* namespace libcamera */ diff --git a/src/ipa/libipa/module.h b/src/ipa/libipa/module.h index c4d778120408..05f39801db47 100644 --- a/src/ipa/libipa/module.h +++ b/src/ipa/libipa/module.h @@ -7,6 +7,12 @@ #pragma once +#include +#include +#include + +#include "algorithm.h" + namespace libcamera { namespace ipa { @@ -23,6 +29,33 @@ public: using Stats = _Stats; virtual ~Module() {} + + static std::unique_ptr> createAlgorithm(const std::string &name) + { + for (const AlgorithmFactoryBase *factory : factories()) { + if (factory->name() == name) + return factory->create(); + } + + return nullptr; + } + + static void registerAlgorithm(AlgorithmFactoryBase *factory) + { + factories().push_back(factory); + } + +private: + static std::vector *> &factories() + { + /* + * The static factories map is defined inside the function to ensure + * it gets initialized on first use, without any dependency on + * link order. + */ + static std::vector *> factories; + return factories; + } }; } /* namespace ipa */