diff --git a/src/steam/engine/media-weaving-pattern.hpp b/src/steam/engine/media-weaving-pattern.hpp index 771080622..583ccc8bc 100644 --- a/src/steam/engine/media-weaving-pattern.hpp +++ b/src/steam/engine/media-weaving-pattern.hpp @@ -152,7 +152,7 @@ namespace engine { /** * Standard implementation for a _Weaving Pattern_ to connect * the input and output data feeds (buffers) into a processing function. - * @tparam INVO a configuration / policy base class to _adapt for invocation_ + * @tparam INVO a configuration class / prototype to _adapt for invocation_ * @note assumptions made regarding the overall structure * - `INVO::Feed` defines an _invocation adapter_ for the processing function * - `INVO::buildFeed()` is a functor to (repeatedly) build `Feed` instances diff --git a/tests/steam/engine/node-opera-test.cpp b/tests/steam/engine/node-opera-test.cpp index dc3e9a030..362083596 100644 --- a/tests/steam/engine/node-opera-test.cpp +++ b/tests/steam/engine/node-opera-test.cpp @@ -19,6 +19,7 @@ #include "test/run.hpp" #include "lib/allocation-cluster.hpp" #include "test/test-rand-ontology.hpp" +#include "vault/out/diagnostic-output-slot.hpp" #include "vault/mem/buffer-provider-setup.hpp" #include "vault/mem/engine-buffer-metadata.hpp" #include "vault/mem/engine-buffer-manager.hpp" @@ -49,6 +50,7 @@ using lib::time::FrameCnt; using lib::time::FrameRate; using lib::time::PGrid; using steam::asset::meta::TimeGrid; +using vault::out::DiagnosticOutputSlot; //using lib::Symbol; //using util::isnil; //using util::isSameObject; @@ -198,6 +200,7 @@ namespace test { /** @test perform a RenderInvocation to pull from a complex node tree into an output sink. * - use a test helper class to build a node topology similar to NodeLink_test * - the ProcNodes and all backing structures are managed by an AllocationCluster + * - use a DiagnosticOutputSlot (by default configured for buffers sized for TestFrame) */ void invokeNodeTree() @@ -205,23 +208,29 @@ namespace test { TestEngineCtx mockEngine; RenderPipeline pipeline; + DiagnosticOutputSlot oSlot; + auto sink0 = * oSlot.getOpenedSinks(); + + const uint OUTPUT_FRAME{123}; + Thread testWorker{[&] /* === perform a render invocation === */ { Time nomTime{rani(60'000),0}; // drive test with a random »nominal Time« <60s with ms granularity ProcessKey key{0}; uint port{0}; - BuffHandle buff = EngineCtx::access().mem.lockBufferFor(); - TestFrame& result = buff.accessAs(); - CHECK (result.isPristine()); + BuffHandle buff = sink0.lockFrame (OUTPUT_FRAME); // claim output buffer + CHECK (not buff.accessAs().isValid()); // underlying buffer is zero initialised, thus no valid TestFrame yet // Trigger Node invocation... buff = pipeline.exitNode.pull (port, buff, nomTime, key); - - CHECK (result.isValid()); - CHECK (not result.isPristine()); - CHECK (result.getChecksum() == pipeline.expectedChecksum (nomTime)); buff.release(); + + // DiagnosticOutputSlot allows to investigate the data sent into the DataSink... + TestFrame const& result = watch(oSlot).feed(0).frame(OUTPUT_FRAME).accessAs(); + CHECK (result.isValid()); // data matches checksum + CHECK (not result.isPristine()); // is not a source frame (but processed) + CHECK (result.getChecksum() == pipeline.expectedChecksum (nomTime)); }}; while (testWorker) diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index c22aed7dc..9a59b5dea 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -89082,7 +89082,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -89096,6 +89096,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ @@ -89104,6 +89105,29 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + +

+ aber nur im Fall von »playback« — denn falls wir rendern,  erzeugen wir im Ergebnis eine Folge von Frames, die wieder der absolute-nominal-time entsprechen +

+ +
+
+ + + + +

+ Und zwar vermittelt duch die Framerate und den jeweiligen Startpunkt im Medium +

+ +
+
+
@@ -89791,12 +89815,19 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + - + + + + + @@ -97265,7 +97296,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -97275,6 +97306,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ +
@@ -98872,16 +98905,13 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

Hier besteht ein »bottleneck« — insofern wir sparsam mit dem Speicher in den Segmenten und der Job-Activity-Language umgehen müssen; möglicherweise lassen sich gewisse (theoretische) Freiheitsgrade zusammenfalten in eine Processing-ID, an die ein Mapping gebunden wird (⟶ Stream-Types, Ausführungs-Zustand, Switchboard). Letztlich wird das aber über mehrere Stufen heruntergebrochen, so daß beim Einstieg in den jeweiligen Node-Pull eigentlich alle Freiheitsgrade und Parameter disjunkt vorliegen sollten...

- -
+
@@ -116680,42 +116710,33 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
- - - +

Das möchte ich so halten zur Dokumentation der Zusammenhänge; hier geht es um Komponenten-Integration — nicht um einen Systemtest. Teils werden jedoch bereits die gleichen Komponenten verwendet, wie in der »echten Engine«, vor allem der BufferProvider mit lokalen Pools. Andererseits werden die RenderNodes noch direkt erzeugt.

- -
+ - - - +

diese Subklasse ist zugleich ein BufferProviderSetup, und etabliert damit auch das Schema mit den local-mem-pools

- -
+
- - - +

...ich wollte diese direkten Referenz-Felder, um im produktiven Einsatz mir jeweils eine Indirektion einzusparen ⟹ das hat die Konsequenz, daß ich auch eine neue Instanz des EngineCtx (als front-End) erzeugen muß, um eine spezielle lokale Instanz des BufferProviderSetup injizieren zu können. Deshalb muß EngineCtx dann doch public konstruierbar sein (und nicht private mit fried für die DependencyFactory). Schade, aber letztlich irrelevant.

- -
+
@@ -116744,20 +116765,15 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - - +

mir fällt auf: das hab ich noch nie getestet

- -
+ - - - +

Wie konnte das passieren....? @@ -116775,24 +116791,20 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) Wie dem auch sei — ich hab mich auf den Standpunkt gestellt, daß dieser ganze Aufbau stark typisiert ist, und deshalb funktionieren muß, sobald er durch den Compiler geht — unter der Vorraussetzung daß die Basis-Technologie funktioniert (und das wäre lib::Several mit AllocationCluster, was in der Tat getestet ist)

- -
+
- - - +

...insofern er identisch ist zu der direkten Verwendung auf lib::SeveralBuilder, welche detailliert per Unit-Test abgedeckt ist

- -
+
@@ -116820,64 +116832,50 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - - +

denn speziell beim AllocationCluster ist die Lage besonders, da ein dedizierter Adaptor zum Einsatz kommt, in dessen Template-Parameter der Zieltyp eingeht; insofern ist dieser Adapter nicht  cross-constructible, obwohl die unterliegende AllocatorCluster-Instanz gleich wäre

- -
+
- - - +

geht einfach, da die Adapter-Policy letztlich nur eine AllocatorPolicy mit dem speziellen Allokator erweitert; insofern ist nur der außen explizit definierte Konstruktor das Problem; aus Gründen der Klarheit ziehe ich es trotzdem vor, den cross-ctor ebenfalls explizit zu definieren, dann aber lediglich an die Basisklasse zu delegieren (die dann selbst auf den unterliegenden Allokator zugreifen kann)

- -
+
- - - +

weiteres Problem: Allocator ist hier explizit nicht monostate

- -
+ - - - +

denn wir verwenden einen bestimmten AllocationCluster

- -
+
- - - +
@@ -116914,23 +116912,19 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
- -
+
- - - +

....denn die Leads sind im Objekt bereits instantiiert, und werden nicht erst im Build-Vorgang erzeugt

- -
+
@@ -116943,9 +116937,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - - +

...denn... @@ -116965,8 +116957,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - + @@ -116974,16 +116965,13 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - - +

sollte exakt die gleiche Kalkulation direkt wiederholen (genauso wie in NodeLink_test) und die Checksumme berechnen...

- -
+
@@ -117005,8 +116993,112 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
+ + + + +

+ Verbindung mit den zwei Grids beachten +

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

+ ...eine kurze Analyse zeigt sofort auf, daß hier so einige Informationen Redundant sind; das hat mich schon mehrfach in Verwirrung gebraucht — aber die Verwirrung besteht wohl ehr in einer Vermischung der Ebenen: lange Zeit (viel zu lange) habe ich den Job als eine Art »Interface« betrachtet (genauer gesagt, ich bin hier naiv Christian's "Analyse" aufgesessen). Das war keine gute Idee, weil damit die Parameter des Jobs eine universelle Gültigkeit beanspruchen, und »richtig« gewählt sein wollen. Tatsächlich ist aber der Job ein Artefakt der Implementierung, und bestimmt sich vornehmlich aus Überlegungen zur Performance; allein daran wäre zu bemessen, ob in diesem Fall Redundanz gut oder schlecht ist. Dem entsprechend sollte die Render-Invocation (die nächste Ebene darunter) wieder alle logisch benötigten Parameter explizit ausweisen. +

+ +
+ +
+
+ + + + +
    +
  • + Da das Source-Grid letztlich an der Verwendung der Quell-Medien hängt, ist die Beziehung dazu bereits im high-level-Model festgelegt und wird in die Nodes »eingebacken« +
  • +
  • + ganz anders das Output-Grid: die Ausgabe-Frame-Nr muß explizit angegeben werden, denn sie stellt die Verbindung zur Ausgabe-Zeit her; im Fall von Realtime-Playback ist das die »wall-clock-time« +
  • +
+ +
+ +
+ + + + +

+ allerdings will ich definitiv keinerlei Frame-Nr irgendwo im Job sehen +

+ +
+ + + +

+ Denn die Gefahr wäre zu groß, daß irgendjemand das dann als General-Koordinate für alles hernimmt — und den Unterschied zwischen Ausgabe-Grid und Source-Koordinaten per Machtspruch unter den Teppich kehrt. Man darf den all den Schwachmaten dieser Welt auch keinen kleinen Finger geben.... +

+ +
+ + + + + +

+ dazu gehören auch Mute-Schalter und das Switchboard — und der Bezug zur Play-Position / bzw. Loop-Play +

+ +
+
+ + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + @@ -117263,18 +117355,84 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + + + + + + + + + + + + +

+ noch nicht klar, ob für den gesamten Play-Process, oder für jeden CalcStream separat. +

+ +
+ + + + +

+ Wenn der Job in einem Worker-Thread startet, muß er eine Mapping-Tabelle mit diesem Key aufsuchen +

+ +
+
+ + + + +

+ Da der Worker ja das Grooming-Token erlangen muß, bevor er den Job aus dem Scheduler nimmt, und außerdem die Job-Planung ebenfalls in einem Job erfolgt (unter Grooming-Token, wenn ich mich recht erinnere...), dann würder der ausführende Worker implizit alles sehen, was der planende Worker in den Speicher geschrieben hat +

+ +
+ +
+
+ + + + +

+ Denn dann hätten wir ohnehin eine Callback-Struktur; wenn wir das akzeptieren, könnte auch die DataSink darüber zugänglich sein +

+ +
+ + + +
+ + + + +

+ Das ist eine Lebenszyklus-Bedingung, die an dieser Stelle prominent auftritt, und den gesamten Zugriff auf die Resultate der Job-Planung betrifft, einschließlich der von ihr referenzierten Model-Segmente. Es könnte sinnvoll sein, das als ein einziges, übergreifendes Lebenszyklus-Problem zu behandeln, und an die Deadlines der Jobs zu binden +

+ +
+ + +
+
- + + @@ -117354,6 +117512,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) +
@@ -125609,6 +125768,21 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + + + + + +

+ selbst nach einem Commit müsen die vorhergehenden Daten noch erhalten bleiben +

+ +
+ +
+ + +
@@ -151276,9 +151450,9 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - +