diff --git a/src/steam/engine/calc-stream.hpp b/src/steam/engine/calc-stream.hpp index 75528d13b..118d6108f 100644 --- a/src/steam/engine/calc-stream.hpp +++ b/src/steam/engine/calc-stream.hpp @@ -96,6 +96,7 @@ namespace engine{ class CalcStream { std::shared_ptr drive_; + //////////////////////////////////////////////////////////////////////TICKET #1301 : need to pass-on the output sink association (and the ModelPort) protected: CalcStream (RenderEnvironment& abstractEngine) @@ -125,7 +126,7 @@ namespace engine{ }; - typedef std::vector CalcStreams; + typedef std::vector CalcStreams; //////////////////////////////////////////////////////TICKET #1297 : probably unnecessary, since we intend to connect always one Feed per ModelPort (and handle multiple channels internally, in the processing nodes) diff --git a/src/steam/engine/engine-service.cpp b/src/steam/engine/engine-service.cpp index 3927a4f52..e20f8523e 100644 --- a/src/steam/engine/engine-service.cpp +++ b/src/steam/engine/engine-service.cpp @@ -119,7 +119,7 @@ namespace engine{ EngineService::activateCalculation (play::DataSink sink, RenderEnvironment& engineCallback) { CalcStream calcStream(engineCallback); - calcStream.sendToOutput (sink); + calcStream.sendToOutput (sink); ////////////////////////////////////////////////////TICKET #1297 : need to re-think the association ModelPort ⟷ output sink return calcStream; } diff --git a/src/steam/engine/frame-coord.hpp b/src/steam/engine/frame-coord.hpp index 424c48810..7bb878ee8 100644 --- a/src/steam/engine/frame-coord.hpp +++ b/src/steam/engine/frame-coord.hpp @@ -72,7 +72,7 @@ namespace engine { TimeVar absoluteRealDeadline; ModelPort modelPort; - uint channelNr; + uint channelNr; ///////////////////////////////////////////////////////////////////////////TICKET #1297 : retract differentiation into channels here (instead use ModelPorts in the Segment) /** build an \em undefined frame location */ diff --git a/src/steam/engine/render-drive.cpp b/src/steam/engine/render-drive.cpp index 25be1abe5..b314194c3 100644 --- a/src/steam/engine/render-drive.cpp +++ b/src/steam/engine/render-drive.cpp @@ -92,7 +92,7 @@ namespace engine { RenderDrive::prepareRenderPlanningFrom (FrameCnt startFrame) { InvocationInstanceID invoKey; - invoKey.frameNumber = startFrame; + invoKey.frameNumber = startFrame;/////////////////////////////////////////////////////////TICKET #1301 : Job should be created similar to what JobTicket does Time nominalPlanningStartTime = getTimings().getFrameStartAt (startFrame); return Job(*this, invoKey, nominalPlanningStartTime); diff --git a/src/steam/engine/render-drive.hpp b/src/steam/engine/render-drive.hpp index 82af5f69f..7c54198b2 100644 --- a/src/steam/engine/render-drive.hpp +++ b/src/steam/engine/render-drive.hpp @@ -27,7 +27,7 @@ ** of the render process itself is performed chunk wise and embedded into the other rendering ** calculations. The _"rendering-as-it-is-planned-right-now"_ can be represented as a closure ** to the jobs, which perform and update this plan on the go. And in fact, the head of the - ** calculation process, the CalcStream, maintains this closure instance, as parametrised + ** planning process, the CalcStream, maintains this closure instance, as parametrised ** with the appropriate configuration for the specific playback/render process underway. ** Enclosed into this instance lives the actual job planning pipeline, connected at the ** rear to the dispatcher and thus to the fixture and the low-level model diff --git a/src/steam/play/render-configurator.cpp b/src/steam/play/render-configurator.cpp index 89416f9c1..9c1aa97ab 100644 --- a/src/steam/play/render-configurator.cpp +++ b/src/steam/play/render-configurator.cpp @@ -160,9 +160,12 @@ namespace play { RenderConfigurator::ConnectFunction buildRenderConfiguration (POutputManager outputPossibilities, Timings playTimings) { - shared_ptr specialConfig (how_to_render (outputPossibilities,playTimings)); + shared_ptr specialConfig{how_to_render (outputPossibilities,playTimings)}; - return bind (&RenderConfigurator::buildActiveFeed, specialConfig, _1 ); + return [specialConfig](ModelPort port) + { + return specialConfig->buildActiveFeed(port); + }; } diff --git a/src/steam/play/render-configurator.hpp b/src/steam/play/render-configurator.hpp index f7a62fc5a..e3c263c8b 100644 --- a/src/steam/play/render-configurator.hpp +++ b/src/steam/play/render-configurator.hpp @@ -82,7 +82,7 @@ namespace play { Feed buildActiveFeed (ModelPort); - typedef function ConnectFunction; + using ConnectFunction = function; protected: /** retrieve a suitable output sink for the data @@ -103,6 +103,7 @@ namespace play { * with the EngineFacade, one for each channel connection. * @note when this strategy function returns, the corresponding * render activities are already up and running. + * @todo get rid of the multiple channel connections /////////////////////////////////////////TICKET #1297 : retract differentiation into channels here (instead use ModelPorts in the Segment) */ virtual engine::CalcStreams buildCalculationStreams (ModelPort, OutputSlot&) =0; diff --git a/tests/46engine.tests b/tests/46engine.tests index 067c4a9a5..37d74ff56 100644 --- a/tests/46engine.tests +++ b/tests/46engine.tests @@ -77,3 +77,7 @@ END PLANNED "scheduler interface" SchedulerInterface_test < + + 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 dispatcher-interface-test.cpp + ** unit test \ref Timings_test + ** + ** @warning as of 5/2023 planning-chunk generation is reworked ///////////////////////////////////////////TICKET #1301 : factor out RenderDrive + */ + + +#include "lib/test/run.hpp" +#include "lib/error.hpp" + +//#include "steam/engine/procnode.hpp" +#include "steam/play/dummy-play-connection.hpp" +#include "steam/mobject/model-port.hpp" +#include "steam/engine/dispatcher.hpp" +#include "steam/play/timings.hpp" +#include "lib/time/timevalue.hpp" +//#include "lib/time/timequant.hpp" +//#include "lib/format-cout.hpp" +#include "lib/depend.hpp" +#include "lib/itertools.hpp" +#include "lib/util-coll.hpp" +#include "lib/util.hpp" + +#include +#include + +using test::Test; +using util::isnil; +using util::last; +using std::vector; +using std::function; +//using std::rand; + + +namespace steam { +namespace engine{ +namespace test { + + using lib::time::FrameRate; + using lib::time::Duration; + using lib::time::Offset; + using lib::time::TimeVar; + using lib::time::Time; + using mobject::ModelPort; + using play::Timings; + + namespace { // Test fixture... + + /* == test parameters == */ + + const uint START_FRAME(10); + + const uint DUMMY_CHANNEL(0); /////////////////////////////////////////////////////////////TICKET #1297 : get rid of the channels (use different ModelPort) + + + ModelPort + getTestPort() + { + using play::test::ModelPorts; + using play::test::PlayTestFrames_Strategy; + using DummyPlaybackSetup = play::test::DummyPlayConnection; + + DummyPlaybackSetup dummySetup; + ModelPorts mockModelPorts = dummySetup.provide_testModelPorts(); + return *mockModelPorts; // using just the first dummy port + } + + } // (End) Test fixture + +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1301 +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1301 + + + + + + + /***************************************************************//** + * @test document and verify the engine::Dispatcher interface, used + * to translate a CalcStream into individual node jobs. + * This test covers the definition of the interface itself, + * together with the supporting types and the default + * implementation of the basic operations. + * It creates and uses a mock Dispatcher implementation. + */ + class Timings_test : public Test + { + + virtual void + run (Arg) + { + verify_simpleFrameStep(); + verify_next_startPoint(); + } + + + /** @test perform the basic dispatch step + * and verify the generated frame coordinates + */ + void + verify_simpleFrameStep() + { + ModelPort modelPort (getTestPort()); + Timings timings (FrameRate::PAL); + ENSURE (START_FRAME == 10); + + TimeAnchor refPoint(timings, START_FRAME); + CHECK (refPoint == Time::ZERO + Duration(10, FrameRate::PAL)); + + FrameCoord frame; /////////////////TODO get / implement offset-by-#-Frames + FrameCnt frameOffset = 15; + + frame.absoluteNominalTime = refPoint; + frame.absoluteFrameNumber = refPoint.getStartFrame(); + frame.absoluteRealDeadline = refPoint.establishDeadlineFor (frameOffset); + frame.modelPort = modelPort; + frame.channelNr = DUMMY_CHANNEL; + + ENSURE (frame.isDefined()); +// frame = dispatcher_->locateRelative (frame, frameOffset); /////////////////////////////OOO MAGIC FAIRY DUST HERE + + CHECK (frame.absoluteNominalTime == Time(0,1)); ///////////////////////////////////OOO Boooooom + CHECK (frame.absoluteFrameNumber == 25); + CHECK (refPoint.remainingRealTimeFor(frame) < Time(FSecs(25,25))); + CHECK (refPoint.remainingRealTimeFor(frame) >= Time(FSecs(24,25))); + CHECK (frame.modelPort == modelPort); + +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1301 +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1301 + } + + + /** action used as "continuation" in #check_ContinuationBuilder + * This function expects to be invoked with a time anchor bumped up + * to point exactly behind the end of the previously planned chunk of Jobs + */ + void + verify_next_startPoint() + { + Timings timings (FrameRate::PAL); + TimeAnchor nextRefPoint(timings, START_FRAME); //////////////////////////////////////OOO : how is this actually determined (not yet implemented....) + UNIMPLEMENTED ("How to determine the start point of the next planning chunk"); + + Duration frameDuration (1, FrameRate::PAL); + Time startAnchor = Time::ZERO + START_FRAME*frameDuration; + Duration time_to_cover = timings.getPlanningChunkDuration(); + + CHECK (Time(nextRefPoint) >= startAnchor + time_to_cover); + CHECK (Time(nextRefPoint) < startAnchor + time_to_cover + 1*frameDuration); + } + }; + + + /** Register this test class... */ + LAUNCHER (Timings_test, "unit engine"); + + + +}}} // namespace steam::engine::test diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 87f1d3236..ec7296323 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -1495,9 +1495,9 @@ at the lowest level within the builder there is the step of building a //connect * by default, a timeline is outfitted with one video and one sound master bus -
+
Calculation stream is an organisational unit used at the interface level of the Lumiera engine.
-Representing a //stream of calculations,// delivering generated data within //timing constraints,// it is used
+Representing a //stream of calculations,// to deliver generated data within //timing constraints,// it is used
 *by the [[play process(es)|PlayProcess]] to define and control properties of the output generation
 *at the engine backbone to feed the [[Scheduler]] with individual [[render jobs|RenderJob]] to implement this stream of calculations
 Calculation stream objects are stateless, constant chunks of definition -- any altering of playback or rendering parameters just causes the respective descriptors to be superseeded. The presence of a CalcStream (being alive within the denoted time span) implies that using any of the associated jobs, dispatcher tables, node and wiring descriptors is safe
@@ -1509,7 +1509,7 @@ Any really interesting calculation stream needs to be retrieved from the EngineF
 !purpose
 When a calculation stream is retrieved from the EngineFaçade it is already registered and attached there and represents an ongoing activity. Under the hood, several further collaborators will hold a copy of that calculation stream descriptor. While, as such, a CalcStream has no explicit state, at any time it //represents a current state.// In case the running time span of that stream is limited, it becomes superseded automatically, just by the passing of time.
 
-Each calculation stream refers a relevant [[frame dispatcher table|FrameDispatcher]]. Thus, for the engine (interface level), the calculation stream allows to produce the individual [[render jobs|RenderJob]] to enqueue with the [[Scheduler]]. This translation step is what links and relates nominal time with running wall clock time, thereby obeying the [[timing constraints|Timings]] given when initially defining the calculation stream.
+Each calculation stream refers a relevant [[frame dispatcher table|FrameDispatcher]]. Thus, for the engine (interface level), the calculation stream allows to produce the individual [[render jobs|RenderJob]] to enqueue with the [[Scheduler]]. This translation step is what links and relates nominal time with running wall clock time, thereby obeying the [[timing constraints|Timings]] established initially together with the calculation stream.
 
 Additionally, each calculation stream knows how to access a //render environment closure,// allowing to re-schedule and re-adjust the setup of this stream. Basically, this closure is comprised of several functors (callbacks), which could be invoked to perform management tasks later on. Amongst others, this allows the calculation stream to redefine, supersede or "cancel itself", without the need to access a central registration table at the engine interface level.
 
@@ -2530,7 +2530,7 @@ Additionally, they may be used for resource management purposes by embedding a r
 #* one OpenGL Dataframe could contain raw texture data (but I am lacking expertise for this topic)
 
-
+
An entity within the RenderEngine, responsible for translating a logical [[calculation stream|CalcStream]] (corresponding to a PlayProcess) into a sequence of individual RenderJob entries, which can then be handed over to the [[Scheduler]]. Performing this operation involves a special application of [[time quantisation|TimeQuant]]: after establishing a suitable starting point, a typically contiguous series of frame numbers need to be generated, together with the time coordinates for each of those frames.
 
 The dispatcher works together with the [[job ticket(s)|JobTicket]] and the scheduler; actually these are the //core abstractions//&nbsp; the process of ''job planning'' relies on. While the actual scheduler implementation lives within the Vault, the job tickets and the dispatcher are located within the [[Segmentation]], which is the backbone of the [[low-level model|LowLevelModel]]. More specifically, the dispatcher interface is //implemented//&nbsp; by a set of &rarr; [[dispatcher tables|DispatcherTables]] within the segmentation.
@@ -2566,6 +2566,7 @@ While the sequence of frame jobs to be planned is possibly infinite, the actual
 
 !!!producing actual jobs
 The JobTicket is created on demand, specialised for a single [[segment|Segmentation]] of the timeline and a single [[feed|Feed]] of data frames to be pulled from a ModelPort. Consequently this means that all frames and all channels within that realm will rely on the same job ticket -- which is a //higher order function,// a function producing another function: when provided with the specific frame coordinates (frame number and time point), the job ticket produces a [[concrete job definition|RenderJob]], which itself is a function to be invoked by the [[scheduler|Scheduler]] to carry out the necessary calculations just in time.
+&rarr; JobPlanningPipeline
 
@@ -4289,6 +4290,9 @@ 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]]//
+
The actual media data is rendered by [[individually scheduled render jobs|RenderJob]]. All these calculations together implement a [[stream of calculations|CalcStream]], as demanded and directed by the PlayProcess. During the preparation of playback, a ''node planning phase'' is performed, to arrange for [[dispatching|FrameDispatcher]] the individual calculations per frame.  The goal of these //preparations//&nbsp; is to find out
 * which [[model ports|ModelPort]] can be processed independently
