diff --git a/src/steam/engine/node-builder.hpp b/src/steam/engine/node-builder.hpp index 9e2d54716..8d2605934 100644 --- a/src/steam/engine/node-builder.hpp +++ b/src/steam/engine/node-builder.hpp @@ -93,6 +93,7 @@ #include "lib/error.hpp" +#include "lib/symbol.hpp" #include "lib/nocopy.hpp" #include "steam/engine/weaving-pattern-builder.hpp" #include "steam/engine/proc-node.hpp" @@ -110,6 +111,7 @@ namespace steam { namespace engine { namespace err = lumiera::error; + using lib::Literal; using util::_Fmt; using std::forward; using std::move; @@ -245,7 +247,7 @@ namespace engine { /** setup standard wiring to adapt the given processing function. * @return a PortBuilder specialised to wrap the given \a FUN */ template - auto invoke (FUN fun); + auto invoke (Literal qualifier, FUN fun); /** specify an `InvocationAdapter` to use explicitly. */ template @@ -373,9 +375,9 @@ namespace engine { private: template - PortBuilder(_Par&& base, FUN&& fun) + PortBuilder(_Par&& base, FUN&& fun, Literal qualifier) : _Par{move(base)} - , weavingBuilder_{forward (fun), _Par::leads_.policyConnect()} + , weavingBuilder_{forward (fun), qualifier, _Par::leads_.policyConnect()} , defaultPort_{_Par::patternData_.size()} { } @@ -384,6 +386,7 @@ namespace engine { /** + * @param qualifier a semantic distinction of the implementation function * @param fun invocation of the actual _data processing operation._ * @remarks * - a _»weaving pattern«_ is applied for the actual implementation, which amounts @@ -406,10 +409,10 @@ namespace engine { template template auto - PortBuilderRoot::invoke (FUN fun) + PortBuilderRoot::invoke (Literal qualifier, FUN fun) { using WeavingBuilder_FUN = WeavingBuilder(), FUN>; - return PortBuilder{move(*this), move(fun)}; + return PortBuilder{move(*this), move(fun), qualifier}; } /* template diff --git a/src/steam/engine/weaving-pattern-builder.hpp b/src/steam/engine/weaving-pattern-builder.hpp index 3566ea323..13e2755ec 100644 --- a/src/steam/engine/weaving-pattern-builder.hpp +++ b/src/steam/engine/weaving-pattern-builder.hpp @@ -101,6 +101,7 @@ //#include "steam/common.hpp" #include "lib/error.hpp" +#include "lib/symbol.hpp" //#include "steam/engine/channel-descriptor.hpp" //#include "vault/gear/job.h" #include "lib/several-builder.hpp" @@ -127,6 +128,7 @@ namespace engine { namespace err = lumiera::error; using std::forward; + using lib::Literal; using lib::Several; using lib::Depend; using util::_Fmt; @@ -376,11 +378,13 @@ namespace engine { Depend ctx; + Literal qualifier_; FUN fun_; template - WeavingBuilder(FUN&& init, INIT&& ...alloInit) + WeavingBuilder(FUN&& init, Literal qual, INIT&& ...alloInit) : leadPorts{forward (alloInit)...} + , qualifier_{qual} , fun_{move(init)} { } diff --git a/tests/core/steam/engine/node-linkage-test.cpp b/tests/core/steam/engine/node-linkage-test.cpp index 3d88c8df6..42e36f143 100644 --- a/tests/core/steam/engine/node-linkage-test.cpp +++ b/tests/core/steam/engine/node-linkage-test.cpp @@ -73,7 +73,7 @@ namespace test { { auto con = prepareNode() .preparePort() - .invoke(dummyOp) + .invoke(TEST_DUMMY, dummyOp) .completePort() .build(); CHECK (isnil (con.leads)); diff --git a/tests/core/steam/engine/test-rand-ontology.cpp b/tests/core/steam/engine/test-rand-ontology.cpp new file mode 100644 index 000000000..d81c8df9a --- /dev/null +++ b/tests/core/steam/engine/test-rand-ontology.cpp @@ -0,0 +1,51 @@ +/* + TestRandOntoloy - implementation of a test framework processing dummy data frames + + Copyright (C) Lumiera.org + 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 test-rand-ontology.cpp + ** Implementation of fake data processing to verify invocation logic. + */ + + +#include "steam/engine/test-rand-ontology.hpp" +#include "lib/error.hpp" + +//#include + + + +namespace steam { +namespace engine{ +namespace test { +// namespace err = lumiera::error; + + namespace { // hidden local support facilities.... + + } // (End) hidden impl details + + + Literal TEST_DUMMY{"Test-Dummy"}; + + + + + +}}} // namespace steam::engine::test diff --git a/tests/core/steam/engine/test-rand-ontology.hpp b/tests/core/steam/engine/test-rand-ontology.hpp index 405740b50..554b03ecc 100644 --- a/tests/core/steam/engine/test-rand-ontology.hpp +++ b/tests/core/steam/engine/test-rand-ontology.hpp @@ -20,7 +20,7 @@ */ -/** @file testframe-rand-ontology.hpp +/** @file test-rand-ontology.hpp ** A faked »media calculation« environment to validate the render node network. */ @@ -29,6 +29,8 @@ #define STEAM_ENGINE_TEST_RAND_ONTOLOGY_H +#include "lib/error.hpp" +#include "lib/symbol.hpp" #include "steam/engine/testframe.hpp" #include @@ -38,10 +40,14 @@ namespace steam { namespace engine{ namespace test { + using lib::Literal; /////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Dummy / Placeholder using NoArg = std::array; using SoloArg = std::array; + + extern Literal TEST_DUMMY; + /** @todo a placeholder operation to wire a prototypical render node */ inline void diff --git a/wiki/renderengine.html b/wiki/renderengine.html index daffcd029..c6d0e794f 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -6391,9 +6391,31 @@ In 2018, the middle Layer was renamed into → Steam-Layer -
-
A data processing node within the Render Engine. Its key feature is the possibility to pull from it one (freely addressable) [[Frame]] of calculated data. Further, each ~ProcNode has the ability to be wired with other nodes and [[Parameter Providers|ParamProvider]]
-{{red{⚠ In-depth rework underway as of 7/2024...}}}
+
+
//A data processing node within the Render Engine.// Its key feature is the ability to pull a [[Frame]] of calculated data -- which may involve the invocation of //predecessor nodes// and the evaluation of [[Parameter Providers|ParamProvider]]. Together, those nodes form a »node-network«, a ''D''irected ''A''cyclic ''G''raph (DAG) known as the LowLevelModel, which is //explicit// to the degree that it can be //performed// to generate or process media. As such it is an internal structure and //compiled// by evaluating and interpreting the HighLevelModel within the [[Session]], which is the symbolic or logical representation of »the film edit« or »media product« established and created by the user.
+
+So each node and all interconnections are //oriented.// Calculation starts from the output side and propagates to acquire the necessary inputs, thereby invoking the predecessor nodes (also known as »leads«). This recursive process leads to performing a sequence of calculations -- just to the degree necessary to deliver the desired result. And since the Render Node Network is generated by a compilation step, which is conducted repeatedly and on-demand by the part of the Lumiera application known as the [[Builder]], all node connectivity can be assumed to be adequate and fitting, each predecessor can be assumed to deliver precisely the necessary data into buffers with the correct format to be directly consumed for the current calculation step. The actual processing algorithm working on these buffers is provided by an ''external Media-processing-library'' -- the LowLevelModel can thus be seen as a pre-determined organisation and orchestration structure to enact externally provided processing functionality.
+→ [[Description of the render process|RenderProcess]]
+
+!Structure of a Render Node
+A {{{steam::engine::ProcNode}}} is an arrangement of descriptors, connectivity and {{{Port}}} objects, residing at a fixed memory location. It holds an //identity record// (the {{{NodeID}}}) and exposes an interface to »pull« and thus invoke calculations, abstracted by a layer of indirection (a virtual method call).
+;Lead
+:each node holds a (possibly empty) collection of //predecessor nodes// known as »leads« to provide prerequisite source data;
+:however, a node can be a //generator// (data producer or data source), in which case it has no leads.
+;Port
+:while each node offers a single well-delineated functionality, the actual calculation can (optionally) be provided in several flavours or configuration variations typically related to data format. E.g. a sound filtering node can be able to process stereo sound, but also deliver the filtering on the left or right channel in isolation. Or video image processing can be provided to work on various image resolutions, each requiring a different buffer layout. Any such processing variants are exposed as »ports« of the node. Since the node network is pre-canned, individual port entries are only allocated when actually required for currently expected rendering functionality; ports are designated by number, and conceivably in practice many nodes will just expose a single port-#0
+;Turnout
+:abstracting by virtual call interface, the {{{Turnout}}} instance is the actual implementation of the interface {{{Port}}}. Only at this level the //actual processing function// is known, and the number and arrangement of input- and output-buffers. The Turnout thus encapsulates a »blue print« for the invocation, especially how to retrieve or provide buffers, how to invoke the external library function and where to drop off the result data. Notably the Turnout embeds a sequence of descriptors to designate //which leads// are actually to be pulled in //what sequence// and especially the number of the port to use on each lead node, which obviously varies to accommodate the actual data format requirements.
+;Feed Manifold
+:when actually invoked, the Turnout creates transient data structures on the call stack, before jumping into recursive invocation of lead ports. A series of input- and output connections is prepared, actually represented as a pointer to some data buffer. The »input slots« are populated with the //result buffers// retrieved from the recursive {{{pull()}}} calls to the lead ports, while the »output slots« are then allocated from a {{{BufferProvider}}} (and will be passed-up the recursive invocation structure when done)
+;Invocation Adapter
+:each Media-processing-library entails a very specific protocol how to invoke processing functionality, which becomes embedded into an individual adaptor object, including the {{{FeedManifold}}}. Typically, the actual invocation will be bound into a λ-closure, and thus the whole compound can be aggressively optimised.
+;Weaving Pattern
+:while each processing variant is materialised into an individual {{{Turnout}}} instance, some more generic wiring- and invocation schemes come to play when adapting the processing functions of any given Media-processing-library. The {{{WeavingPattern}}} thus defines a distinct scheme how to arrange and connect inputs and outputs and how to actually invoke the processing function. Notably, some operations allow for in-place processing, where the input-buffer is also the output-buffer and data is directly manipulated in-place, while other libraries require some elaborate layout scheme for the data buffers to work efficiently. And while Lumiera provides a set of //building blocks for weaving patterns,// each Media-processing-library actually must be adapted through a Lumiera plug-in, which entails using those building blocks or even completely different yet compatible weaving patterns as appropriate. In the end, each instantiation of such a weaving pattern becomes embedded into the render node as a {{{Turnout}}} instance and can be invoked through the {{{Port}}} interface.
+
+!Building a Render Node
+!The render invocation
+{{red{⚠ In-depth rework underway as of 10/2024...}}}
 ^^┅┅┅┅┅┅the following text is ''superseded''┅┅┅┅┅┅┅┅┅^^
 
 !! {{red{open questions}}}
