From 94fe4a4becce3ca133e116d4e46ded47d460193e Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 2 Jun 2023 02:31:34 +0200 Subject: [PATCH] Dispatcher-Pipeline: draft builder-API ...which leads to the next daunting problems: - we need some mocked ModelPort and DataSink placeholders - we need a way how to inherit from a partial TreeExplorer pipeline --- src/lib/handle.hpp | 11 +- src/lib/iter-tree-explorer.hpp | 7 -- src/steam/engine/dispatcher.hpp | 22 ++++ src/steam/play/dummy-play-connection.cpp | 9 +- src/steam/play/dummy-play-connection.hpp | 49 +++++++- .../engine/dispatcher-interface-test.cpp | 2 +- .../steam/engine/job-planning-setup-test.cpp | 15 ++- tests/core/steam/engine/mock-dispatcher.hpp | 115 +++++++++++------- .../steam/play/dummy-play-connection-test.cpp | 2 +- wiki/thinkPad.ichthyo.mm | 98 ++++++++++++++- 10 files changed, 261 insertions(+), 69 deletions(-) diff --git a/src/lib/handle.hpp b/src/lib/handle.hpp index 0a05d34b8..bf9aabca8 100644 --- a/src/lib/handle.hpp +++ b/src/lib/handle.hpp @@ -69,7 +69,7 @@ namespace lib { * the use count. */ template - class Handle + class Handle { protected: typedef std::shared_ptr SmPtr; @@ -107,7 +107,7 @@ namespace lib { /** Activation of the handle by the managing service. * @param impl the implementation object this handle is tied to - * @param whenDead functor to be invoked when reaching end-of-life + * @param whenDead functor to be invoked when reaching end-of-life * @throw std::bad_alloc, in which case \c whenDead(impl) is invoked */ template @@ -140,12 +140,15 @@ namespace lib { * went out of scope, the associated implementation * reaches end-of-life. */ - void close () { smPtr_.reset(); } + void close () + { + smPtr_.reset(); + } protected: - IMP& + IMP& impl() const { REQUIRE (smPtr_.get(), "Lifecycle-Error"); diff --git a/src/lib/iter-tree-explorer.hpp b/src/lib/iter-tree-explorer.hpp index e672d0f9b..b78ce532c 100644 --- a/src/lib/iter-tree-explorer.hpp +++ b/src/lib/iter-tree-explorer.hpp @@ -374,13 +374,6 @@ namespace lib { > { }; - template - struct shall_use_StateCore - : __and_<__not_> - ,is_StateCore - > - { }; - template struct shall_use_Lumiera_Iter : __and_ diff --git a/src/steam/engine/dispatcher.hpp b/src/steam/engine/dispatcher.hpp index 243bacbe4..1db71684f 100644 --- a/src/steam/engine/dispatcher.hpp +++ b/src/steam/engine/dispatcher.hpp @@ -42,6 +42,7 @@ #include "steam/engine/frame-coord.hpp" #include "steam/engine/job-ticket.hpp" #include "steam/engine/job-planning.hpp" +#include "steam/play/output-slot.hpp" #include "lib/time/timevalue.hpp" #include @@ -52,6 +53,8 @@ namespace engine { using std::function; using mobject::ModelPort; + using play::Timings; + using play::DataSink; using lib::time::FrameCnt; using lib::time::TimeSpan; using lib::time::FSecs; @@ -84,6 +87,7 @@ namespace engine { class Dispatcher : public FrameLocator { +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1301 : obsolete struct JobBuilder { Dispatcher* dispatcher_; @@ -100,12 +104,30 @@ namespace engine { *dispatcher_); } }; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1301 : obsolete + + struct PipelineBuilder + : lib::SingleValIter ////////////////////////////////////////OOO placeholder type; should rather be a TreeExplorer! + { + PipelineBuilder& + timeRange (Time start, Time after) + { + UNIMPLEMENTED ("setup dispatch time range"); + } + }; public: virtual ~Dispatcher(); ///< this is an interface +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1301 : obsolete JobBuilder onCalcStream (ModelPort modelPort, uint channel); +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1301 : obsolete + + PipelineBuilder forCalcStream(Timings timings, ModelPort port, DataSink sink) + { + UNIMPLEMENTED ("create Pipeline builder"); + } protected: diff --git a/src/steam/play/dummy-play-connection.cpp b/src/steam/play/dummy-play-connection.cpp index bc734034b..d75fda100 100644 --- a/src/steam/play/dummy-play-connection.cpp +++ b/src/steam/play/dummy-play-connection.cpp @@ -37,18 +37,21 @@ -namespace steam { +namespace steam{ namespace play { +namespace test { namespace { // hidden local details of the service implementation.... + } // (End) hidden service impl details + UnimplementedConnection::~UnimplementedConnection() { } ///< emit VTable here... - /** */ + /** */ -}} // namespace steam::play +}}} // namespace steam::play diff --git a/src/steam/play/dummy-play-connection.hpp b/src/steam/play/dummy-play-connection.hpp index 7655b6156..36f557197 100644 --- a/src/steam/play/dummy-play-connection.hpp +++ b/src/steam/play/dummy-play-connection.hpp @@ -82,6 +82,7 @@ //#include "include/display-facade.h" //#include "common/instancehandle.hpp" //#include "lib/singleton-ref.hpp" +#include "steam/play/output-slot-connection.hpp" #include "steam/play/output-manager.hpp" #include "steam/mobject/model-port.hpp" #include "lib/time/timequant.hpp" @@ -108,7 +109,29 @@ namespace test { // using lumiera::DummyPlayer; using lib::time::Duration; - typedef lib::IterSource::iterator ModelPorts; + using ModelPorts = lib::IterSource::iterator; + + using DummyOutputLink = std::pair; + + /** + * @todo 5/2023 quick-n-dirty placeholder to be able to fabricate fake DataSink handles (`Handle`) + */ + class UnimplementedConnection + : public play::OutputSlot::Connection + { + BuffHandle claimBufferFor(FrameID) override { UNIMPLEMENTED ("claimBufferFor(FrameID)"); } + bool isTimely (FrameID, TimeValue) override { return true; } + void transfer (BuffHandle const&) override { UNIMPLEMENTED ("transfer (BuffHandle const&)"); } + void pushout (BuffHandle const&) override { UNIMPLEMENTED ("pushout (BuffHandle const&)"); } + void discard (BuffHandle const&) override { UNIMPLEMENTED ("discard (BuffHandle const&)"); } + void shutDown () override { UNIMPLEMENTED ("shutDown() Connection"); } + + public: + ~UnimplementedConnection(); + UnimplementedConnection() = default; + }; + + struct PlayTestFrames_Strategy @@ -153,7 +176,7 @@ namespace test { const string namePortA("bus-A"); const string namePortB("bus-B"); - /** + /** * helper for dummy render engine: * Simulate the result of a build process, * without actually running the builder. @@ -165,6 +188,7 @@ namespace test { ModelPortRegistry* existingRegistry_; std::vector modelPorts_; + std::vector dataSinks_; /** setup */ SimulatedBuilderContext() @@ -199,6 +223,10 @@ namespace test { // now "bus-A" and "bus-B" are known as model ports modelPorts_.push_back (ModelPort(pipeA)); modelPorts_.push_back (ModelPort(pipeB)); + + // prepare corresponding placeholder DataSink (a fake active output connection) + dataSinks_.emplace_back().activate(std::make_shared()); + dataSinks_.emplace_back().activate(std::make_shared()); } @@ -207,6 +235,15 @@ namespace test { { return lib::iter_source::eachEntry (modelPorts_.begin(), modelPorts_.end()); } + + DummyOutputLink + getModelPort (uint index) + { + REQUIRE (index < modelPorts_.size()); + return {modelPorts_[index] + ,dataSinks_[index] + }; + } }; } @@ -230,11 +267,17 @@ namespace test { public: ModelPorts - provide_testModelPorts() + getAllModelPorts() { return mockBuilder_.getAllModelPorts(); } + DummyOutputLink + getModelPort (uint index) + { + return mockBuilder_.getModelPort (index); + } + POutputManager provide_testOutputSlot() { diff --git a/tests/core/steam/engine/dispatcher-interface-test.cpp b/tests/core/steam/engine/dispatcher-interface-test.cpp index 5c35ee910..185abe774 100644 --- a/tests/core/steam/engine/dispatcher-interface-test.cpp +++ b/tests/core/steam/engine/dispatcher-interface-test.cpp @@ -107,7 +107,7 @@ namespace test { ModelPort provideMockModelPort() { - ModelPorts mockModelPorts = dummySetup_.provide_testModelPorts(); + ModelPorts mockModelPorts = dummySetup_.getAllModelPorts(); return *mockModelPorts; // using just the first dummy port } }; diff --git a/tests/core/steam/engine/job-planning-setup-test.cpp b/tests/core/steam/engine/job-planning-setup-test.cpp index 2c5ba9803..e3f69f84b 100644 --- a/tests/core/steam/engine/job-planning-setup-test.cpp +++ b/tests/core/steam/engine/job-planning-setup-test.cpp @@ -157,18 +157,27 @@ namespace test { void buildBaseTickGenerator() { - auto grid = frameGrid(FrameRate::PAL); + auto grid = frameGrid(FrameRate::PAL); // one frame ≙ 40ms CHECK (materialise ( treeExplore (eachNum(5,13)) - .transform([&](FrameCnt frameNr) -> TimeVar + .transform([&](FrameCnt frameNr) -> TimeVar //////////////////////////////////TICKET #1261 : transform-iterator unable to handle immutable time { return grid->timeOf (frameNr); }) ) == "200ms-240ms-280ms-320ms-360ms-400ms-440ms-480ms"_expect); - UNIMPLEMENTED ("foundation of state core"); + + MockDispatcher dispatcher; + play::Timings timings (FrameRate::PAL); + auto [port,sink] = dispatcher.getDummyConnection(0); + + auto pipeline = dispatcher.forCalcStream(timings, port, sink) + .timeRange(Time{200,0}, Time{480,0}); + + CHECK (materialise (pipeline) + == "200ms-240ms-280ms-320ms-360ms-400ms-440ms-480ms"_expect); } diff --git a/tests/core/steam/engine/mock-dispatcher.hpp b/tests/core/steam/engine/mock-dispatcher.hpp index 5f322d0c9..f57090e22 100644 --- a/tests/core/steam/engine/mock-dispatcher.hpp +++ b/tests/core/steam/engine/mock-dispatcher.hpp @@ -46,6 +46,7 @@ #include "lib/test/test-helper.hpp" +#include "steam/play/dummy-play-connection.hpp" #include "steam/fixture/segmentation.hpp" #include "steam/mobject/model-port.hpp" #include "steam/engine/dispatcher.hpp" @@ -78,56 +79,13 @@ namespace test { namespace { // used internally -// using play::PlayTestFrames_Strategy; -// using play::ModelPorts; + using play::test::ModelPorts; + using play::test::PlayTestFrames_Strategy; using vault::engine::JobClosure; using vault::engine::JobParameter; using vault::engine::DummyJob; -// typedef play::DummyPlayConnection DummyPlaybackSetup; - - - class MockDispatcherTable - : public Dispatcher - { - -// DummyPlaybackSetup dummySetup_; - - - /* == mock Dispatcher implementation == */ - - FrameCoord - locateRelative (FrameCoord const&, FrameCnt frameOffset) - { - UNIMPLEMENTED ("dummy implementation of the core dispatch operation"); - } - - bool - isEndOfChunk (FrameCnt, ModelPort port) - { - UNIMPLEMENTED ("determine when to finish a planning chunk"); - } - - JobTicket& - accessJobTicket (ModelPort, TimeValue nominalTime) - { - UNIMPLEMENTED ("dummy implementation of the model backbone / segmentation"); - } - - public: - - ModelPort - provideMockModelPort() - { -// ModelPorts mockModelPorts = dummySetup_.provide_testModelPorts(); -// return *mockModelPorts; // using just the first dummy port - } - }; - - /// @deprecated this setup is confusing and dangerous (instance identity is ambiguous) - lib::Depend mockDispatcher; -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1221 -#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1221 + using DummyPlaybackSetup = play::test::DummyPlayConnection; @@ -299,5 +257,70 @@ namespace test { } + + class MockDispatcher + : public Dispatcher + { + + DummyPlaybackSetup dummySetup_; + MockSegmentation mockSeg_; + + + /* == mock Dispatcher implementation == */ + + FrameCoord + locateRelative (FrameCoord const&, FrameCnt frameOffset) + { + UNIMPLEMENTED ("dummy implementation of the core dispatch operation"); + } + + bool + isEndOfChunk (FrameCnt, ModelPort port) + { + UNIMPLEMENTED ("determine when to finish a planning chunk"); + } + + JobTicket& + accessJobTicket (ModelPort, TimeValue nominalTime) + { + UNIMPLEMENTED ("dummy implementation of the model backbone / segmentation"); + } + + public: + + MockDispatcher() = default; + + MockDispatcher (std::initializer_list specs) + : mockSeg_(specs) + { } + + + ModelPort + provideMockModelPort() + { + ModelPorts mockModelPorts = dummySetup_.getAllModelPorts(); + return *mockModelPorts; // using just the first dummy port + } + + /** + * The faked builder/playback setup provides some preconfigured ModelPort and + * corresponding DataSink handles. These are stored into a dummy registry and only available + * during the lifetime of the DummyPlaybackSetup instance. + * @param index number of the distinct port / connection + * @return a `std::pair` + * @warning as of 5/2023, there are two preconfigured "slots", + * and they are not usable in any way other then refering to their identity + */ + play::test::DummyOutputLink + getDummyConnection(uint index) + { + return dummySetup_.getModelPort (index); + } + }; + +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1221 +#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1221 + + }}} // namespace steam::engine::test #endif /*STEAM_ENGINE_TEST_MOCK_DISPATCHER_H*/ diff --git a/tests/core/steam/play/dummy-play-connection-test.cpp b/tests/core/steam/play/dummy-play-connection-test.cpp index 1c57108e3..db21f7661 100644 --- a/tests/core/steam/play/dummy-play-connection-test.cpp +++ b/tests/core/steam/play/dummy-play-connection-test.cpp @@ -75,7 +75,7 @@ namespace test { CHECK (!dummy.isWired()); Play::Controller player - = Play::facade().perform ( dummy.provide_testModelPorts() + = Play::facade().perform ( dummy.getAllModelPorts() , dummy.provide_testOutputSlot()); CHECK ( dummy.isWired()); diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index caa850860..993d97633 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -73519,8 +73519,22 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + + + + + + + + + + + + + + @@ -73541,10 +73555,92 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + + + + + + + + + + + + + + +

+ ...oder genauer gesagt, ein Design-Mismatch — das ganze ID-System in Lumiera ist magisch und „hintenrum“ mit globalen Tabellen verbunden; damals erschien mir das gradezu natürlich, heute sehe ich leider keine bessere Lösung, die man in C++ realisieren kann (Scala löst dieses Problem mit den Implicits bzw. Givens) +

+ +
+ +
+ + + + + + +

+ ...und nicht das ultimative Medien-Framework!! +

+

+ ....also ist es durchaus im Rahmen, wenn es eine fest vereinbarte Hintertür gibt für die Tests +

+ +
+ +
+ + + + + + +

+ es lebe die DummyPlayConnection +

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

+ DataSink ist ein lib::Handle<play::OutputSlot::Connection> +

+

+ Also muß es im einfachsten Fall auf eine Subklasse von Connection zeigen; diese füge ich hinzu mit lauter UNIMPLEMENTED stubs +

+ +
+ +
+
+