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
This commit is contained in:
Fischlurch 2023-06-02 02:31:34 +02:00
parent dda37365cc
commit 94fe4a4bec
10 changed files with 261 additions and 69 deletions

View file

@ -69,7 +69,7 @@ namespace lib {
* the use count.
*/
template<class IMP>
class Handle
class Handle
{
protected:
typedef std::shared_ptr<IMP> 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<typename DEL>
@ -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");

View file

@ -374,13 +374,6 @@ namespace lib {
>
{ };
template<class SRC>
struct shall_use_StateCore
: __and_<__not_<can_IterForEach<SRC>>
,is_StateCore<SRC>
>
{ };
template<class SRC>
struct shall_use_Lumiera_Iter
: __and_<can_IterForEach<SRC>

View file

@ -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 <functional>
@ -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<TimeVar> ////////////////////////////////////////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:

View file

@ -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

View file

@ -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<mobject::ModelPort>::iterator ModelPorts;
using ModelPorts = lib::IterSource<mobject::ModelPort>::iterator;
using DummyOutputLink = std::pair<mobject::ModelPort, play::DataSink>;
/**
* @todo 5/2023 quick-n-dirty placeholder to be able to fabricate fake DataSink handles (`Handle<Connection>`)
*/
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<ModelPort> modelPorts_;
std::vector<DataSink> 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<UnimplementedConnection>());
dataSinks_.emplace_back().activate(std::make_shared<UnimplementedConnection>());
}
@ -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()
{

View file

@ -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
}
};

View file

@ -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);
}

View file