@@ -6937,10 +6959,12 @@ Besides housing the planning pipeline, the RenderDrive is also a JobFunctor for
 → [[Player]]
 
-
-
The [[Render Engine|Rendering]] only carries out the low-level and performance critical tasks. All configuration and decision concerns are to be handled by [[Builder]] and [[Dispatcher|SteamDispatcher]]. While the actual connection of the Render Nodes can be highly complex, basically each Segment of the Timeline with uniform characteristics is handled by one Processor, which is a graph of [[Processing Nodes|ProcNode]] discharging into a ExitNode. The Render Engine Components as such are //stateless// themselves; for the actual calculations they are combined with a StateProxy object generated by and connected internally to the Controller {{red{really?? 2018}}}, while at the same time holding the Data Buffers (Frames) for the actual calculations.
+
+
{{red{⚠ In-depth rework underway as of 10/2024...}}}
+^^┅┅┅┅┅┅the following text is ''superseded''┅┅┅┅┅┅┅┅┅^^
+The [[Render Engine|Rendering]] only carries out the low-level and performance critical tasks. All configuration and decision concerns are to be handled by [[Builder]] and [[Dispatcher|SteamDispatcher]]. While the actual connection of the Render Nodes can be highly complex, basically each Segment of the Timeline with uniform characteristics is handled by one Processor, which is a graph of [[Processing Nodes|ProcNode]] discharging into a ExitNode. The Render Engine Components as such are //stateless// themselves; for the actual calculations they are combined with a StateProxy object generated by and connected internally to the Controller {{red{really?? 2018}}}, while at the same time holding the Data Buffers (Frames) for the actual calculations.
 
