From 86e76bf7fe4793b04a25afc38278657de44d5851 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 17 Aug 2013 03:37:36 +0200 Subject: [PATCH] define setup and chaining of render planning chunks (#920) --- src/lib/hash-value.h | 4 +- src/proc/engine/calc-plan-continuation.hpp | 53 ++++++++++++++-------- src/proc/engine/calc-stream.hpp | 36 ++++++++------- src/proc/engine/engine-service.cpp | 21 ++++++--- src/proc/engine/job.cpp | 8 ++-- src/proc/engine/job.hpp | 17 +++++-- src/proc/engine/time-anchor.hpp | 32 ++++--------- 7 files changed, 97 insertions(+), 74 deletions(-) diff --git a/src/lib/hash-value.h b/src/lib/hash-value.h index 237704d14..06fe86d18 100644 --- a/src/lib/hash-value.h +++ b/src/lib/hash-value.h @@ -1,5 +1,5 @@ /* - HASH-UTIL.hpp - collection of tools and definitions for working with hashes + HASH-VALUE.hpp - collection of tools and definitions for working with hashes Copyright (C) Lumiera.org 2012, Hermann Vosseler @@ -21,7 +21,7 @@ */ -/** @file hash-util.h +/** @file hash-value.h ** Hash value types and utilities. ** This header defines the basic hash value types and provides some simple ** utilities to support working with hash values. diff --git a/src/proc/engine/calc-plan-continuation.hpp b/src/proc/engine/calc-plan-continuation.hpp index f16392935..4bb246408 100644 --- a/src/proc/engine/calc-plan-continuation.hpp +++ b/src/proc/engine/calc-plan-continuation.hpp @@ -63,8 +63,8 @@ namespace engine { , boost::noncopyable { - Dispatcher* dispatcher_; - TimeAnchor refPoint_; + play::Timings const& timings_; + Dispatcher& dispatcher_; const ModelPort modelPort_; const uint channel_; @@ -87,7 +87,9 @@ namespace engine { void invokeJobOperation (JobParameter parameter) { - UNIMPLEMENTED ("representation of the job functor, especially the invocation instance ID for this planning chunk"); + ASSERT (parameter.nominalTime == timings_.getFrameStartAt (parameter.invoKey.frameNumber)); + + this->performJobPlanningChunk (parameter.invoKey.frameNumber); } @@ -97,7 +99,7 @@ namespace engine { UNIMPLEMENTED ("what needs to be done when a planning continuation cant be invoked?"); } - + public: /** @@ -106,39 +108,52 @@ namespace engine { CalcPlanContinuation(play::Timings const& timings ,Dispatcher& dispatcher ,ModelPort modelPort - ,int64_t startFrame ,uint channel) - : dispatcher_(&dispatcher) - , refPoint_(TODO) + : timings_(timings) + , dispatcher_(dispatcher) , modelPort_(modelPort) , channel_(channel) - { - UNIMPLEMENTED ("how to set up the initial playback start point"); - } + { } + /** create the "start trigger job" + * Scheduling this job will effectively get a calculation stream + * into active processing, since it causes the first chunk of job planning + * plus the automated scheduling of follow-up planning jobs. The relation + * to real (wall clock) time will be established when the returned job + * is actually invoked + * @param startFrame where to begin rendering, relative to the nominal + * time grid implicitly related to the ModelPort to be pulled + */ Job - initiateRenderPlanning () + prepareRenderPlanningFrom (int64_t startFrame) { - UNIMPLEMENTED ("setup of the initial planning job"); + InvocationInstanceID invoKey; + invoKey.frameNumber = startFrame; + Time nominalPlanningStartTime = timings_.getFrameStartAt (startFrame); + + return Job(this, invoKey, nominalPlanningStartTime); } private: void - performJobPlanningChunk() + performJobPlanningChunk(int64_t nextStartFrame) { - JobPlanningSequence jobs = dispatcher_->onCalcStream(modelPort_, channel_) - .establishNextJobs(refPoint_); + TimeAnchor refPoint(timings_, nextStartFrame); + JobPlanningSequence jobs = dispatcher_.onCalcStream(modelPort_, channel_) + .establishNextJobs(refPoint); + + Job nextChunkOfPlanning = buildFollowUpJobFrom (refPoint); UNIMPLEMENTED ("the actual meat: access the scheduler and fed those jobs"); } + Job - buildFollowUpJobFromThis() + buildFollowUpJobFrom (TimeAnchor const& refPoint) { - refPoint_.setNextAnchorPoint(); - - UNIMPLEMENTED ("create the follow-up job, wired with this closure"); + return this->prepareRenderPlanningFrom( + refPoint.getNextAnchorPoint()); } }; diff --git a/src/proc/engine/calc-stream.hpp b/src/proc/engine/calc-stream.hpp index e3341502a..e945afad3 100644 --- a/src/proc/engine/calc-stream.hpp +++ b/src/proc/engine/calc-stream.hpp @@ -101,6 +101,14 @@ namespace engine{ friend class EngineService; + + CalcStream + sendToOutput (play::DataSink) + { + UNIMPLEMENTED ("set up dispatcher to start calculating and feeding to the given output sink"); + return *this; + } + public: CalcStream() @@ -109,25 +117,19 @@ namespace engine{ { } ~CalcStream() { } + + // using standard copy operations - // using standard copy operations - CalcStream - sendToOutput (play::DataSink) - { - UNIMPLEMENTED ("set up dispatcher to start calculating and feeding to the given output sink"); - return *this; - } - - play::Timings const& - getTimings() - { - if (!eng_) - throw error::State ("attempt to get the playback timings " - "of an unconfigured, disabled or halted calculation stream" - ,error::LUMIERA_ERROR_LIFECYCLE); - return eng_->effectiveTimings(); - } + play::Timings const& + getTimings() + { + if (!eng_) + throw error::State ("attempt to get the playback timings " + "of an unconfigured, disabled or halted calculation stream" + ,error::LUMIERA_ERROR_LIFECYCLE); + return eng_->effectiveTimings(); + } }; diff --git a/src/proc/engine/engine-service.cpp b/src/proc/engine/engine-service.cpp index bd27e0eb7..8f52a9ad8 100644 --- a/src/proc/engine/engine-service.cpp +++ b/src/proc/engine/engine-service.cpp @@ -90,7 +90,7 @@ namespace engine{ return runningCalculations; /////////////////////////////////////////////////////////////////////////////////////////////TICKET #874 : use a pipeline builder to write it as follows: // treat_all(output.getOpenedSinks()) -// .apply (activateCalculation, renderConfig, _1) +// .apply (activateCalculation, _1, renderConfig) // .buildVector(); } @@ -123,13 +123,20 @@ namespace engine{ /** @internal extension point - * Install and activate a single, ongoing calculation effort. - * Configure and prepare all the internal components, pre-allocate - * resources and add entries to the registration tables to get this - * render activity into running state - * @return CalcStream representing this newly started rendering activity + * Create the environment for rendering a connected and related set of output streams. + * Configure and prepare all the internal components, pre-allocate resources and add + * entries to the registration tables necessary to get the related render activities + * into "running" state. The created setup will typically be used to generate all + * the individual channel streams linked together for playback or rendering; + * they all share the same media type and quality settings. + * @return an abstracted representation of the specific setup for this render; + * from this point on, this RenderEnvironmentClosure will be the only way + * for client code to talk to "the engine". The actual instance of this + * closure is just a handle and can be copied; any CalcStream created + * off this closure will be linked to the same "environment" and be + * tracked and managed for resource usage automatically. * @note variations and especially mock implementations of the render engine - * might choose to configure internal differently. As long as the + * might choose to configure internals differently. As long as the * CalcStream and the embedded RenderEnvironmentClosure are consistent, * such a specific configuration remains opaque for the user of the * created render activity diff --git a/src/proc/engine/job.cpp b/src/proc/engine/job.cpp index f92001d8f..3ed4a674d 100644 --- a/src/proc/engine/job.cpp +++ b/src/proc/engine/job.cpp @@ -72,16 +72,16 @@ namespace engine { /** @todo WIP-WIP 2/12 */ void - Job::triggerJob () const + Job::triggerJob() const { - myClosure(this).invokeJobOperation (parameter); + myClosure(this).invokeJobOperation (parameter, currentTime); } void - Job::signalFailure () const + Job::signalFailure() const { - UNIMPLEMENTED ("how to organise job failure and abortion"); + myClosure(this).signalFailure (parameter, now); } diff --git a/src/proc/engine/job.hpp b/src/proc/engine/job.hpp index d55ff9fca..676d800e4 100644 --- a/src/proc/engine/job.hpp +++ b/src/proc/engine/job.hpp @@ -26,18 +26,28 @@ #include "lib/llist.h" +#include "lib/hash-value.h" #include -typedef uint64_t InvocationInstanceID; /////////////////TODO +/** opaque ID attached to each individual job invocation. + * Used by the implementation of the Jobs (i.e. the JobClosure) + * for internal organisation; will be fed back on job activation. + */ +union InvocationInstanceID + { + int64_t frameNumber; + lumiera_uid luid; + }; + enum JobState { - DONE, ///< already done, nothing to do + DONE, ///< mission accomplished RUNNING, ///< job is currently running - WAITING, ///< waits for some prerequisite resource + WAITING, ///< waiting for some prerequisite REJECTED, ///< sorry, can't do that Dave EXPIRED, ///< deadline expired ABORTED ///< got aborted @@ -51,6 +61,7 @@ enum JobKind }; + /** * closure representing the execution context of a job. * The information reachable through this closure is specific diff --git a/src/proc/engine/time-anchor.hpp b/src/proc/engine/time-anchor.hpp index 9a5fb27cb..8474bbb5e 100644 --- a/src/proc/engine/time-anchor.hpp +++ b/src/proc/engine/time-anchor.hpp @@ -109,44 +109,32 @@ namespace engine { } + public: TimeAnchor (play::Timings timings, int64_t startFrame, Offset startDelay =Offset::ZERO) : timings_(timings) , anchorPoint_(startFrame) , relatedRealTime_(expectedTimeofArival(timings,startFrame,startDelay)) { } - public: // using default copy operations - /** create a TimeAnchor for playback/rendering start at the given startFrame. - * For latency calculations, the EngineConfig will be queried behind the scenes. - * regarding the reaction latency required to get the engine - * @note this builder function adds an additional, hard wired start margin - * of one frame duration, to compensate for first time effects. - */ - static TimeAnchor - build (play::Timings timings, int64_t startFrame) - { - Offset startDelay(timings.getFrameDurationAt(startFrame)); - return TimeAnchor (timings,startFrame,startDelay); - } - /** set a follow-up TimeAnchor point. * After planning a chunk of jobs, the dispatcher uses * this function to set up a new breaking point (TimeAnchor) * and places a continuation job to resume the planning activity. - * @note precisely satisfies the planning chunk duration: - * afterwards the start point will be anchored at the grid point - * following the end of the previous planning chunk, resulting - * in a seamless coverage of the timeline + * @note precisely satisfies the planning chunk duration + * @return a frame number suitable to build the next TimeAnchor + * based on the current play::Timings. This new start point + * will be anchored at the grid point following the end of + * the previous planning chunk, resulting in a seamless + * coverage of the timeline */ - void - setNextAnchorPoint() + int64_t + getNextAnchorPoint() const { - this->anchorPoint_ = timings_.establishNextPlanningChunkStart (this->anchorPoint_); - this->relatedRealTime_ = expectedTimeofArival(this->timings_,this->anchorPoint_, Offset::ZERO); + return timings_.establishNextPlanningChunkStart (this->anchorPoint_); }