From 9393942366731a06d1e8d052c69b370714d03ac2 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 7 Dec 2024 18:15:44 +0100 Subject: [PATCH] Invocation: Analysis pertaining to storage for param data During Render Node invocation, automation parameter data must be maintained. For the simple standard path, this just implies to store the ''absolute nominal Time'' directly in the invoking stack frame and let some parameter adaptors do the translation. However, it is conceivable to have much more elaborate translation functions, and thus we must be prepared to handle an arbitrary number of parameter slots, where each slot has arbitrary storage requirements. The conclusion is to start with an intrusive linked list of overflow buckets. --- src/lib/time/timecode.cpp | 4 +- src/lib/time/timecode.hpp | 4 +- src/steam/engine/turnout-system.hpp | 15 +- tests/basics/time/quantiser-basics-test.cpp | 2 +- tests/basics/time/time-quantisation-test.cpp | 34 +- tests/core/steam/engine/node-base-test.cpp | 65 +--- tests/core/steam/engine/node-feed-test.cpp | 19 +- wiki/thinkPad.ichthyo.mm | 322 +++++++++++++++---- 8 files changed, 329 insertions(+), 136 deletions(-) diff --git a/src/lib/time/timecode.cpp b/src/lib/time/timecode.cpp index 3bbb422cf..e9034c5a4 100644 --- a/src/lib/time/timecode.cpp +++ b/src/lib/time/timecode.cpp @@ -343,14 +343,14 @@ namespace time { /** */ HmsTC::HmsTC (QuTime const& quantisedTime) : TCode(quantisedTime) -// : tpoint_(quantisedTime) /////////////////////////////TODO bullshit +// : tpoint_(quantisedTime) //////////////////////////////////////////////////////////////////////TICKET #736 implement HMS format { } /** */ Secs::Secs (QuTime const& quantisedTime) : TCode(quantisedTime) -// : sec_(TimeVar(quantisedTime) / GAVL_TIME_SCALE) /////////////TODO bullshit +// : sec_(TimeVar(quantisedTime) / GAVL_TIME_SCALE) //////////////////////////////////////////////////////TICKET #736 implement Seconds format { } diff --git a/src/lib/time/timecode.hpp b/src/lib/time/timecode.hpp index da088578f..4564bf8da 100644 --- a/src/lib/time/timecode.hpp +++ b/src/lib/time/timecode.hpp @@ -177,7 +177,7 @@ namespace time { /** * @warning missing implementation - */ + */ ////////////////////////////////////////////////////////////////////////////////////////////////TICKET #736 implement HMS format class HmsTC : public TCode { @@ -202,7 +202,7 @@ namespace time { /** * @warning partially missing implementation - */ + */ ////////////////////////////////////////////////////////////////////////////////////////////////TICKET #736 implement Seconds format class Secs : public TCode { diff --git a/src/steam/engine/turnout-system.hpp b/src/steam/engine/turnout-system.hpp index 1561ce0a2..12621155e 100644 --- a/src/steam/engine/turnout-system.hpp +++ b/src/steam/engine/turnout-system.hpp @@ -25,9 +25,10 @@ ** _Switch Board. ** ** The TurnoutSystem is related to the actual incidence and is created dynamically, - ** while connecting to all the existing \ref Turnout elements sitting in the render node ports. - ** It acts as mediator and data exchange hub, while gearing up the actual invocation to cause - ** calculation of media data in the render nodes connected below + ** while connecting to all the pre-existing \ref Turnout elements, sitting in the ports + ** of those render nodes touched by the actual render invocation. It acts as mediator and + ** data exchange hub, while gearing up the actual invocation to cause calculation of media data + ** in the render nodes connected below, passing coordination parameters alongside. ** @todo WIP-WIP-WIP 12/2024 now combining the draft from 2009 / 2012 with recent engine development */ @@ -38,10 +39,13 @@ #include "steam/engine/state-closure.hpp" /////////////////////OOO will take on a different role (if any) /////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation +#include "lib/time/timevalue.hpp" namespace steam { namespace engine { + + using lib::time::Time; @@ -52,9 +56,12 @@ namespace engine { * and initiates the recursive pull()-call into the render node network as attached for this call. */ class TurnoutSystem - /////////////////////////////////////////OOO von wo erbt das?? laut ursprünglichem Konzept von StateClosure ... bin mir aber nicht mehr sicher { + /////////////////////////////////////////////////////////OOO Storage: ich brauche Overflow-Buckets. KISS ==> erst mal intrusive linked List public: + TurnoutSystem (Time absoluteNominalTime) + { } + // this is a copyable front-end object }; diff --git a/tests/basics/time/quantiser-basics-test.cpp b/tests/basics/time/quantiser-basics-test.cpp index 81909f596..dc4189826 100644 --- a/tests/basics/time/quantiser-basics-test.cpp +++ b/tests/basics/time/quantiser-basics-test.cpp @@ -61,7 +61,7 @@ namespace test{ * value, the quantiser yields a time value aligned * at the next lower frame bound. Besides that, * time values are confined to be within - * the interval (Time::MIN, Time::Max) + * the interval (Time::MIN, Time::MAX) * * @see TimeQuantisation_test */ diff --git a/tests/basics/time/time-quantisation-test.cpp b/tests/basics/time/time-quantisation-test.cpp index df491d362..148540ac1 100644 --- a/tests/basics/time/time-quantisation-test.cpp +++ b/tests/basics/time/time-quantisation-test.cpp @@ -13,6 +13,7 @@ /** @file time-quantisation-test.cpp ** unit test \ref TimeQuantisation_test + ** @todo 2024/24 only two of the four timecode formats are implemented /////////////////////////////////////TICKET #736 : HMS and Seconds not implemented */ @@ -39,7 +40,7 @@ namespace test{ /****************************************************//** * @test verify handling of quantised time values. - * - the simple usage, just referring to an + * - the simple usage, just referring to an * predefined grid by name * - explicitly defining an quantiser * - converting these quantised values into @@ -54,18 +55,22 @@ namespace test{ if (isnil(arg)) {// use random time value for all tests seedRand(); - return 1 + rani(10000); + return 1 + rani(100'000); } - else - return lexical_cast (arg[1]); + else // use argument as 1/10 seconds + return 10 * lexical_cast (arg[1]); } + /** + * @param arg number as 1/10sec + * @note using random time 0..100s if no argument given + */ virtual void - run (Arg arg) + run (Arg arg) { - Time ref (0,random_or_get(arg),0,0); + Time ref (random_or_get(arg),0,0,0); CHECK (TimeValue(0) < ref); checkSimpleUsage (ref); @@ -85,17 +90,20 @@ namespace test{ FrameNr count(qVal); // materialise this quantised time into.. int n = count; // frame count, accessible as plain number - CHECK (Time(FSecs(n-1, 25)) <= org); // verify quantisation: the original time - CHECK (org < Time(FSecs(n+1, 25))); // is properly bracketed by (n-1, n+1) + CHECK (Time(FSecs(n, 25)) <= org); // verify quantisation: the original time + CHECK (org < Time(FSecs(n+1, 25))); // is properly bracketed by [n, n+1[ } void check_theFullStory (TimeValue org) { + cout << "TEST rawTime:"<()); CHECK ( qVal.supports()); @@ -103,21 +111,21 @@ namespace test{ showTimeCode (smpteTCode); HmsTC pureTimeCode = qVal.formatAs(); - showTimeCode (pureTimeCode); + showTimeCode (pureTimeCode); ////////////////////////////////////////////////////////////////TICKET #736 : HMS not implemented yet FrameNr frameTCode = qVal.formatAs(); showTimeCode (frameTCode); Secs seconds = qVal.formatAs(); - showTimeCode (seconds); + showTimeCode (seconds); ////////////////////////////////////////////////////////////////TICKET #736 : Seconds not implemented yet } template void showTimeCode (TC timecodeValue) { - cout << timecodeValue.describe() - << " time = "<< timecodeValue.getTime() + cout << timecodeValue.describe() + << " time = "<< timecodeValue.getTime() << " code = "<< timecodeValue << endl; } @@ -150,7 +158,7 @@ namespace test{ QuTime funny (org, "special_funny_grid"); // now OK, grid is known int cnt = funny.formatAs(); - // and now performing quantisation is OK + // and now performing quantisation is OK SmpteTC smpte (funny); // also converting into SMPTE (which implies frame quantisation) CHECK (0 == smpte.frames); // we have 1fps, thus the frame part is always zero! CHECK (cnt % 60 == smpte.secs); // and the seconds part will be in sync with the frame count diff --git a/tests/core/steam/engine/node-base-test.cpp b/tests/core/steam/engine/node-base-test.cpp index 24c8ddf42..9e3f7733f 100644 --- a/tests/core/steam/engine/node-base-test.cpp +++ b/tests/core/steam/engine/node-base-test.cpp @@ -17,13 +17,10 @@ #include "lib/test/run.hpp" +//#include "lib/test/test-helper.hpp" #include "steam/engine/proc-node.hpp" -//#include "steam/engine/nodewiring-obsolete.hpp" /////////////////////////////////////////////////////TICKET #1367 : sort out dependencies for reworked Node Invocation #include "steam/engine/turnout.hpp" #include "steam/engine/turnout-system.hpp" -#include "steam/engine/channel-descriptor.hpp" -#include "steam/mobject/session/effect.hpp" -#include "lib/allocation-cluster.hpp" //#include "lib/format-cout.hpp" //#include "lib/util.hpp" @@ -35,32 +32,10 @@ namespace steam { namespace engine{ namespace test { - using lib::AllocationCluster; - using mobject::session::PEffect; - namespace { // Test fixture - /** - * Mock StateClosure/Invocation object. - * Used as a replacement for the real RenderInvocation, - * so the test can verify that calculations are actually - * happening in correct order. */ - class TestContext -// : public StateProxy - { - - //////////////TODO: facility to verify the right access operations get called - - }; - - - inline PEffect - createTestEffectMObject() - { - UNIMPLEMENTED ("how to create a dummy Effect for tests"); - } } @@ -69,32 +44,22 @@ namespace test { */ class NodeBase_test : public Test { - virtual void run(Arg) + virtual void + run (Arg) { + seedRand(); + verify_TurnoutSystem(); UNIMPLEMENTED ("build a simple render node and then activate it"); - - AllocationCluster alloc; -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1367 : Rebuild the Node Invocation - NodeFactory nodeFab(alloc); - - ProcNode * testSource; ///////////TODO: how to fabricate a test Source-Node???? - - - WiringSituation setup(testSource); - - PEffect pEffect = createTestEffectMObject(); - ProcNode* pNode = nodeFab (pEffect, setup); - CHECK (pNode); -#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1367 : Rebuild the Node Invocation - - 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 - } + } + + /** @test the TurnoutSystem as transient coordinator for node invocation + */ + void + verify_TurnoutSystem() + { + Time nomTime{rani(10'000),0}; // drive test with a random »nominal Time« <10s with ms granularity + TurnoutSystem invoker{nomTime}; // a time spec is mandatory, all further parameters are optional + } }; diff --git a/tests/core/steam/engine/node-feed-test.cpp b/tests/core/steam/engine/node-feed-test.cpp index 0ed6c19da..6c1eed43e 100644 --- a/tests/core/steam/engine/node-feed-test.cpp +++ b/tests/core/steam/engine/node-feed-test.cpp @@ -30,15 +30,26 @@ namespace test { - /***************************************************************//** - * @test the source reading render node. + /************************************************************************//** + * @test demonstrate how to feed data into, through and out of render nodes. */ class NodeFeed_test : public Test { - virtual void run(Arg) + virtual void + run (Arg) { + feedParam(); UNIMPLEMENTED ("render node pulling source data from vault"); - } + } + + /** @test feed parameter data to nodes */ + void + feedParam() + { + TODO ("implement the logic for the TurnoutSystem --> node-base-test.cpp"); + TODO ("implement a simple Builder for ParamAgent-Node"); + TODO ("then use both together to demonstrate a param data feed here"); + } }; diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 9f28952b0..e891656a7 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -20765,9 +20765,7 @@ - - - +

Dies wäre dann das Rückgrat in der View-Behandlung in der Timeline @@ -21144,9 +21142,7 @@ - - - +

und diese Info ist komplett redundant @@ -21847,9 +21843,7 @@ - - - +

...insofern nämlich auf dem Canvas einzelne Clip-Widgets liegen, und diese können wiederum einen eingebetteten Canvas haben, den man ggfs auch in Form eines nested ViewHook handhaben möchte. Die Details dazu sind aber im Moment noch nebulös, und ich sollte diesem Fall (noch) nicht zu viel Beachtung schenken. @@ -22566,9 +22560,7 @@ - - - +

d.h. eine LUID @@ -23373,9 +23365,7 @@ - - - +

...das ist die minimale Einsparung... @@ -25406,9 +25396,7 @@ - - - +

Clip-Drag reagiert manchmal nicht »live« @@ -29195,9 +29183,7 @@ - - - +

nämlich diejenige für Typen ohne Support auf dem API. @@ -33922,9 +33908,7 @@ - - - +

weil die Canvas-Controls tief eingewickelt in der Struktur liegen @@ -37889,9 +37873,7 @@ - - - +

...d.h. es wäre zu vermeiden, daß ein irgendwo vorgegebenes Konfigurations-Setup an anderer Stelle im Code noch passend verankert oder korrespondierend eingerichtet werden muß.

Konkret: die drag-Fähigkeit eines Clip wird konfiguriert im Clip-Presenter. Fertig. @@ -39695,9 +39677,7 @@ - - - +

Sollte als Nächstes versäubert und verallgemeinert werden! @@ -40590,9 +40570,7 @@ - - - +

Tatsächlich kann ein µTick-Grid auch Sound-Samples korrekt addressieren — man darf dann nur nicht diese Zeit-Werte für weitere Berechnungen verwenden (denn sonst sammeln sich Rundungsfehler an). Es könnte also eine Implementierung eben wissen, daß hier Sound-Samples dargestellt/verarbeitet werden, und intern mit der exakten Skala arbeiten. Im Grunde ist das ein Lösungsvorgriff auf die 3.Lösungsvariante (Problem ignorieren und per Metadaten tunneln)... siehe Diskussion in #1258 @@ -41002,9 +40980,7 @@ - - - +

...vergrößern, weil damit die Metrik kleiner wird und unter der Schwelle MAX_ZOOM gehalten wird @@ -41551,9 +41527,7 @@ - - - +

⟹ dann paßt der Wertebereich im Extremfall grade so rein (1px-Window mit 1µ-Tick, und das per halb-Steps von Time::MIN ⟼ Time::MAX bringen:  lb <= 62 ) @@ -41864,9 +41838,7 @@ - - - +

...denn dadurch würde man die kreuzweise Multiplikation verhindern @@ -87411,7 +87383,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -87420,7 +87392,31 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + + + + +

+ per Default mit absolute nominal Time zu erzeugen +

+ +
+ +
+ + + + +

+ Das muß so sein aus Gründen der logischen Konsistenz: Der Invocation-Mechanismus der Render-Engine ist generisch, und das bedeutet, er kann nichts implizit über das zu rendernde Modell wissen; zwar wird für den Build-Vorgang in absolute Placements  reduziert, aber diese beziehen sich immer noch auf eine bestimmte Timeline — ebenso wie der Render-Vorgang, der auf einer Timeline  abläuft. Das bedeutet, für den Rendervorgang ist das Koordinatensystem implizit, und er gibt nur eine absolute nominal Time relativ dazu an; jedoch wird dieser implizite Kontext in der Job-Planung übersetzt in den Zugriff auf eine bestimmte konkrete Exit-Node. Insofern kann dann ein Job komplett generisch auf der Render-Engine laufen, denn er tarnsportiert sowohl die absolute nominal Time, alsauch die konkrete ExitNode. Das Turnout-System selber ist ebenfalls generisch, und das heißt, es wird nur sinnvoll in Verbindung mit einer ExitNode zur Aufführung gebracht +

+ + +
+ +
+ @@ -87439,6 +87435,139 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ und diese ist massiv (Millionen Zyklen, allerdings in Speicher, der dann im Cache liegt) +

+ + +
+
+ + + + + + +

+ Vorsicht Falle: nicht in heißer Loop messen, sondern in einem realistischen Szenario unter Speicher-Druck +

+ +
+
+ + + + +

+ ...oder werden sie von der Medien-Berechnung verdrängt? +

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

+ WeavingPattern ⟶ TurnoutSystem (Stack) ⟶ Index-Tabelle (Buffer) ⟶ Storage (same Buffer) +

+ +
+
+ + + + +
    +
  • + der erste Slot ist stets günstig, denn er liegt grundsätzlich im TurnoutSystem selber (die nominal Time) +
  • +
  • + wenn es nur einen weiteren zusätzlichen Parameter gibt, wäre die Index-Tabelle ein nutzloser Overhead, sie muß ja auch aufgebaut werden +
  • +
  • + bei mehr als drei Slots sind wir im Vorteil (wobei der lokale Hebel erst mal gering sein dürfte, denn spätestens nach dem ersten Zugriff liegt der Buffer im Cache) +
  • +
+ + +
+
+ + + + +

+ ....die intrusive linked List habe ich nämlich fertig und getestet, zudem ist der Code dafür sehr robust zu verwenden, wenn man ohnehin einen privatenTyp für ein Bucket definiert. Dem gegenüber müßte man die Index-Tabellen-Lösung erst mal konzipieren und austesten, und zudem wäre die wohl eine Spezial-Implementierung und daher auch jedes Mal wieder zu verstehen. Damit ist die Entscheidung klar, man muß wirklich erst mal zeigen daß ein Problem besteht... +

+ + +
+
+ + + + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + @@ -87568,12 +87697,55 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + +

+ ja... lang ist's her ☺ +

+

+ Zur Erinnerung: +

+
    +
  • + an Zeit-Werten fummelt man nicht herum +
  • +
  • + sie sind opaque — will man „reinschauen“, dann braucht man einen Timecode +
  • +
  • + und dann eine QuantisedTime, welche ein Grid impliziert. +
  • +
  • + es gibt keinen natürlichen Default und aus diesem Grund gibt es auch keine »convenience method« für die armen Tester +
  • +
  • + So ist es, Ende der Diskussion! (die Interne Zeit ist eine Abstraktion, den „wirklichen Wert“ gibt es nicht) +
  • +
+ +
+
+ + + + + +
- - + + + + @@ -87708,6 +87880,16 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + + @@ -93879,7 +94061,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -93920,8 +94102,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
Hab mich in den letzten Tagen wieder in einem Knoten festgefahren — der nun zum Glück wenigstens in meinem Kopf schon gelöst ist....  Trotzdem ist die Situation sehr schwierig, da ich mehrere »intuitiv geklärte« Sachverhalte gleichzeitig aufbauen muß, und nicht recht weiß, wo beginnen....

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

- +
@@ -93955,12 +94136,12 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + - + @@ -94630,8 +94811,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + @@ -94681,7 +94862,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -94714,8 +94895,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + @@ -95888,8 +96069,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
Framework und Services aus dem produktiven Setup verwenden, möglichst auch den realen Memory-Buffer-Provider. Damit stellt sich die Frage, wie hier überhaupt verifiziert werden kann; vermutlich werde ich Instrumentierungs-Hilfsmittel einführen und dafür auch Zugangspunkte in die produktiven Services einführen müssen — ähnlich wie ich es erfolgreich für den Block-Flow-Allokator im Scheduler getan habe

- -
+
@@ -96658,6 +96838,28 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + +

+ per Default ist stets eine absolute nominal Time gegeben +

+ + +
+ + + +

+ das folgt aus der Aufruf-Struktur der Render-Engine; diese Zeitangabe ist aber für sich sinnlos und wird erst interpretiert auf Basis einer konkreten ExitNode, welche sich dann implizit auf eine Timeline und durch den verwendeten Port auch auf ein konkretes FrameGrid bezieht; die Übersetzung der nominal Time in eine konkrete Frame-Nummer passiert innerhalb des Node-Graphen +

+ +
+