Design: elaborating how GUI model updates might work
esp. regarding parallelism
This commit is contained in:
parent
a35a6b0724
commit
6c663a5c9e
1 changed files with 14 additions and 6 deletions
|
|
@ -1958,13 +1958,15 @@ To make the intended use of the classes more clear, consider the following two e
|
|||
The render nodes network is always built separate for each [[timeline segment|Segmentation]], which is //constant in wiring configuration.// Thus, while exit node(s) are per segment, the corresponding exit nodes of consecutive segments together belong to a ModelPort, which in turn corresponds to a global pipe (master bus not connected any further). These relations guide the possible configuration for an exit node: It may still provide multiple channels -- but all those channels are bound to belong to a single logical stream -- same StreamPrototype, always handled as bundle, connected and routed in one step. For example, when there is an 5.1 Audio master bus with a single fader, then "5.1 Audio" would be a prototype and these 6 channels will always be handled together; in such a case it makes perfectly sense to access these 6 audio channels through a single exit node, which is keyed (identified) by the same PipeID as used at the corresponding ModelPort and the corresponding [[global pipe|GlobalPipe]] ("5.1 Audio master bus")
|
||||
</pre>
|
||||
</div>
|
||||
<div title="ExplicitPlacement" modifier="Ichthyostega" created="200706220304" modified="201012122052" tags="def">
|
||||
<div title="ExplicitPlacement" modifier="Ichthyostega" created="200706220304" modified="201410260125" tags="def" changecount="1">
|
||||
<pre>A special kind (subclass) of [[Placement]]. As such it is always linked to a //Subject//, i.e. a MObject. But contrary to the (standard) placements, which may exhibit all kinds of fancy dynamic and scope dependent behaviour, within an explicit placement all properties are resolved and materialised. While the (standard) placement may contain an arbitrary list of LocatingPin objects, the resolution into an explicit placement performs a kind of »orthogonalisation«: each remaining LocatingPin defines exactly one degree of freedom independent of all others. Most notably, the explicit placement always specifies a absolute time and [[output designation|OutputDesignation]] for for locating the Subject. Explicit placements are ''immutable''.
|
||||
|
||||
!!Implementation considerations
|
||||
Explicit placements are just created and never mutated, but copying and storage might become a problem.
|
||||
It would thus be desirable to have a fixed-sized allocation, able to hold the placement body as well as the (fixed) locating pins inline.
|
||||
</pre>
|
||||
|
||||
!!!Storage
|
||||
Explicit placements are value objects and stored at the respective usage site, most notably the [[Segmentation]]. They are //not// attached to the placement index in the session, nor do they bear any referential or indexing semantics. The only dynamic side effect of an explicit placement is to keep the reference count of the corresponding MObject up and thus keep it alive and accessible.</pre>
|
||||
</div>
|
||||
<div title="Factories" modifier="Ichthyostega" created="200708100401" modified="201310132317" tags="def Concepts" changecount="6">
|
||||
<pre>The use of factories separates object creation, configuration and lifecycle from the actual usage context. Hidden behind a factory function
|
||||
|
|
@ -2280,19 +2282,21 @@ Thus, the Proc-Layer exposes (one or several) facade interfaces for the GUI to u
|
|||
|
||||
Probably the most important aspect regarding the GUI integration is how to get [[access to and operate on the Session|SessionInterface]]. More specifically, this includes [[referring to individual objects|MObjectRef]]. On top of these generic access mechanisms, we create a [[proxy GUI model|GuiModel]] for binding. The interface of this GUI model is tailored for display and translation into UI entities.</pre>
|
||||
</div>
|
||||
<div title="GuiModel" creator="Ichthyostega" modifier="Ichthyostega" created="201410170142" modified="201410250111" tags="GuiIntegration design draft" changecount="4">
|
||||
<div title="GuiModel" creator="Ichthyostega" modifier="Ichthyostega" created="201410170142" modified="201410270246" tags="GuiIntegration design draft" changecount="7">
|
||||
<pre>Building a layered architecture is a challenge, since the lower layer //really// needs to be self-contained, while prepared for usage by the higher layer.
|
||||
A major fraction of all desktop applications is written in a way where operational logic is built around the invocation from UI events -- what should be a shell turns into a backbone. One possible way to escape from this common anti pattern is to introduce a mediating entity, to translate between two partially incompatible demands and concerns: Sure, the "tangible stuff" is what matters, but you can not build any significant piece of technology if all you want is to "serve" the user.
|
||||
|
||||
Within the Lumiera GTK GUI, we use a proxying model as a mediating entity. It is based upon the ''generic aspect'' of the SessionInterface, but packaged and conditioned in a way to allow a direct mapping of GUI entities on top. The widgets in the GUI can be conceived as decorating this model. Callbacks can be wired back, allowing to transform UI events into a stream of commands for the Proc-Layer sitting below.
|
||||
|
||||
The GUI model is largely comprised of immutable ID elements, which can be treated as values. A mutated model configuration in Proc-Layer is pushed upwards as a new structure to be consumed by the GUI widgets; it is broken into parts while being consumed -- leaving it to the leaf widgets to adapt themselves to reflect the new situation. &rarr; [[GUI update mechanics|GuiModelUpdate]]
|
||||
The GUI model is largely comprised of immutable ID elements, which can be treated as values. A mutated model configuration in Proc-Layer is pushed upwards as a new structure and translated into a ''diff'' against the previous structure -- ready to be consumed by the GUI widgets; this diff can be broken down into parts and consumed recursively -- leaving it to the leaf widgets to adapt themselves to reflect the new situation. &rarr; [[GUI update mechanics|GuiModelUpdate]]
|
||||
|
||||
!synchronisation guarantees
|
||||
We acknowledge that the gui model is typically used from within the GUI event dispatch thread. This is //not// the thread where any session state is mutated. Thus it is the repsonsibility of this proxying model within the GUI to ensure that the retrieved structure is a coherent snapshot of the session state. Especially the {{{gui::model::SessionFacade}}} ensures that there was a read barrier between the state retrieval and any preceding mutation command. Actually, this is implemented down in Proc-Layer, with the help of the ProcDispatcher.
|
||||
We acknowledge that the gui model is typically used from within the GUI event dispatch thread. This is //not// the thread where any session state is mutated. Thus it is the responsibility of this proxying model within the GUI to ensure that the retrieved structure is a coherent snapshot of the session state. Especially the {{{gui::model::SessionFacade}}} ensures that there was a read barrier between the state retrieval and any preceding mutation command. Actually, this is implemented down in Proc-Layer, with the help of the ProcDispatcher.
|
||||
|
||||
Forwarding the model changes to the GUI widgets is another concern, since notifications from session mutations arrive asynchronous after each [[Builder]] run. In this case, we send a notification to the widgets registered as listeners, but wait for //them// to call back and fetch the [[diffed state|TreeDiffModel]]. This callback will be scheduled by the widgets to perform in the GUI event thread.
|
||||
</pre>
|
||||
</div>
|
||||
<div title="GuiModelUpdate" creator="Ichthyostega" modifier="Ichthyostega" created="201410250121" modified="201410250136" tags="GuiIntegration GuiPattern design decision discuss draft" changecount="6">
|
||||
<div title="GuiModelUpdate" creator="Ichthyostega" modifier="Ichthyostega" created="201410250121" modified="201410270247" tags="GuiIntegration GuiPattern design decision discuss draft" changecount="10">
|
||||
<pre>Considerations regarding the [[structure of custom timeline widgets|GuiTimelineWidgetStructure]] highlight again the necessity of a clean separation of concerns and an "open closed design". For the purpose of updating the timeline(s) to reflect the HighLevelModel in Proc-Layer, several requirements can be identified
|
||||
* we need incremental updates: we must not start redrawing each and everything on each tiny change
|
||||
* we need recursive programming, since this is the only sane way to deal with tree like nested structures.
|
||||
|
|
@ -2317,6 +2321,10 @@ Hereby we introduce a new in-layer abstraction.
|
|||
* thus there is no need for any ownership or resource tracking
|
||||
* we use simple language functors.
|
||||
|
||||
|
||||
!initiating model updates
|
||||
Model updates are always pushed up from Proc-Layer, coordinated by the ProcDispatcher. A model update can be requested by the GUI -- but the actual update will arrive asynchronously. The update informations originate from within the [[build process|BuildFixture]]. {{red{TODO 10/2014 clarify the specifics}}}. When update informations arrive, a ''diff is generated'' against the current GuiModel contents. The GuiModel is updated to reflect the differences and the Receivers or Listeners are signalled. It is their responsibility in turn to schedule an update operation into the GUI event thread. When performing this update, the Listener thus actively retrieves and pulls the diffed information from within the GUI event thread. The GuiModel's object monitor is sufficient to coordinate this handover.
|
||||
&rarr; representation of changes as a [[tree of diffs|TreeDiffModel]]
|
||||
</pre>
|
||||
</div>
|
||||
<div title="GuiNotificationFacade" modifier="Ichthyostega" created="200902080659" tags="spec">
|
||||
|
|
|
|||
Loading…
Reference in a new issue