2009-08-29 16:13:42 +02:00
|
|
|
/*
|
|
|
|
|
NODEWIRING-CONFIG.hpp - Helper for representing and selecting the wiring case
|
2010-12-17 23:28:49 +01:00
|
|
|
|
2009-08-29 16:13:42 +02:00
|
|
|
Copyright (C) Lumiera.org
|
|
|
|
|
2008, Hermann Vosseler <Ichthyostega@web.de>
|
2010-12-17 23:28:49 +01:00
|
|
|
|
2009-08-29 16:13:42 +02:00
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU General Public License as
|
2010-12-17 23:28:49 +01:00
|
|
|
published by the Free Software Foundation; either version 2 of
|
|
|
|
|
the License, or (at your option) any later version.
|
|
|
|
|
|
2009-08-29 16:13:42 +02:00
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
2010-12-17 23:28:49 +01:00
|
|
|
|
2009-08-29 16:13:42 +02:00
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
2010-12-17 23:28:49 +01:00
|
|
|
|
2009-08-29 16:13:42 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/** @file nodewiring-config.hpp
|
|
|
|
|
** Sometimes we need to choose a different implementation for dealing with
|
|
|
|
|
** some special cases. While for simple cases, just testing a flag or using a
|
|
|
|
|
** switch statement will do the job, matters get more difficult when we have to
|
|
|
|
|
** employ a completely different execution path for each of the different cases,
|
|
|
|
|
** while using a set of common building blocks.
|
|
|
|
|
** \par
|
|
|
|
|
** In the Lumiera render engine, right on the critical path, we need some glue code
|
|
|
|
|
** for invoking the predecessor nodes when pulling a given processing node. The actual
|
|
|
|
|
** sequence is quite dependent on the specific situation each node is wired up, regarding
|
|
|
|
|
** buffer allocation, cache querying and the possible support for GPU processing and
|
|
|
|
|
** render farms. The solution is to define specialisations of a Strategy template
|
|
|
|
|
** using the specific configuration as template argument. Based on these, we can
|
|
|
|
|
** create a collection of factories, which in turn will build the internal wiring
|
|
|
|
|
** for the individual ProcNode instances in accordance to the situation determined
|
|
|
|
|
** for this node, expressed as a set of flags. As a net result, each node has an
|
|
|
|
|
** individual configuration (as opposed to creating a lot of hand-written individual
|
|
|
|
|
** ProcNode subclasses), but parts of this configuration assembly is done already at
|
|
|
|
|
** compile time, allowing for additional checks by typing and for possible optimisation.
|
|
|
|
|
**
|
|
|
|
|
** @see proc::engine::config::Strategy
|
|
|
|
|
** @see nodewiring.hpp
|
|
|
|
|
** @see configflags.hpp
|
2009-09-05 04:10:51 +02:00
|
|
|
** @see config-flags-test.cpp
|
2009-08-29 16:13:42 +02:00
|
|
|
**
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef ENGINE_NODEWIRING_CONFIG_H
|
|
|
|
|
#define ENGINE_NODEWIRING_CONFIG_H
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "lib/meta/configflags.hpp"
|
2011-12-02 17:50:44 +01:00
|
|
|
#include "lib/util.hpp"
|
2009-08-29 16:13:42 +02:00
|
|
|
|
2014-04-03 22:42:48 +02:00
|
|
|
#include <functional>
|
2009-08-29 16:13:42 +02:00
|
|
|
#include <bitset>
|
|
|
|
|
#include <map>
|
|
|
|
|
|
|
|
|
|
|
2011-12-02 16:10:03 +01:00
|
|
|
namespace proc {
|
2009-08-29 16:13:42 +02:00
|
|
|
namespace engine {
|
|
|
|
|
namespace config {
|
|
|
|
|
|
|
|
|
|
using util::contains;
|
2011-12-03 02:56:50 +01:00
|
|
|
using lib::meta::FlagInfo;
|
2009-08-29 16:13:42 +02:00
|
|
|
|
2011-12-03 02:56:50 +01:00
|
|
|
using lib::meta::CONFIG_FLAGS_MAX;
|
2009-08-29 16:13:42 +02:00
|
|
|
|
2011-12-02 17:50:44 +01:00
|
|
|
typedef size_t IxID; ///////////////////////////////TICKET #863
|
|
|
|
|
|
2009-08-29 16:13:42 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Helper for fabricating ProcNode Wiring configurations.
|
|
|
|
|
* This object builds a table of factories, holding one factory
|
|
|
|
|
* for each possible node configuration. Provided with the desired
|
|
|
|
|
* configuration encoded as bits, the related factory can be invoked,
|
|
|
|
|
* thus producing a product object for the given configuration.
|
|
|
|
|
*
|
|
|
|
|
* \par implementation notes
|
|
|
|
|
* The actual factory class is templated, so it will be defined
|
|
|
|
|
* at the use site of ConfigSelector. Moreover, this factory
|
|
|
|
|
* usually expects an ctor argument, which will be fed through
|
|
|
|
|
* when creating the ConfigSelector instance. This is one of
|
|
|
|
|
* the reasons why we go through all these complicated factory
|
|
|
|
|
* building: this ctor argument usually brings in a reference
|
|
|
|
|
* to the actual memory allocator. Thus we have to rebuild the
|
|
|
|
|
* ConfigSelector each time we switch and rebuild the ProcNode
|
|
|
|
|
* factories, which in turn happens each time we use a new
|
|
|
|
|
* bulk allocation memory block -- typically for each separate
|
|
|
|
|
* segment of the Timeline and processing node graph.
|
|
|
|
|
*
|
|
|
|
|
* Now the selection of the possible flag configurations, for which
|
|
|
|
|
* Factory instances are created in the table, is governed by the
|
|
|
|
|
* type parameter of the ConfigSelector ctor. This type parameter
|
|
|
|
|
* needs to be a Typelist of Typelists, each representing a flag
|
|
|
|
|
* configuration. The intention is to to drive this selection by
|
|
|
|
|
* the use of template metaprogramming for extracting all
|
|
|
|
|
* currently defined StateProxy object configurations.
|
|
|
|
|
* @todo as the factories live only within the enclosed table (map)
|
|
|
|
|
* we could allocate them in-place. Unfortunately this is
|
|
|
|
|
* non-trivial, because the STL containers employ
|
|
|
|
|
* value semantics and thus do a copy even on insert.
|
|
|
|
|
* Thus, for now we use a shared_ptr to hold the factory
|
|
|
|
|
* heap allocated. ---> see Ticket #248
|
|
|
|
|
*/
|
|
|
|
|
template< template<class CONF> class Factory
|
|
|
|
|
, typename FUNC ///< common function type of all Factory instances
|
|
|
|
|
, typename PAR ///< ctor parameter of the Factories
|
|
|
|
|
>
|
|
|
|
|
class ConfigSelector
|
|
|
|
|
{
|
2014-04-03 22:42:48 +02:00
|
|
|
typedef std::function<FUNC> FacFunction;
|
2009-08-29 16:13:42 +02:00
|
|
|
|
|
|
|
|
template<class FAC>
|
|
|
|
|
struct FactoryHolder ///< impl type erasure
|
|
|
|
|
: private FAC,
|
|
|
|
|
public FacFunction
|
|
|
|
|
{
|
|
|
|
|
FactoryHolder(PAR p)
|
|
|
|
|
: FAC(p),
|
2009-08-30 14:11:14 +02:00
|
|
|
FacFunction (static_cast<FAC&> (*this))
|
2009-08-29 16:13:42 +02:00
|
|
|
{ }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2014-04-03 22:42:48 +02:00
|
|
|
typedef std::shared_ptr<FacFunction> PFunc;
|
2011-12-02 17:50:44 +01:00
|
|
|
typedef std::map<IxID, PFunc> ConfigTable;
|
2009-08-29 16:13:42 +02:00
|
|
|
|
|
|
|
|
ConfigTable possibleConfig_; ///< Table of factories
|
|
|
|
|
|
2009-08-30 14:11:14 +02:00
|
|
|
|
|
|
|
|
/** Helper: a visitor usable with FlagInfo.
|
|
|
|
|
* Used to create a factory for each config */
|
2009-08-29 16:13:42 +02:00
|
|
|
struct FactoryTableBuilder
|
|
|
|
|
{
|
|
|
|
|
PAR ctor_param_;
|
|
|
|
|
ConfigTable& factories_;
|
|
|
|
|
|
|
|
|
|
FactoryTableBuilder (ConfigTable& tab, PAR p)
|
|
|
|
|
: ctor_param_(p),
|
|
|
|
|
factories_(tab) { }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* === visitation interface === */
|
|
|
|
|
|
|
|
|
|
typedef void Ret;
|
|
|
|
|
|
|
|
|
|
template<class CONF>
|
|
|
|
|
void
|
2011-12-02 17:50:44 +01:00
|
|
|
visit (IxID code)
|
2009-08-29 16:13:42 +02:00
|
|
|
{
|
|
|
|
|
PFunc pFactory (new FactoryHolder<Factory<CONF> > (ctor_param_));
|
|
|
|
|
factories_[code] = pFactory;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void done() {}
|
|
|
|
|
};
|
|
|
|
|
|
2009-08-30 14:11:14 +02:00
|
|
|
|
2009-08-29 16:13:42 +02:00
|
|
|
public:
|
|
|
|
|
template<class CONFS>
|
|
|
|
|
ConfigSelector(CONFS const&, PAR factory_ctor_param)
|
|
|
|
|
{
|
|
|
|
|
FactoryTableBuilder buildTable(this->possibleConfig_,
|
|
|
|
|
factory_ctor_param );
|
|
|
|
|
// store a new Factory instance
|
|
|
|
|
// for each possible Flag-Configuration
|
|
|
|
|
FlagInfo<CONFS>::accept (buildTable);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FacFunction&
|
2011-12-02 17:50:44 +01:00
|
|
|
operator[] (IxID configFlags) ///< retrieve the factory corresponding to the given config
|
2009-08-29 16:13:42 +02:00
|
|
|
{
|
|
|
|
|
if (contains (possibleConfig_, configFlags))
|
|
|
|
|
return *possibleConfig_[configFlags];
|
|
|
|
|
else
|
|
|
|
|
throw lumiera::error::Invalid("ConfigSelector: No preconfigured factory for config-bits="
|
|
|
|
|
+std::bitset<CONFIG_FLAGS_MAX>(configFlags).to_string());
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-12-02 17:50:44 +01:00
|
|
|
}}} // namespace proc::engine::config
|
2009-08-29 16:13:42 +02:00
|
|
|
#endif
|