diff --git a/src/proc/play/play-process.hpp b/src/proc/play/play-process.hpp index 9207a3b10..5045544b7 100644 --- a/src/proc/play/play-process.hpp +++ b/src/proc/play/play-process.hpp @@ -21,7 +21,27 @@ */ /** @file play-process.hpp - * + ** Organisational unit of an ongoing render- or playback process. + ** A process object doesn't perform any work in itself, rather it's + ** an entry in the process table maintained within the PlayService. + ** This table entry is used to keep track of the individual data feeds, + ** each corresponding to one of the global pipes to be "performed" in order + ** to generate output data. Usually, these global pipes all belong to a given + ** Timeline (but other setups are possible as well). + ** + ** Each of these Feed objects comprising a play process is in turn responsible + ** for getting one or multiple CalculationStream entities configured and operative + ** within the actual render engine. Each of these calculation streams corresponds + ** to a running series of calculations for consecutive frames, to be delivered + ** in a time-bound fashion from the render engine into an OutputSlot, allocated + ** for rendering this specific feed. + ** + ** A PlayProcess isn't exposed directly to client code -- it's the body object, + ** while a Play::Controller handle is returned to the client (PImpl pattern). + ** Using this controller frontend, clients are allowed to control and change + ** the playback or rendering state and goals, which then causes the PlayProcess + ** to reconfigure the ongoing or planned calculations. + ** ** @see lumiera::DummyPlayer ** @see gui::PlaybackController usage example */ @@ -31,6 +51,7 @@ #define PROC_PLAY_PLAY_PROCESS_H +#include "lib/error.hpp" //#include "include/dummy-player-facade.h" //#include "include/display-facade.h" //#include "common/instancehandle.hpp" @@ -49,8 +70,21 @@ namespace play { // using lumiera::Display; // using lumiera::DummyPlayer; + namespace error = lumiera::error; + /** + * Rendering data feed, corresponding to a single + * global pipe and to be delivered into a single OutputSlot. + * A feed may still be comprised of multiple channels, but is + * bound to operate on a single type of media data only. + */ + class Feed + : boost::noncopyable + { + + }; + /****************************************************** * Playback/Render process within the Lumiera Player. * This is a top-level implementation entity, created @@ -72,7 +106,14 @@ namespace play { { public: - + template + PlayProcess (CONS pipeConnections) + { + if (isnil (pipeConnections)) + throw error::State ("creating a PlayProcess without any usable output connections"); + + UNIMPLEMENTED ("iterate over the connections and allocate/establish each of them, creating and storing Feed objects"); + } }; diff --git a/src/proc/play/play-service.cpp b/src/proc/play/play-service.cpp index 50077545a..72e89fa35 100644 --- a/src/proc/play/play-service.cpp +++ b/src/proc/play/play-service.cpp @@ -23,12 +23,13 @@ #include "proc/play/play-service.hpp" #include "proc/play/play-process.hpp" -#include "lib/scoped-ptrvect.hpp" +#include "lib/itertools.hpp" #include //#include -//#include +#include +#include //#include @@ -53,6 +54,10 @@ namespace play { //using std::tr1::bind; using lib::Sync; using lib::RecursiveLock_NoWait; + using lib::filterIterator; + using std::tr1::weak_ptr; + using std::tr1::bind; + using std::tr1::placeholders::_1; namespace { // hidden local details of the service implementation.... @@ -62,8 +67,6 @@ namespace play { - /* ================== define an lumieraorg_DummyPlayer instance ======================= */ - } // (End) hidden service impl details @@ -71,12 +74,29 @@ namespace play { class ProcessTable : public Sync { - typedef lib::ScopedPtrVect ProcTable; + typedef std::vector > ProcTable; ProcTable processes_; public: + lumiera::Play::Controller + establishProcess (PlayProcess* newProcess) + { + lumiera::Play::Controller frontend; + + frontend.activate (newProcess, bind (&ProcessTable::endProcess, this, _1 )); + processes_.push_back (frontend); + return frontend; + } + + private: + void + endProcess (PlayProcess* dyingProcess) + { + delete dyingProcess; + UNIMPLEMENTED ("process deregistration"); /// note the process might not be registered at all + } }; @@ -114,6 +134,9 @@ namespace play { PlayService::connect(ModelPorts dataGenerators, Output outputDestinations) { UNIMPLEMENTED ("build a PlayProcess"); + pTable_->establishProcess( + new PlayProcess (filterIterator (dataGenerators, + resolve(outputDestinations)))); } diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 927c2b79b..ce2cd3f38 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -3313,7 +3313,7 @@ Thus the mapping is a copyable value object, based on a associative array. It ma 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<DEF>}}} 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. -
+
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 can be added and removed dynamically from various components (backend, GUI), all using the same resolution and mapping mechanisms (&rarr; OutputManagement)
 
