diff --git a/src/proc/engine/buffhandle.hpp b/src/proc/engine/buffhandle.hpp index 60ca7758d..51ce1c135 100644 --- a/src/proc/engine/buffhandle.hpp +++ b/src/proc/engine/buffhandle.hpp @@ -84,6 +84,21 @@ namespace engine { }; + class ProcNode; + typedef ProcNode* PNode; + + + struct ChannelDescriptor ///////TODO collapse this with BufferDescriptor? + { + BufferDescriptor bufferType; + }; + + struct InChanDescriptor : ChannelDescriptor + { + PNode dataSrc; ///< the ProcNode to pull this input from + uint srcChannel; ///< output channel to use on the predecessor node + }; + } // namespace engine #endif diff --git a/src/proc/engine/nodeinvocation.hpp b/src/proc/engine/nodeinvocation.hpp new file mode 100644 index 000000000..2b5c0afbb --- /dev/null +++ b/src/proc/engine/nodeinvocation.hpp @@ -0,0 +1,216 @@ +/* + NODEINVOCATION.hpp - Organize the invocation state within a single pull() call + + 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 nodeinvocation.hpp + ** Organize the state related to the invocation of s single ProcNode::pull() call + ** This header defines part of the "glue" which holds together the render node network + ** and enables to pull a result frames from the nodes. Doing so requires some invocation + ** local state tobe maintained, especially a table of buffers used to carry out the + ** calculations. Further, getting the input buffers filled requires to issue recursive + ** \c pull() calls, which on the whole creates a stack-like assembly of local invocation + ** state. + ** The actual steps to be carried out for a \c pull() call are dependant on the configuration + ** of the node to pull. Each node has been preconfigured by the builder with a WiringDescriptor + ** and a concrete type of a StateAdapter. The actual sequence of steps is defined in the header + ** nodeoperation.hpp out of a set of basic operation steps. These steps all use the passed in + ** Invocation object (a sub-interface of StateAdapter) to access the various aspects of the + ** invocation state. + ** + ** \par composition of the Invocation State + ** For each individual ProcNode#pull() call, the WiringAdapter#callDown() builds an StateAdapter + ** instance directly on the stack, holding the actual buffer pointers and state references. Using this + ** StateAdapter, the predecessor nodes are pulled. The way these operations are carried out is encoded + ** in the actual StateAdapter type known to the NodeWiring (WiringAdapter) instance. All of these actual + ** StateAdapter types are built as implementing the engine::State interface. + ** + ** @see engine::ProcNode + ** @see engine::StateProxy + ** @see engine::BuffTable + ** @see nodewiring.hpp interface for building/wiring the nodes + ** + */ + +#ifndef ENGINE_NODEINVOCATION_H +#define ENGINE_NODEINVOCATION_H + + +#include "proc/state.hpp" +#include "proc/engine/procnode.hpp" +#include "proc/engine/buffhandle.hpp" +#include "proc/engine/bufftable.hpp" + + + + +namespace engine { + + + /** + * Adapter to shield the ProcNode from the actual buffer management, + * allowing the processing function within ProcNode to use logical + * buffer IDs. StateAdapter is created on the stack for each pull() + * call, using setup/wiring data preconfigured by the builder. + * Its job is to provide the actual implementation of the Cache + * push / fetch and recursive downcall to render the source frames. + */ + class StateAdapter + : public State + { + protected: + State& parent_; + State& current_; + + StateAdapter (State& callingProcess) + : parent_ (callingProcess), + current_(callingProcess.getCurrentImplementation()) + { } + + virtual State& getCurrentImplementation () { return current_; } + + + + public: /* === proxying the State interface === */ + + virtual void releaseBuffer (BuffHandle& bh) { current_.releaseBuffer (bh); } + + virtual void is_calculated (BuffHandle const& bh) { current_.is_calculated (bh); } + + virtual BuffHandle fetch (FrameID const& fID) { return current_.fetch (fID); } + + // note: allocateBuffer() is choosen specifically based on the actual node wiring + + }; + + + + + + /** + * Invocation context state. + * A ref to this type is carried through the chain of NEXT::step() functions + * which form the actual invocation sequence. The various operations in this sequence + * access the context via the references in this struct, while also using the inherited + * public State interface. The object instance actually used as Invocation is created + * on the stack and parametrized according to the necessities of the invocation sequence + * actually configured. Initially, this real instance is configured without BuffTable, + * because the invocation may be short-circuited due to Cache hit. Otherwise, when + * the invocation sequence actually prepares to call the process function of this + * ProcNode, a buffer table chunk is allocated by the StateProxy and wired in. + */ + struct Invocation + : StateAdapter + { + WiringDescriptor const& wiring; + const uint outNr; + + BuffTable* buffTab; + + protected: + /** creates a new invocation context state, without BuffTable */ + Invocation (State& callingProcess, WiringDescriptor const& w, uint o) + : StateAdapter(callingProcess), + wiring(w), outNr(o), + buffTab(0) + { } + + const uint nrO() const { return wiring.getNrO(); } + const uint nrI() const { return wiring.getNrI(); } + const uint buffTabSize() const { return nrO()+nrI(); } + + /** setup the link to an externally allocated buffer table */ + void setBuffTab (BuffTable* b) { this->buffTab = b; } + + bool + buffTab_isConsistent () + { + return (buffTab) + && (0 < buffTabSize()) + && (nrO()+nrI() <= buffTabSize()) + && (buffTab->inBuff == &buffTab->outBuff[nrO()] ) + && (buffTab->inHandle == &buffTab->outHandle[nrO()]) + ; + } + + + }; + + + struct AllocBufferFromParent ///< using the parent StateAdapter for buffer allocations + : Invocation + { + AllocBufferFromParent (State& sta, WiringDescriptor const& w, const uint outCh) + : Invocation(sta, w, outCh) {} + + virtual BuffHandle + allocateBuffer (BufferDescriptor const& bd) { return parent_.allocateBuffer(bd); } + }; + + struct AllocBufferFromCache ///< using the global current State, which will delegate to Cache + : Invocation + { + AllocBufferFromCache (State& sta, WiringDescriptor const& w, const uint outCh) + : Invocation(sta, w, outCh) {} + + virtual BuffHandle + allocateBuffer (BufferDescriptor const& bd) { return current_.allocateBuffer(bd); } + }; + + + /** + * The real invocation context state implementation. It is created + * by the NodeWiring (WiringDescriptor) of the processing node which + * is pulled by this invocation, hereby using the internal configuration + * information to guide the selecton of the real call sequence + * + * \par assembling the call sequence implementation + * Each ProcNode#pull() call creates such a StateAdapter subclass on the stack, + * with a concrete type according to the WiringDescriptor of the node to pull. + * This concrete type encodes a calculation Strategy, which is assembled + * as a chain of policy templates on top of OperationBase. For each of the + * possible configuratons we define such a chain (see bottom of nodeoperation.hpp). + * The WiringFactory defined in nodewiring.cpp actually drives the instantiation + * of all those possible combinations. + */ + template + class ActualInvocationProcess + : public BufferProvider + { + public: + ActualInvocationProcess (State& callingProcess, WiringDescriptor const& w, const uint outCh) + : Invocation(callingProcess, w, outCh) + { } + + /** contains the details of Cache query and recursive calls + * to the predecessor node(s), eventually followed by the + * ProcNode::process() callback + */ + BuffHandle retrieve () + { + return Strategy::step (*this); + } + }; + + + + +} // namespace engine +#endif diff --git a/src/proc/engine/nodeoperation.hpp b/src/proc/engine/nodeoperation.hpp index c52c48618..144050d39 100644 --- a/src/proc/engine/nodeoperation.hpp +++ b/src/proc/engine/nodeoperation.hpp @@ -22,28 +22,33 @@ /** @file nodeoperation.hpp ** Chunks of operation for invoking the rendernodes. - ** This header defines the "glue" which holds together the render node network + ** This header defines part of the "glue" which holds together the render node network ** and enables to pull a result frames from the nodes. Especially, the aspect of - ** buffer management is covered here. Each node has been preconfigured by the builder - ** with a WiringDescriptor and a concrete type of a StateAdapter. These concrete - ** StateAdapter objects are assembled out of the building blocks defined in this header, - ** depending on the desired mode of operation. Any node can be built to + ** buffer management and cache query is covered here. Each node has been preconfigured by + ** the builder with a WiringDescriptor and a concrete type of a StateAdapter, including + ** a specific Configuration, because the node can be built to ** - participate in the Caching or ignore the cache ** - actually process a result or just pull frames from a source ** - employ in-Place calculations or use separate in/out buffers ** Additionally, each node may have a given number of input/output pins, expecting to ** be provided with buffers holding a specific kind of data. ** - ** \par composition of the StateAdapter - ** For each individual ProcNode#pull() call, the WiringAdapter#callDown() builds an StateAdapter - ** instance directly on the stack, holding the actual buffer pointers and state references. Using this + ** \par composition of the invocation Strategy + ** For each individual ProcNode#pull() call, the WiringAdapter#callDown() builds an Invocation state + ** instance directly on the stack, holding references to the actual buffer pointers and state. Using this ** StateAdapter, the predecessor nodes are pulled. The way these operations are carried out is encoded - ** in the actual StateAdapter type known to the NodeWiring (WiringAdapter) instance. All of these actual - ** StateAdapter types are built as implementing the engine::State interface, on top of the InvocationStateBase - ** and inheriting from a chain of strategy classes (single inheritance, mostly \em no virtual functions). + ** in the actual type of Strategy, which is defined at the bottom of this header. Each Strategy is a chain + ** of elementary operations invoking each other (\c NEXT::step(invocation) ). Notably, all those possible + ** configurations are pre-build 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). which is actually instantiated and used in nodewiring.cpp, which is the object + ** file holding all those instantiations. ** ** @see engine::ProcNode - ** @see engine::StateProxy + ** @see engine::Invocation + ** @see engine::State + ** @see engine::NodeFactory + ** @see nodewiringconfig.hpp ** @see nodewiring.hpp interface for building/wiring the nodes ** */ @@ -56,8 +61,8 @@ #include "proc/engine/procnode.hpp" #include "proc/engine/buffhandle.hpp" #include "proc/engine/bufftable.hpp" +#include "proc/engine/nodeinvocation.hpp" #include "proc/engine/nodewiringconfig.hpp" -#include "lib/appconfig.hpp" @@ -65,154 +70,6 @@ namespace engine { - /** - * Adapter to shield the ProcNode from the actual buffer management, - * allowing the processing function within ProcNode to use logical - * buffer IDs. StateAdapter is created on the stack for each pull() - * call, using setup/wiring data preconfigured by the builder. - * Its job is to provide the actual implementation of the Cache - * push / fetch and recursive downcall to render the source frames. - */ - class StateAdapter - : public State - { - protected: - State& parent_; - State& current_; - - StateAdapter (State& callingProcess) - : parent_ (callingProcess), - current_(callingProcess.getCurrentImplementation()) - { } - - virtual State& getCurrentImplementation () { return current_; } - - - - public: /* === proxying the State interface === */ - - virtual void releaseBuffer (BuffHandle& bh) { current_.releaseBuffer (bh); } - - virtual void is_calculated (BuffHandle const& bh) { current_.is_calculated (bh); } - - virtual BuffHandle fetch (FrameID const& fID) { return current_.fetch (fID); } - - // note: allocateBuffer() is choosen specifically based on the actual node wiring - - }; - - - - - - /** - * Invocation context state. - * A ref to this type is carried through the chain of NEXT::step() functions - * which form the actual invocation sequence. The various operations in this sequence - * access the context via the references in this struct, while also using the inherited - * public State interface. The object instance actually used as Invocation is created - * on the stack and parametrized according to the necessities of the invocation sequence - * actually configured. Initially, this real instance is configured without BuffTable, - * because the invocation may be short-circuited due to Cache hit. Otherwise, when - * the invocation sequence actually prepares to call the process function of this - * ProcNode, a buffer table chunk is allocated by the StateProxy and wired in. - */ - struct Invocation - : StateAdapter - { - WiringDescriptor const& wiring; - const uint outNr; - - BuffTable* buffTab; - - protected: - /** creates a new invocation context state, without BuffTable */ - Invocation (State& callingProcess, WiringDescriptor const& w, uint o) - : StateAdapter(callingProcess), - wiring(w), outNr(o), - buffTab(0) - { } - - const uint nrO() const { return wiring.getNrO(); } - const uint nrI() const { return wiring.getNrI(); } - const uint buffTabSize() const { return nrO()+nrI(); } - - /** setup the link to an externally allocated buffer table */ - void setBuffTab (BuffTable* b) { this->buffTab = b; } - - bool - buffTab_isConsistent () - { - return (buffTab) - && (0 < buffTabSize()) - && (nrO()+nrI() <= buffTabSize()) - && (buffTab->inBuff == &buffTab->outBuff[nrO()] ) - && (buffTab->inHandle == &buffTab->outHandle[nrO()]) - ; - } - - - }; - - - struct AllocBufferFromParent ///< using the parent StateAdapter for buffer allocations - : Invocation - { - AllocBufferFromParent (State& sta, WiringDescriptor const& w, const uint outCh) - : Invocation(sta, w, outCh) {} - - virtual BuffHandle - allocateBuffer (BufferDescriptor const& bd) { return parent_.allocateBuffer(bd); } - }; - - struct AllocBufferFromCache ///< using the global current State, which will delegate to Cache - : Invocation - { - AllocBufferFromCache (State& sta, WiringDescriptor const& w, const uint outCh) - : Invocation(sta, w, outCh) {} - - virtual BuffHandle - allocateBuffer (BufferDescriptor const& bd) { return current_.allocateBuffer(bd); } - }; - - - /** - * The real invocation context state implementation. It is created - * by the NodeWiring (WiringDescriptor) of the processing node which - * is pulled by this invocation, hereby using the internal configuration - * information to guide the selecton of the real call sequence - * - * \par assembling the call sequence implementation - * Each ProcNode#pull() call creates such a StateAdapter subclass on the stack, - * with a concrete type according to the WiringDescriptor of the node to pull. - * This concrete type encodes a calculation Strategy, which is assembled - * as a chain of policy templates on top of OperationBase. For each of the - * possible configuratons we define such a chain (see bottom of nodeoperation.hpp). - * The WiringFactory defined in nodewiring.cpp actually drives the instantiation - * of all those possible combinations. - */ - template - class ActualInvocationProcess - : public BufferProvider - { - public: - ActualInvocationProcess (State& callingProcess, WiringDescriptor const& w, const uint outCh) - : Invocation(callingProcess, w, outCh) - { } - - /** contains the details of Cache query and recursive calls - * to the predecessor node(s), eventually followed by the - * ProcNode::process() callback - */ - BuffHandle retrieve () - { - return Strategy::step (*this); - } - }; - - - - /** * Collection of functions used to build up the invocation sequence. */ @@ -311,7 +168,7 @@ namespace engine { for (uint i = 0; i < ivo.nrO(); ++i ) { outBuff[i] = - *(outH[i] = ivo.allocateBuffer (ivo.wiring.out[i].bufferType); + *(outH[i] = ivo.allocateBuffer (ivo.wiring.out[i].bufferType)); // now Output buffer for channel #i is available... } return NEXT::step (ivo); @@ -343,9 +200,11 @@ namespace engine { BuffHandle step (Invocation& ivo) { - // declare all Outputs as finished - ivo.is_calculated(ivo.buffTab->outHandle, - ivo.nrO()); + for (uint i = 0; i < ivo.nrO(); ++i ) + { + // declare all Outputs as finished + ivo.is_calculated(ivo.buffTab->outHandle[i]); + } return NEXT::step (ivo); } diff --git a/src/proc/engine/nodewiring.cpp b/src/proc/engine/nodewiring.cpp index 023253a0e..a9cafa1a8 100644 --- a/src/proc/engine/nodewiring.cpp +++ b/src/proc/engine/nodewiring.cpp @@ -46,7 +46,8 @@ namespace engine { { UNIMPLEMENTED ("build the actual wiring descriptor based on given operation options"); - return selectConfig(cache, process, inplace).fabricate(); +// Bits config (FlagInfo::CODE); +// return selector(config); } // BlockAlloc > > >::fabricate(); diff --git a/src/proc/engine/procnode.hpp b/src/proc/engine/procnode.hpp index 2d5af1a3a..74fa86254 100644 --- a/src/proc/engine/procnode.hpp +++ b/src/proc/engine/procnode.hpp @@ -60,6 +60,12 @@ namespace engine { typedef ProcNode* PNode; + template + struct RefArray + { + virtual E const& operator[] (uint i) const =0; + virtual ~RefArray() {} + }; /** * Interface: Description of the input and output ports, @@ -73,6 +79,13 @@ namespace engine { virtual uint getNrI() const =0; ///////////TODO: indeed need a virtual function?? virtual uint getNrO() const =0; + RefArray& out; + RefArray& in; + + typedef void (ProcFunc) (BuffHandle::PBuff, uint); + + ProcFunc* processFunction; + protected: /** the wiring-dependent part of the node operation. * Includes the creation of a one-way state object on the stack