-{{red{Warning: obsolete as of 9/11}}}
+{{red{🗲🗲 Warning: what follows is an early draft from 2009, obsoleted by actual plans and development as of 10/2024 🗲🗲}}}
 Currently the Render/Playback is beeing targetted for implementation; almost everything in this diagram will be implemented in a slightly differently way....
 [img[Entities comprising the Render Engine|uml/fig128389.png]]
 
@@ -7154,8 +7178,18 @@ An Activity is //performed// by invoking its {{{activate(now, ctx)}}} function - In a similar vein, also ''dependency notifications'' need to happen decoupled from the activity chain from which they originate; thus the Post-mechanism is also used for dispatching notifications. Yet notifications are to be treated specially, since they are directed towards a receiver, which in the standard case is a {{{GATE}}}-Activity and will respond by //decrementing its internal latch.// Consequently, notifications will be sent through the ''λ-post'' -- which operationally re-schedules a continuation as a follow-up job. Receiving such a notification may cause the Gate to become opened; in this case the trigger leads to //activation of the chain// hooked behind the Gate, which at some point typically enters into another calculation job. Otherwise, if the latch (in the Gate) is already zero (or the deadline has passed), nothing happens. Thus the implementation of state transition logic ensures the chain behind a Gate can only be //activated once.//
-
-
{{red{⚠ In-depth rework underway as of 7/2024...}}}
+
+
At a high level, the Render Process is what „runs“ a playback or render. Using the EngineFaçade, the [[Player]] creates a descriptor for such a process, which notably defines a [[»calculation stream«|CalcStream]] for each individual //data feed// to be produced. To actually implement such an //ongoing stream of timed calculations,// a series of data frames must be produced, for which some source data must be loaded and then individual calculations must be scheduled to work on this data and deliver results within a well defined time window for each frame. Thus, on the implementation level, a {{{CalcStream}}} comprises a pipeline to define [[render jobs|RenderJob]], and a self-repeating re-scheduling mechanism to repeatedly plan and dispatch a //chunk of render jobs// to the [[Scheduler]], which cares to invoke the individual jobs in due time.
+
+This leads to a even more detailed implementation level of the ''render processing''. Within the [[Session]], the user has defined the »edit« or the definition of the media product as an arrangement of media elements placed and arranged into a [[Timeline]]. A repeatedly-running, demand-driven, compiler-like process in Lumiera (known as [[the Builder|Builder]]) consolidates this [[»high-level definition«|HighLevelModel]] into a [[Fixture]] and an directly attached [[network of Render Nodes|LowLevelModel]]. The Fixture hereby defines a [[segment for each part of the timeline|Segmentation]], which can be represented by a single topology of connected render nodes. So each segment spans a time range, quantised into a range of frames -- and the node network attached below this segment is capable of producing media data for each frame within definition range, when given the actual frame number, and some designation of the actual data feed required at that point. Yet it depends on the circumstances what this »data feed« //actually is;// as a rule, anything which can be produced and consumed as compound will be represented as //a single feed.// The typical video will thus comprise a video feed and a stereo sound feed, while another setup may require to deliver individual sound feeds for the left and right channel, or whatever channel layout the sound system has, and it may require two distinct beamer feeds for the two channels of stereoscopic video. However -- as a general rule of architecture -- the Lumiera Render Engine is tasked to perform //all of the processing work,// up to and including all adaptation steps to reach the desired final result. Thus, for rendering into a media container, only a single feed is required, which can be drawn from an encoder node, which in turn consumes several data feeds for its constituents.
+
+To summarise this break-down of the rendering process defined thus far, the [[Scheduler]] ''invokes'' individual [[frame render jobs|RenderJob]], each of which defines a set of »coordinates«:
+* an ID of the calculation stream allowing to retrieve the output sink
+* a frame number relative to the timeline, encoding a //nominal frame time//
+* a specification of the Segment and the ExitNode to pull
+
+
+{{red{⚠ In-depth rework underway as of 7/2024...}}}
 ^^┅┅┅┅┅┅the following text is ''superseded''┅┅┅┅┅┅┅┅┅^^
 For each segment (of the effective timeline), there is a Processor holding the exit node(s) of a processing network, which is a "Directed Acyclic Graph" of small, preconfigured, stateless [[processing nodes|ProcNode]]. This network is operated according to the ''pull principle'', meaning that the rendering is just initiated by "pulling" output from the exit node, causing a cascade of recursive downcalls or prerequisite calculations to be scheduled as individual [[jobs|RenderJob]]. Each node knows its predecessor(s), thus the necessary input can be pulled from there. Consequently, there is no centralized "engine object" which may invoke nodes iteratively or table driven — rather, the rendering can be seen as a passive service provided for the Vault, which may pull from the exit nodes at any time, in any order (?), and possibly multithreaded.
 All State necessary for a given calculation process is encapsulated and accessible by a StateProxy object, which can be seen as the representation of "the process". At the same time, this proxy provides the buffers holding data to be processed and acts as a gateway to the Vault to handle the communication with the Cache. In addition to this //top-level State,// each calculation step includes a small [[state adapter object|StateAdapter]] (stack allocated), which is pre-configured by the builder and serves the purpose to isolate the processing function from the detals of buffer management.
