diff --git a/tests/steam/play/dummy-builder-context.hpp b/tests/steam/play/dummy-builder-context.hpp index e5c1e1364..1a728f5fd 100644 --- a/tests/steam/play/dummy-builder-context.hpp +++ b/tests/steam/play/dummy-builder-context.hpp @@ -37,6 +37,10 @@ ** _component integration test_ -- yet for this to work, we'd need ** - a fake calculation ** - a fake OutputSlot + ** @todo 5/2026 now I have beefed up the OutputSlot so that it can receive + ** two feeds with an arbitrary number of frames. Still not sure if it's needed; + ** however it should be noted that the MockDispatcher relies on the DummyPlayConnection, + ** which in turn uses SimulatedBuilderContext, mostly to get _just some model ports_. ** ** @see mock-dispatcher.hpp ** @see JobPlanningPipeline_test @@ -47,6 +51,8 @@ #define STEAM_PLAY_DUMMY_BUILDER_CONTEXT_H +#include "lib/error.hpp" +#include "lib/format-string.hpp" #include "steam/mobject/model-port.hpp" #include "steam/fixture/model-port-registry.hpp" #include "vault/out/output-slot-connection.hpp" @@ -61,11 +67,14 @@ #include "lib/util.hpp" #include +#include +#include namespace steam{ namespace play { namespace test { + namespace err = lumiera::error; using fixture::ModelPortRegistry; using vault::mem::Buff; @@ -73,44 +82,83 @@ namespace test { using vault::out::DataSink; using vault::out::FrameID; using lib::time::TimeValue; + using util::_Fmt; + + /** - * @todo 5/2023 quick-n-dirty placeholder to be able to fabricate fake DataSink handles (`Handle`) - */ /////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : after the refactoring of OutputSlot 3/2026 it is not that easy any more. We need a Fake OutputSlot - class UnimplementedConnection - : public vault::out::OutputSlot::Connection - { - size_t getBufferSize() const override { UNIMPLEMENTED ("getBufferSize()"); } - Buff* claimBufferFor (FrameID) override; - void publish (Buff*) override { UNIMPLEMENTED ("publish buffer content"); } - void release (Buff*) override { UNIMPLEMENTED ("complete buffer cycle"); } - void shutDown () override { UNIMPLEMENTED ("shutDown() Connection"); } - - public: - ~UnimplementedConnection(); - UnimplementedConnection() = default; - }; - - - /** - * A placeholder/dummy OutputSlot - * @todo 5/2026 it can barely be created right now; + * A placeholder/dummy OutputSlot that captures all + * delivered output data into heap-allocated memory. + * @todo 5/2026 it can now be created and allocates a fixed layout + * of buffer storage, which implies it should not be copied + * and is thus used differently than a real OutputSlot; * should reconsider what is actually needed here! + * @warning this used to be placeholder code, and now it was adapted + * to store frames, yet this new functionality is untested as of 5/2026 */ - struct FakeSlot + struct FakeOutput : OutputSlot + , util::NonCopyable { - static constexpr uint NUM_CONNECTIONS = 2; + static constexpr uint NUM_FEEDS = 2; static constexpr bool SINGLE_THREADED_TEST = true; - using Connections = lib::ScopedCollection; - using MockConnectState = OutputSlot::AllocState; - FakeSlot() - : OutputSlot{std::make_unique (NUM_CONNECTIONS, Connections::fill())} + using DummyDat = uint64_t; + static constexpr size_t DUMMY_BUFF_SIZ = 1_KiB * sizeof(DummyDat); + + using DummyBuff = std::array; + using DummyBuffSeq = std::deque; + + /** + * @todo 5/2026 quick-n-dirty placeholder code + * to expose some output buffers and provide + * the corresponding DataSink handles + */ + class DummyOutputConnection + : public vault::out::OutputSlot::Connection + { + DummyBuffSeq& buffers_; + + size_t getBufferSize() const override { return DUMMY_BUFF_SIZ; } + Buff* claimBufferFor (FrameID) override; + void publish (Buff*) override { /* fake "publish buffer content" */ } + void release (Buff*) override { /* fake "complete buffer cycle" */ } + void shutDown () override { /* fake "shutDown() Connection" */ } + + public: + ~DummyOutputConnection(); + DummyOutputConnection (DummyBuffSeq& buffers) + : buffers_{buffers} + { } + // OutputSlot::Connection is non-copyable + }; + + using Connections = lib::ScopedCollection; + using MockConnectState = OutputSlot::AllocState; + + using OutBuffs = std::array; + OutBuffs buffers_{}; + + FakeOutput() + : OutputSlot{std::make_unique (NUM_FEEDS + ,[&,i=0](auto& storage) mutable + { + storage.template create (buffers_[i++]); + })} { } }; + inline Buff* + FakeOutput::DummyOutputConnection::claimBufferFor (FrameID fra) + { + REQUIRE (fra >= 0); + if (uint64_t(fra) >= buffers_.size()) + buffers_.resize(fra+10); + return reinterpret_cast (& buffers_[fra]); + } + + using asset::Pipe; using asset::PPipe; using asset::Struct; @@ -159,6 +207,8 @@ namespace test { std::vector modelPorts_; std::vector dataSinks_; + FakeOutput fakeOutput_; + /** setup */ SimulatedBuilderContext() : registry_() @@ -194,11 +244,9 @@ namespace test { modelPorts_.push_back (ModelPort(pipeB)); // prepare corresponding placeholder DataSink (a fake active output connection) - FakeSlot fakeSlot; dataSinks_.clear(); - lib::explore(fakeSlot.getOpenedSinks()) + lib::explore(fakeOutput_.getOpenedSinks()) .effuse (dataSinks_); - // Note: keeps FakeSlot alive (due to embedded ref-count)... } @@ -216,12 +264,32 @@ namespace test { ,dataSinks_[index] }; } - }; - inline vault::mem::Buff* UnimplementedConnection::claimBufferFor (FrameID) + /** + * Access a generated output frame. + * @remark FakeOutput maintains Deque-Storage for each feed. + * @tparam X data type to assume as content of the frame (only checked for size) + * @param feed number of the output feed to access + * @param frame frame numer within the output feed + */ + template + X& + accessOutputBufferAs (uint feed, FrameID frame) { - UNIMPLEMENTED ("claimBufferFor(FrameID)"); + static_assert (sizeof(X) <= FakeOutput::DUMMY_BUFF_SIZ + ,"desired data type would not fit into FakeOutput buffer"); + if (feed >= FakeOutput::NUM_FEEDS) + throw err::Invalid{_Fmt{"Feed #%i > %i allowed"} + % feed % (FakeOutput::NUM_FEEDS-1)}; + + auto availFrames = fakeOutput_.buffers_[feed].size(); + if (frame >= availFrames) + throw err::Invalid{_Fmt{"Frame #%02i > %02i available frames"} + % frame % availFrames}; + + return reinterpret_cast (fakeOutput_.buffers_[feed][frame]); } + }; - }}} // namespace steam::play::test +}}} // namespace steam::play::test #endif /*STEAM_PLAY_DUMMY_BUILDER_CONTEXT_H*/ diff --git a/tests/steam/play/dummy-play-connection.cpp b/tests/steam/play/dummy-play-connection.cpp index be9e25955..e47395c17 100644 --- a/tests/steam/play/dummy-play-connection.cpp +++ b/tests/steam/play/dummy-play-connection.cpp @@ -38,7 +38,7 @@ namespace test { } // (End) hidden service impl details - UnimplementedConnection::~UnimplementedConnection() { } ///< emit VTable here... + FakeOutput::DummyOutputConnection::~DummyOutputConnection() { } ///< emit VTable here...