diff --git a/src/steam/engine/dispatcher.hpp b/src/steam/engine/dispatcher.hpp index 32ec7b142..7004ecae1 100644 --- a/src/steam/engine/dispatcher.hpp +++ b/src/steam/engine/dispatcher.hpp @@ -113,6 +113,7 @@ namespace engine { struct PipeFrameTick; struct PipeExpander; + template struct PipelineBuilder; @@ -120,7 +121,7 @@ namespace engine { public: virtual ~Dispatcher(); ///< this is an interface - PipelineBuilder forCalcStream (Timings timings); + PipelineBuilder forCalcStream (Timings timings); template class PlanningPipeline @@ -189,6 +190,7 @@ namespace engine { FrameCnt frameNr{0}; + /* === state protocol API for IterStateWrapper === */ bool checkPoint() const @@ -208,55 +210,80 @@ namespace engine { ++frameNr; currPoint = timings.getFrameStartAt (frameNr); } - }; - - - - /** - * Job-planning Step-3: monadic depth-first exploration of Prerequisites - */ - struct Dispatcher::PipeExpander - {}; - - - - /** - * Job-planning Step-2: select data feed connection between ModelPort - * and DataSink; this entails to select the actually active Node pipeline - */ - struct Dispatcher::PipelineBuilder - : PipeFrameTick - { - /** Builder: start frame sequence */ - PipelineBuilder - timeRange (Time start, Time after) + protected: + void + activate (Time start, Time after) { stopPoint = after; frameNr = timings.getBreakPointAfter(start); currPoint = timings.getFrameStartAt (frameNr); - - return move(*this); // expected to invoke buildFeed(port,sink) } + }; + + + + + /** + * A Builder wrapper, allowing to build a Job-planning pipeline + * step by step, while supplying contextual information from the CalcStream. + * @remark This builder is created from \ref Dispatcher::forCalcStream, and thus + * internally wired back to the `Dispatcher` implementation, to access the + * Fixture and low-level-Model data-structures to back generated render Jobs. + * Client code is expected to invoke all builder functions consecutively, + * and then place the result into the CalcStream for generating render Jobs. + */ + template + struct Dispatcher::PipelineBuilder + : SRC + { - /** Terminal builder: setup processing feed ModelPort -> DataSink */ + /** + * Builder: start frame sequence + */ auto - buildFeed (mobject::ModelPort port, play::DataSink sink) + timeRange (Time start, Time after) { - using TicketDepend = std::pair; - - // start iterator pipeline based on this as »state core« - auto pipeline = lib::treeExplore (frameTickCore()) - .transform([port,sink](PipeFrameTick& core) -> TicketDepend + PipelineBuilder::activate (start,after); + return buildPipeline (lib::treeExplore (move(*this))); + } // expected next to invoke pullFrom(port,sink) + + + /** Package a Ticket together with a direct dependency, + * to allow setup of schedule times in downstream processing */ + using TicketDepend = std::pair; + + + /** + * Builder: connect to the JobTicket defining the actual processing + * for the nominal time of this frame and the given ModelPort + */ + auto + pullFrom (mobject::ModelPort port) + { + return buildPipeline ( + this->transform([port](PipeFrameTick& core) -> TicketDepend { FrameCoord frame; ///////////////////////////////////////////OOO need a better ctor for FrameCoord frame.absoluteNominalTime = core.currPoint; frame.modelPort = port; - return {& core.dispatcher->getSinkTicketFor(sink) + return {nullptr ,& core.dispatcher->getJobTicketFor(frame) }; - }) - .expand([](TicketDepend& currentLevel) + })); + } + + + /** + * Builder: cause a exhaustive depth-first search + * to recursively discover all prerequisites of each + * top-level JobTicket + */ + auto + expandPrerequisites() + { + return buildPipeline ( + this->expand([](TicketDepend& currentLevel) { JobTicket const* parent = currentLevel.second; return lib::transformIterator (parent->getPrerequisites(0) @@ -266,27 +293,50 @@ namespace engine { } ); }) - .expandAll() - /////////////////////////////////////////////////////////////////////////////OOO do Step-4 here: build JobPlanning - ; - + .expandAll()); + } + + /** + * Terminal builder: setup processing feed to the given DataSink. + * @return Iterator to pull a sequence of render jobs, ready for processing + */ + auto + feedTo (play::DataSink sink) + { + auto pipeline = this->transform([sink](TicketDepend& currentLevel) + { + return currentLevel.second; ///////////////////////////////OOO construct a JobPlanning here + }); using PipeIter = decltype(pipeline); return PlanningPipeline{move (pipeline)}; } + protected: - PipeFrameTick&& - frameTickCore() + /** @internal type rebinding helper to move the given tree-Explorer pipeline + * and layer a new PipelineBuilder subclass on top. + * @note TreeExplorer itself is defined in a way to always strip away any existing + * top-level TreeExplorer, then add a new processing layer and finally + * place a new TreeExplorer layer on top. Taken together, this setup will + * *slice away* the actual PipelineBuilder layer, move the resulting pipeline + * into the next building step and finally produce a cleanly linked processing + * pipeline without any interspersed builders. Yet still, partially constructed + * pipelines are valid iterators and can be unit tested in isolation. + */ + template + PipelineBuilder + buildPipeline(PIP&& treeExplorer) { - return move (static_cast(*this)); + return PipelineBuilder {move (treeExplorer)}; } }; - - inline Dispatcher::PipelineBuilder + + + inline Dispatcher::PipelineBuilder Dispatcher::forCalcStream(Timings timings) { - return PipelineBuilder{this, timings}; + return PipelineBuilder {this, timings}; } diff --git a/wiki/renderengine.html b/wiki/renderengine.html index cd8d95264..3903a0be6 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -4291,7 +4291,7 @@ Thus an invocation trail represents one specific path leading to the invocation ''Note'': {{red{future plans and visions -- no clear and distinct meaning -- as of 4/21}}} -
+
//Depth-first evaluation pipeline used in the FrameDispatcher to generate the next chunk of [[render jobs|RenderJob]]//
 This is an implementation structure backed and established by the [[Dispatcher|FrameDispatcher]] and operated by the {{{RenderDrive}}} core of each CalcStream, where it is assembled by a //builder notation// -- backed by the {{{TreeExplorer}}} iterator pipeline framework; besides the typical filter and transform operations, the latter offers an »expansion« mechanism to integrate a //monadic exhaustive depth-first search,// allowing to pick up all prerequisites of a given calculation step by step within a local planning context.
 
@@ -4299,12 +4299,14 @@ This is an implementation structure backed and established by the [[Dispatcher|F
 ;frame-tick
 :establish a sequence of frame start times
 ;selector
-:choose suitable data feed connection between ModelPort and {{{DataSink}}};
+:choose a suitable ModelPort and associated JobTicket;
 :this entails to select the actually active ProcNode pipeline
 ;expander
 :monadic depth-first exploration of calculation prerequisites
 ;job-planning
 :collect the complete planning context and determine time frame
+:*especially add a {{{DataSink}}} specification to the JobFunctor closure
+:*and evaluate the dependency structure from the //exploration step// to establish Job deadlines
 
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 4a73d5fff..58e6f57e1 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -73755,6 +73755,28 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + +

+ das löst ganz elegant beide Probleme +

+
    +
  • + da es sich um ein Template handelt, findet der Definitions-Check erst später statt, wenn die tatsächliche Pipeline gebaut wird +
  • +
  • + der jeweilige Quell-Iterator-Typ ist als Template-Parameter gegeben, und kann damit direkt abgegriffen werden und in die nächste Instanz einfließen, welche einfach von ihm erbt +
  • +
+ +
+ + +
@@ -73768,26 +73790,81 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- +

- Fazit: Anwendung von TreeExplorer passiert nur in einem Funktions-Scope + Zwischen-Fazit: Anwendung von TreeExplorer passiert nur in einem Funktions-Scope

- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + + + + + @@ -73817,9 +73894,14 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + + + + + @@ -73858,9 +73940,24 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + - + + + + + + + + + + +

+ ...und zwar durch den gleichen Template-Slicing-Trick, der auch schon bei TreeExplorer selber so erfolgreich funktioniert: der Builder wird durch ein std::move auf die Basisklasse beschnitten und fällt dann als Temporary am Ende der Builder-Expressison einfach weg, aber aller relevanter Content ist in das Ergebnis geschoben worden, welches wegen RVO direkt am Zielort konstruiert wird +

+ +
+
@@ -73874,15 +73971,15 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + - - - + + + - + @@ -73897,15 +73994,16 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + - + + - + - + @@ -73957,19 +74055,12 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + - - - - - - -

- Es fällt auf, daß wir einen zweifach geschichteten Transform-Iterator haben. Zunächst einmal: ein Iterator muß hier rauskommen, da wir ein monadisches flatMap machen. Aber anstatt diese Paarung mit der jeweilgen Verschiebung erst in der Expander-Funktion zu machen, könnte man das auch direkt schon im JobTicket so aufsetzen — schließlich wäre der „Parent“ auch in diesem Kontext schon ganz natürlich gegeben (also das JobTicket selber, dessen prerequisites hier aufgelistet werden) -

- -
-