[libcamera-devel,8/8] libcamera: pipeline_handler: Implement factories through class templates
diff mbox series

Message ID 20221003212128.32429-9-laurent.pinchart@ideasonboard.com
State Accepted
Headers show
Series
  • libcamera: Use class templates for auto-registration
Related show

Commit Message

Laurent Pinchart Oct. 3, 2022, 9:21 p.m. UTC
The REGISTER_PIPELINE_HANDLER() macro defines a class type that inherits
from the PipelineHandlerFactory class, and implements a constructor and
a createInstance() function. Replace the code generation through macro
with the C++ equivalent, a class template, as done in libipa with the
Algorithm and CameraSensorHelper factories.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 include/libcamera/internal/pipeline_handler.h | 44 +++++++------
 src/libcamera/camera_manager.cpp              |  6 +-
 src/libcamera/pipeline_handler.cpp            | 65 ++++++++++++-------
 test/ipa/ipa_interface_test.cpp               |  6 +-
 4 files changed, 71 insertions(+), 50 deletions(-)

Comments

Xavier Roumegue Oct. 5, 2022, 11:17 a.m. UTC | #1
Hi Laurent,

Thanks for the patch.

On 10/3/22 23:21, Laurent Pinchart via libcamera-devel wrote:
> The REGISTER_PIPELINE_HANDLER() macro defines a class type that inherits
> from the PipelineHandlerFactory class, and implements a constructor and
> a createInstance() function. Replace the code generation through macro
> with the C++ equivalent, a class template, as done in libipa with the
> Algorithm and CameraSensorHelper factories.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>   include/libcamera/internal/pipeline_handler.h | 44 +++++++------
>   src/libcamera/camera_manager.cpp              |  6 +-
>   src/libcamera/pipeline_handler.cpp            | 65 ++++++++++++-------
>   test/ipa/ipa_interface_test.cpp               |  6 +-
>   4 files changed, 71 insertions(+), 50 deletions(-)
> 
> diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h
> index ad74dc823290..b6139a88d421 100644
> --- a/include/libcamera/internal/pipeline_handler.h
> +++ b/include/libcamera/internal/pipeline_handler.h
> @@ -95,23 +95,23 @@ private:
>   	Mutex lock_;
>   	unsigned int useCount_ LIBCAMERA_TSA_GUARDED_BY(lock_);
>   
> -	friend class PipelineHandlerFactory;
> +	friend class PipelineHandlerFactoryBase;
>   };
>   
> -class PipelineHandlerFactory
> +class PipelineHandlerFactoryBase
>   {
>   public:
> -	PipelineHandlerFactory(const char *name);
> -	virtual ~PipelineHandlerFactory() = default;
> +	PipelineHandlerFactoryBase(const char *name);
> +	virtual ~PipelineHandlerFactoryBase() = default;
>   
>   	std::shared_ptr<PipelineHandler> create(CameraManager *manager) const;
>   
>   	const std::string &name() const { return name_; }
>   
> -	static std::vector<PipelineHandlerFactory *> &factories();
> +	static std::vector<PipelineHandlerFactoryBase *> &factories();
>   
>   private:
> -	static void registerType(PipelineHandlerFactory *factory);
> +	static void registerType(PipelineHandlerFactoryBase *factory);
>   
>   	virtual std::unique_ptr<PipelineHandler>
>   	createInstance(CameraManager *manager) const = 0;
> @@ -119,19 +119,23 @@ private:
>   	std::string name_;
>   };
>   
> -#define REGISTER_PIPELINE_HANDLER(handler)				\
> -class handler##Factory final : public PipelineHandlerFactory		\
> -{									\
> -public:									\
> -	handler##Factory() : PipelineHandlerFactory(#handler) {}	\
> -									\
> -private:								\
> -	std::unique_ptr<PipelineHandler>				\
> -	createInstance(CameraManager *manager) const			\
> -	{								\
> -		return std::make_unique<handler>(manager);		\
> -	}								\
> -};									\
> -static handler##Factory global_##handler##Factory;
> +template<typename _PipelineHandler>
> +class PipelineHandlerFactory final : public PipelineHandlerFactoryBase
> +{
> +public:
> +	PipelineHandlerFactory(const char *name)
> +		: PipelineHandlerFactoryBase(name)
> +	{
> +	}
> +
> +	std::unique_ptr<PipelineHandler>
> +	createInstance(CameraManager *manager) const override
> +	{
> +		return std::make_unique<_PipelineHandler>(manager);
> +	}
> +};
> +
> +#define REGISTER_PIPELINE_HANDLER(handler) \
> +static PipelineHandlerFactory<handler> global_##handler##Factory(#handler);
>   
>   } /* namespace libcamera */
> diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp
> index 2c3f2d86c469..2c100c24af4d 100644
> --- a/src/libcamera/camera_manager.cpp
> +++ b/src/libcamera/camera_manager.cpp
> @@ -142,10 +142,10 @@ void CameraManager::Private::createPipelineHandlers()
>   	 * file and only fallback on all handlers if there is no
>   	 * configuration file.
>   	 */
> -	const std::vector<PipelineHandlerFactory *> &factories =
> -		PipelineHandlerFactory::factories();
> +	const std::vector<PipelineHandlerFactoryBase *> &factories =
> +		PipelineHandlerFactoryBase::factories();
>   
> -	for (const PipelineHandlerFactory *factory : factories) {
> +	for (const PipelineHandlerFactoryBase *factory : factories) {
>   		LOG(Camera, Debug)
>   			<< "Found registered pipeline handler '"
>   			<< factory->name() << "'";
> diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
> index 488dd8d32cdf..44f6fc531ad7 100644
> --- a/src/libcamera/pipeline_handler.cpp
> +++ b/src/libcamera/pipeline_handler.cpp
> @@ -64,8 +64,7 @@ LOG_DEFINE_CATEGORY(Pipeline)
>    *
>    * In order to honour the std::enable_shared_from_this<> contract,
>    * PipelineHandler instances shall never be constructed manually, but always
> - * through the PipelineHandlerFactory::create() function implemented by the
> - * respective factories.
> + * through the PipelineHandlerFactoryBase::create() function.
>    */
>   PipelineHandler::PipelineHandler(CameraManager *manager)
>   	: manager_(manager), useCount_(0)
> @@ -643,27 +642,25 @@ void PipelineHandler::disconnect()
>    */
>   
>   /**
> - * \class PipelineHandlerFactory
> - * \brief Registration of PipelineHandler classes and creation of instances
> + * \class PipelineHandlerFactoryBase
> + * \brief Base class for pipeline handler factories
>    *
> - * To facilitate discovery and instantiation of PipelineHandler classes, the
> - * PipelineHandlerFactory class maintains a registry of pipeline handler
> - * classes. Each PipelineHandler subclass shall register itself using the
> - * REGISTER_PIPELINE_HANDLER() macro, which will create a corresponding
> - * instance of a PipelineHandlerFactory subclass and register it with the
> - * static list of factories.
> + * The PipelineHandlerFactoryBase class is the base of all specializations of
> + * the PipelineHandlerFactory class template. It implements the factory
> + * registration, maintains a registry of factories, and provides access to the
> + * registered factories.
>    */
>   
>   /**
> - * \brief Construct a pipeline handler factory
> + * \brief Construct a pipeline handler factory base
>    * \param[in] name Name of the pipeline handler class
>    *
> - * Creating an instance of the factory registers is with the global list of
> + * Creating an instance of the factory base registers is with the global list of
s/is/it/
>    * factories, accessible through the factories() function.
>    *
>    * The factory \a name is used for debug purpose and shall be unique.
>    */
> -PipelineHandlerFactory::PipelineHandlerFactory(const char *name)
> +PipelineHandlerFactoryBase::PipelineHandlerFactoryBase(const char *name)
>   	: name_(name)
>   {
>   	registerType(this);
> @@ -676,7 +673,7 @@ PipelineHandlerFactory::PipelineHandlerFactory(const char *name)
>    * \return A shared pointer to a new instance of the PipelineHandler subclass
>    * corresponding to the factory
>    */
> -std::shared_ptr<PipelineHandler> PipelineHandlerFactory::create(CameraManager *manager) const
> +std::shared_ptr<PipelineHandler> PipelineHandlerFactoryBase::create(CameraManager *manager) const
>   {
>   	std::unique_ptr<PipelineHandler> handler = createInstance(manager);
>   	handler->name_ = name_.c_str();
> @@ -684,7 +681,7 @@ std::shared_ptr<PipelineHandler> PipelineHandlerFactory::create(CameraManager *m
>   }
>   
>   /**
> - * \fn PipelineHandlerFactory::name()
> + * \fn PipelineHandlerFactoryBase::name()
>    * \brief Retrieve the factory name
>    * \return The factory name
>    */
> @@ -696,9 +693,10 @@ std::shared_ptr<PipelineHandler> PipelineHandlerFactory::create(CameraManager *m
>    * The caller is responsible to guarantee the uniqueness of the pipeline handler
>    * name.
>    */
> -void PipelineHandlerFactory::registerType(PipelineHandlerFactory *factory)
> +void PipelineHandlerFactoryBase::registerType(PipelineHandlerFactoryBase *factory)
>   {
> -	std::vector<PipelineHandlerFactory *> &factories = PipelineHandlerFactory::factories();
> +	std::vector<PipelineHandlerFactoryBase *> &factories =
> +		PipelineHandlerFactoryBase::factories();
>   
>   	factories.push_back(factory);
>   }
> @@ -707,26 +705,45 @@ void PipelineHandlerFactory::registerType(PipelineHandlerFactory *factory)
>    * \brief Retrieve the list of all pipeline handler factories
>    * \return the list of pipeline handler factories
>    */
> -std::vector<PipelineHandlerFactory *> &PipelineHandlerFactory::factories()
> +std::vector<PipelineHandlerFactoryBase *> &PipelineHandlerFactoryBase::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<PipelineHandlerFactory *> factories;
> +	static std::vector<PipelineHandlerFactoryBase *> factories;
>   	return factories;
>   }
>   
> +/**
> + * \class PipelineHandlerFactory
> + * \brief Registration of PipelineHandler classes and creation of instances
> + * \tparam _PipelineHandler The pipeline handler class type for this factory
> + *
> + * To facilitate discovery and instantiation of PipelineHandler classes, the
> + * PipelineHandlerFactory class implements auto-registration of pipeline
> + * handlers. Each PipelineHandler subclass shall register itself using the
> + * REGISTER_PIPELINE_HANDLER() macro, which will create a corresponding
> + * instance of a PipelineHandlerFactory and register it with the static list of
> + * factories.
> + */
> +
> +/**
> + * \fn PipelineHandlerFactory::PipelineHandlerFactory(const char *name)
> + * \brief Construct a pipeline handler factory
> + * \param[in] name Name of the pipeline handler class
> + *
> + * Creating an instance of the factory registers is with the global list ofs/is/it/
> + * factories, accessible through the factories() function.
> + *
> + * The factory \a name is used for debug purpose and shall be unique.
> + */
> +
>   /**
>    * \fn PipelineHandlerFactory::createInstance() const
>    * \brief Create an instance of the PipelineHandler corresponding to the factory
>    * \param[in] manager The camera manager
> - *
> - * This virtual function is implemented by the REGISTER_PIPELINE_HANDLER()
> - * macro. It creates a pipeline handler instance associated with the camera
> - * \a manager.
> - *
>    * \return A unique pointer to a newly constructed instance of the
>    * PipelineHandler subclass corresponding to the factory
>    */
> diff --git a/test/ipa/ipa_interface_test.cpp b/test/ipa/ipa_interface_test.cpp
> index a629abc28da7..6b93e976a587 100644
> --- a/test/ipa/ipa_interface_test.cpp
> +++ b/test/ipa/ipa_interface_test.cpp
> @@ -52,9 +52,9 @@ protected:
>   		ipaManager_ = make_unique<IPAManager>();
>   
>   		/* Create a pipeline handler for vimc. */
> -		const std::vector<PipelineHandlerFactory *> &factories =
> -			PipelineHandlerFactory::factories();
> -		for (const PipelineHandlerFactory *factory : factories) {
> +		const std::vector<PipelineHandlerFactoryBase *> &factories =
> +			PipelineHandlerFactoryBase::factories();
> +		for (const PipelineHandlerFactoryBase *factory : factories) {
>   			if (factory->name() == "PipelineHandlerVimc") {
>   				pipe_ = factory->create(nullptr);
>   				break;

With the typos fixed:

Reviewed-by: Xavier Roumegue <xavier.roumegue@oss.nxp.com>
Jacopo Mondi Oct. 7, 2022, 2:34 p.m. UTC | #2
Hi Laurent

On Tue, Oct 04, 2022 at 12:21:28AM +0300, Laurent Pinchart via libcamera-devel wrote:
> The REGISTER_PIPELINE_HANDLER() macro defines a class type that inherits
> from the PipelineHandlerFactory class, and implements a constructor and
> a createInstance() function. Replace the code generation through macro
> with the C++ equivalent, a class template, as done in libipa with the
> Algorithm and CameraSensorHelper factories.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

I briefly tried to temaple PipelineHandlerFactoryBase directly, but
quickly gave up :)

Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>

Thanks
  j

> ---
>  include/libcamera/internal/pipeline_handler.h | 44 +++++++------
>  src/libcamera/camera_manager.cpp              |  6 +-
>  src/libcamera/pipeline_handler.cpp            | 65 ++++++++++++-------
>  test/ipa/ipa_interface_test.cpp               |  6 +-
>  4 files changed, 71 insertions(+), 50 deletions(-)
>
> diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h
> index ad74dc823290..b6139a88d421 100644
> --- a/include/libcamera/internal/pipeline_handler.h
> +++ b/include/libcamera/internal/pipeline_handler.h
> @@ -95,23 +95,23 @@ private:
>  	Mutex lock_;
>  	unsigned int useCount_ LIBCAMERA_TSA_GUARDED_BY(lock_);
>
> -	friend class PipelineHandlerFactory;
> +	friend class PipelineHandlerFactoryBase;
>  };
>
> -class PipelineHandlerFactory
> +class PipelineHandlerFactoryBase
>  {
>  public:
> -	PipelineHandlerFactory(const char *name);
> -	virtual ~PipelineHandlerFactory() = default;
> +	PipelineHandlerFactoryBase(const char *name);
> +	virtual ~PipelineHandlerFactoryBase() = default;
>
>  	std::shared_ptr<PipelineHandler> create(CameraManager *manager) const;
>
>  	const std::string &name() const { return name_; }
>
> -	static std::vector<PipelineHandlerFactory *> &factories();
> +	static std::vector<PipelineHandlerFactoryBase *> &factories();
>
>  private:
> -	static void registerType(PipelineHandlerFactory *factory);
> +	static void registerType(PipelineHandlerFactoryBase *factory);
>
>  	virtual std::unique_ptr<PipelineHandler>
>  	createInstance(CameraManager *manager) const = 0;
> @@ -119,19 +119,23 @@ private:
>  	std::string name_;
>  };
>
> -#define REGISTER_PIPELINE_HANDLER(handler)				\
> -class handler##Factory final : public PipelineHandlerFactory		\
> -{									\
> -public:									\
> -	handler##Factory() : PipelineHandlerFactory(#handler) {}	\
> -									\
> -private:								\
> -	std::unique_ptr<PipelineHandler>				\
> -	createInstance(CameraManager *manager) const			\
> -	{								\
> -		return std::make_unique<handler>(manager);		\
> -	}								\
> -};									\
> -static handler##Factory global_##handler##Factory;
> +template<typename _PipelineHandler>
> +class PipelineHandlerFactory final : public PipelineHandlerFactoryBase
> +{
> +public:
> +	PipelineHandlerFactory(const char *name)
> +		: PipelineHandlerFactoryBase(name)
> +	{
> +	}
> +
> +	std::unique_ptr<PipelineHandler>
> +	createInstance(CameraManager *manager) const override
> +	{
> +		return std::make_unique<_PipelineHandler>(manager);
> +	}
> +};
> +
> +#define REGISTER_PIPELINE_HANDLER(handler) \
> +static PipelineHandlerFactory<handler> global_##handler##Factory(#handler);
>
>  } /* namespace libcamera */
> diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp
> index 2c3f2d86c469..2c100c24af4d 100644
> --- a/src/libcamera/camera_manager.cpp
> +++ b/src/libcamera/camera_manager.cpp
> @@ -142,10 +142,10 @@ void CameraManager::Private::createPipelineHandlers()
>  	 * file and only fallback on all handlers if there is no
>  	 * configuration file.
>  	 */
> -	const std::vector<PipelineHandlerFactory *> &factories =
> -		PipelineHandlerFactory::factories();
> +	const std::vector<PipelineHandlerFactoryBase *> &factories =
> +		PipelineHandlerFactoryBase::factories();
>
> -	for (const PipelineHandlerFactory *factory : factories) {
> +	for (const PipelineHandlerFactoryBase *factory : factories) {
>  		LOG(Camera, Debug)
>  			<< "Found registered pipeline handler '"
>  			<< factory->name() << "'";
> diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
> index 488dd8d32cdf..44f6fc531ad7 100644
> --- a/src/libcamera/pipeline_handler.cpp
> +++ b/src/libcamera/pipeline_handler.cpp
> @@ -64,8 +64,7 @@ LOG_DEFINE_CATEGORY(Pipeline)
>   *
>   * In order to honour the std::enable_shared_from_this<> contract,
>   * PipelineHandler instances shall never be constructed manually, but always
> - * through the PipelineHandlerFactory::create() function implemented by the
> - * respective factories.
> + * through the PipelineHandlerFactoryBase::create() function.
>   */
>  PipelineHandler::PipelineHandler(CameraManager *manager)
>  	: manager_(manager), useCount_(0)
> @@ -643,27 +642,25 @@ void PipelineHandler::disconnect()
>   */
>
>  /**
> - * \class PipelineHandlerFactory
> - * \brief Registration of PipelineHandler classes and creation of instances
> + * \class PipelineHandlerFactoryBase
> + * \brief Base class for pipeline handler factories
>   *
> - * To facilitate discovery and instantiation of PipelineHandler classes, the
> - * PipelineHandlerFactory class maintains a registry of pipeline handler
> - * classes. Each PipelineHandler subclass shall register itself using the
> - * REGISTER_PIPELINE_HANDLER() macro, which will create a corresponding
> - * instance of a PipelineHandlerFactory subclass and register it with the
> - * static list of factories.
> + * The PipelineHandlerFactoryBase class is the base of all specializations of
> + * the PipelineHandlerFactory class template. It implements the factory
> + * registration, maintains a registry of factories, and provides access to the
> + * registered factories.
>   */
>
>  /**
> - * \brief Construct a pipeline handler factory
> + * \brief Construct a pipeline handler factory base
>   * \param[in] name Name of the pipeline handler class
>   *
> - * Creating an instance of the factory registers is with the global list of
> + * Creating an instance of the factory base registers is with the global list of
>   * factories, accessible through the factories() function.
>   *
>   * The factory \a name is used for debug purpose and shall be unique.
>   */
> -PipelineHandlerFactory::PipelineHandlerFactory(const char *name)
> +PipelineHandlerFactoryBase::PipelineHandlerFactoryBase(const char *name)
>  	: name_(name)
>  {
>  	registerType(this);
> @@ -676,7 +673,7 @@ PipelineHandlerFactory::PipelineHandlerFactory(const char *name)
>   * \return A shared pointer to a new instance of the PipelineHandler subclass
>   * corresponding to the factory
>   */
> -std::shared_ptr<PipelineHandler> PipelineHandlerFactory::create(CameraManager *manager) const
> +std::shared_ptr<PipelineHandler> PipelineHandlerFactoryBase::create(CameraManager *manager) const
>  {
>  	std::unique_ptr<PipelineHandler> handler = createInstance(manager);
>  	handler->name_ = name_.c_str();
> @@ -684,7 +681,7 @@ std::shared_ptr<PipelineHandler> PipelineHandlerFactory::create(CameraManager *m
>  }
>
>  /**
> - * \fn PipelineHandlerFactory::name()
> + * \fn PipelineHandlerFactoryBase::name()
>   * \brief Retrieve the factory name
>   * \return The factory name
>   */
> @@ -696,9 +693,10 @@ std::shared_ptr<PipelineHandler> PipelineHandlerFactory::create(CameraManager *m
>   * The caller is responsible to guarantee the uniqueness of the pipeline handler
>   * name.
>   */
> -void PipelineHandlerFactory::registerType(PipelineHandlerFactory *factory)
> +void PipelineHandlerFactoryBase::registerType(PipelineHandlerFactoryBase *factory)
>  {
> -	std::vector<PipelineHandlerFactory *> &factories = PipelineHandlerFactory::factories();
> +	std::vector<PipelineHandlerFactoryBase *> &factories =
> +		PipelineHandlerFactoryBase::factories();
>
>  	factories.push_back(factory);
>  }
> @@ -707,26 +705,45 @@ void PipelineHandlerFactory::registerType(PipelineHandlerFactory *factory)
>   * \brief Retrieve the list of all pipeline handler factories
>   * \return the list of pipeline handler factories
>   */
> -std::vector<PipelineHandlerFactory *> &PipelineHandlerFactory::factories()
> +std::vector<PipelineHandlerFactoryBase *> &PipelineHandlerFactoryBase::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<PipelineHandlerFactory *> factories;
> +	static std::vector<PipelineHandlerFactoryBase *> factories;
>  	return factories;
>  }
>
> +/**
> + * \class PipelineHandlerFactory
> + * \brief Registration of PipelineHandler classes and creation of instances
> + * \tparam _PipelineHandler The pipeline handler class type for this factory
> + *
> + * To facilitate discovery and instantiation of PipelineHandler classes, the
> + * PipelineHandlerFactory class implements auto-registration of pipeline
> + * handlers. Each PipelineHandler subclass shall register itself using the
> + * REGISTER_PIPELINE_HANDLER() macro, which will create a corresponding
> + * instance of a PipelineHandlerFactory and register it with the static list of
> + * factories.
> + */
> +
> +/**
> + * \fn PipelineHandlerFactory::PipelineHandlerFactory(const char *name)
> + * \brief Construct a pipeline handler factory
> + * \param[in] name Name of the pipeline handler class
> + *
> + * Creating an instance of the factory registers is with the global list of
> + * factories, accessible through the factories() function.
> + *
> + * The factory \a name is used for debug purpose and shall be unique.
> + */
> +
>  /**
>   * \fn PipelineHandlerFactory::createInstance() const
>   * \brief Create an instance of the PipelineHandler corresponding to the factory
>   * \param[in] manager The camera manager
> - *
> - * This virtual function is implemented by the REGISTER_PIPELINE_HANDLER()
> - * macro. It creates a pipeline handler instance associated with the camera
> - * \a manager.
> - *
>   * \return A unique pointer to a newly constructed instance of the
>   * PipelineHandler subclass corresponding to the factory
>   */
> diff --git a/test/ipa/ipa_interface_test.cpp b/test/ipa/ipa_interface_test.cpp
> index a629abc28da7..6b93e976a587 100644
> --- a/test/ipa/ipa_interface_test.cpp
> +++ b/test/ipa/ipa_interface_test.cpp
> @@ -52,9 +52,9 @@ protected:
>  		ipaManager_ = make_unique<IPAManager>();
>
>  		/* Create a pipeline handler for vimc. */
> -		const std::vector<PipelineHandlerFactory *> &factories =
> -			PipelineHandlerFactory::factories();
> -		for (const PipelineHandlerFactory *factory : factories) {
> +		const std::vector<PipelineHandlerFactoryBase *> &factories =
> +			PipelineHandlerFactoryBase::factories();
> +		for (const PipelineHandlerFactoryBase *factory : factories) {
>  			if (factory->name() == "PipelineHandlerVimc") {
>  				pipe_ = factory->create(nullptr);
>  				break;
> --
> Regards,
>
> Laurent Pinchart
>

Patch
diff mbox series

diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h
index ad74dc823290..b6139a88d421 100644
--- a/include/libcamera/internal/pipeline_handler.h
+++ b/include/libcamera/internal/pipeline_handler.h
@@ -95,23 +95,23 @@  private:
 	Mutex lock_;
 	unsigned int useCount_ LIBCAMERA_TSA_GUARDED_BY(lock_);
 
-	friend class PipelineHandlerFactory;
+	friend class PipelineHandlerFactoryBase;
 };
 
-class PipelineHandlerFactory
+class PipelineHandlerFactoryBase
 {
 public:
-	PipelineHandlerFactory(const char *name);
-	virtual ~PipelineHandlerFactory() = default;
+	PipelineHandlerFactoryBase(const char *name);
+	virtual ~PipelineHandlerFactoryBase() = default;
 
 	std::shared_ptr<PipelineHandler> create(CameraManager *manager) const;
 
 	const std::string &name() const { return name_; }
 
-	static std::vector<PipelineHandlerFactory *> &factories();
+	static std::vector<PipelineHandlerFactoryBase *> &factories();
 
 private:
-	static void registerType(PipelineHandlerFactory *factory);
+	static void registerType(PipelineHandlerFactoryBase *factory);
 
 	virtual std::unique_ptr<PipelineHandler>
 	createInstance(CameraManager *manager) const = 0;
@@ -119,19 +119,23 @@  private:
 	std::string name_;
 };
 
-#define REGISTER_PIPELINE_HANDLER(handler)				\
-class handler##Factory final : public PipelineHandlerFactory		\
-{									\
-public:									\
-	handler##Factory() : PipelineHandlerFactory(#handler) {}	\
-									\
-private:								\
-	std::unique_ptr<PipelineHandler>				\
-	createInstance(CameraManager *manager) const			\
-	{								\
-		return std::make_unique<handler>(manager);		\
-	}								\
-};									\
-static handler##Factory global_##handler##Factory;
+template<typename _PipelineHandler>
+class PipelineHandlerFactory final : public PipelineHandlerFactoryBase
+{
+public:
+	PipelineHandlerFactory(const char *name)
+		: PipelineHandlerFactoryBase(name)
+	{
+	}
+
+	std::unique_ptr<PipelineHandler>
+	createInstance(CameraManager *manager) const override
+	{
+		return std::make_unique<_PipelineHandler>(manager);
+	}
+};
+
+#define REGISTER_PIPELINE_HANDLER(handler) \
+static PipelineHandlerFactory<handler> global_##handler##Factory(#handler);
 
 } /* namespace libcamera */
diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp
index 2c3f2d86c469..2c100c24af4d 100644
--- a/src/libcamera/camera_manager.cpp
+++ b/src/libcamera/camera_manager.cpp
@@ -142,10 +142,10 @@  void CameraManager::Private::createPipelineHandlers()
 	 * file and only fallback on all handlers if there is no
 	 * configuration file.
 	 */
-	const std::vector<PipelineHandlerFactory *> &factories =
-		PipelineHandlerFactory::factories();
+	const std::vector<PipelineHandlerFactoryBase *> &factories =
+		PipelineHandlerFactoryBase::factories();
 
-	for (const PipelineHandlerFactory *factory : factories) {
+	for (const PipelineHandlerFactoryBase *factory : factories) {
 		LOG(Camera, Debug)
 			<< "Found registered pipeline handler '"
 			<< factory->name() << "'";
diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
index 488dd8d32cdf..44f6fc531ad7 100644
--- a/src/libcamera/pipeline_handler.cpp
+++ b/src/libcamera/pipeline_handler.cpp
@@ -64,8 +64,7 @@  LOG_DEFINE_CATEGORY(Pipeline)
  *
  * In order to honour the std::enable_shared_from_this<> contract,
  * PipelineHandler instances shall never be constructed manually, but always
- * through the PipelineHandlerFactory::create() function implemented by the
- * respective factories.
+ * through the PipelineHandlerFactoryBase::create() function.
  */
 PipelineHandler::PipelineHandler(CameraManager *manager)
 	: manager_(manager), useCount_(0)
@@ -643,27 +642,25 @@  void PipelineHandler::disconnect()
  */
 
 /**
- * \class PipelineHandlerFactory
- * \brief Registration of PipelineHandler classes and creation of instances
+ * \class PipelineHandlerFactoryBase
+ * \brief Base class for pipeline handler factories
  *
- * To facilitate discovery and instantiation of PipelineHandler classes, the
- * PipelineHandlerFactory class maintains a registry of pipeline handler
- * classes. Each PipelineHandler subclass shall register itself using the
- * REGISTER_PIPELINE_HANDLER() macro, which will create a corresponding
- * instance of a PipelineHandlerFactory subclass and register it with the
- * static list of factories.
+ * The PipelineHandlerFactoryBase class is the base of all specializations of
+ * the PipelineHandlerFactory class template. It implements the factory
+ * registration, maintains a registry of factories, and provides access to the
+ * registered factories.
  */
 
 /**
- * \brief Construct a pipeline handler factory
+ * \brief Construct a pipeline handler factory base
  * \param[in] name Name of the pipeline handler class
  *
- * Creating an instance of the factory registers is with the global list of
+ * Creating an instance of the factory base registers is with the global list of
  * factories, accessible through the factories() function.
  *
  * The factory \a name is used for debug purpose and shall be unique.
  */
-PipelineHandlerFactory::PipelineHandlerFactory(const char *name)
+PipelineHandlerFactoryBase::PipelineHandlerFactoryBase(const char *name)
 	: name_(name)
 {
 	registerType(this);
@@ -676,7 +673,7 @@  PipelineHandlerFactory::PipelineHandlerFactory(const char *name)
  * \return A shared pointer to a new instance of the PipelineHandler subclass
  * corresponding to the factory
  */
-std::shared_ptr<PipelineHandler> PipelineHandlerFactory::create(CameraManager *manager) const
+std::shared_ptr<PipelineHandler> PipelineHandlerFactoryBase::create(CameraManager *manager) const
 {
 	std::unique_ptr<PipelineHandler> handler = createInstance(manager);
 	handler->name_ = name_.c_str();
@@ -684,7 +681,7 @@  std::shared_ptr<PipelineHandler> PipelineHandlerFactory::create(CameraManager *m
 }
 
 /**
- * \fn PipelineHandlerFactory::name()
+ * \fn PipelineHandlerFactoryBase::name()
  * \brief Retrieve the factory name
  * \return The factory name
  */
@@ -696,9 +693,10 @@  std::shared_ptr<PipelineHandler> PipelineHandlerFactory::create(CameraManager *m
  * The caller is responsible to guarantee the uniqueness of the pipeline handler
  * name.
  */
-void PipelineHandlerFactory::registerType(PipelineHandlerFactory *factory)
+void PipelineHandlerFactoryBase::registerType(PipelineHandlerFactoryBase *factory)
 {
-	std::vector<PipelineHandlerFactory *> &factories = PipelineHandlerFactory::factories();
+	std::vector<PipelineHandlerFactoryBase *> &factories =
+		PipelineHandlerFactoryBase::factories();
 
 	factories.push_back(factory);
 }
@@ -707,26 +705,45 @@  void PipelineHandlerFactory::registerType(PipelineHandlerFactory *factory)
  * \brief Retrieve the list of all pipeline handler factories
  * \return the list of pipeline handler factories
  */
-std::vector<PipelineHandlerFactory *> &PipelineHandlerFactory::factories()
+std::vector<PipelineHandlerFactoryBase *> &PipelineHandlerFactoryBase::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<PipelineHandlerFactory *> factories;
+	static std::vector<PipelineHandlerFactoryBase *> factories;
 	return factories;
 }
 
+/**
+ * \class PipelineHandlerFactory
+ * \brief Registration of PipelineHandler classes and creation of instances
+ * \tparam _PipelineHandler The pipeline handler class type for this factory
+ *
+ * To facilitate discovery and instantiation of PipelineHandler classes, the
+ * PipelineHandlerFactory class implements auto-registration of pipeline
+ * handlers. Each PipelineHandler subclass shall register itself using the
+ * REGISTER_PIPELINE_HANDLER() macro, which will create a corresponding
+ * instance of a PipelineHandlerFactory and register it with the static list of
+ * factories.
+ */
+
+/**
+ * \fn PipelineHandlerFactory::PipelineHandlerFactory(const char *name)
+ * \brief Construct a pipeline handler factory
+ * \param[in] name Name of the pipeline handler class
+ *
+ * Creating an instance of the factory registers is with the global list of
+ * factories, accessible through the factories() function.
+ *
+ * The factory \a name is used for debug purpose and shall be unique.
+ */
+
 /**
  * \fn PipelineHandlerFactory::createInstance() const
  * \brief Create an instance of the PipelineHandler corresponding to the factory
  * \param[in] manager The camera manager
- *
- * This virtual function is implemented by the REGISTER_PIPELINE_HANDLER()
- * macro. It creates a pipeline handler instance associated with the camera
- * \a manager.
- *
  * \return A unique pointer to a newly constructed instance of the
  * PipelineHandler subclass corresponding to the factory
  */
diff --git a/test/ipa/ipa_interface_test.cpp b/test/ipa/ipa_interface_test.cpp
index a629abc28da7..6b93e976a587 100644
--- a/test/ipa/ipa_interface_test.cpp
+++ b/test/ipa/ipa_interface_test.cpp
@@ -52,9 +52,9 @@  protected:
 		ipaManager_ = make_unique<IPAManager>();
 
 		/* Create a pipeline handler for vimc. */
-		const std::vector<PipelineHandlerFactory *> &factories =
-			PipelineHandlerFactory::factories();
-		for (const PipelineHandlerFactory *factory : factories) {
+		const std::vector<PipelineHandlerFactoryBase *> &factories =
+			PipelineHandlerFactoryBase::factories();
+		for (const PipelineHandlerFactoryBase *factory : factories) {
 			if (factory->name() == "PipelineHandlerVimc") {
 				pipe_ = factory->create(nullptr);
 				break;