From 6da18f76c0c6428262ec96437eb43d09672a5680 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 29 Aug 2009 16:13:42 +0200 Subject: [PATCH] re-read the code, some cleanup, define Tickets... --- src/proc/engine/nodefactory.cpp | 6 +- src/proc/engine/nodeoperation.hpp | 4 +- src/proc/engine/nodewiring-config.hpp | 181 ++++++++++++++++++++++ src/proc/engine/nodewiring.cpp | 2 +- src/proc/engine/nodewiringconfig.hpp | 183 ----------------------- src/proc/engine/procnode.hpp | 8 +- src/proc/mobject/builder/toolfactory.cpp | 122 +++++++-------- src/proc/mobject/builder/toolfactory.hpp | 71 +++++---- tests/lib/meta/config-flags-test.cpp | 4 +- tests/lib/meta/typelist-manip-test.cpp | 2 +- 10 files changed, 290 insertions(+), 293 deletions(-) create mode 100644 src/proc/engine/nodewiring-config.hpp delete mode 100644 src/proc/engine/nodewiringconfig.hpp diff --git a/src/proc/engine/nodefactory.cpp b/src/proc/engine/nodefactory.cpp index 628e247e2..580fd3a90 100644 --- a/src/proc/engine/nodefactory.cpp +++ b/src/proc/engine/nodefactory.cpp @@ -57,9 +57,9 @@ namespace engine { return *newNode; /* - * Problems to be solved: - * - write a generic allocator, which later on can be augmented to do block wise bulk allocation - * - the allocator needs to keep track of the objects; actually he owns the objects + * Problems to be solved: /////////////TODO: see Ticket #247 + * - write a generic allocator, which later on can be augmented to do block wise bulk allocation /////////////DONE: AllocationCluster + * - the allocator needs to keep track of the objects; actually he owns the objects /////////////DONE * - we need to access the wiring descriptor of the predecessor nodes. Which means, the code * must be in the body of NodeFactory (because the latter is friend of ProcNode and can access the wiring descriptor) * - btw reconsider if this level of protection is necessary, or if the const WiringDescriptor cant be just on the public interface of ProcNode diff --git a/src/proc/engine/nodeoperation.hpp b/src/proc/engine/nodeoperation.hpp index c7c973977..9ab36e93c 100644 --- a/src/proc/engine/nodeoperation.hpp +++ b/src/proc/engine/nodeoperation.hpp @@ -41,14 +41,14 @@ ** of elementary operations invoking each other (\c NEXT::step(invocation) ). Notably, all those possible ** configurations are pre-built while compiling (it's a small number below 32 configuration instance). ** To be able to select the Strategy for each configuration, we need a Factory (ConfigSelector defined in - ** nodewiringconfig.hpp). which is actually instantiated and used in nodewiring.cpp, which is the object + ** nodewiring-config.hpp). which is actually instantiated and used in nodewiring.cpp, which is the object ** file holding all those instantiations. ** ** @see engine::ProcNode ** @see engine::Invocation ** @see engine::State ** @see engine::NodeFactory - ** @see nodewiringconfig.hpp + ** @see nodewiring-config.hpp ** @see nodewiring.hpp interface for building/wiring the nodes ** */ diff --git a/src/proc/engine/nodewiring-config.hpp b/src/proc/engine/nodewiring-config.hpp new file mode 100644 index 000000000..981c1e177 --- /dev/null +++ b/src/proc/engine/nodewiring-config.hpp @@ -0,0 +1,181 @@ +/* + NODEWIRING-CONFIG.hpp - Helper for representing and selecting the wiring case + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + 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. + + 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. + +*/ + +/** @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 + ** + */ + + +#ifndef ENGINE_NODEWIRING_CONFIG_H +#define ENGINE_NODEWIRING_CONFIG_H + + +#include "lib/util.hpp" +#include "lib/meta/configflags.hpp" + +#include +#include +#include + + +namespace engine { +namespace config { + + using lumiera::typelist::FlagInfo; + using util::contains; + + using lumiera::typelist::CONFIG_FLAGS_MAX; + + + /** + * 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 Factory + , typename FUNC ///< common function type of all Factory instances + , typename PAR ///< ctor parameter of the Factories + > + class ConfigSelector + { + typedef std::tr1::function FacFunction; + + template + struct FactoryHolder ///< impl type erasure + : private FAC, + public FacFunction + { + FactoryHolder(PAR p) + : FAC(p), + FacFunction( static_cast(*this)) + { } + }; + + + typedef std::tr1::shared_ptr PFunc; + typedef std::map ConfigTable; + + ConfigTable possibleConfig_; ///< Table of factories + + /** Helper: a visitor usable with FlagInfo */ + struct FactoryTableBuilder + { + PAR ctor_param_; + ConfigTable& factories_; + + FactoryTableBuilder (ConfigTable& tab, PAR p) + : ctor_param_(p), + factories_(tab) { } + + + /* === visitation interface === */ + + typedef void Ret; + + template + void + visit (size_t code) + { + PFunc pFactory (new FactoryHolder > (ctor_param_)); + factories_[code] = pFactory; + } + + void done() {} + }; + + public: + template + 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::accept (buildTable); + } + + FacFunction& + operator[] (size_t configFlags) ///< retrieve the factory corresponding to the given config + { + if (contains (possibleConfig_, configFlags)) + return *possibleConfig_[configFlags]; + else + throw lumiera::error::Invalid("ConfigSelector: No preconfigured factory for config-bits=" + +std::bitset(configFlags).to_string()); + } + }; + + + +}} // namespace engine::config +#endif diff --git a/src/proc/engine/nodewiring.cpp b/src/proc/engine/nodewiring.cpp index ccb0824a3..7b827c9fc 100644 --- a/src/proc/engine/nodewiring.cpp +++ b/src/proc/engine/nodewiring.cpp @@ -24,7 +24,7 @@ #include "proc/engine/procnode.hpp" #include "proc/engine/nodewiring.hpp" #include "proc/engine/nodeoperation.hpp" -#include "proc/engine/nodewiringconfig.hpp" +#include "proc/engine/nodewiring-config.hpp" #include "lib/meta/typelist-util.hpp" diff --git a/src/proc/engine/nodewiringconfig.hpp b/src/proc/engine/nodewiringconfig.hpp deleted file mode 100644 index 65c2369c7..000000000 --- a/src/proc/engine/nodewiringconfig.hpp +++ /dev/null @@ -1,183 +0,0 @@ -/* - NODEWIRINGCONFIG.hpp - Helper for representing and selecting the wiring case - - Copyright (C) Lumiera.org - 2008, Hermann Vosseler - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - 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. - - 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. - -*/ - -/** @file nodewiringconfig.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 - ** - */ - - -#ifndef ENGINE_NODEWIRINGCONFIG_H -#define ENGINE_NODEWIRINGCONFIG_H - - -#include "lib/util.hpp" -#include "lib/meta/configflags.hpp" - -#include -#include -#include - - -namespace engine { - namespace config { - - using lumiera::typelist::FlagInfo; - using util::contains; - - using lumiera::typelist::CONFIG_FLAGS_MAX; - - - /** - * 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. - */ - template< template class Factory - , typename FUNC ///< common function type of all Factory instances - , typename PAR ///< ctor parameter of the Factories - > - class ConfigSelector - { - typedef std::tr1::function FacFunction; - - template - struct FactoryHolder ///< impl type erasure - : private FAC, - public FacFunction - { - FactoryHolder(PAR p) - : FAC(p), - FacFunction( static_cast(*this)) - { } - }; - - - typedef std::tr1::shared_ptr PFunc; - typedef std::map ConfigTable; - - ConfigTable possibleConfig_; ///< Table of factories - - /** Helper: a visitor usable with FlagInfo */ - struct FactoryTableBuilder - { - PAR ctor_param_; - ConfigTable& factories_; - - FactoryTableBuilder (ConfigTable& tab, PAR p) - : ctor_param_(p), - factories_(tab) { } - - - /* === visitation interface === */ - - typedef void Ret; - - template - void - visit (size_t code) - { - PFunc pFactory (new FactoryHolder > (ctor_param_)); - factories_[code] = pFactory; - } - - void done() {} - }; - - public: - template - 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::accept (buildTable); - } - - FacFunction& - operator[] (size_t configFlags) ///< retrieve the factory corresponding to the given config - { - if (contains (possibleConfig_, configFlags)) - return *possibleConfig_[configFlags]; - else - throw lumiera::error::Invalid("ConfigSelector: No preconfigured factory for config-bits=" - +std::bitset(configFlags).to_string()); - } - }; - - - - } // namespace config - -} // namespace engine -#endif diff --git a/src/proc/engine/procnode.hpp b/src/proc/engine/procnode.hpp index 392576c41..2d95bd7cb 100644 --- a/src/proc/engine/procnode.hpp +++ b/src/proc/engine/procnode.hpp @@ -31,7 +31,7 @@ ** ** By using the builder interface, concrete node and wiring descriptor classes are created, ** based on some templates. These concrete classes form the "glue" to tie the node network - ** together and contain much of the operation beahviour in a hard wired fashion. + ** together and contain much of the operation behaviour in a hard wired fashion. ** ** @see nodefactory.hpp ** @see operationpoint.hpp @@ -130,16 +130,16 @@ namespace engine { public: /** Engine Core operation: render and pull output from this node. - * On return, currentProcess will hold onto output buffer(s) + * On return, currentProcess will hold onto output buffer(s) * containing the calculated result frames. In case this node - * calculates a multichannel output, only one channel can be + * calculates a multichannel output, only one channel can be * retrieved by such a \c pull() call, but you can expect data * of the other channels to be processed and fed to cache. * @param currentProcess the current processing state for * managing buffers and accessing current parameter values * @param requestedOutputNr the output channel requested * (in case this node delivers more than one output channel) - * @return handle to the buffer containing the calculated result. + * @return handle to the buffer containing the calculated result. */ BuffHandle pull (State& currentProcess, uint requestedOutputNr=0) const diff --git a/src/proc/mobject/builder/toolfactory.cpp b/src/proc/mobject/builder/toolfactory.cpp index 79a305142..278580754 100644 --- a/src/proc/mobject/builder/toolfactory.cpp +++ b/src/proc/mobject/builder/toolfactory.cpp @@ -22,73 +22,73 @@ #include "proc/mobject/builder/toolfactory.hpp" -#include "common/util.hpp" +#include "lib/util.hpp" //#include namespace mobject { - namespace builder { - - using util::isnil; - - - struct BuildProcessState - { - - session::Fixture & fixedTimeline_; - std::auto_ptr procSegment_; - - boost::scoped_ptr segmentation_; - boost::scoped_ptr fabrication_; - - - BuildProcessState (session::Fixture& theTimeline) - : fixedTimeline_(theTimeline), - procSegment_(new engine::RenderGraph()) - { } - - }; - - ToolFactory::ToolFactory (session::Fixture& theTimeline) - : state_(new BuildProcessState (theTimeline)) +namespace builder { + + using util::isnil; + using std::auto_ptr; + using boost::scoped_ptr; + + + struct BuildProcessState { - ENSURE (state_->fixedTimeline_.isValid()); - ENSURE (state_->procSegment_); - } - - - SegmentationTool & - ToolFactory::configureSegmentation () - { - REQUIRE (state_->fixedTimeline_.isValid()); - REQUIRE (state_->procSegment_); - state->segmentation_.reset (new SegmentationTool (state->fixedTimeline_)); - return *(state->segmentation_); - } - - - NodeCreatorTool & - ToolFactory::configureFabrication () //////////////////////TODO: should iterate in some way! - { - REQUIRE (state_->procSegment_); - REQUIRE (!isnil (*(state_>segmentation))); + session::Fixture & fixedTimeline_; + auto_ptr procSegment_; - state->fabrication_.reset (new NodeCreatorTool(*this)); - return *(state->fabrication_); - } + scoped_ptr segmentation_; + scoped_ptr fabrication_; + + + BuildProcessState (session::Fixture& theTimeline) + : fixedTimeline_(theTimeline), + procSegment_(new engine::RenderGraph()) + { } + + }; + + ToolFactory::ToolFactory (session::Fixture& theTimeline) + : state_(new BuildProcessState (theTimeline)) + { + ENSURE (state_->fixedTimeline_.isValid()); + ENSURE (state_->procSegment_); + } + + + SegmentationTool & + ToolFactory::configureSegmentation () + { + REQUIRE (state_->fixedTimeline_.isValid()); + REQUIRE (state_->procSegment_); + state->segmentation_.reset (new SegmentationTool (state->fixedTimeline_)); + return *(state->segmentation_); + } + + + NodeCreatorTool & + ToolFactory::configureFabrication () //////////////////////TODO: should iterate in some way! + { + REQUIRE (state_->procSegment_); + REQUIRE (!isnil (*(state_>segmentation))); - std::auto_ptr - ToolFactory::getProduct () - { - state_->segmentation_.reset(0); - state_->fabrication_.reset(0); - return state_->procSegment_; - } - - - - } // namespace mobject::builder - -} // namespace mobject + state->fabrication_.reset (new NodeCreatorTool(*this)); + return *(state->fabrication_); + } + + + auto_ptr + ToolFactory::getProduct () + { + state_->segmentation_.reset(0); + state_->fabrication_.reset(0); + return state_->procSegment_; + } + + + +}} // namespace mobject::builder diff --git a/src/proc/mobject/builder/toolfactory.hpp b/src/proc/mobject/builder/toolfactory.hpp index aac40e827..b283bea60 100644 --- a/src/proc/mobject/builder/toolfactory.hpp +++ b/src/proc/mobject/builder/toolfactory.hpp @@ -31,44 +31,43 @@ #include "proc/engine/rendergraph.hpp" #include +#include namespace mobject { - namespace builder { - - struct BuildProcessState; - - - /** - * provides the builder with the necessary, preconfigured tools. - * Dedicated to a single build process, it holds the internal state - * of this process and thus serves to coordinate and link together all - * the individual parts fabricated by using the various tools. - */ - class ToolFactory - { - boost::scoped_ptr state_; - - public: - /** prepare a builder tool kit for dealing with the given Fixture, - * which is a snapshot of some timeline made explicit. */ - ToolFactory (session::Fixture&); - - /** prepare a tool for properly segmenting the Fixture */ - SegmentationTool & configureSegmentation (); - - /** prepare a tool for building the render engine (graph) for a single segment */ - NodeCreatorTool & configureFabrication (); - - /** receive the finished product of the build process; effectively - * releases any other builder tool object */ - std::auto_ptr getProduct (); - }; - - - - } // namespace mobject::builder - -} // namespace mobject +namespace builder { + + struct BuildProcessState; + + + /** + * provides the builder with the necessary, preconfigured tools. + * Dedicated to a single build process, it holds the internal state + * of this process and thus serves to coordinate and link together all + * the individual parts fabricated by using the various tools. + */ + class ToolFactory + { + boost::scoped_ptr state_; + + public: + /** prepare a builder tool kit for dealing with the given Fixture, + * which is a snapshot of some timeline made explicit. */ + ToolFactory (session::Fixture&); + + /** prepare a tool for properly segmenting the Fixture */ + SegmentationTool & configureSegmentation (); + + /** prepare a tool for building the render engine (graph) for a single segment */ + NodeCreatorTool & configureFabrication (); + + /** receive the finished product of the build process; effectively + * releases any other builder tool object */ + std::auto_ptr getProduct (); + }; + + + +}} // namespace mobject::builder #endif diff --git a/tests/lib/meta/config-flags-test.cpp b/tests/lib/meta/config-flags-test.cpp index fd1e085ed..1d11a244d 100644 --- a/tests/lib/meta/config-flags-test.cpp +++ b/tests/lib/meta/config-flags-test.cpp @@ -32,7 +32,7 @@ ** ** @see configflags.hpp ** @see typelistmanip.hpp - ** @see nodewiringconfig.hpp real world usage example + ** @see nodewiring-config.hpp real world usage example ** */ @@ -43,7 +43,7 @@ #include "lib/meta/typelist-util.hpp" #include "lib/meta/configflags.hpp" #include "meta/typelist-diagnostics.hpp" -#include "proc/engine/nodewiringconfig.hpp" +#include "proc/engine/nodewiring-config.hpp" #include "lib/util.hpp" #include diff --git a/tests/lib/meta/typelist-manip-test.cpp b/tests/lib/meta/typelist-manip-test.cpp index a7e37f18b..0f28ca961 100644 --- a/tests/lib/meta/typelist-manip-test.cpp +++ b/tests/lib/meta/typelist-manip-test.cpp @@ -33,7 +33,7 @@ ** ** @see typelist-test.cpp ** @see typelist-util.hpp - ** @see nodewiringconfig.hpp real world usage example + ** @see nodewiring-config.hpp real world usage example ** */