@@ -7167,10 +7201,10 @@ __see also__
 → the protocol [[how to operate the nodes|NodeOperationProtocol]]
 
-
+
The rendering of input sources to the desired output ports happens within the »''Render Engine''«, which can be seen as a collaboration of Steam- amd ~Vault-Layer together with external/library code for the actual data manipulation. In preparation of the RenderProcess, the [[Builder]] as wired up a network of [[processing nodes|ProcNode]] called the ''low-level model'' (in contrast to the high-level model of objects placed within the session). Generally, this network is a "Directed Acyclic Graph" starting at the //exit nodes// (output ports) and pointing down to the //source readers.// In Lumiera, rendering is organized according to the ''pull principle'': when a specific frame of rendered data is requested from an exit node, a recursive calldown happens, as each node asks his predecessor(s) for the necessary input frame(s). This may include pulling frames from various input sources and for several time points, thus pull rendering is more powerful (but also more difficult to understand) than push rendering, where the process would start out with a given source frame.
 
-Rendering can be seen as a passive service available to the Vault, which remains in charge what to render and when. Render processes may be running in parallel without any limitations. All of the storage and data management falls into the realm of the Vault. The render nodes themselves are ''completely stateless'' — if some state is necessary for carrying out the calculations, the Vault will provide a //state frame// in addition to the data frames.
+Rendering can be seen as a passive service available to the Vault, which remains in charge what to render and when. Render processes may be running in parallel without any limitations. All of the storage and data management falls into the realm of the Vault. The render nodes themselves are ''completely stateless'' -- state is translated into structure or attached at the level of individual invocations in the form of invocation parameters, automation and input data.
a special kind of [[render job|RenderJob]], used to retrieve input data relying on external IO.
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index 37c676b1e..ada768538 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -13376,9 +13376,7 @@
 
 
 