@ -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<play::PlayTestFrames_Strategy> 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<MockDispatcherTable> mockDispatcher;
#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1221
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1221
using DummyPlaybackSetup = play::test::DummyPlayConnection<PlayTestFrames_Strategy>;
@ -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<GenNode> 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<ModelPort,DataSink>`
* @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*/

View file

@ -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());

View file

@ -73519,8 +73519,22 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node COLOR="#338800" CREATED="1685635382818" ID="ID_182297187" MODIFIED="1685635412661" TEXT="Vorstufe: die Kern-Funktionalit&#xe4;t direkt als Iterator-Pipeline demonstrieren">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1685635478500" ID="ID_1622487483" MODIFIED="1685635500053" TEXT="geeignetes Builder-API ausarbeiten">
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1685635478500" ID="ID_1622487483" MODIFIED="1685676386317" TEXT="geeignetes Builder-API ausarbeiten">
<linktarget COLOR="#a44d82" DESTINATION="ID_1622487483" ENDARROW="Default" ENDINCLINATION="23;31;" ID="Arrow_ID_1017802335" SOURCE="ID_60016786" STARTARROW="None" STARTINCLINATION="93;-2;"/>
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1685676367077" ID="ID_497119837" MODIFIED="1685676383553" TEXT="Builder-Syntax schaffen">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1685676373201" ID="ID_290916668" MODIFIED="1685676382028" TEXT="soll von TreeExplorer erben">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1685676390323" ID="ID_1302265239" MODIFIED="1685676394025" TEXT="geht das?">
<icon BUILTIN="help"/>
<node CREATED="1685676395607" ID="ID_840485660" MODIFIED="1685676404942" TEXT="erinnere mich an den EventLog-Filter"/>
<node CREATED="1685676405602" ID="ID_1339853853" MODIFIED="1685676416909" TEXT="das l&#xe4;uft auf einen decltype-Trick hinaus">
<icon BUILTIN="idea"/>
</node>
</node>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1685583497277" ID="ID_1911386159" MODIFIED="1685583620738" TEXT="sinnvolles Erg&#xe4;nzungs-API bereitstellen">
@ -73541,10 +73555,92 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1685066492396" ID="ID_1906962794" MODIFIED="1685066501049" TEXT="API f&#xfc;r Zugriff kl&#xe4;ren">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1685676202669" ID="ID_1528500239" MODIFIED="1685676214053" TEXT="analog zu MockSegmentation">
<icon BUILTIN="yes"/>
</node>
<node COLOR="#338800" CREATED="1685676215324" ID="ID_1375641669" MODIFIED="1685676224971" TEXT="MockDispatcher kann einfach instantiiert werden">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1685676225634" ID="ID_201099858" MODIFIED="1685676286815" TEXT="er h&#xe4;lt intern eine DummyPlayConnection">
<arrowlink COLOR="#58b681" DESTINATION="ID_161203143" ENDARROW="Default" ENDINCLINATION="79;-62;" ID="Arrow_ID_502535652" STARTARROW="None" STARTINCLINATION="90;6;"/>
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1685676320949" ID="ID_60016786" MODIFIED="1685676362183" TEXT="ein neuer Builder wird in der Dispatcher-Basisklasse implementiert">
<arrowlink COLOR="#a44d82" DESTINATION="ID_1622487483" ENDARROW="Default" ENDINCLINATION="23;31;" ID="Arrow_ID_1017802335" STARTARROW="None" STARTINCLINATION="93;-2;"/>
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1685066474347" ID="ID_122826612" MODIFIED="1685066485373" TEXT="Grid in den Mock-Dispatcher legen">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1685662239880" ID="ID_1505090088" MODIFIED="1685662250525" TEXT="brauche ModelPort und Sink-Instanzen">
<icon BUILTIN="flag-pink"/>
<node CREATED="1685662251607" ID="ID_1360980940" MODIFIED="1685662442877" TEXT="t&#xfc;ckisches Problem....">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...oder genauer gesagt, ein Design-Mismatch &#8212; das ganze ID-System in Lumiera ist <i>magisch</i>&#160;und &#8222;hintenrum&#8220; mit globalen Tabellen verbunden; <i>damals</i>&#160;erschien mir das gradezu nat&#252;rlich, <i>heute</i>&#160;sehe ich leider keine bessere L&#246;sung, die man in C++ realisieren kann (Scala l&#246;st dieses Problem mit den Implicits bzw. Givens)
</p>
</body>
</html></richcontent>
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1685662448009" ID="ID_881674588" MODIFIED="1685662511675" TEXT="andererseits ist Lumiera &#x201e;blo&#xdf;&#x201c; eine Applikation">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...und nicht das ultimative Medien-Framework!!
</p>
<p>
....also ist es durchaus im Rahmen, wenn es eine fest vereinbarte Hintert&#252;r gibt f&#252;r die Tests
</p>
</body>
</html></richcontent>
<icon BUILTIN="yes"/>
</node>
<node CREATED="1685662517358" ID="ID_161203143" MODIFIED="1685676286816">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
es lebe die <b><font face="Monospaced" color="#3d1ca2">DummyPlayConnection</font></b>
</p>
</body>
</html></richcontent>
<linktarget COLOR="#58b681" DESTINATION="ID_161203143" ENDARROW="Default" ENDINCLINATION="79;-62;" ID="Arrow_ID_502535652" SOURCE="ID_201099858" STARTARROW="None" STARTINCLINATION="90;6;"/>
<icon BUILTIN="idea"/>
<node CREATED="1685676072753" ID="ID_29155074" MODIFIED="1685676082592" TEXT="dort gibt es schon zwei fake-ModelPorts">
<icon BUILTIN="idea"/>
</node>
<node COLOR="#338800" CREATED="1685676083734" ID="ID_1387602910" MODIFIED="1685676114044" TEXT="nun auch noch zwei korrespondierende DataSink hinzugef&#xfc;gt">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1685676098707" ID="ID_970617797" MODIFIED="1685676172210" TEXT="und als Platzhalter: UnimplementedConnection">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
DataSink ist ein lib::Handle&lt;play::OutputSlot::Connection&gt;
</p>
<p>
Also mu&#223; es im einfachsten Fall auf eine Subklasse von Connection zeigen; diese f&#252;ge ich hinzu mit lauter UNIMPLEMENTED stubs
</p>
</body>
</html></richcontent>
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1681742836996" ID="ID_1790705283" MODIFIED="1684878198471" TEXT="invoke the dispatcher to retrieve the top-level JobTicket">