@@ -6185,7 +6189,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]]
 
@@ -6206,7 +6210,7 @@ __May.23__: taking a //prototyping approach// now, since further development was
 * ✔ build a {{{MockSegmentation}}} to hold onto ~JobTickets, which can be created as Mock
 * ✔define a simple specification language (based on the existing {{{GenNode}}}-DSL to define segments, tickets and prerequisite jobs
 * ✔ implement a »~Split-Splice« algorithm for &rarr; SegmentationChange, rigged accordingly to generate a mocked Segementation for now
-* 🗘 create a testbed to assemble a DispatcherPipeline step by step (&rarr; [[#920|https://issues.lumiera.org/ticket/920]] and [[#1275|https://issues.lumiera.org/ticket/1275|]])
+* 🗘 create a testbed to assemble a JobPlanningPipeline step by step (&rarr; [[#920|https://issues.lumiera.org/ticket/920]] and [[#1275|https://issues.lumiera.org/ticket/1275|]])
 
 !Decisions
 ;Scheduler
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index 16407fe60..cb0f6046b 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -64540,6 +64540,12 @@
 
 
 
+
+
+
+
+
+
 
 
 
@@ -69257,7 +69263,7 @@
 
 
 
-
+
 
 
 
@@ -69377,6 +69383,7 @@
 
 
 
+
 
 
 
@@ -69399,13 +69406,21 @@
 
 
 
-
+
+
+
+
+
+
 
 
 
 
 
-
+
+
+
+
 
 
 
@@ -69782,6 +69797,24 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + +

+ sehr altes Ticket... +

+

+ Effektiv ist das der Implementierungs-Kern; seinerzeit hatte ich unter diesem Ticket die Idee der CalcPlanContinuation entwickelt, welche nun zum RenderDrive wird... +

+ +
+ + + +
@@ -72993,6 +73026,45 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + +

+ also besser dann als separaten Test dokumentieren +

+ +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + +
@@ -73001,11 +73073,166 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+
+ + + + + + + + + + + + +
    +
  • + non-Copyable-Objekte in einem Vector sind nicht möglich... +
  • +
  • + die Zahl der Feeds und CalcStreams muß offen bleiben ⟹ Heap +
  • +
  • + aber spätestens vom RenderDrive darf es nur noch eine Instanz geben (pro realem CalcStream) +
  • +
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + +

+ lib::Handle<OutputSlot::Connection> +

+ +
+
+ + + + + + +

+ denn die Inovcation muß in diese Sink rendern +

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

+ Verhältnis von JobPlanning +

+

+ und JobTicket::Provision klären +

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

+ InvocationInstanceID invoKey{timeHash (nominalTime, provision.invocationSeed)}; +

+ +
+ +
+ + + + + + +

+ brauche dann aber einen Weg, +

+

+ um die Frame-Nummer zu transportieren +

+ +
+ + + + + + + + +
+
+ + + + +
@@ -73184,6 +73411,26 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + + +

+ Und zwar, weil es so am Einfachsten ist für die Implementierung der OutputConnection = slot.allocate() .... +

+

+ Denn es kann durchaus so sein, daß sich hinter einer Connection gleich mehrere Sinks auf Hardware / Driver-Ebene befinden. In diesem Fall wäre es andernfalls notwendig, wieder innerhalb der OutputConnection ein de-Multiplexing zu machen. Und das will ich nicht, sowas gehört in die Engine. Der OutputSink ist wirklich nur noch ein Buffer, der mit gewissen Timing-Constraints bespielt werden muß +

+ +
+
+
@@ -73301,6 +73548,54 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ und alle müssen an dieser Stelle auf einen Schlag angebunden werden +

+ +
+
+ + + + + + + +
+
+
@@ -73437,6 +73732,27 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + + + + + + + + + + + + +
@@ -73453,6 +73769,108 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + + + +

+ dispatches a JobFunctor into an appropriate worker thread, based on the job definition's execution spec +

+

+ no further dependency checks; Activities attached to the job are re-dispatched after the job function's completion +

+ +
+
+ + + + + + +

+ verify a given number of dependencies has been satisfied, otherwise inhibit the indicated target Activity +

+ +
+
+ + + + + + +

+ signal start of some processing — for the purpose of timing measurement, but also to detect crashed tasks +

+ +
+
+ + + + + + +

+ correspondingly signal end of some processing +

+ +
+
+ + + + + + +

+ push a message to another Activity or process record +

+ +
+
+ + + + + + +

+ invoke a closure within engine context; inhibit another target Activity, depending on the result. +

+ +
+
+ + + + + + +

+ internal engine »heart beat« -- invoke internal maintenance hook(s) +

+

+   +

+ +
+
+
+ + + + + +
@@ -73474,17 +73892,96 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -73544,7 +74041,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -73622,7 +74119,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -79703,12 +80200,27 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + + + + + + + @@ -79745,6 +80257,10 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + +