diff --git a/src/proc/engine/dispatcher.cpp b/src/proc/engine/dispatcher.cpp index 07a22728c..37ded0273 100644 --- a/src/proc/engine/dispatcher.cpp +++ b/src/proc/engine/dispatcher.cpp @@ -30,7 +30,8 @@ namespace proc { namespace engine { - Dispatcher::~Dispatcher() { } // emit VTable here.... + Dispatcher::~Dispatcher() { } // emit VTables and Typeinfo here.... + FrameSequencer::~FrameSequencer() { } /** */ @@ -65,17 +66,8 @@ namespace engine { UNIMPLEMENTED ("wrap already planned jobs, appending a continuation to pick up later"); return *this; } - - - /** */ - JobTicket& - Dispatcher::accessJobTicket (FrameCoord const& frameID) - { - UNIMPLEMENTED ("figure out and create the actual JobTicket, for the current segment and the given port"); - } - diff --git a/src/proc/engine/dispatcher.hpp b/src/proc/engine/dispatcher.hpp index b084f6c83..d329039d3 100644 --- a/src/proc/engine/dispatcher.hpp +++ b/src/proc/engine/dispatcher.hpp @@ -49,20 +49,40 @@ namespace engine { // class ExitNode; /** - * @todo 11/11 extremely fuzzy at the moment + * Internal abstraction: a service within the engine + * for translating a logical calculation stream (corresponding to a PlayProcess) + * into a sequence of individual RenderJob entries for calculations and data access. + * The actual implementation of this service is tied to the low-level-model, i.e. + * the render nodes network. The Dispatcher service is used to implement the CalcStreams + * during playback and rendering; there will be a continuous, chunk-wise proceeding + * evaluation and planning of new jobs, which can then be handed over to the Scheduler + * for time-bound activation. + * + * \par usage considerations + * the asynchronous and ongoing nature of the render process mandates to avoid a central + * instance for operating this planning process. Instead, each chunk of planned jobs + * contains a continuation job, which -- on activation -- will pick up the planning + * of the next chunk. The Dispatcher interface was shaped to support this process, + * with a local JobBuilder to be used within the continuation job, and a TimeAnchor + * to represent the continuation point. All the complexities of planning jobs are + * hidden within the JobPlanningSequence, which, for the purpose of dispatching + * a series of jobs just looks like a sequence of job descriptors + * + * @todo 10/12 still WIP, but conceptually settled by now */ class Dispatcher - : boost::noncopyable + : public FrameLocator { struct JobBuilder { Dispatcher& dispatcher_; + TimeAnchor refPoint_; ModelPort modelPort_; uint channel_; /////TODO need storage for the continuation - FrameCoord relativeFrameLocation (TimeAnchor refPoint, uint frameCountOffset); + FrameCoord relativeFrameLocation (TimeAnchor refPoint, uint frameCountOffset =0); JobBuilder& establishNextJobs (TimeAnchor refPoint); @@ -70,11 +90,10 @@ namespace engine { operator JobPlanningSequence() { - UNIMPLEMENTED ("how to represent the closure for defining and scheduling jobs"); + TODO ("build the continuation job if necessary, wrap the sequence"); - ////////TODO: use a closure based on FrameCoord plus a back-reference to the Dispatcher. - //////////// Thus actually we need a *generator* for a sequence of FrameCoord - //////////// This generator is then wrapped up into an evaluation-Monad (IterExplorer) + return JobPlanningSequence( + relativeFrameLocation(refPoint_), dispatcher_); } }; @@ -84,11 +103,12 @@ namespace engine { JobBuilder onCalcStream (ModelPort modelPort, uint channel); - JobTicket& accessJobTicket (FrameCoord const&); protected: virtual FrameCoord locateRelative (FrameCoord, uint frameCountOffset) =0; - virtual FrameCoord locateRelative (TimeAnchor, uint frameCountOffset) =0; + virtual FrameCoord locateRelative (TimeAnchor, uint frameCountOffset) =0; //////////TODO is this really an interface operation, or just a convenience shortcut? + + virtual JobTicket& accessJobTicket (ModelPort, TimeValue nominalTime) =0; }; diff --git a/src/proc/engine/frame-coord.hpp b/src/proc/engine/frame-coord.hpp index a73be8d96..e90a2bc7b 100644 --- a/src/proc/engine/frame-coord.hpp +++ b/src/proc/engine/frame-coord.hpp @@ -39,7 +39,7 @@ namespace engine { //using lib::time::TimeSpan; using lib::time::Duration; //using lib::time::FSecs; - using lib::time::Time; + using lib::time::TimeVar; // // class ExitNode; @@ -50,7 +50,7 @@ namespace engine { * A frame render job can be characterised by * - the nominal (timeline) time of the frame * - the corresponding frame-number - * - the real wall-clock time of expected delivery + * - the real wall-clock time of expected delivery//////////////TODO : might be handy, but not sure if this information is substantial here * - timing constraints (e.g. latency to observe) //////////////TODO : not clear if we repeat this information here * - the actual node to pull data from * - the segment holding that node //////////////TODO : is this information really required?? @@ -64,7 +64,7 @@ namespace engine { { public: - Time absoluteNominalTime; + TimeVar absoluteNominalTime; int64_t absoluteFrameNumber; ModelPort modelPort; diff --git a/src/proc/engine/job-planning.hpp b/src/proc/engine/job-planning.hpp index f0268b289..9a4e90344 100644 --- a/src/proc/engine/job-planning.hpp +++ b/src/proc/engine/job-planning.hpp @@ -28,8 +28,8 @@ //#include "proc/state.hpp" #include "proc/engine/job.hpp" #include "proc/engine/job-ticket.hpp" -#include "proc/engine/time-anchor.hpp" -//#include "proc/engine/frame-coord.hpp" +//#include "proc/engine/time-anchor.hpp" +#include "proc/engine/frame-coord.hpp" //#include "lib/time/timevalue.hpp" //#include "lib/time/timequant.hpp" //#include "lib/meta/function.hpp" @@ -226,7 +226,27 @@ namespace engine { - + + /** + * Abstraction: a Facility to establish frame coordinates + * and identify and access the execution plan for this frame. + * @see Dispatcher the service interface actually used + */ + class FrameLocator + : public FrameSequencer + { + public: + + JobTicket& + getJobTicketFor (FrameCoord location) + { + return accessJobTicket (location.modelPort, location.absoluteNominalTime); + } + + protected: + virtual JobTicket& accessJobTicket (ModelPort, TimeValue nominalTime) =0; + }; + /** * Generate a sequence of starting points for Job planning, @@ -240,25 +260,22 @@ namespace engine { */ class PlanningStepGenerator { - engine::FrameSequencer* locationGenerator_; - engine::FrameCoord current_; + FrameLocator* locationGenerator_; + FrameCoord currentLocation_; public: typedef JobPlanning value_type; typedef JobPlanning& reference; typedef JobPlanning * pointer; -// PlanningStepGenerator() { } - PlanningStepGenerator(engine::TimeAnchor startPoint) - : anchor_(startPoint) + PlanningStepGenerator(FrameCoord startPoint, FrameLocator& locator) + : locationGenerator_(&locator) + , currentLocation_(startPoint) { } - //////////////////////////////////////////////////////////////TODO actually we need two distinct services - //////////////////////////////////////////////////////////////TODO - getting the next FrameCoord - //////////////////////////////////////////////////////////////TODO - getting the JobTicket for this location - //////////////////////////////////////////////////////////////TODO Actually, the Dispatcher would provide exactly those services, - //////////////////////////////////////////////////////////////TODO but depending on the Dispatcher constitutes a cyclic dependency. - //////////////////////////////////////////////////////////////TODO There seems to be a problem hidden somewhere in this design. + + // default copyable + /* === Iteration control API for IterStateWrapper== */ @@ -325,10 +342,10 @@ namespace engine { public: // JobPlanningSequence() { } - JobPlanningSequence(engine::TimeAnchor startPoint) + JobPlanningSequence(engine::FrameCoord startPoint, FrameLocator& locator) : ExpandedPlanningSequence( JobPlanningChunkStartPoint( - PlanningStepGenerator(startPoint)) + PlanningStepGenerator(startPoint,locator)) >>= expandPrerequisites) { } diff --git a/src/proc/mobject/builder/segmentation.hpp b/src/proc/mobject/builder/segmentation.hpp index 0eed4ed78..617445c18 100644 --- a/src/proc/mobject/builder/segmentation.hpp +++ b/src/proc/mobject/builder/segmentation.hpp @@ -63,8 +63,9 @@ namespace builder { : boost::noncopyable { + /////////////////////////////////////////////////TODO: placeholder code + /////////////////////////////////////////////////TODO: see the planned structure at http://lumiera.org/wiki/renderengine.html#Fixture typedef ID PID; -// typedef ID StID; public: diff --git a/tests/components/proc/engine/dispatcher-interface-test.cpp b/tests/components/proc/engine/dispatcher-interface-test.cpp index 86d19e1bb..b7dfc1476 100644 --- a/tests/components/proc/engine/dispatcher-interface-test.cpp +++ b/tests/components/proc/engine/dispatcher-interface-test.cpp @@ -83,6 +83,22 @@ namespace test { { UNIMPLEMENTED ("dummy implementation of the core dispatch operation"); } + FrameCoord + locateRelative (FrameCoord, uint frameCountOffset) + { + UNIMPLEMENTED ("dummy implementation of the core dispatch operation"); + } + FrameCoord + locateRelative (TimeAnchor, uint frameCountOffset) + { + UNIMPLEMENTED ("dummy implementation of the core dispatch operation"); + } + + JobTicket& + accessJobTicket (ModelPort, TimeValue nominalTime) + { + UNIMPLEMENTED ("dummy implementation of the model backbone / segmentation"); + } public: @@ -153,7 +169,7 @@ namespace test { CHECK (coordinates.modelPort == modelPort); CHECK (coordinates.channelNr == channel); - JobTicket& executionPlan = dispatcher.accessJobTicket (coordinates); + JobTicket& executionPlan = dispatcher.getJobTicketFor (coordinates); CHECK (executionPlan.isValid()); Job frameJob = executionPlan.createJobFor (coordinates); //////////////////////////////TODO this is wrong: we never create a single job! @@ -184,11 +200,11 @@ namespace test { // Verify the planned Jobs -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #880 CHECK (!isnil (jobs)); vector plannedChunk; lib::append_all (jobs, plannedChunk); +#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #880 uint chunksize = plannedChunk.size(); CHECK (chunksize == timings.getPlanningChunkSize());