@@ -3341,6 +3341,13 @@ The assumption is for the client to have elaborate timing capabilities at his di
 !!!Lifecycle and storage
 The concrete OutputSlot implementation is owned and managed by the facility actually providing this output possibility. For example, the GUI provides viewer widgets, while some sound output backend provides sound ports. This implementation object is required to stay alive as long as it's registered with some OutputManager. It needs to be deregistered explicitly prior to destruction -- and this deregistration may block until all clients using this slot are terminated. Beyond that, an output slot implementation is expected to handle all kinds of failures gracefully -- preferrably just emitting a signal (callback functor).
 
+-----
+!Implementation / design problems
+How to handle the selection of those two data exchange models!
+-- Problem is, typically this choice isn't up to the client; rather, the concrete OutputSlot implementation dictates what model to use. Yet I wanted to handle these through //generic programming// -- because they can't be subsumed under a single interface without distorting the usage or the structure.
+
+Thus: Client gets an {{{OutputSlot&}}}, without knowing the exact implementation type &rArr; how can the client pick up the right strategy, note, at //compile time!//
+
 
@@ -4201,7 +4208,7 @@ We need a way of addressing existing [[pipes|Pipe]]. Besides, as the Pipes and T <<tasksum end>>
-
+
With //play process//&nbsp; we denote an ongoing effort to calculate a stream of frames for playback or rendering.
 The play process is an conceptual entity linking together several activities in the [[Backend]] and the RenderEngine. Creating a play process is the central service provided by the [[player subsystem|Player]]: it maintains a registration entry for the process to keep track of associated entities, resources allocated and calls [[dispatched|FrameDispatcher]] as a consequence, and it wires and exposes a PlayController to serve as an interface and information hub.
 
@@ -4214,7 +4221,7 @@ The play process is an conceptual entity linking together several activities in
 !Anatomy of a Play Process
 The Controller is exposed to the client and acts as frontend handle, while the play process body groups and manages all the various parts cooperating to generate output. For each of the participating global pipes we get a feed to drive that pipeline to deliver media of a specific kind.
 
-Right within the play process, there is a separation into two realms, relying on different programming paradigms. Obviously the play controller is a state machine, and similarily the body object (play process) has a distinct operation state. Moreover, the individual objects hooked up at any given instance is a stateful variable. To the contrary, when we enter the realm of actual processing, operations are carried out in parallel, relying on stateless descriptor objects, hooked up into individual calculation jobs, to be scheduled as non-blocking units of operation. For each series of consecutive frames to be calculated, there is a descriptor object, the CalculationStream, which also links to a specificaly tailored dispatcher table, allowing to schedule the individual frame jobs. Whenever the controller determines a change in the playback plan (speed change, skip, scrubbing, looping, ...), a new CalculationStream is created, while the existing one is just used to mark any not-yet processed job as superseded.
+Right within the play process, there is a separation into two realms, relying on different programming paradigms. Obviously the play controller is a state machine, and similarily the body object (play process) has a distinct operation state. Moreover, the current collection of individual objects hooked up at any given instance is a stateful variable. To the contrary, when we enter the realm of actual processing, operations are carried out in parallel, relying on stateless descriptor objects, wired into individual calculation jobs, to be scheduled as non-blocking units of operation. For each series of consecutive frames to be calculated, there is a descriptor object, the CalculationStream, which also links to a specificaly tailored dispatcher table, allowing to schedule the individual frame jobs. Whenever the controller determines a change in the playback plan (speed change, skip, scrubbing, looping, ...), a new CalculationStream is created, while the existing one is just used to mark any not-yet processed job as superseded.