2012-02-13 00:37:57 +01:00
|
|
|
/*
|
|
|
|
|
JOB-TICKET.hpp - execution plan for render jobs
|
|
|
|
|
|
|
|
|
|
Copyright (C) Lumiera.org
|
|
|
|
|
2012, Hermann Vosseler <Ichthyostega@web.de>
|
|
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU General Public License as
|
|
|
|
|
published by the Free Software Foundation; either version 2 of
|
|
|
|
|
the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef PROC_ENGINE_JOB_TICKET_H
|
|
|
|
|
#define PROC_ENGINE_JOB_TICKET_H
|
|
|
|
|
|
|
|
|
|
#include "proc/common.hpp"
|
|
|
|
|
//#include "proc/state.hpp"
|
2012-02-18 19:42:20 +01:00
|
|
|
#include "proc/engine/job.hpp"
|
|
|
|
|
#include "proc/engine/frame-coord.hpp"
|
2012-02-13 00:37:57 +01:00
|
|
|
//#include "lib/time/timevalue.hpp"
|
|
|
|
|
//#include "lib/time/timequant.hpp"
|
2013-04-29 01:36:32 +02:00
|
|
|
#include "lib/hierarchy-orientation-indicator.hpp"
|
2012-05-05 05:02:29 +02:00
|
|
|
#include "lib/linked-elements.hpp"
|
2012-07-21 20:27:52 +02:00
|
|
|
#include "lib/iter-adapter.hpp"
|
2012-09-03 01:49:14 +02:00
|
|
|
#include "lib/util.hpp"
|
2012-02-13 00:37:57 +01:00
|
|
|
|
|
|
|
|
#include <boost/noncopyable.hpp>
|
2012-07-22 03:11:01 +02:00
|
|
|
#include <stack>
|
2012-02-13 00:37:57 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace proc {
|
|
|
|
|
namespace engine {
|
|
|
|
|
|
|
|
|
|
//using lib::time::TimeSpan;
|
|
|
|
|
//using lib::time::Duration;
|
|
|
|
|
//using lib::time::FSecs;
|
|
|
|
|
//using lib::time::Time;
|
2012-05-05 05:02:29 +02:00
|
|
|
using lib::LinkedElements;
|
2013-04-29 01:36:32 +02:00
|
|
|
using lib::OrientationIndicator;
|
2012-09-03 01:49:14 +02:00
|
|
|
using util::isnil;
|
2012-02-13 00:37:57 +01:00
|
|
|
//
|
|
|
|
|
//class ExitNode;
|
|
|
|
|
|
2012-04-28 04:18:00 +02:00
|
|
|
|
2012-02-13 00:37:57 +01:00
|
|
|
/**
|
|
|
|
|
* execution plan for pulling a specific exit node.
|
|
|
|
|
* Usable as blue print for generating actual render jobs.
|
|
|
|
|
* Job tickets are created on demand, specialised for each segment
|
|
|
|
|
* of the low-level model, and for each individual feed (corresponding
|
|
|
|
|
* to a single model port). Once created, they are final for this segment,
|
|
|
|
|
* stored together with the other descriptor objects (ProcNode and WiringDescriptor)
|
|
|
|
|
* and finally discarded in bulk, in case that segment of the low-level model becomes
|
2012-05-05 05:02:29 +02:00
|
|
|
* obsolete and is replaced by a newly built new version of this model segment.
|
2012-02-13 00:37:57 +01:00
|
|
|
*
|
|
|
|
|
* Job tickets are created by a classical recursive descent call on the exit node,
|
|
|
|
|
* which figures out everything to be done for generating data from this node.
|
|
|
|
|
* To turn a JobTicket into an actual job, we need the additional information
|
|
|
|
|
* regarding the precise frame number (=nominal time) and the channel number
|
2012-02-18 00:49:53 +01:00
|
|
|
* to calculate (in case the actual feed is multichannel, which is the default).
|
|
|
|
|
* This way, the JobTicket acts as <i>higher order function:</i> a function
|
|
|
|
|
* generating on invocation another, specific function (= the job).
|
2012-02-13 00:37:57 +01:00
|
|
|
*
|
|
|
|
|
* @todo 1/12 WIP-WIP-WIP defining the invocation sequence and render jobs
|
|
|
|
|
*/
|
|
|
|
|
class JobTicket
|
|
|
|
|
: boost::noncopyable
|
|
|
|
|
{
|
2012-05-05 05:02:29 +02:00
|
|
|
struct Provision
|
|
|
|
|
{
|
|
|
|
|
Provision* next;
|
2013-01-13 23:20:20 +01:00
|
|
|
////////////////////TODO some channel or format descriptor here
|
2012-05-05 05:02:29 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct Prerequisite
|
|
|
|
|
{
|
|
|
|
|
Prerequisite* next;
|
2012-07-22 03:11:01 +02:00
|
|
|
JobTicket* descriptor;
|
2012-05-05 05:02:29 +02:00
|
|
|
};
|
|
|
|
|
|
2012-07-01 03:42:50 +02:00
|
|
|
struct Prerequisites ///< per channel
|
2012-05-05 05:02:29 +02:00
|
|
|
{
|
|
|
|
|
Prerequisites* next;
|
2012-07-21 20:27:52 +02:00
|
|
|
LinkedElements<Prerequisite> requiredJobs_;
|
2012-05-05 05:02:29 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2012-07-21 20:27:52 +02:00
|
|
|
|
2012-07-01 03:42:50 +02:00
|
|
|
LinkedElements<Provision> channelConfig_;
|
2012-05-05 05:02:29 +02:00
|
|
|
LinkedElements<Prerequisites> requirement_;
|
2012-02-13 00:37:57 +01:00
|
|
|
|
2012-07-01 03:42:50 +02:00
|
|
|
|
2012-08-22 10:43:55 +02:00
|
|
|
public:
|
2012-07-22 03:11:01 +02:00
|
|
|
class ExplorationState;
|
|
|
|
|
friend class ExplorationState;
|
2012-07-01 03:42:50 +02:00
|
|
|
|
2012-02-13 00:37:57 +01:00
|
|
|
|
|
|
|
|
JobTicket()
|
|
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED ("job representation, planning and scheduling");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-09-04 01:55:11 +02:00
|
|
|
ExplorationState startExploration() const;
|
2012-09-03 01:49:14 +02:00
|
|
|
ExplorationState discoverPrerequisites (uint channelNr) const;
|
2012-07-21 20:27:52 +02:00
|
|
|
|
2012-04-29 04:43:24 +02:00
|
|
|
Job createJobFor (FrameCoord coordinates);
|
|
|
|
|
|
2012-02-18 19:42:20 +01:00
|
|
|
|
2012-02-13 00:37:57 +01:00
|
|
|
bool
|
|
|
|
|
isValid() const
|
|
|
|
|
{
|
2012-09-03 01:49:14 +02:00
|
|
|
if (channelConfig_.size() != requirement_.size())
|
|
|
|
|
return false;
|
|
|
|
|
|
2012-02-13 00:37:57 +01:00
|
|
|
UNIMPLEMENTED ("validity self check");
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2012-07-22 03:11:01 +02:00
|
|
|
|
|
|
|
|
class JobTicket::ExplorationState
|
|
|
|
|
{
|
|
|
|
|
typedef LinkedElements<Prerequisite>::iterator SubTicketSeq;
|
|
|
|
|
typedef std::stack<SubTicketSeq> SubTicketStack; //////////////////////////TODO use a custom container to avoid heap allocations
|
|
|
|
|
|
|
|
|
|
SubTicketStack toExplore_;
|
2013-04-29 01:36:32 +02:00
|
|
|
OrientationIndicator orientation_;
|
2012-07-22 03:11:01 +02:00
|
|
|
|
|
|
|
|
public:
|
2012-09-04 00:17:28 +02:00
|
|
|
ExplorationState() { }
|
|
|
|
|
|
|
|
|
|
ExplorationState (Prerequisites& prerequisites)
|
|
|
|
|
{
|
|
|
|
|
if (!isnil (prerequisites.requiredJobs_))
|
|
|
|
|
toExplore_.push (prerequisites.requiredJobs_.begin());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// using default copy operations
|
2012-07-22 03:11:01 +02:00
|
|
|
|
|
|
|
|
|
2012-08-22 10:43:55 +02:00
|
|
|
bool
|
|
|
|
|
empty() const
|
|
|
|
|
{
|
2012-09-03 01:49:14 +02:00
|
|
|
return toExplore_.empty();
|
2012-08-22 10:43:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-04-29 01:36:32 +02:00
|
|
|
void
|
|
|
|
|
markTreeLocation()
|
|
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED ("establish tree relation to previous point");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-08-22 10:43:55 +02:00
|
|
|
void
|
|
|
|
|
pullNext()
|
|
|
|
|
{
|
2012-09-03 01:49:14 +02:00
|
|
|
if (empty())
|
|
|
|
|
throw lumiera::error::Logic ("Exploration of Job prerequisites floundered. "
|
|
|
|
|
"Attempt to iterate beyond the end of prerequisite list"
|
|
|
|
|
,lumiera::error::LUMIERA_ERROR_ITER_EXHAUST);
|
|
|
|
|
ASSERT (toExplore_.top().isValid());
|
|
|
|
|
|
|
|
|
|
++(toExplore_.top());
|
|
|
|
|
while ( !toExplore_.empty()
|
|
|
|
|
&& toExplore_.top().empty())
|
|
|
|
|
toExplore_.pop();
|
|
|
|
|
|
|
|
|
|
ENSURE (empty() || toExplore_.top().isValid());
|
2012-08-22 10:43:55 +02:00
|
|
|
}
|
2012-07-22 03:11:01 +02:00
|
|
|
|
2012-09-03 01:49:14 +02:00
|
|
|
|
2012-07-22 03:11:01 +02:00
|
|
|
void
|
2013-04-29 01:36:32 +02:00
|
|
|
push (ExplorationState subExploration) // note: passing deliberately by value
|
2012-07-22 03:11:01 +02:00
|
|
|
{
|
2012-09-03 01:49:14 +02:00
|
|
|
if (subExploration.empty()) return;
|
|
|
|
|
|
|
|
|
|
pushAllPrerequisites (subExploration.toExplore_);
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-22 10:43:55 +02:00
|
|
|
|
|
|
|
|
JobTicket*
|
|
|
|
|
operator->() const
|
|
|
|
|
{
|
2012-09-03 01:49:14 +02:00
|
|
|
REQUIRE (!empty() && toExplore_.top().isValid());
|
|
|
|
|
REQUIRE (toExplore_.top()->descriptor);
|
|
|
|
|
REQUIRE (toExplore_.top()->descriptor->isValid());
|
|
|
|
|
|
|
|
|
|
return toExplore_.top()->descriptor;
|
2012-08-22 10:43:55 +02:00
|
|
|
}
|
|
|
|
|
|
2012-09-03 01:49:14 +02:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void
|
|
|
|
|
pushAllPrerequisites (SubTicketStack& furtherPrerequisites)
|
|
|
|
|
{
|
|
|
|
|
REQUIRE (!isnil (furtherPrerequisites));
|
|
|
|
|
|
|
|
|
|
if (1 == furtherPrerequisites.size())
|
|
|
|
|
{
|
|
|
|
|
this->toExplore_.push (furtherPrerequisites.top());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{ // pathological case: several levels of prerequisites
|
|
|
|
|
// --> push recursively to retain level ordering
|
|
|
|
|
SubTicketSeq deepestLevel (furtherPrerequisites.top());
|
|
|
|
|
furtherPrerequisites.pop();
|
|
|
|
|
pushAllPrerequisites (furtherPrerequisites);
|
|
|
|
|
this->toExplore_.push (deepestLevel);
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-07-22 03:11:01 +02:00
|
|
|
};
|
2012-09-03 01:49:14 +02:00
|
|
|
|
2012-08-22 10:43:55 +02:00
|
|
|
|
2012-07-22 03:11:01 +02:00
|
|
|
|
|
|
|
|
|
2012-09-04 01:55:11 +02:00
|
|
|
inline JobTicket::ExplorationState
|
|
|
|
|
JobTicket::startExploration() const
|
|
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED ("somehow build a self-referential pseudo-prerequisite, and seed an ExplorationState with that");
|
|
|
|
|
/////////////////////TODO problem is: we need an JobTicket::Prerequisite instance, where the descriptor points to "self" (this JobTicket)
|
|
|
|
|
/////////////////////TODO : but this instance needs to reside somewhere at a safe location, since we want to embed an LinkedElements-iterator
|
|
|
|
|
/////////////////////TODO : into the ExplorationState. And obviously we do not want that instance in each JobTicket, only in the top level ones
|
2012-10-06 02:29:19 +02:00
|
|
|
|
|
|
|
|
/////////////////////TODO : on second thought -- better have a top-level entry point to the evaluation of a frame
|
|
|
|
|
/////////////////////TODO basically this inherits from Prerequisite and lives somehow in the dispatcher-table or segment
|
2012-09-04 01:55:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-08-22 10:43:55 +02:00
|
|
|
inline JobTicket::ExplorationState
|
2012-09-03 01:49:14 +02:00
|
|
|
JobTicket::discoverPrerequisites (uint channelNr) const
|
2012-07-22 03:11:01 +02:00
|
|
|
{
|
2012-09-03 01:49:14 +02:00
|
|
|
REQUIRE (channelNr < requirement_.size());
|
|
|
|
|
|
2012-09-04 00:17:28 +02:00
|
|
|
return ExplorationState (requirement_[channelNr]);
|
2012-07-22 03:11:01 +02:00
|
|
|
}
|
|
|
|
|
|
2012-07-01 03:42:50 +02:00
|
|
|
|
2012-02-13 00:37:57 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
}} // namespace proc::engine
|
|
|
|
|
#endif
|