From 17dcb7495fb0349e505af1d84a0a188cbf229586 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 21 Jun 2024 16:14:24 +0200 Subject: [PATCH] Invocation: establish a concept for the rework As outlined in #1367, the integration effort requires some rework of existing code, which will be driven ahead by the `NodeLinkage_test` * redefine Node Connectivity * build simple `ProcNode` directly in scope * create an `TurnoutSystem` instance * perform a ''dummy Node-Invocation'' --- .../{nodefactory.cpp => node-factory.cpp} | 5 +- .../{nodefactory.hpp => node-factory.hpp} | 11 +- src/steam/engine/node-wiring-builder.hpp | 8 +- src/steam/engine/nodeinvocation.hpp | 20 +- src/steam/engine/nodeoperation.hpp | 2 +- src/steam/engine/nodewiring.hpp | 2 +- src/steam/engine/proc-node.hpp | 33 +- src/steam/engine/render-invocation.cpp | 2 + src/steam/engine/rendergraph.cpp | 2 +- src/steam/engine/rendergraph.hpp | 2 +- src/steam/engine/state-closure-obsolete.hpp | 122 ++++++ src/steam/engine/state-closure.hpp | 5 +- src/steam/engine/turnout-system.hpp | 10 +- src/steam/engine/turnout.hpp | 257 +++++++++++ src/steam/mobject/builder/operationpoint.cpp | 2 +- .../core/steam/engine/feed-manifold-test.cpp | 2 +- tests/core/steam/engine/node-basic-test.cpp | 4 +- wiki/renderengine.html | 4 +- wiki/thinkPad.ichthyo.mm | 399 +++++++++++++++++- 19 files changed, 831 insertions(+), 61 deletions(-) rename src/steam/engine/{nodefactory.cpp => node-factory.cpp} (93%) rename src/steam/engine/{nodefactory.hpp => node-factory.hpp} (88%) create mode 100644 src/steam/engine/state-closure-obsolete.hpp create mode 100644 src/steam/engine/turnout.hpp diff --git a/src/steam/engine/nodefactory.cpp b/src/steam/engine/node-factory.cpp similarity index 93% rename from src/steam/engine/nodefactory.cpp rename to src/steam/engine/node-factory.cpp index 2ce8f476d..a5e053814 100644 --- a/src/steam/engine/nodefactory.cpp +++ b/src/steam/engine/node-factory.cpp @@ -21,16 +21,17 @@ * *****************************************************/ -/** @file nodefactory.cpp +/** @file node-factory.cpp ** Implementation of render node setup and wiring ** @todo draft from the early days of the Lumiera project, reworked in 2009 ** Development activity in that area as stalled ever since. In the end, ** it is highly likely we'll _indeed need_ a node factory though... + ** @todo WIP-WIP 2024 to be reworked from ground up for the »Playback Vertical Slice« */ #include "steam/engine/exit-node.hpp" -#include "steam/engine/nodefactory.hpp" +#include "steam/engine/node-factory.hpp" #include "steam/mobject/session/effect.hpp" #include "lib/allocation-cluster.hpp" diff --git a/src/steam/engine/nodefactory.hpp b/src/steam/engine/node-factory.hpp similarity index 88% rename from src/steam/engine/nodefactory.hpp rename to src/steam/engine/node-factory.hpp index 25191a86e..71d8561fc 100644 --- a/src/steam/engine/nodefactory.hpp +++ b/src/steam/engine/node-factory.hpp @@ -1,5 +1,5 @@ /* - NODEFACTORY.hpp - Service for creating processing nodes of various kinds + NODE-FACTORY.hpp - Service for creating processing nodes of various kinds Copyright (C) Lumiera.org 2008, Hermann Vosseler @@ -21,16 +21,17 @@ */ -/** @file nodefactory.hpp +/** @file node-factory.hpp ** A factory to build processing nodes ** @todo draft from the early days of the Lumiera project, reworked in 2009 ** Development activity in that area as stalled ever since. In the end, ** it is highly likely we'll _indeed need_ a node factory though... + ** @todo about to be reworked for the »Playback Vertical Slice« in 2024 */ -#ifndef ENGINE_NODEFACTORY_H -#define ENGINE_NODEFACTORY_H +#ifndef STEAM_ENGINE_NODE_FACTORY_H +#define STEAM_ENGINE_NODE_FACTORY_H #include "steam/engine/proc-node.hpp" #include "steam/mobject/placement.hpp" @@ -85,4 +86,4 @@ namespace engine { }; }} // namespace steam::engine -#endif +#endif /*STEAM_ENGINE_NODE_FACTORY_H*/ diff --git a/src/steam/engine/node-wiring-builder.hpp b/src/steam/engine/node-wiring-builder.hpp index 04e9056aa..d81f3e128 100644 --- a/src/steam/engine/node-wiring-builder.hpp +++ b/src/steam/engine/node-wiring-builder.hpp @@ -20,7 +20,7 @@ */ -/** @file nodewiring-def.hpp +/** @file node-wiring-builder.hpp ** Helper for defining the desired wiring and operation mode for a render node. ** During the Builder run, the render nodes network is wired up starting from the ** source (generating) nodes up to the exit nodes. As the wiring is implemented through @@ -29,6 +29,8 @@ ** the desired operation mode of this node need to be available. Thus we use this temporary ** information record to assemble all these pieces of information. ** + ** @deprecated WIP-WIP-WIP 2024 Node-Invocation is reworked from ground up -- not clear yet what happens with the builder + ** ** @see steam::engine::NodeFactory ** @see nodewiring.hpp ** @see node-basic-test.cpp @@ -66,7 +68,9 @@ namespace engine { * Thus, we start with one or several existing nodes, specifying which * output should go to which input pin of the yet-to-be created new node. * When intending to create a source node, a default WiringSituation - * should be used, without adding any connection information. + * should be used, without adding any connection information. + * + * @deprecated WIP-WIP-WIP 2024 Node-Invocation is reworked from ground up for the »Playback Vertical Slice« */ class WiringSituation : util::NonCopyable diff --git a/src/steam/engine/nodeinvocation.hpp b/src/steam/engine/nodeinvocation.hpp index 9fedede95..6d62d1560 100644 --- a/src/steam/engine/nodeinvocation.hpp +++ b/src/steam/engine/nodeinvocation.hpp @@ -56,7 +56,7 @@ #include "steam/engine/proc-node.hpp" -#include "steam/engine/state-closure.hpp" +#include "steam/engine/state-closure-obsolete.hpp" #include "steam/engine/channel-descriptor.hpp" #include "steam/engine/feed-manifold.hpp" @@ -76,18 +76,18 @@ namespace engine { * push / fetch and recursive downcall to render the source frames. */ class StateAdapter - : public StateClosure + : public StateClosure_OBSOLETE { protected: - StateClosure& parent_; - StateClosure& current_; + StateClosure_OBSOLETE& parent_; + StateClosure_OBSOLETE& current_; - StateAdapter (StateClosure& callingProcess) + StateAdapter (StateClosure_OBSOLETE& callingProcess) : parent_ (callingProcess), current_(callingProcess.getCurrentImplementation()) { } - virtual StateClosure& getCurrentImplementation () { return current_; } + virtual StateClosure_OBSOLETE& getCurrentImplementation () { return current_; } @@ -131,7 +131,7 @@ namespace engine { protected: /** creates a new invocation context state, without FeedManifold */ - Invocation (StateClosure& callingProcess, Connectivity const& w, uint o) + Invocation (StateClosure_OBSOLETE& callingProcess, Connectivity const& w, uint o) : StateAdapter(callingProcess), wiring(w), outNr(o), feedManifold(0) @@ -179,7 +179,7 @@ namespace engine { struct AllocBufferFromParent ///< using the parent StateAdapter for buffer allocations : Invocation { - AllocBufferFromParent (StateClosure& sta, Connectivity const& w, const uint outCh) + AllocBufferFromParent (StateClosure_OBSOLETE& sta, Connectivity const& w, const uint outCh) : Invocation(sta, w, outCh) {} virtual BuffHandle @@ -189,7 +189,7 @@ namespace engine { struct AllocBufferFromCache ///< using the global current StateClosure, which will delegate to Cache : Invocation { - AllocBufferFromCache (StateClosure& sta, Connectivity const& w, const uint outCh) + AllocBufferFromCache (StateClosure_OBSOLETE& sta, Connectivity const& w, const uint outCh) : Invocation(sta, w, outCh) {} virtual BuffHandle @@ -218,7 +218,7 @@ namespace engine { , private Strategy { public: - ActualInvocationProcess (StateClosure& callingProcess, Connectivity const& w, const uint outCh) + ActualInvocationProcess (StateClosure_OBSOLETE& callingProcess, Connectivity const& w, const uint outCh) : BufferProvider(callingProcess, w, outCh) { } diff --git a/src/steam/engine/nodeoperation.hpp b/src/steam/engine/nodeoperation.hpp index c119ab6bd..0ab1b1a21 100644 --- a/src/steam/engine/nodeoperation.hpp +++ b/src/steam/engine/nodeoperation.hpp @@ -58,7 +58,7 @@ #include "steam/engine/proc-node.hpp" -#include "steam/engine/state-closure.hpp" +#include "steam/engine/state-closure-obsolete.hpp" #include "steam/engine/channel-descriptor.hpp" #include "steam/engine/nodeinvocation.hpp" #include "steam/engine/feed-manifold.hpp" diff --git a/src/steam/engine/nodewiring.hpp b/src/steam/engine/nodewiring.hpp index b2109e5c0..856aa4d97 100644 --- a/src/steam/engine/nodewiring.hpp +++ b/src/steam/engine/nodewiring.hpp @@ -76,7 +76,7 @@ namespace engine { private: virtual BuffHandle - callDown (StateClosure& currentProcess, uint requestedOutputNr) const + callDown (StateClosure_OBSOLETE& currentProcess, uint requestedOutputNr) const { STATE thisStep (currentProcess, *this, requestedOutputNr); return thisStep.retrieve (); // fetch or calculate results diff --git a/src/steam/engine/proc-node.hpp b/src/steam/engine/proc-node.hpp index 40df64026..db14ba6ad 100644 --- a/src/steam/engine/proc-node.hpp +++ b/src/steam/engine/proc-node.hpp @@ -32,19 +32,21 @@ ** 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 behaviour in a hard wired fashion. - ** + ** + ** @todo WIP-WIP-WIP 2024 Node-Invocation is reworked from ground up for the »Playback Vertical Slice« + ** ** @see nodefactory.hpp ** @see operationpoint.hpp */ -#ifndef ENGINE_PROC_NODE_H -#define ENGINE_PROC_NODE_H +#ifndef STEAM_ENGINE_PROC_NODE_H +#define STEAM_ENGINE_PROC_NODE_H #include "lib/error.hpp" #include "steam/common.hpp" #include "steam/asset/proc.hpp" #include "steam/mobject/parameter.hpp" -#include "steam/engine/state-closure.hpp" +#include "steam/engine/state-closure-obsolete.hpp" /////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation #include "steam/engine/channel-descriptor.hpp" #include "lib/frameid.hpp" #include "lib/ref-array.hpp" @@ -59,8 +61,10 @@ namespace engine { using std::vector; using lumiera::NodeID; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation class ProcNode; typedef ProcNode* PNode; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation /** @@ -73,10 +77,13 @@ namespace engine { * starting from the player. Anyhow, you can expect the basic setup to remain as-is: there will * be a ProcNode and a Connectivity descriptor, telling how it's connected to its predecessors, * and defining how the Node is supposed to operate + * + * @todo WIP-WIP-WIP 2024 Node-Invocation is reworked from ground up for the »Playback Vertical Slice« */ class Connectivity { public: /* === public information record describing the node graph === */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation uint nrO; uint nrI; @@ -90,8 +97,10 @@ namespace engine { NodeID const& nodeID; virtual ~Connectivity() {} +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation protected: +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation Connectivity (lib::RefArray& o, lib::RefArray& i, ProcFunc pFunc, NodeID const& nID) @@ -102,8 +111,10 @@ namespace engine { nrO = out.size(); nrI = in.size(); } +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation /* ==== strategy API for configuring the node operation ==== */ friend class ProcNode; /////////////////////////////////TODO 1/12 : wouldn't it be better to extract that API into a distinct strategy? @@ -114,7 +125,8 @@ namespace engine { * @see NodeWiring#callDown default implementation */ virtual BuffHandle - callDown (StateClosure& currentProcess, uint requiredOutputNr) const =0; + callDown (StateClosure_OBSOLETE& currentProcess, uint requiredOutputNr) const =0; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation }; @@ -130,6 +142,7 @@ namespace engine { * The alternative would be to push down these information-retrieval part into a * configurable element within Connectivity, in which case we even might drop * ProcNode as a frontend entirely. + * @todo WIP-WIP-WIP 2024 Node-Invocation is reworked from ground up for the »Playback Vertical Slice« */ class ProcNode : util::NonCopyable @@ -140,18 +153,22 @@ namespace engine { const Connectivity& wiringConfig_; public: +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation ProcNode (Connectivity const& wd) : wiringConfig_(wd) { } virtual ~ProcNode() {}; /////////////////////////TODO: do we still intend to build a hierarchy below ProcNode??? +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation public: +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation bool isValid() const; /** output channel count */ uint nrO() { return wiringConfig_.nrO; } +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation /** Engine Core operation: render and pull output from this node. @@ -167,14 +184,16 @@ namespace engine { * @return handle to the buffer containing the calculated result. */ BuffHandle - pull (StateClosure& currentProcess, uint requestedOutputNr=0) const + pull (StateClosure_OBSOLETE& currentProcess, uint requestedOutputNr=0) const { return this->wiringConfig_.callDown (currentProcess, requestedOutputNr); } +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation }; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation inline bool ProcNode::isValid() const { @@ -184,4 +203,4 @@ namespace engine { }} // namespace steam::engine -#endif /*ENGINE_PROC_NODE_H*/ +#endif /*STEAM_ENGINE_PROC_NODE_H*/ diff --git a/src/steam/engine/render-invocation.cpp b/src/steam/engine/render-invocation.cpp index 038007b0b..e8abf6731 100644 --- a/src/steam/engine/render-invocation.cpp +++ b/src/steam/engine/render-invocation.cpp @@ -59,7 +59,9 @@ namespace engine { REQUIRE (channel < size()); StateProxy invocationState; +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1367 : Rebuild the Node Invocation return theNode_->pull(invocationState, channel); +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1367 : Rebuild the Node Invocation } diff --git a/src/steam/engine/rendergraph.cpp b/src/steam/engine/rendergraph.cpp index 831fb6e05..2fc9697db 100644 --- a/src/steam/engine/rendergraph.cpp +++ b/src/steam/engine/rendergraph.cpp @@ -27,7 +27,7 @@ #include "steam/engine/rendergraph.hpp" -#include "steam/engine/state-closure.hpp" +#include "steam/engine/state-closure-obsolete.hpp" #include "lib/frameid.hpp" namespace lumiera { diff --git a/src/steam/engine/rendergraph.hpp b/src/steam/engine/rendergraph.hpp index 6b1e7706d..a3fe83bd5 100644 --- a/src/steam/engine/rendergraph.hpp +++ b/src/steam/engine/rendergraph.hpp @@ -30,7 +30,7 @@ #define STEAM_ENGINE_RENDERGRAPH_H #include "steam/common.hpp" -#include "steam/engine/state-closure.hpp" +#include "steam/engine/state-closure-obsolete.hpp" #include "lib/time/timevalue.hpp" diff --git a/src/steam/engine/state-closure-obsolete.hpp b/src/steam/engine/state-closure-obsolete.hpp new file mode 100644 index 000000000..59263e4cc --- /dev/null +++ b/src/steam/engine/state-closure-obsolete.hpp @@ -0,0 +1,122 @@ +/* + STATE-CLOSURE.hpp - Key Interface representing a render process and encapsulating state + + 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 state-closure.hpp + ** Access point to an ongoing render's processing state. + ** + ** @deprecated 2024 Node-Invocation is reworked from ground up for the »Playback Vertical Slice« + */ + + +#ifndef STEAM_ENGINE_STATE_CLOSURE_OBSOLETE_H +#define STEAM_ENGINE_STATE_CLOSURE_OBSOLETE_H + + +#include "lib/error.hpp" +#include "lib/frameid.hpp" +#include "steam/engine/buffhandle.hpp" + +#include + + +namespace steam { +namespace engine { + + using lumiera::FrameID; + using lumiera::NodeID; + + class StateAdapter; + class BuffTableStorage; + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation + /** + * Abstraction to access the state of a currently ongoing render/calculation process, + * as it is tied to the supporting facilities of the vault layer. An StateClosure (subclass) instance + * is the sole connection for the render node to invoke services of the vault needed + * to carry out the calculations. + * + * @see engine::RenderInvocation top-level entrance point + * @see nodeinvocation.hpp impl. used from \em within the nodes + */ + class StateClosure_OBSOLETE + { + ////////////////////////////////////////////////TICKET #826 expected to be reworked to quite some extent (9/2011) + public: + /** allocate a new writable buffer with type and size according to + * the BufferDescriptor. The actual provider of this buffer depends + * on the StateClosure implementation; it could be a temporary, located in + * the cache, used for feeding calculated frames over a network, etc. + * @return a BuffHandle encapsulating the information necessary to get + * at the actual buffer address and for releasing the buffer. + */ + virtual BuffHandle allocateBuffer (const lumiera::StreamType*) =0; + + /** resign control of the buffer denoted by the handle */ + virtual void releaseBuffer (BuffHandle&) =0; + + /** declare the data contained in the Buffer to be ready. + * The caller is required to restrain itself from modifying the data + * afterwards, as this buffer now can be used (readonly) by other + * calculation processes in parallel. + */ + virtual void is_calculated (BuffHandle const&) =0; + + /** generate (or calculate) an ID denoting a media data frame + * appearing at the given position in the render network, + * for the time point this rendering process is currently + * calculating data for. + * @param NodeID the unique identification of a specific node + * @param chanNo the number of the output channel of this node + * @return a complete FrameID which unambiguously denotes this + * specific frame and can be used for caching + */ + virtual FrameID const& genFrameID (NodeID const&, uint chanNo) =0; + + /** try to fetch an existing buffer containing the denoted frame + * from a cache or similar backing system (e.g. network peer). + * @return either a handle to a readonly buffer, or a null handle + * @note the client is responsible for not modifying the provided data + */ + virtual BuffHandle fetch (FrameID const&) =0; + + /** necessary for creating a local BuffTableChunk */ + virtual BuffTableStorage& getBuffTableStorage() =0; + + + protected: + virtual ~StateClosure_OBSOLETE() {}; + + /** resolves to the StateClosure object currently "in charge". + * Intended as a performance shortcut to avoid calling + * up through a chain of virtual functions when deep down + * in chained ProcNode::pull() calls. This allows derived + * classes to proxy the state interface. + */ + virtual StateClosure_OBSOLETE& getCurrentImplementation () =0; + + friend class engine::StateAdapter; + }; + +}} // namespace steam::engine +#endif /*STEAM_ENGINE_STATE_CLOSURE_OBSOLETE_H*/ diff --git a/src/steam/engine/state-closure.hpp b/src/steam/engine/state-closure.hpp index d6b8ed831..cdcdf8a6a 100644 --- a/src/steam/engine/state-closure.hpp +++ b/src/steam/engine/state-closure.hpp @@ -23,6 +23,9 @@ /** @file state-closure.hpp ** Access point to an ongoing render's processing state. + ** + ** @todo WIP-WIP-WIP 2024 Node-Invocation is reworked from ground up for the »Playback Vertical Slice« + ** */ @@ -58,7 +61,7 @@ namespace engine { */ class StateClosure { - ////////////////////////////////////////////////TICKET #826 expected to be reworked to quite some extent (9/2011) +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : to be Reworked for »Playback Vertical Slice« public: /** allocate a new writable buffer with type and size according to * the BufferDescriptor. The actual provider of this buffer depends diff --git a/src/steam/engine/turnout-system.hpp b/src/steam/engine/turnout-system.hpp index d7da73e30..75286f1c8 100644 --- a/src/steam/engine/turnout-system.hpp +++ b/src/steam/engine/turnout-system.hpp @@ -33,11 +33,13 @@ */ -#ifndef ENGINE_TURNOUT_SYSTEM_H -#define ENGINE_TURNOUT_SYSTEM_H +#ifndef STEAM_ENGINE_TURNOUT_SYSTEM_H +#define STEAM_ENGINE_TURNOUT_SYSTEM_H +#include "steam/engine/proc-node.hpp" #include "steam/engine/state-closure.hpp" +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation namespace steam { @@ -45,6 +47,7 @@ namespace engine { +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation class StateProxy : public StateClosure { @@ -66,8 +69,9 @@ namespace engine { virtual StateClosure& getCurrentImplementation () { return *this; } }; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation }} // namespace steam::engine -#endif /*ENGINE_TURNOUT_SYSTEM_H*/ +#endif /*STEAM_ENGINE_TURNOUT_SYSTEM_H*/ diff --git a/src/steam/engine/turnout.hpp b/src/steam/engine/turnout.hpp new file mode 100644 index 000000000..387304a00 --- /dev/null +++ b/src/steam/engine/turnout.hpp @@ -0,0 +1,257 @@ +/* + TURNOUT.hpp - Organise the invocation state within a single pull() call + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + 2024, 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 turnout.hpp + ** Organise 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 result frames from the nodes. Doing so requires some invocation + ** local state to be 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 dependent on the configuration + ** of the node to pull. Each node has been preconfigured by the builder with a Connectivity + ** descriptor 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. + ** + ** # composition of the Invocation State + ** + ** For each individual ProcNode#pull() call, the WiringAdapter#callDown() builds an StateAdapter + ** instance directly on the stack, managing 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::StateClosure interface. + ** + ** @todo relies still on an [obsoleted implementation draft](\ref bufftable-obsolete.hpp) + ** @see engine::ProcNode + ** @see engine::StateProxy + ** @see engine::FeedManifold + ** @see nodewiring.hpp interface for building/wiring the nodes + ** + ** @warning as of 4/2023 a complete rework of the Dispatcher is underway ///////////////////////////////////////////TICKET #1275 + ** + */ + + +#ifndef STEAM_ENGINE_TURNOUT_H +#define STEAM_ENGINE_TURNOUT_H + +#include +#include "steam/common.hpp" +#include "steam/engine/proc-node.hpp" +#include "steam/engine/turnout-system.hpp" +#include "steam/engine/feed-manifold.hpp" +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation +#include "steam/engine/channel-descriptor.hpp" +//#include "vault/gear/job.h" +//#include "steam/engine/exit-node.hpp" +//#include "lib/time/timevalue.hpp" +//#include "lib/linked-elements.hpp" +//#include "lib/util-foreach.hpp" +//#include "lib/iter-adapter.hpp" +//#include "lib/itertools.hpp" +//#include "lib/util.hpp" + +//#include +//#include + + +namespace steam { +namespace engine { + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation + /** + * 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 StateClosure + { + protected: + StateClosure& parent_; + StateClosure& current_; + + StateAdapter (StateClosure& callingProcess) + : parent_ (callingProcess), + current_(callingProcess.getCurrentImplementation()) + { } + + virtual StateClosure& getCurrentImplementation () { return current_; } + + + + public: /* === proxying the StateClosure 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); } + + virtual BuffTableStorage& getBuffTableStorage() { return current_.getBuffTableStorage(); } + + // note: allocateBuffer() is chosen 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 parametrised according to the necessities of the invocation sequence + * actually configured. Initially, this real instance is configured without FeedManifold, + * 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 + { + Connectivity const& wiring; + const uint outNr; + + FeedManifold* feedManifold; + + protected: + /** creates a new invocation context state, without FeedManifold */ + Invocation (StateClosure& callingProcess, Connectivity const& w, uint o) + : StateAdapter(callingProcess), + wiring(w), outNr(o), + feedManifold(0) + { } + + public: + uint nrO() const { return wiring.nrO; } + uint nrI() const { return wiring.nrI; } + uint buffTabSize() const { return nrO()+nrI(); } + + /** setup the link to an externally allocated buffer table */ + void setBuffTab (FeedManifold* b) { this->feedManifold = b; } + + bool + buffTab_isConsistent () + { + return (feedManifold) + && (0 < buffTabSize()) + && (nrO()+nrI() <= buffTabSize()) + && (feedManifold->inBuff == &feedManifold->outBuff[nrO()] ) + && (feedManifold->inHandle == &feedManifold->outHandle[nrO()]) + ; + } + + + public: + /** specialised version filling in the additional information, i.e + * the concrete node id and the channel number in question */ + virtual FrameID const& + genFrameID () + { + return current_.genFrameID(wiring.nodeID, outNr); + } + + virtual FrameID const& + genFrameID (NodeID const& nID, uint chanNo) + { + return current_.genFrameID (nID,chanNo); + } + + }; + + + ////////////TICKET #249 this strategy should better be hidden within the BuffHandle ctor (and type-erased after creation) + struct AllocBufferFromParent ///< using the parent StateAdapter for buffer allocations + : Invocation + { + AllocBufferFromParent (StateClosure& sta, Connectivity const& w, const uint outCh) + : Invocation(sta, w, outCh) {} + + virtual BuffHandle + allocateBuffer (const lumiera::StreamType* ty) { return parent_.allocateBuffer(ty); } ////////////TODO: actually implement the "allocate from parent" logic! + }; + + struct AllocBufferFromCache ///< using the global current StateClosure, which will delegate to Cache + : Invocation + { + AllocBufferFromCache (StateClosure& sta, Connectivity const& w, const uint outCh) + : Invocation(sta, w, outCh) {} + + virtual BuffHandle + allocateBuffer (const lumiera::StreamType* ty) { return current_.allocateBuffer(ty); } + }; + + + /** + * The real invocation context state implementation. It is created + * by the NodeWiring (Connectivity) of the processing node which + * is pulled by this invocation, hereby using the internal configuration + * information to guide the selection 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 Connectivity 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 configurations 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 + , private Strategy + { + public: + ActualInvocationProcess (StateClosure& callingProcess, Connectivity const& w, const uint outCh) + : BufferProvider(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); + } + }; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation + + + +}}// namespace steam::engine +#endif /*STEAM_ENGINE_TURNOUT_H*/ diff --git a/src/steam/mobject/builder/operationpoint.cpp b/src/steam/mobject/builder/operationpoint.cpp index e9ed2e54d..2a3ab55f3 100644 --- a/src/steam/mobject/builder/operationpoint.cpp +++ b/src/steam/mobject/builder/operationpoint.cpp @@ -31,7 +31,7 @@ #include "steam/engine/proc-node.hpp" #include "steam/asset/media.hpp" #include "steam/asset/proc.hpp" -#include "steam/engine/nodefactory.hpp" +#include "steam/engine/node-factory.hpp" #include "steam/streamtype.hpp" //#include "common/util.hpp" diff --git a/tests/core/steam/engine/feed-manifold-test.cpp b/tests/core/steam/engine/feed-manifold-test.cpp index 26737d6c6..da084e1a3 100644 --- a/tests/core/steam/engine/feed-manifold-test.cpp +++ b/tests/core/steam/engine/feed-manifold-test.cpp @@ -77,7 +77,7 @@ namespace test { virtual uint getNrI() const { return ii; } virtual uint getNrO() const { return oo; } - virtual BuffHandle callDown (StateClosure&, uint) const + virtual BuffHandle callDown (StateClosure_OBSOLETE&, uint) const { throw lumiera::Error("not intended to be called"); } }; diff --git a/tests/core/steam/engine/node-basic-test.cpp b/tests/core/steam/engine/node-basic-test.cpp index a3b0b4bf2..442529936 100644 --- a/tests/core/steam/engine/node-basic-test.cpp +++ b/tests/core/steam/engine/node-basic-test.cpp @@ -26,7 +26,7 @@ #include "lib/test/run.hpp" -#include "steam/engine/nodefactory.hpp" +#include "steam/engine/node-factory.hpp" #include "steam/engine/nodewiring.hpp" #include "steam/engine/turnout-system.hpp" #include "steam/engine/channel-descriptor.hpp" @@ -94,10 +94,12 @@ namespace test { CHECK (pNode); TestContext simulatedInvocation; +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1367 : Rebuild the Node Invocation BuffHandle result = pNode->pull(simulatedInvocation, 0); CHECK (result); // CHECK we got calculated data in the result buffer +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1367 : Rebuild the Node Invocation } }; diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 991e2b2dd..1bd12d549 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -6183,7 +6183,7 @@ This is the core service provided by the player subsystem. The purpose is to cre :any details of this processing remain opaque for the clients; even the player subsystem just accesses the EngineFaçade -
+
//Integration effort to promote the development of rendering, playback and video display in the GUI//
 This IntegrationSlice was started in {{red{2023}}} as [[Ticket #1221|https://issues.lumiera.org/ticket/1221]] to coordinate the completion and integration of various implementation facilities, planned, drafted and built during the last years; this effort marks the return of development focus to the lower layers (after years of focussed UI development) and will implement the asynchronous and time-bound rendering coordinated by the [[Scheduler]] in the [[Vault|Vault-Layer]]
 
@@ -6219,7 +6219,9 @@ The Scheduler will be structured into two Layers, where the lower layer is imple
 __December.23__: building the Scheduler required time and dedication, including some related topics like a [[suitable memory management scheme|SchedulerMemory]], rework and modernisation of the [[#1279 thread handling framework|https://issues.lumiera.org/ticket/1279]], using a [[worker pool|SchedulerWorker]] and developing the [[foundation for load control|SchedulerLoadControl]]. This amounts to the creation of a considerable body of new code; some &rarr;[[load- and stress testing|SchedulerTest]] helps to establish &rarr;[[performance characteristics and traits|SchedulerBehaviour]].
 
 __April.24__: after completing an extended round of performance tests for the new Scheduler, development focus is shifted now shifted upwards to the [[Render Node Network|ProcNode]], where Engine activity is carried out. This part was addressed at the very start of the project, and later again -- yet could never be completed, due to a lack of clear reference points and technical requirements. Hope to achieve a breakthrough rests on this integration effort now.
+__June.24__: assessment of the existing code indicated some parts not well suited to the expected usage. Notably the {{{AllocationCluster}}}, which is the custom allocator used by the render nodes network, was reworked and simplified. Moreover, a new custom container was developed, to serve as //link to connect the nodes.// Beyond that, in-depth review validated the existing design for the render nodes, while also implying some renaming and rearrangements
 * 🗘 establish a test setup for developing render node functionality
+* 🗘 build, connect and invoke some dummy render nodes directly in a test setup
 * ⌛ introduce a middle layer for linking the JobTicket to the actual invocation
 * ⌛ rework and complete the existing node invocation code
 
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index 8edde2b2a..497df1ee4 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -80157,7 +80157,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200

- + @@ -80180,7 +80180,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200

- + @@ -80386,6 +80386,25 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + + + + + + + + + + + @@ -80570,7 +80589,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + @@ -80699,8 +80719,11 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + + + + @@ -80709,6 +80732,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + @@ -80944,6 +80970,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ @@ -81048,8 +81075,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + + @@ -81077,12 +81105,20 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + - - + + - + + + + + @@ -81096,16 +81132,27 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + - - - - + + + + + + + + + + + + + + @@ -81217,7 +81264,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + @@ -81271,7 +81319,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -81571,8 +81619,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + + @@ -84939,14 +84988,17 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + - + + + @@ -84955,9 +85007,96 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + +
    +
  • + WiringDescriptor, und dann eine Impl NodeWiring +
  • +
  • + aber die eigentliche Impl steckt dann in einem Parameter-Typ STATE +
  • +
  • + die ProcNode delegiert durch ein SAM-Interface +
  • +
  • + und der tatsächliche Aufruf greift aber wieder auf die In/Out-Arrays durch +
  • +
  • + der StateProxy schwirrt irgendwo dazwischen auch noch herum +
  • +
+ +
+
+ + + + +

+ aus dem NodeWiring-Konstruktor passieren jede Menge Callbacks in die WiringSituation +

+ + +
+
+ + + + + + + +

+ man geht von ProcNode durch Connectivity, dann NodeWiring ... und wenn man Glück hat, fällt einem der Header nodeoperaton.hpp auf...  ⚠ denn sonst ist der tatsächliche Einstiegspunkt mit üblichen Methoden der Code-Suche praktisch nicht zu finden: Er steckt in nodewiring.hpp in der konkreten Definition der virtuellen Funktion callDown()  — und von dort in eine dependent Method thisStep.retrieve(), die tatsächlich im Template ActualInvocationProcess an STRATEGY::step()  weitergereicht wird — und vermutlich ist nur mir klar, daß damit die verketteten step()-Methoden in nodeoperation.hpp gemeint sind... +

+ + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -84978,6 +85117,14 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + @@ -84992,9 +85139,215 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ Die Analyse ergab mehrere Perspektiven auf das Thema, die sich zwar stark unterscheiden, wenn man sie als praktische Handlungsanweisungen interpretiert, die jedoch praktisch auf dasselbe hinauslaufen, wenn man sie gedanklich auffaßt. Meine Schlußfolgerung daraus ist, daß es stets einer Übersetzung bedarf, und es daher untunlich wäre, sich auf ein Modell festzulegen... +

+
    +
  • + topologisch haben wir es mit einem DAG zu tun, und es kann Mehrfachverbindungen auch zwischen unmittelbaren Nachbarknoten geben +
  • +
  • + eine Node-Aktivierung erzeugt immer alle Ausgaben, die dann irgendwo aufgefangen werden müssen +
  • +
  • + im Allgemeinen ist ein Umordnen und ggfs Auswählen und Verteilen dieser Ausgaben erforderlich +
  • +
  • + der Berechnungs-Vorgang hat K Eingaben +
  • +
  • + jede Eingabe ist ein bestimmtes Ergebnis von einem bestimmten Vorläufer +
  • +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ faßt das Konzept eines »Port« enger +

+ +
+
+ + + + +

+ nämlich indem der Ergebnis-Datenframe paßgenau sein muß +

+ +
+
+ + + + + + + + + + + + + +

+ Auch dort zeigt sich die Wahl zwischen einer high-level-Sicht, welche in den Ports noch Raum für sub-Differenzierung läßt, und somit näher an der Domänen-Modellierung liegt — und auf der anderen Seite einer radikalen low-Level-Lösung, die auf restlos explizit gemachten Möglichkeiten besteht +

+ + +
+ +
+ + + + + + + + + + + + + + +

+ ich neige zunehmend Richtung Model-1 +

+ + +
+ + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +