BufferProvider: re-assessment of OutputSlot API requirements

One of the goals of this extended clean-up and refactoring is to allow
access to the data buffers of a `DataSink` through a `BuffHandle` as front-end.
Which essentially means that the ''Buffer Provider Protocol'' and the
''Output Slot Protocol'' mesh together well.

After the clean-up of the `BufferProvider` implementation hierarchy,
the viability of this idea was demonstrated with the `BufferProxyAdapter` draft;
so it is now roughly clear what must be changed within the existing implementation
of `OutputSlot`. More specifically, the only actual implementation ever completed
was a dummy implementation for test (`DiagnosticOutputSlot`), which hooked
confusingly into the corresponding dummy implementation of `BufferProvider`,
that was written one year earlier (and was also without actual implementation
at that time).

So the second half of the task ahead seems very similar to the first part:
 - the base implementation of the ''Output Slot Protocol'' seems roughly acceptable
 - but the actual dummy implementation was somewhat confused and should be
   re-written from scratch, without ''any attempt to cut corners by re-using other dummy code''


__Note__ as part of this analysis I discovered some gap in the design
regarding timeout handling ⟶ Ticket #1417
This commit is contained in:
Fischlurch 2026-03-10 19:57:41 +01:00
parent 7dee16ba90
commit 4fa18cf1d2
5 changed files with 562 additions and 63 deletions

View file