-  
-    
-  
+  
   
     

was ist der Locator? @@ -13780,9 +13778,7 @@ - - - +

Perspective elided @@ -14610,9 +14606,7 @@ - - - +

...was bis jetzt nicht gegeben ist! @@ -16105,9 +16099,7 @@ - - - +

model::Tangible ist schön, @@ -17938,9 +17930,7 @@ - - - +

...denn das Kontext-Menü soll auf dem ganzen Widget liegen (und konkurriert übrigens mit der Drag-Geste) @@ -20778,9 +20768,7 @@ - - - +

Das war zwar schon meine Bauchgefühl, @@ -26623,9 +26611,7 @@ - - - +

ViewHooks können nach Hause telefonieren @@ -48064,9 +48050,7 @@ - - - +

...in Fällen, in denen der konkrete onion-layer @@ -48616,9 +48600,7 @@ - - - +

reflektiert die Zahl der Struktur-Element @@ -49127,9 +49109,7 @@ - - - +

...was ich einen Monat später schon wieder vergessen hatte... @@ -49367,9 +49347,7 @@ - - - +

Spaltung in Pragmatismus und Vision @@ -49716,9 +49694,7 @@ - - - +

act, note: Nachricht upstream @@ -57125,8 +57101,7 @@ TestFrame : verifizierbare Dummy-Berechnungen