@ -86,7 +86,7 @@ namespace test {
PID pipe = Pipe::query("id(dummy)");
ModelPort port(pipe);
OutputSlot& oSlot = DiagnosticOutputSlot::build();
DiagnosticOutputSlot oSlot;
Allocation& output = oSlot.allocate();
Timings timings (FrameRate::PAL); /////////TODO

View file

@ -27,23 +27,27 @@
#include "include/logging.h"
#include "steam/play/output-slot.hpp"
#include "steam/play/output-slot-connection.hpp"
#include "steam/asset/meta/time-grid.hpp"
#include "vault/mem/buffhandle.hpp"
#include "vault/mem/naive-buffer-setup.hpp"
#include "lib/time/timevalue.hpp"
#include "lib/scoped-ptrvect.hpp"
#include "lib/iter-source.hpp"
#include "lib/time/grid.hpp"
#include "lib/p.hpp"
#include "lib/null-value.hpp"
#include "lib/iter-explorer.hpp"
#include "lib/iter-source.hpp" /////////////OOO wech
#include "lib/symbol.hpp"
#include "lib/util.hpp"
#include "vessel/advice.hpp"
#include "test/test-frame.hpp"
#include <unordered_set>
#include <vector>
#include <memory>
namespace steam {
namespace play {
namespace err = lumiera::error;
using lib::Symbol;
using lib::HashVal;
@ -51,19 +55,23 @@ namespace play {
using util::contains;
using test::TestFrame;
using lib::time::FrameRate;
using steam::asset::meta::PGrid;
using steam::asset::meta::TimeGrid;
using lib::time::TimeVar;
using lib::time::Time;
using vault::mem::NaiveBufferSetup;
using vault::mem::BuffHandle;
using vault::mem::BuffDescr;
using std::shared_ptr;
using PGrid = lib::P<lib::time::Grid>;
namespace { // diagnostics & internals....
inline PGrid
getTestTimeGrid()
{
#if false //////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : disabled code to disentangle BufferProvider implementation
Symbol gridID("DiagnosticOutputSlot-buffer-grid");
vessel::advice::Request<PGrid> query4grid(gridID) ;
PGrid testGrid25 = query4grid.getAdvice();
@ -72,7 +80,9 @@ namespace play {
testGrid25 = TimeGrid::build (gridID, FrameRate::PAL);
ENSURE (testGrid25);
return testGrid25;
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : (end) disabled code
PGrid testGrid; ////////OOO Kaboooom!
return testGrid;
}
}
@ -247,10 +257,73 @@ namespace play {
};
///////////////////////////////////////////////////////////////////////
/// ///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1395 : draft compatible Tracking-API
namespace diagn {
using Buff = vault::mem::Buff;
struct FraInfo
{
TimeVar locked{Time::NEVER};
TimeVar emitted{Time::NEVER};
TimeVar released{Time::NEVER};
bool wasLocked() const { return locked != Time::NEVER; }
bool wasEmitted() const { return locked != Time::NEVER; }
bool wasReleased() const { return locked != Time::NEVER; }
size_t buffSize{0};
Buff* storage{nullptr};
Buff* accessMemory() const { return storage; }
template<typename BU>
BU const& accessAs() const;
template<typename BU>
bool operator== (BU const&) const;
};
struct FeedLog
{
FraInfo const&
frame (uint fraNr) const
{
///////////////////////////OOO access stored log
return lib::NullValue<FraInfo>::get();
}
auto
blockIter(uint startFrame =0) const
{
return lib::explore (lib::NumIter{startFrame, std::numeric_limits<uint>::max()})
.transform([this](uint idx){ return frame(idx); })
;
}
};
template<typename BU>
inline BU const&
FraInfo::accessAs() const
{
if (not storage)
throw err::Logic ("buffer for this frame was never actually locked"
, LERR_(LIFECYCLE));
return *reinterpret_cast<BU const*> (storage);
}
template<typename BU>
inline bool
FraInfo::operator== (BU const& refVal) const
{
return storage
and accessAs<BU>() == refVal;
}
}//(End)Diagnostic data
class OutputDiagnostic;
@ -271,7 +344,7 @@ namespace play {
: public OutputSlotImplBase
{
static const uint MAX_CHANNELS = 5;
static const uint MAX_CHANNELS = 5; ///////////////////////////////OOO Build heap-based implementation with arbitrary number of feeds!!
/** @note a real OutputSlot implementation
* would rely on some kind of embedded
@ -279,7 +352,7 @@ namespace play {
uint
getOutputChannelCount()
{
return MAX_CHANNELS;
return MAX_CHANNELS; /////////////OOO No!
}
@ -296,7 +369,9 @@ namespace play {
void
buildConnection(ConnectionStorage storage)
{
#if false //////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : disabled code to disentangle BufferProvider implementation
storage.create<TrackingInMemoryBlockSequence>();
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : (end) disabled code
}
public:
@ -317,9 +392,6 @@ namespace play {
getOutputChannelCount());
}
/** @internal is self-managed and non-copyable.
* Clients use #build() to get an instance */
DiagnosticOutputSlot() { }
/** @internal access the implementation object
* representing a single stream connection
@ -334,21 +406,8 @@ namespace play {
public:
/** build a new Diagnostic Output Slot instance,
* discard the existing one. Use the static query API
* for investigating collected data. */
static OutputSlot&
build()
{
static lib::ScopedPtrVect<OutputSlot> diagnosticSlots;
return diagnosticSlots.manage(new DiagnosticOutputSlot);
}
DiagnosticOutputSlot() { }
static DiagnosticOutputSlot&
access (OutputSlot& to_investigate)
{
return dynamic_cast<DiagnosticOutputSlot&> (to_investigate);
}
@ -394,18 +453,22 @@ namespace play {
OutFrames
getChannel (uint channel)
{
#if false //////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : disabled code to disentangle BufferProvider implementation
REQUIRE (channel < MAX_CHANNELS);
return OutputFramesLog::build(
new OutputFramesLog (
accessSequence(channel)));
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : (end) disabled code
}
bool
frame_was_allocated (uint channel, FrameID nominalFrame)
{
#if false //////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : disabled code to disentangle BufferProvider implementation
return accessSequence(channel)
.wasAllocated(nominalFrame);
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : (end) disabled code
}
@ -431,8 +494,54 @@ namespace play {
and block->was_closed();
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : (end) disabled code
}
///////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1395 : draft compatible Tracking-API
std::vector<diagn::FeedLog> feed_;
private:
/// „backdoor“ to watch instrumentation from tests
friend class OutputDiagnostic;
};
/** Accessor-proxy to investigate transactions */
class OutputDiagnostic
: util::MoveOnly
{
DiagnosticOutputSlot& dos_;
public:
OutputDiagnostic (DiagnosticOutputSlot& theSlot)
: dos_{theSlot}
{ }
uint cntLocked() { return 0; }
uint cntEmitted() { return 0; }
uint cntReleased() { return 0; }
auto const&
feed (uint feedNr)
{
if (feedNr < dos_.feed_.size())
return dos_.feed_[feedNr];
else
return lib::NullValue<diagn::FeedLog>::get();
}
auto
getFeed (uint feedNr)
{
return feed(feedNr).blockIter();
}
};
inline OutputDiagnostic
watch (OutputSlot& theSlot)
{
return OutputDiagnostic{static_cast<DiagnosticOutputSlot&> (theSlot)};
}
}} // namespace steam::play

View file

@ -56,7 +56,7 @@ namespace test {
// In real usage, the OutputSlot will be preconfigured
// (Media format, number of channels, physical connections)
// and then registered with / retrieved from an OutputManager
OutputSlot& oSlot = DiagnosticOutputSlot::build();
DiagnosticOutputSlot oSlot;
// Client claims the OutputSlot
// and opens it for exclusive use.
@ -66,47 +66,55 @@ namespace test {
// "calculation streams" for the individual
// Channels to be output through this slot.
OutputSlot::OpenedSinks sinks = alloc.getOpenedSinks();
DataSink sink1 = *sinks;
DataSink sink2 = *++sinks;
DataSink sink0 = *sinks;
DataSink sink1 = *++sinks;
// within the frame-calculation "loop"
// we perform a data exchange cycle
FrameCnt frameNr = 123;
BuffHandle buff00 = sink1.lockBufferFor (frameNr);
BuffHandle buff10 = sink2.lockBufferFor (frameNr);
BuffHandle buff00 = sink0.lockBufferFor (frameNr);
BuffHandle buff10 = sink1.lockBufferFor (frameNr);
// rendering process calculates content....
buff00.accessAs<TestFrame>() = testData(0,0);
// while further frames might be processed in parallel
BuffHandle buff11 = sink2.lockBufferFor (++frameNr);
BuffHandle buff11 = sink1.lockBufferFor (frameNr+1);
buff11.accessAs<TestFrame>() = testData(1,1);
buff10.accessAs<TestFrame>() = testData(1,0);
// Now it's time to emit the output
sink2.emit (frameNr-1, buff10);
sink2.emit (frameNr , buff11);
sink1.emit (frameNr-1, buff00);
buff11.emit();
buff00.emit();
// Buffers must be marked as released when done
buff00.release();
buff10.release();
buff11.release();
// that's all for the client
// Verify sane operation....
DiagnosticOutputSlot& checker = DiagnosticOutputSlot::access(oSlot);
CHECK ( checker.frame_was_allocated (0,123));
CHECK (!checker.frame_was_allocated (0,124));
CHECK ( checker.frame_was_allocated (1,123));
CHECK ( checker.frame_was_allocated (1,124));
CHECK (watch(oSlot).cntLocked() == 3);
CHECK (watch(oSlot).cntEmitted() == 2);
CHECK (watch(oSlot).cntReleased() == 3);
CHECK (checker.output_was_closed (0,0));
CHECK (checker.output_was_closed (1,0));
CHECK (checker.output_was_closed (1,1));
CHECK ( watch(oSlot).feed(0).frame(123).wasLocked());
CHECK (not watch(oSlot).feed(0).frame(124).wasLocked());
CHECK ( watch(oSlot).feed(1).frame(123).wasLocked());
CHECK ( watch(oSlot).feed(1).frame(124).wasLocked());
CHECK ( checker.output_was_emitted (0,0));
CHECK (!checker.output_was_emitted (0,1));
CHECK ( checker.output_was_emitted (1,0));
CHECK ( checker.output_was_emitted (1,1));
CHECK ( watch(oSlot).feed(0).frame(123).wasEmitted());
CHECK (not watch(oSlot).feed(0).frame(124).wasEmitted());
CHECK (not watch(oSlot).feed(1).frame(123).wasEmitted());
CHECK ( watch(oSlot).feed(1).frame(124).wasEmitted());
DiagnosticOutputSlot::OutFrames stream0 = checker.getChannel(0);
DiagnosticOutputSlot::OutFrames stream1 = checker.getChannel(1);
CHECK ( watch(oSlot).feed(0).frame(123).wasReleased());
CHECK (not watch(oSlot).feed(0).frame(124).wasReleased());
CHECK ( watch(oSlot).feed(1).frame(123).wasReleased());
CHECK ( watch(oSlot).feed(1).frame(124).wasReleased());
auto stream0 = watch(oSlot).getFeed(0);
auto stream1 = watch(oSlot).getFeed(1);
CHECK ( stream0);
CHECK (*stream0 == testData(0,0)); ++stream0;

View file

@ -5151,7 +5151,7 @@ Thus the mapping is a copyable value object, using an associative array. It may
First and foremost, mapping can be seen as a //functional abstraction.// As it's used at implementation level, encapsulation of detail types in't the primary concern, so it's a candidate for generic programming: For each of those use cases outlined above, a distinct mapping type is created by instantiating the {{{OutputMapping&lt;DEF&gt;}}} template with a specifically tailored definition context ({{{DEF}}}), which takes on the role of a strategy. Individual instances of this concrete mapping type may be default created and copied freely. This instantiation process includes picking up the concrete result type and building a functor object for resolving on the fly. Thus, in the way typical for generic programming, the more involved special details are moved out of sight, while being still in scope for the purpose of inlining. But there //is// a concern better to be encapsulated and concealed at the usage site, namely accessing the rules system. Thus mapping leads itself to the frequently used implementation pattern where there is a generic frontend as header, calling into opaque functions embedded within a separate compilation unit.
</pre>
</div>
<div title="OutputSlot" modifier="Ichthyostega" created="201106162339" modified="202602082122" tags="def Concepts Player spec img" changecount="7">
<div title="OutputSlot" modifier="Ichthyostega" created="201106162339" modified="202603101557" tags="def Concepts Player spec img" changecount="16">
<pre>Within the Lumiera player and output subsystem, actually sending data to an external output requires to allocate an ''output slot''
This is the central metaphor for the organisation of actual (system level) outputs; using this concept allows to separate and abstract the data calculation and the organisation of playback and rendering from the specifics of the actual output sink. Actual output possibilities (video in GUI window, video fullscreen, using a beamer, sound, Jack, rendering to file) can be added and removed dynamically from various components (Vault, Stage), all using the same resolution and mapping mechanisms (&amp;rarr; OutputManagement)
@ -5164,23 +5164,25 @@ In order to be usable as //output sink,// an output slot needs to be //allocated
Once allocated, the output slot returns a set of concrete ''sink handles'' (one for each physical channel expecting data). The calculating process feeds its results into those handles. Size and other characteristics of the data frames are assumed to be suitable, which typically won't be verified at that level anymore (but the sink handle provides a hook for assertions). Besides that, the allocation of an output slot reveals detailed ''timing expectations''. The client is required to comply to these [[timings|Timings]] when ''emitting'' data -- he's even required to provide a //current time specification,// alongside with the data. Based on this information, the output slot has the ability to handle timing failures gracefully; the concrete output slot implementation is expected to provide some kind of de-click or de-flicker facility, which kicks in automatically when a timing failure is detected.
!!!usage and implementation
Clients retrieve a reference to an output slot by asking a suitable OutputManager for an output possibility supporting a specific format. Usually, they just &quot;claim&quot; this slot by invoking {{{allocate()}}}, which behind the scenes causes building of the actual output connections and mechanisms. For each such connection -- corresponding to a single channel within the media format handled by this ~OutputSlot -- the client gets a smart-handle {{{DataSink}}}. The concrete ~OutputSlot implementation performs operations quite specific to the kind of output and external interface in question -- thereby calling directly into a specific connection implementation.
Clients retrieve a reference to an output slot by asking a suitable OutputManager for an output possibility that supports some specific media and format. Usually, they just &quot;claim&quot; this slot by invoking {{{allocate()}}}, which causes actual output connections to be built and data handover mechanisms to be established, behind the scenes. For each such connection -- corresponding to a single distinct data feed within the media format handled by this ~OutputSlot -- the client gets a smart-handle {{{DataSink}}}. The feed may, or may not correspond to a nominal channel in the media format, since some output interfaces require to deliver the data in separate buffers per channel, while others require data to be interleaved. Generally speaking, the concrete ~OutputSlot implementation performs operations rather specific to the kind of output and external interface in question -- thereby calling directly into a specific connection implementation. The »''Output Slot Protocol''« however is designed in a way to abstract from all those technical details.
!!!timing expectations
Besides the sink handles, allocation of an output slot defines some timing constraints, to which the client must comply. These [[Timings]] are detailed and explicit, including a grid of deadlines for each frame to deliver, plus a fixed //latency.// Within this context, &amp;raquo;latency&amp;laquo; means the requirement to be ahead of the nominal time by a certain amount, to compensate for the processing time necessary to propagate the media to the physical output pin. The output slot implementation itself is bound by external constraints to deliver data at a fixed framerate and aligned to an externally defined timing grid, plus the data needs to be handed over ahead of these time points by an time amount given by the latency. Depending on the data exchange model, there is an additional time window limiting the buffer management.
Besides the sink handles, allocation of an output slot defines some timing constraints, to which the client must comply. These [[Timings]] are detailed and explicit, including a grid of deadlines for each frame to deliver, plus a fixed //latency.// Within this context, &amp;raquo;latency&amp;laquo; implies a requirement to be ahead of the nominal time by a certain amount, to compensate for the processing time that is necessary to propagate the media to the physical output pin. The output slot implementation itself is bound by external constraints to deliver data at a fixed framerate and aligned to an externally defined timing grid, and furthermore the data needs to be handed over ahead of these time points by an time amount given by the latency. Depending on the data exchange model, additional timing constraints may be imposed to further limit the time window when the buffer must be provided, transferred and released.
The assumption is for the client to have elaborate timing capabilities at his disposal. More specifically, the client is assumed to be a job running within the engine scheduler and thus can be configured to run //after// another job has finished, and to run within certain time limits. Thus the client is able to provide a //current nominal time// -- which is suitably close to the actual wall clock time. This enables the output slot implementation to work out from this time specification if the call is timely or overdue -- and react accordingly.
Within this setup, the assumption is for the client to have elaborate timing capabilities at his disposal. More specifically, the „client“ is assumed to be a //job// running within the engine scheduler and thus can be configured to run //after// some other job has finished, and to run within certain time limits. Thus the client is able to run within a //window of current nominal time// -- which is suitably close to the actual system time. On the other hand, the [[Timings]] linked to each {{{DataSink}}} are likewise aligned with the current system time. This enables the output slot implementation to work out from the current system time is a call is timely or overdue -- and to react accordingly.
!!!output modes
some concrete output connections and drivers embody a specific operation mode (e.g. sample rate or number of channels). The decision and setup of these operational configuration is initiated together with the [[resolution|OutputMapping]] of an OutputDesignation within the OutputManager, finally leading to an output slot (reference), which can be assumed to be suitably configured, before the client allocates this slot for active use. Moreover, an individual output sink (corresponding to a single channel) may just remain unused -- until there is an {{{emit()}}} call and successful data handover, this channel will just feature silence or remain black. (There are some output systems with additional flexibility, e.g. ~Jack-Audio, that allow to generate an arbitrary number of output pins -- Lumiera will support this by allowing to set up additional output slots and attach this information to the current session &amp;rarr; SessionConfigurationAttachment)
some concrete output connections and drivers embody a specific operation mode (e.g. sample rate or number of channels). The decision and setup of these operational configuration is initiated together with the [[resolution|OutputMapping]] of an OutputDesignation within the OutputManager, finally leading to an output slot (reference), which can be assumed to be suitably configured, before the client allocates this slot for active use. Moreover, an individual output sink (corresponding to some data feed) may just remain unused -- generally speaking, any output channel will just feature silence or remain black, unless or until until there is an {{{emit()}}} call and a successful data handover took place.
As an aside, it is acknowledged that there are some output systems with additional flexibility, e.g. ~Jack-Audio, that allow to generate an arbitrary number of output pins -- Lumiera will support this flexibility by allowing to set up additional output slots and attach this information to the current session &amp;rarr; SessionConfigurationAttachment
!!!Lifecycle and storage
The concrete OutputSlot implementation is owned and managed by the facility that actually provides the output capability in question. For example, the GUI provides viewer widgets, while some sound output backend provides sound ports. The associated OutputSlot implementation object is required to stay alive as long as it's registered with some OutputManager. It needs to be de-registered explicitly prior to destruction -- and this deregistration may block until all clients using this slot did terminate. Beyond that, an output slot implementation is expected to handle all kinds of failures gracefully -- preferably just emitting a signal (callback functor).
The concrete OutputSlot implementation is owned and managed by the facility that actually provides the output capability in question. Once such an output facility becomes usable within Lumiera, it will register this implementation through a suitable OutputManager. For example, the GUI provides several video viewer widgets, while some sound output backend provides sound ports. The associated OutputSlot implementation object is required to stay alive as long as it's registered with an OutputManager. It needs to be de-registered explicitly prior to destruction -- and this deregistration may block until all clients using this slot did terminate. Beyond that, an output slot implementation is responsible to handle all kinds of failures gracefully -- preferably by just emitting a signal (callback functor).
{{red{TODO 7/11: Deregistration is an unsolved problem....}}}
!!!unified data exchange cycle
The planned delivery time of a frame is used as an ID throughout that cycle
# within a defined time window prior to delivery, the client can ''allocate and retrieve the buffer'' from the BufferProvider.
# within a defined time window prior to delivery, the client can ''allocate and retrieve the buffer'' from the {{{DataSink}}}
# the client has to ''emit'' within a (short) time window prior to deadline
# now the slot gets exclusive access to the buffer for output, signalling the buffer release to the buffer provider when done.
@ -5199,8 +5201,8 @@ This data exchange protocol operates on a rather low level; there is only limite
|~|buffer unavailable ||serious malfunction of playback | request playback stop |
Thus there are two serious problem situations
* allocating the buffer out of time window bears the danger of output data corruption; but the general assumption is for the scheduler to ensure each job start time remains within the defined window and all prerequisite jobs have terminated successfully. To handle clean-up, we additionally need special jobs running always, in order, and be notified of prerequisite failures.
* failure to release a buffer in a timely fashion blocks any further use of that buffer, any further jobs in need of that buffer will die immediately. This situation can only be caused by a serious problem //within the slot, related to the output mechanism.// Thus there should be some kind of trigger (e.g. when this happens 2 times consecutively) to request aborting the playback or render as a whole.
* allocating the buffer out of time window bears the danger of output data corruption; but the general assumption is for the scheduler to ensure each job start time remains within the defined window and all prerequisite jobs have terminated successfully. Yet it is not possible to preclude that such an out-of window access may happen. The {{{DataSink}}} is required to short-circuit in this case and to return an //invalid//-BuffHandle. The Render Node {{{pull()}}} processing has to react to this condition by //unwinding sanely.// -- {{red{not yet implemented as of 3/2026}}} &amp;rarr; [[#1417|https://issues.lumiera.org/ticket/1417]]
* failure to release a buffer in a timely fashion blocks any further use of that buffer, any further jobs in need of that buffer will die immediately. This situation can either be caused by a serious problem //within the slot, related to the output mechanism.// But unfortunately it can also happen in a »runaway« situation, where a preceding job took too long to complete and thus the output buffer designated for the given frame number is still blocked. The response to this situation is the same as above (//invalid// handle), but, in addition, there should be some kind of trigger (e.g. when this happens 2 times consecutively) to request aborting the playback or render as a whole.
&amp;rarr; SchedulerRequirements
&amp;rarr; OutputSlotDesign
&amp;rarr; OutputSlotImpl

View file

@ -110780,7 +110780,7 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
</node>
</node>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1719880204169" ID="ID_826687521" MODIFIED="1720538363696" TEXT="Diskussion / offene Fragen">
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1719880204169" ID="ID_826687521" MODIFIED="1773106788771" TEXT="Diskussion / offene Fragen">
<icon BUILTIN="bell"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1720537748722" HGAP="55" ID="ID_155032865" MODIFIED="1733426613642" STYLE="bubble" TEXT="es ist kein filligranes Protokoll notwendig" VSHIFT="62">
<richcontent TYPE="NOTE"><html>
@ -110828,6 +110828,31 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
<icon BUILTIN="messagebox_warning"/>
</node>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1773106587628" ID="ID_14774780" MODIFIED="1773167973444" TEXT="Erweiterte Anforderung: Call-unwind">
<linktarget COLOR="#ff1543" DESTINATION="ID_14774780" ENDARROW="Default" ENDINCLINATION="-1473;112;" ID="Arrow_ID_116123183" SOURCE="ID_1318788103" STARTARROW="None" STARTINCLINATION="-1264;77;"/>
<linktarget COLOR="#ff1543" DESTINATION="ID_14774780" ENDARROW="Default" ENDINCLINATION="-1473;112;" ID="Arrow_ID_1204522057" SOURCE="ID_495439947" STARTARROW="None" STARTINCLINATION="1721;172;"/>
<icon BUILTIN="yes"/>
<node CREATED="1773106807352" ID="ID_694860370" MODIFIED="1773107285964" TEXT="Anforderung (3/2026) im Output-Management entdeckt">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Die alten Entw&#252;rfe zum Buffer- und Output-Management von 2012 waren zu dem Ergebnis gekommen, da&#223; man praktisch alle Fehlersituationen ger&#228;uschlos im Framework abfangen kann. Diese Einsch&#228;tzung erweist sich nun als vorschnell; tats&#228;chlich kann <i>ein Verfehlen des Ausgabe-Zeitfensters zum schrittweisen Entgleisen des Ausgabevorgangs f&#252;hren. </i>Daher mu&#223; ein Notausgang vorgesehen werden, aber <i>Exceptions schlie&#223;e ich aus anderen Gr&#252;nden als L&#246;sung aus</i>&#160;(abgesehen davon, da&#223; Exceptions generell nur f&#252;r Ausnahmesituationen gedacht sind, und jeweils zu einem Subsystem-Shutdown f&#252;hren; man sollte sie nicht als einen &#187;goto&#171;-Mechanismus verwenden, um regul&#228;r auftretende, und auch beherrschbare Codepfade einfach zu implementieren).
</p>
<p>
</p>
<p>
Also ergibt sich die Konsequenz, da&#223; in den rekursiven pull()-Call ein Mechanismus eingebaut werden mu&#223;, der die Call-Sequenz <b>abk&#252;rzt</b>, aber trotzdem <b>alle Resourcen regul&#228;r handhabt</b>.
</p>
</body>
</html></richcontent>
<icon BUILTIN="info"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1773108766174" ID="ID_926797316" LINK="https://issues.lumiera.org/ticket/1417" MODIFIED="1773108781099" TEXT="#1417 unwind from Render Node pull">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1719881279352" ID="ID_1378956447" MODIFIED="1719881489034" TEXT="Re-Entrance f&#xfc;r Buffer-Lebenszyklus-Schritte?">
<richcontent TYPE="NOTE"><html>
<head/>
@ -114096,7 +114121,66 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
</node>
</node>
<node CREATED="1771534962783" ID="ID_234219781" MODIFIED="1771534967343" TEXT="Umbau-Plan">
<node CREATED="1771534972584" ID="ID_1377276921" MODIFIED="1771534982037" TEXT="neues Tracking-API entwerfen"/>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1771534972584" ID="ID_1377276921" MODIFIED="1773167651952" TEXT="neues Tracking-API entwerfen">
<arrowlink COLOR="#604371" DESTINATION="ID_76417582" ENDARROW="Default" ENDINCLINATION="-588;-641;" ID="Arrow_ID_1083444621" STARTARROW="None" STARTINCLINATION="-741;71;"/>
<node CREATED="1773158721999" ID="ID_815516118" MODIFIED="1773158772114" TEXT="k&#xfc;nftig alles per Instanz">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
keine statsische Magie, keine implizite Instanz, das zahlt sich nicht aus in der Praxis!
</p>
</body>
</html></richcontent>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1773158703456" ID="ID_290906159" MODIFIED="1773167678342" TEXT="Konfiguration von Limits">
<icon BUILTIN="hourglass"/>
<node CREATED="1773158795105" ID="ID_1401626971" MODIFIED="1773158803668" TEXT="speichert intern eine Config"/>
<node CREATED="1773158555452" ID="ID_1602470940" MODIFIED="1773158691959" TEXT="Builder-Qualifier in den Konstruktor akzeptieren">
<linktarget COLOR="#3c5f88" DESTINATION="ID_1602470940" ENDARROW="Default" ENDINCLINATION="-1050;65;" ID="Arrow_ID_1529902301" SOURCE="ID_1664483213" STARTARROW="None" STARTINCLINATION="44;-727;"/>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1773167692429" ID="ID_678395312" MODIFIED="1773167723575" TEXT="noch nicht klar wie viel davon (jetzt) implementiert wird...">
<icon BUILTIN="bell"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#d0020d" CREATED="1773167732440" ID="ID_218577469" MODIFIED="1773167854628" TEXT="eigentlich brauch ich das gar nicht....">
<font NAME="SansSerif" SIZE="9"/>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#9c012d" CREATED="1773167741822" ID="ID_1294825278" MODIFIED="1773167841049" TEXT="...zumindest bis irgendwo tats&#xe4;chliche Konsistenz-Checks implementiert werden">
<font NAME="SansSerif" SIZE="10"/>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#9e2065" CREATED="1773167764771" ID="ID_979693912" MODIFIED="1773167850493" TEXT=".....oder bis die Engine mit &#xbb;null-Buffern&#xab; umgehen kann">
<font NAME="SansSerif" SIZE="11"/>
<node BACKGROUND_COLOR="#f2cdb2" COLOR="#ff0000" CREATED="1773105886426" HGAP="31" ID="ID_495439947" LINK="https://issues.lumiera.org/ticket/1417" MODIFIED="1773168035923" TEXT="&#xbb;unwind&#xab;-Pfad &#x27f6; #1417" VSHIFT="7">
<edge COLOR="#fe3c19" STYLE="sharp_linear" WIDTH="2"/>
<arrowlink COLOR="#ff1543" DESTINATION="ID_14774780" ENDARROW="Default" ENDINCLINATION="-1473;112;" ID="Arrow_ID_1204522057" STARTARROW="None" STARTINCLINATION="1721;172;"/>
<font NAME="SansSerif" SIZE="9"/>
</node>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1773159363311" ID="ID_361405303" MODIFIED="1773167687038" TEXT="eine TimeVar f&#xfc;r &#xbb;now&#xab; vorsehen">
<icon BUILTIN="hourglass"/>
</node>
<node CREATED="1773159125087" ID="ID_885287826" MODIFIED="1773159130969" TEXT="Diagnose nach dem Test">
<node CREATED="1773159133396" ID="ID_1831214129" MODIFIED="1773159144772" TEXT="fluent API bauen">
<icon BUILTIN="yes"/>
</node>
<node CREATED="1773159147279" ID="ID_351923331" MODIFIED="1773159237859" TEXT="aber hier nur Zugriff per Feed und Frame-Nr">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Die Situation ist diesbez&#252;glich ganz anders als beim BufferProvider: hier ist es sinnlos, die globale Folge der ausgegebenen Buffer zu betrachten, da jeder Feed separat l&#228;uft.
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1773159386871" ID="ID_1559145751" MODIFIED="1773159399319" TEXT="f&#xfc;r jeden Frame">
<node CREATED="1773159400515" ID="ID_1117722980" MODIFIED="1773159411046" TEXT="wurde er gelockt?"/>
<node CREATED="1773159412124" ID="ID_536687578" MODIFIED="1773159418649" TEXT="wurde er emitted?"/>
<node CREATED="1773159421453" ID="ID_548976578" MODIFIED="1773159441321" TEXT="jeweils die &#xbb;now&#xab;-Time kopieren"/>
</node>
</node>
</node>
<node CREATED="1771535088123" ID="ID_1559134812" MODIFIED="1771535104984" TEXT="nun einen DiagnosticBufferProvider &#xbb;Huckepack&#xab; nehmen"/>
<node CREATED="1771535954283" ID="ID_83611307" MODIFIED="1771536165619" TEXT="mu&#xdf; hier sofort einen ProxyBufferStore vorsehen und anlegen">
<linktarget COLOR="#ff0020" DESTINATION="ID_83611307" ENDARROW="Default" ENDINCLINATION="-142;6;" ID="Arrow_ID_47613106" SOURCE="ID_1312596627" STARTARROW="None" STARTINCLINATION="6;-31;"/>
@ -114104,6 +114188,20 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1771535979276" ID="ID_117213353" MODIFIED="1771536009626" TEXT="alles andere wegholzen und erst mal sonst nichts machen">
<icon BUILTIN="yes"/>
<icon BUILTIN="flag-pink"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1773021218420" ID="ID_686997096" MODIFIED="1773021340196" TEXT="Querverbindung zum Layer-Refactoring">
<arrowlink COLOR="#fe4769" DESTINATION="ID_819469629" ENDARROW="Default" ENDINCLINATION="542;21;" ID="Arrow_ID_254929972" STARTARROW="None" STARTINCLINATION="407;28;"/>
<icon BUILTIN="idea"/>
</node>
<node CREATED="1773021653678" ID="ID_1544005457" MODIFIED="1773021899340" TEXT="nur eine Grid-Abstraktion durchreichen">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Diese Feststellung bezeichnet einen Knotenpunkt in der bestehenden Platzhalter-Implementierung, welche dadruch unn&#246;tigerweise an die Assets gebunden ist. Tats&#228;chlich mu&#223; es mir gelingen, die Interfaces so zu strukturieren, da&#223; nur ein Verweis auf ein Grid(Interface) durchgereicht wird. Das dazu geh&#246;rige, tats&#228;chliche Grid ist n&#228;mlich etwas in der konkreten Session; es wird verm&#246;ge der Player-Output-Connection in das Output-System durchgereicht; andererseits gibt es irgendwo in der externen Anbindung an konkrete Hardware-Outputs so etwas wie einen Timing-Anker, an dem das tats&#228;chliche Frame-Grid ausgerichtet wird (zumindest f&#252;r real-Time output)
</p>
</body>
</html></richcontent>
</node>
</node>
</node>
</node>
@ -115620,6 +115718,20 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1772478179206" ID="ID_1477396819" MODIFIED="1772933010916" TEXT="OutputSlot">
<icon BUILTIN="help"/>
<node CREATED="1773021243177" ID="ID_819469629" MODIFIED="1773021647136" TEXT="das &#xbb;Entkernen&#xab; des DiagnosticOutputSlot erm&#xf6;glicht Umzug nach &#xbb;Vault&#xab;">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...und zwar geht es hier um den &#187;Knackpunkt&#171; mit time::Grid vs asset::Grid.
</p>
<p>
Die Definition der Interfaces l&#228;&#223;t sich komplett auf das Grid-Interface in der Library reduzieren; deshalb sollte es auch m&#246;glich sein, den OutputSlot und die Basis des OutputManagement letztlich in die &#187;Vault&#171; zu verlegen. Die bestehende Draft/Platzhalter-Implementierung allerdings verwendet asset::Grid auf eine undurchsichtige Weise, die ich l&#228;ngerfristig f&#252;r obsolet halte, ohne &#252;berhaupt noch Aufwand zu betreiben, sie zu verstehen. Der Grund ist, da&#223; die Verwaltung der Grids letztlich mit der Session zusammenh&#228;ngt, und daher in der geplanten L&#246;sung es nicht Aufgrabe des OutputSlot sein kann, ein Grid zu erzeugen; vielmehr wird ein im Model bereits bestehendes Grid referenziert. Es kommt also darauf an, die Interaces und die Basis-Implementierung so zu bauen, da&#223; nur eine Grid-Abstraktion durchgereicht wird.
</p>
</body>
</html></richcontent>
<linktarget COLOR="#fe4769" DESTINATION="ID_819469629" ENDARROW="Default" ENDINCLINATION="542;21;" ID="Arrow_ID_254929972" SOURCE="ID_686997096" STARTARROW="None" STARTINCLINATION="407;28;"/>
</node>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1772478185740" ID="ID_1860322406" MODIFIED="1772933014495" TEXT="OutputManagement">
<icon BUILTIN="help"/>
@ -117216,9 +117328,10 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
<node CREATED="1771532667033" ID="ID_1615837421" MODIFIED="1771532682643" TEXT="zun&#xe4;chst ist das Protokoll zu korrigieren">
<node CREATED="1771532702299" ID="ID_1332714293" MODIFIED="1771532711704" TEXT="dokumentiert durch OutputSlotProtocol_test">
<node CREATED="1771532730104" ID="ID_874519449" MODIFIED="1771532748289" TEXT="im bestehenden Code lief der Test (mit einer Dummy-Implementierung)"/>
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1771532716678" ID="ID_459952316" MODIFIED="1771533105051" TEXT="dieser Test ist nun gebrochen">
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1771532716678" ID="ID_459952316" MODIFIED="1773076794402" TEXT="dieser Test ist nun gebrochen">
<linktarget COLOR="#fe1909" DESTINATION="ID_459952316" ENDARROW="Default" ENDINCLINATION="75;-1691;" ID="Arrow_ID_176448794" SOURCE="ID_158180438" STARTARROW="None" STARTINCLINATION="-554;79;"/>
<linktarget COLOR="#f90134" DESTINATION="ID_459952316" ENDARROW="Default" ENDINCLINATION="-843;75;" ID="Arrow_ID_1183488081" SOURCE="ID_690666245" STARTARROW="None" STARTINCLINATION="345;27;"/>
<linktarget COLOR="#b22cbe" DESTINATION="ID_459952316" ENDARROW="Default" ENDINCLINATION="-137;3;" ID="Arrow_ID_168875434" SOURCE="ID_1722330743" STARTARROW="Default" STARTINCLINATION="-9;-63;"/>
<icon BUILTIN="broken-line"/>
</node>
</node>
@ -117230,6 +117343,52 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
<arrowlink COLOR="#b1000a" DESTINATION="ID_580664253" ENDARROW="Default" ENDINCLINATION="-769;59;" ID="Arrow_ID_1374111018" STARTARROW="None" STARTINCLINATION="366;17;"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1773077339408" ID="ID_9353167" MODIFIED="1773077409753" TEXT="Protokoll final">
<icon BUILTIN="yes"/>
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1773077433700" HGAP="106" ID="ID_1896993671" MODIFIED="1773077470074" TEXT="der &#xbb;Vertical Slice&#xab; soll das Protokoll validieren" VSHIFT="-9">
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
<icon BUILTIN="yes"/>
</node>
</node>
</node>
<node CREATED="1773076719646" ID="ID_884669133" MODIFIED="1773076734458" TEXT="mu&#xdf; zus&#xe4;tzlich eine Dummy-Implementierung bauen">
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1773076745969" ID="ID_1722330743" MODIFIED="1773077118998" TEXT="Test mu&#xdf; laufen">
<arrowlink COLOR="#b22cbe" DESTINATION="ID_459952316" ENDARROW="Default" ENDINCLINATION="-137;3;" ID="Arrow_ID_168875434" STARTARROW="Default" STARTINCLINATION="-9;-63;"/>
<icon BUILTIN="yes"/>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1773077173730" ID="ID_76417582" MODIFIED="1773167628789" TEXT="Neubau Diagnose-API &#x27fa; Vorentwurf Implementierung">
<linktarget COLOR="#604371" DESTINATION="ID_76417582" ENDARROW="Default" ENDINCLINATION="-588;-641;" ID="Arrow_ID_1083444621" SOURCE="ID_1377276921" STARTARROW="None" STARTINCLINATION="-741;71;"/>
<icon BUILTIN="pencil"/>
</node>
<node CREATED="1773077306179" ID="ID_791772240" MODIFIED="1773078563511" TEXT="Analyse mu&#xdf; dieses Mal bottom-up vorgehen">
<arrowlink COLOR="#df165b" DESTINATION="ID_597179173" ENDARROW="Default" ENDINCLINATION="-647;-29;" ID="Arrow_ID_694305976" STARTARROW="None" STARTINCLINATION="-136;1688;"/>
<node CREATED="1773077507482" ID="ID_1084930435" MODIFIED="1773078209970" TEXT="das ist die Konsequenz aus diesem &#xbb;Mismatch&#xab;">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
&#187;man&#171; hatte sich seinerzeit was ausgedacht, ohne sehen zu k&#246;nnen, wohin das f&#252;hrt und wo das <i>vielleicht aneckt.</i>&#160;Durch eine halbe Protion Gl&#252;ck hat sich eine Parallele mit dem Buffer-Provider-Protokoll aufgetan, die zudem nicht richtig funktionert. So da&#223; das &#8222;eigentlich fertige&#8220; Protokoll-Setup nicht zu gebrauchen ist. W&#252;rde ich das ganze Zeug jetzt wegwerfen, und neu bauen, dann w&#228;re es darauf hinausgelaufen, da&#223; das alles ein Irrtum und eine Sackgasse war. Deshalb werde ich das <i>nicht tun, sondern mich an dem vermurksten Entwurf abarbeiten, </i>um aus den Schwierigkeiten<i>&#160;eine R&#252;ckmeldung der Wirklichkeit zu gewinnen</i>
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1773077521860" ID="ID_1181588301" MODIFIED="1773078399225" TEXT="kommt letztlich nicht &#xfc;berraschend...">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Seinerzeit war das Output-Slot-Protokoll der Versuch, einen ganzen Themenbereich erstmals einzufangen &#8212; durch einen <i>Entwurf in's Blaue. </i>
</p>
<p>
</p>
<p>
Folglich ist das Protokoll aus einem prinzipiellen Verst&#228;ndnis des Sachverhalts gesch&#246;pft, und die Implementierung zappelt im leeren Raum. Praktisch zeigt (und zeigte) sich das so, da&#223; die Implementierung v&#246;llig <i>ohne Gehalt ist, </i>und daher der Test gewisserma&#223;en nach &#187;Selbstbefriedigung&#171; riecht: man kippt irgengendwelches Zeug in die Tasche und fummelt es auf der anderen Seite wieder heraus. Was sollte da denn auch getestet werden &#8212; eine Implementierung ist gar nicht gegeben. Diese ganze Veranstaltung <i>kann aber sinnvoll gemacht werden, </i>indem die (nicht-vorhandene) Implementierung auf (noch nicht erfahrenen) Schwierigkeiten der tats&#228;chlichen Realisierung aufbaut
</p>
</body>
</html></richcontent>
</node>
</node>
</node>
</node>
</node>
@ -137006,6 +137165,227 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1771532488034" ID="ID_690666245" MODIFIED="1771533022127" TEXT="DiagnosticOutputSlot aufr&#xe4;umen">
<arrowlink COLOR="#f90134" DESTINATION="ID_459952316" ENDARROW="Default" ENDINCLINATION="-843;75;" ID="Arrow_ID_1183488081" STARTARROW="None" STARTINCLINATION="345;27;"/>
<icon BUILTIN="pencil"/>
<node CREATED="1773078490823" HGAP="34" ID="ID_474163351" MODIFIED="1773078511878" TEXT="ein neues sinvolleres Diagnose-API entwerfen" VSHIFT="30">
<node CREATED="1773078412215" ID="ID_597179173" MODIFIED="1773078565947" TEXT="Test-Dummy bereitet die Prototyp-Implementierung vor">
<linktarget COLOR="#df165b" DESTINATION="ID_597179173" ENDARROW="Default" ENDINCLINATION="-647;-29;" ID="Arrow_ID_694305976" SOURCE="ID_791772240" STARTARROW="None" STARTINCLINATION="-136;1688;"/>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1773078521008" ID="ID_363846303" MODIFIED="1773078569280" TEXT="Grundlage: wie k&#xf6;nnte man dieses API realistischerweise implementieren?">
<icon BUILTIN="help"/>
<node CREATED="1773088095124" ID="ID_1797165728" MODIFIED="1773088185793" TEXT="Gegebenheiten">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Das sage ich hier dem <i>virtuellen Christian:</i>&#160;sorry, Junge, das ist nicht was, was <i>wir</i>&#160;uns so richten k&#246;nnen, wie es uns grad schmeckt.....
</p>
</body>
</html></richcontent>
<node CREATED="1773087884607" ID="ID_1637402213" MODIFIED="1773087894190" TEXT="Output-Mechanik">
<node CREATED="1773088070000" ID="ID_1869895337" MODIFIED="1773088073781" TEXT="umkopieren"/>
<node CREATED="1773088059850" ID="ID_437421950" MODIFIED="1773088068438" TEXT="Buffer-&#xdc;bergabe"/>
<node CREATED="1773087896734" ID="ID_1789068166" MODIFIED="1773087907322" TEXT="zeitgesteuerter Flip"/>
<node CREATED="1773088019426" ID="ID_1141427050" MODIFIED="1773088024426" TEXT="Shared-Memory"/>
<node CREATED="1773087945042" ID="ID_1216518753" MODIFIED="1773087946557" TEXT="DMA"/>
</node>
<node CREATED="1773088186969" ID="ID_262693747" MODIFIED="1773088190454" TEXT="Kontrollstruktur">
<node CREATED="1773088521183" ID="ID_1542583105" MODIFIED="1773088652574" TEXT="callback">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Eine user-provided-Function wird aufgerufen, mit einer Buffer-Adresse als Argument. Sie hat dann eine (meist nur ungef&#228;hr definierte) Zeitspanne, um Daten in diese Adresse zu bekommen
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1773088239889" ID="ID_1341314044" MODIFIED="1773088338215" TEXT="push">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
ein &#187;Client&#171; der Output-Senke triggert die &#220;bergabe
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1773088405898" ID="ID_50943174" MODIFIED="1773088520034" TEXT="pull">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
ein Repr&#228;sentant des Output-Mechanismus holt sich Daten oder initiiert den n&#228;chsten &#187;Flip&#171;
</p>
</body>
</html></richcontent>
</node>
</node>
<node CREATED="1773088654168" ID="ID_941261288" MODIFIED="1773088708159" TEXT="Formen des Scheiterns">
<node CREATED="1773088749227" ID="ID_443400266" MODIFIED="1773093074959" TEXT="passiv">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Dieser Fall ist sehr h&#228;ufig, mutma&#223;lich sogar die Regel: der Ausgabe-Mechanismus l&#228;uft blind, und &#252;bernimmt die Daten, die eben da sind, oft sogar zu einem Zeitpunkt, der nicht ganz pr&#228;zise vorherzusagen ist.
</p>
</body>
</html></richcontent>
<node CREATED="1773088778186" ID="ID_948288214" MODIFIED="1773088784970" TEXT="M&#xfc;ll im Ausgabekanal"/>
<node CREATED="1773088787302" ID="ID_827699280" MODIFIED="1773088843690" TEXT="sonst ohne Konsequenz"/>
</node>
<node CREATED="1773088910293" ID="ID_1420156535" MODIFIED="1773093425065" TEXT="undefiniert">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Dieser Fall hat leider eine gewisse Relevanz; er kommt zustande durch den speziellen Fokus auf Performance, der dem Thema inh&#228;rent ist. Absicherung gegen Timing-Fehler verursacht Kosten, und wird als besonders irrelevant eingestuft, da der Benutzer eines IO-Kanals ein nat&#252;rliches Interesse an korrekter Verwendung haben sollte &#8212; was leider ein Kurzschlu&#223; ist, denn die wenigsten Probleme werden mutwillig verursacht, und unbekannte Probleme sind schwieriger zu erkennen, reparieren und zu verhindern
</p>
</body>
</html></richcontent>
<node CREATED="1773088964462" ID="ID_1196646352" MODIFIED="1773088971156" TEXT="Konsequenzen sind nicht absehbar"/>
<node CREATED="1773088973456" ID="ID_135157864" MODIFIED="1773089011981" TEXT="Ausgabesysteme k&#xf6;nnen h&#xe4;ngenbleiben"/>
</node>
<node CREATED="1773089069187" ID="ID_755394799" MODIFIED="1773101625525" TEXT="markiert">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Dieses Muster ist nicht so h&#228;ufig anzutreffen, jedoch sehr vorteilhaft, weil dadurch effektiv eine weitere Sicherheitsbarriere gegeben ist; abgesehen davon ist es jedoch nicht relevant f&#252;r die Implementierund der Datenanlieferung f&#252;r den Output, denn man sollte ohnehin Sorge tragen, das Protokoll einzuhalten
</p>
</body>
</html></richcontent>
<node CREATED="1773089074119" ID="ID_500702692" MODIFIED="1773089082186" TEXT="Protokollverletzung wird automatisch erkannt"/>
<node CREATED="1773089106075" ID="ID_1995564014" MODIFIED="1773089118377" TEXT="Versagen wird gekennzeichnet"/>
</node>
<node CREATED="1773089171482" ID="ID_1409584074" MODIFIED="1773101682100" TEXT="bestraft">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Auch diese Variante (die oft mit der vorherigen einhergeht) stellt ein Sicherheitsnetz dar, da eine <i>aus dem Ruder laufende</i>&#160;Datenversorgung rasch gestoppt wird.
</p>
</body>
</html></richcontent>
<node CREATED="1773089177453" ID="ID_423648183" MODIFIED="1773101391427" TEXT="Erkennung kann passiv oder aktiv sein"/>
<node CREATED="1773089189999" ID="ID_1851045464" MODIFIED="1773089215032" TEXT="Verbindung wird gesperrt oder getrennt"/>
</node>
</node>
</node>
<node CREATED="1773101687926" ID="ID_1945550225" MODIFIED="1773101705981" TEXT="&#xdc;berlegungen und Konsequenzen">
<node CREATED="1773101760561" ID="ID_1216626497" MODIFIED="1773102025488" TEXT="eine qualitativ hochwertige Implementierung verhindert Protokollfehler">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...was im Umkehrschlu&#223; bedeutet, da&#223; es nicht gen&#252;gt, lediglich die Fehler <i>unwahrscheinlicher zu machen.</i>&#160;In dieser Hinsicht waren meine &#220;berlegungen 2012 voreilig und unausgewogen; zwar wollte ich einen de-Clicker, aber wollte mir dann mit einem Implementierungstrick helfen
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1773101818138" ID="ID_317443240" MODIFIED="1773105699999" TEXT="dies erfordert (und rechtfertigt) eine gewisse Infrastruktur">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...die wir gr&#246;&#223;tenteils sowiso haben; neu ist nur, da&#223; wir nun eingestehen, <b>eigens f&#252;r die Korrektheit sorgen zu m&#252;ssen</b>. Das Erkennen von Fehlern mu&#223; dabei in der Implementierung liegen, denn die abzudeckenden Situationen sind viel zu divers, um sie sinnvoll in einem einzigen Schema fassen zu k&#246;nnen
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1773105708404" ID="ID_457586692" MODIFIED="1773105746195" TEXT="&#x27f9; die Implementierung pr&#xfc;ft ob der Zugriff im Zeitfenster liegt"/>
<node CREATED="1773105754652" ID="ID_611290260" MODIFIED="1773105791739">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
Im Besonderen ein lock() au&#223;erhalb des Zeitfensters mu&#223; <b>aktiv unterbunden</b>&#160;werden
</p>
</body>
</html></richcontent>
</node>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1773105808702" ID="ID_1988312173" MODIFIED="1773105855803" TEXT="Das ist eine neue Anforderung f&#xfc;r den Node-pull()">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1773105903720" ID="ID_598676426" MODIFIED="1773106038816" TEXT="Exceptions habe ich grunds&#xe4;tzlich ausgeschlossen">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Und zwar, weil ich den Overhead f&#252;r automatisches Resource-Management nicht f&#252;r gerechtfertigt halte
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1773105864557" ID="ID_355832289" MODIFIED="1773105880567" TEXT="es k&#xf6;nnen NULL-Handles geliefert werden"/>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1773105886426" ID="ID_1318788103" LINK="https://issues.lumiera.org/ticket/1417" MODIFIED="1773108850040" TEXT="es braucht einen &#xbb;unwind&#xab;-Pfad &#x27f6; #1417">
<arrowlink COLOR="#ff1543" DESTINATION="ID_14774780" ENDARROW="Default" ENDINCLINATION="-1473;112;" ID="Arrow_ID_116123183" STARTARROW="None" STARTINCLINATION="-1264;77;"/>
<icon BUILTIN="yes"/>
</node>
</node>
<node CREATED="1773108918866" ID="ID_1178267018" MODIFIED="1773108936427" TEXT="die OutputSlot-Basis-Implementierung sollte ein verletztes Protokollmuster erkennen"/>
<node CREATED="1773108937563" ID="ID_224988870" MODIFIED="1773109149753" TEXT="aber nur der konkrete ConnectionStateManager kann darauf reagieren">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...weil es realisitischerweise kein generisches Implementierungs-Schema geben wird. Es ist nicht einmal klar, wann genau eine Blockade stattfindet, und dann infolgedessen ein Abbruch getriggert werden mu&#223;. Wir k&#246;nnen lediglich annehmen, da&#223;, aufgrund einer solchen intern erkannten Problemsituation, der weitere Zugang zu den Ausgabe-Puffern unterbunden werden mu&#223;.
</p>
</body>
</html></richcontent>
</node>
</node>
</node>
<node CREATED="1773155990443" ID="ID_1190993728" MODIFIED="1773156025049" TEXT="Diagnose-Mechanismen">
<node CREATED="1773156135431" ID="ID_1267997680" MODIFIED="1773156181565" TEXT="eigenst&#xe4;ndige Instanzen ohne &#xbb;magische Registrierung&#xab;"/>
<node CREATED="1773156027518" ID="ID_1029550355" MODIFIED="1773156061189" TEXT="Grunds&#xe4;tzlich gibt es unlimitierte Output-Kapazit&#xe4;t">
<node CREATED="1773156063226" ID="ID_1574408155" MODIFIED="1773156071119" TEXT="beliebig viele Kan&#xe4;le"/>
<node CREATED="1773156072059" ID="ID_482463660" MODIFIED="1773156096687" TEXT="darin kann jeder beliebige Frame jederzeit bespielt werden"/>
</node>
<node CREATED="1773156183808" ID="ID_1664483213" MODIFIED="1773158691959" TEXT="Konfig einer neuen Instanz kann Limits vorgeben">
<arrowlink COLOR="#3c5f88" DESTINATION="ID_1602470940" ENDARROW="Default" ENDINCLINATION="-1050;65;" ID="Arrow_ID_1529902301" STARTARROW="None" STARTINCLINATION="44;-727;"/>
<node CREATED="1773156196542" ID="ID_1234849755" MODIFIED="1773156209009" TEXT="das plane ich als optionale Erweiterung"/>
<node CREATED="1773156210393" ID="ID_553064748" MODIFIED="1773156223211" TEXT="Anzahl Kan&#xe4;le beschr&#xe4;nken"/>
<node CREATED="1773156223947" ID="ID_1079197667" MODIFIED="1773156237383" TEXT="Frame-Grid vorgeben"/>
<node CREATED="1773156241816" ID="ID_1158422515" MODIFIED="1773156277373" TEXT="Anzahl zugleich gesperrter Buffer limitieren"/>
<node CREATED="1773156341660" ID="ID_407686738" MODIFIED="1773156348999" TEXT="Ausgabezeitfenster limitieren"/>
</node>
<node CREATED="1773156351674" ID="ID_1963645100" MODIFIED="1773156369117" TEXT="die Implementierung wird komplett isoliert geschrieben">
<icon BUILTIN="yes"/>
<node CREATED="1773156370948" ID="ID_794565342" MODIFIED="1773156513730" TEXT="diese Lehre ziehe ich aus dem &#xbb;Desaster&#xab; mit der ersten Implementierung von 2012">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Eine echte Implementierung f&#252;r eine spezifische Output-Technologie war damals (und heute leider genauso) noch nicht geschrieben; in einer solchen Lage w&#228;re es brandgef&#228;hrlich, sofort eine &#187;default-Implementierung&#171; anzulegen.
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1773156516269" ID="ID_1341134692" MODIFIED="1773156541757" TEXT="die Test-Implementierung sehe ich als Prototyp bez&#xfc;glich der Konsistenz-Limits"/>
<node CREATED="1773156543145" ID="ID_364217869" MODIFIED="1773156636849" TEXT="wenn ich sie &#xfc;berhaupt jetzt entwickle....">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...das ist n&#228;mlich nicht notwendig, um die n&#228;chsten beiden Vertical Slices &#252;ber die B&#252;hne zu bekommen; f&#252;r Video-Output hat man es i.d.R. mit double-buffering zu tun, und <i>daf&#252;r ergeben sich relativ einfache Limits praktisch von selbst, aus der Implementierung</i>
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1773156642079" ID="ID_1747459491" MODIFIED="1773156658302" TEXT="zun&#xe4;chst wird nur die unlimitierte H&#xfc;lle ben&#xf6;tigt, um das Protokoll zu testen"/>
</node>
<node CREATED="1773156927734" ID="ID_1001788653" MODIFIED="1773156986131">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
<u>Diagnose bedeutet</u>: nachtr&#228;glich alle Ausgabevorg&#228;nge &#252;berpr&#252;fen k&#246;nnen
</p>
</body>
</html></richcontent>
<node CREATED="1773157002897" ID="ID_365322825" MODIFIED="1773157028020" TEXT="also analog zum Baumuster des DiagnostricBufferProviders"/>
<node CREATED="1773157051468" ID="ID_241171757" MODIFIED="1773157072045" TEXT="Zugriffs-Koordinaten hier: (Feed, Frame-#)"/>
</node>
</node>
</node>
</node>
</node>
<node CREATED="1771532464268" ID="ID_1570776013" MODIFIED="1771532466986" TEXT="Aufbau"/>