- -
+ @@ -57137,8 +57112,7 @@ belegen daß eine Berechnung stattgefunden hat

- - +
@@ -57258,8 +57232,7 @@ es gibt einen fest eingebauten Seed-Mechanismus, der auf der Kanal- und Sequenz-Nummer beruht

- - +
@@ -81333,7 +81306,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + @@ -81343,10 +81317,20 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + - + + + + +

+ er wird tatsächlich auf Level-3 gebildet, und besteht zunächst auf einer inhaltlichen Identifikation des Proc-Asset, dann ggfs. noch einer technischen Differenzierung, welche die Domain-Ontology anhängt, sofern die errechneten Ergebnis-Mediendaten dadurch abweichen, und schließlich aus der Liste aller Input/Output Stream-Implementierungstypen +

+ +
+
+ @@ -91053,11 +91037,15 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + - - + + + + + @@ -91093,6 +91081,16 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + +
@@ -91145,8 +91143,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -91156,6 +91154,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + @@ -91497,6 +91498,16 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + + @@ -91732,15 +91743,79 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + +

+ ...im Grunde ist die Identität zunächst einmal, daß es die Node gibt, daß sie an einer Speicheradresse sitzt; im aktuellen Design ist es jedoch nicht notwendig, die Node anhand der Identität finden zu können, denn man findet sie über die Verschaltung auf eine Exit-Node +

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

+ Rein technische Informationen wären z.B. ein Funktions-Symbol im Executable oder Quellcode oder eine Parametersignatur; von solchen Daten kommt man niemals direkt zu einem Urteil "äquivalent für den User" +

+ + +
+
+ + + + + +

+ mindestens Level-3, denn auf Level-2 gehen wir bereits davon aus, daß Buffer-Typen blindlings passen +

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

+ ...und dieser ist zwar global eindeutig, andererseits aber auch implementation-defined und für jeden Programmlauf anders +

+ +
+
+
@@ -91752,6 +91827,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ @@ -91766,6 +91842,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+
@@ -91775,8 +91852,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
es sollte eine human-readable-Ausprägung geben

- -
+
@@ -91880,8 +91956,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
Und das ganz bewußt nur auf Basis eines intuitiven Verständnisses der Anforderungen und API-Strukturen einer in C geschriebenen Media-Handling-Library — also explizit ohne direkte Analyse konkreter Libraries wie FFmpeg oder GStreamer. Denn mein Ziel ist, zunächst eine Hohlform zu bekommen, eine Ausprägung der inneren Anforderungen, aus meinem generellen Verständnis des Sachverhalts, sowie der bisher geschaffenen Implementierung der Render-Nodes. Die entstehende Struktur soll sich zunächst gradlinig entwickeln können, und dann erst später, in weiteren Prototyping-Schritten auf konkrete Anforderungen adapteiert werden.

- - +
@@ -91891,8 +91966,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
Inkrementelles Prototyping schafft mir hier einen Mittelweg zwischen deduktivem top-down-Ansatz und einem induktiven bottom-up-Aufbau; ich gehe aus von einigen, intuitiv gewählten Formen in der Mitte des auszuspannenden Raumes und stelle von dort einen ersten Durchgang her. Die Belange der Performance und die Datenstruktur spielen dabei ebenso eine Rolle, wie das Streben nach Klarheit, welches die geschaffene Struktur nachhalltig macht.

- -
+ @@ -131057,15 +131131,41 @@ std::cout << tmpl.render({"what", "World"}) << s - - - + + + + + + +

+ Scheduler-Entwicklung: #1280 build Scheduler implementation +

+ +
- - + + + + +

+ Render-Processing: #235 Render/Playback process high-level design +

+ +
- - + + + + +

+ Engine-Steuerung: #1284 Render Engine operational control +

+ +
+
+ + +
@@ -132842,8 +132942,7 @@ std::cout << tmpl.render({"what", "World"}) << s - - +