WIP some further musing about how to do a simple invocation for unit testing ProcNode
This commit is contained in:
parent
83067aa318
commit
391181e699
11 changed files with 136 additions and 84 deletions
|
|
@ -41,6 +41,7 @@
|
|||
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/streamtype.hpp"
|
||||
#include "lib/bool-checkable.hpp"
|
||||
|
||||
|
||||
namespace engine {
|
||||
|
|
@ -52,22 +53,36 @@ namespace engine {
|
|||
* The real buffer pointer can be retrieved by dereferencing this smart-handle class.
|
||||
*/
|
||||
struct BuffHandle
|
||||
: lib::BoolCheckable<BuffHandle>
|
||||
{
|
||||
typedef lumiera::StreamType::ImplFacade::DataBuffer Buff;
|
||||
typedef Buff* PBuff;
|
||||
|
||||
PBuff
|
||||
operator->() const
|
||||
operator->() const
|
||||
{
|
||||
return pBuffer_;
|
||||
}
|
||||
Buff&
|
||||
operator* () const
|
||||
operator* () const
|
||||
{
|
||||
ENSURE (pBuffer_);
|
||||
return *pBuffer_;
|
||||
}
|
||||
|
||||
bool
|
||||
isValid() const
|
||||
{
|
||||
return pBuffer_;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////TODO: the whole logic how to create a BuffHandle needs to be solved in a more clever way. --> Ticket 249
|
||||
BuffHandle()
|
||||
: pBuffer_(0),
|
||||
sourceID_(0)
|
||||
{ }
|
||||
|
||||
private:
|
||||
PBuff pBuffer_;
|
||||
long sourceID_;
|
||||
|
|
|
|||
|
|
@ -203,6 +203,7 @@ namespace config {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
template<class NEXT>
|
||||
struct FeedCache : NEXT
|
||||
{
|
||||
|
|
@ -219,6 +220,7 @@ namespace config {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
template<class NEXT>
|
||||
struct ReleaseBuffers : NEXT /////////////////TODO: couldn't this be done automatically by BuffTab's dtor??
|
||||
{ ///////////////// this would require BuffHandle to be a smart ref....
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ namespace engine {
|
|||
|
||||
/** create and configure a concrete wiring descriptor to tie
|
||||
* a ProcNode to its predecessor nodes. This includes selecting
|
||||
* the actual StateProxy type, configuring it out of some operation
|
||||
* the actual StateAdapter type, configuring it out of some operation
|
||||
* control templates (policy classes). Compiling this operator function
|
||||
* actually drives the necessary template instantiations for all cases
|
||||
* encountered while building the node network.
|
||||
|
|
|
|||
|
|
@ -83,10 +83,7 @@ namespace engine {
|
|||
setup.makeInDescriptor(),
|
||||
setup.resolveProcessingFunction(),
|
||||
setup.createNodeID())
|
||||
{
|
||||
nrO = out.size();
|
||||
nrI = in.size();
|
||||
}
|
||||
{ }
|
||||
|
||||
friend class WiringFactory;
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,10 @@ namespace engine {
|
|||
: out(o), in(i),
|
||||
procFunction(pFunc),
|
||||
nodeID(nID)
|
||||
{ }
|
||||
{
|
||||
nrO = out.size();
|
||||
nrI = in.size();
|
||||
}
|
||||
|
||||
/** the wiring-dependent part of the node operation.
|
||||
* Includes the creation of a one-way state object on the stack
|
||||
|
|
@ -129,6 +132,9 @@ namespace engine {
|
|||
|
||||
public:
|
||||
|
||||
/** output channel count */
|
||||
uint nrO() { return wiringConfig_.nrO; }
|
||||
|
||||
/** Engine Core operation: render and pull output from this node.
|
||||
* On return, currentProcess will hold onto output buffer(s)
|
||||
* containing the calculated result frames. In case this node
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
|
||||
#include "proc/engine/render-invocation.hpp"
|
||||
#include "proc/engine/stateproxy.hpp"
|
||||
|
||||
|
||||
namespace engine {
|
||||
|
||||
|
|
@ -35,51 +37,21 @@ namespace engine {
|
|||
// using mobject::session::Effect;
|
||||
|
||||
|
||||
/** @internal */
|
||||
/** @note this builds a one-way off invocation state context
|
||||
* and then forwards the call; this may or may not cause
|
||||
* actual calculations, depending on the cache.
|
||||
* @todo for real use within the engine, the pull()-call should be
|
||||
* dispatched through the scheduler; of course then the call semantics
|
||||
* would be completely different. Maybe this invocation will be test only?
|
||||
*/
|
||||
BuffHandle
|
||||
RenderInvocation::allocateBuffer (BufferDescriptor const&)
|
||||
RenderInvocation::operator[] (size_t channel)
|
||||
{
|
||||
UNIMPLEMENTED ("allocate a suitable buffer to hold a frame of the denoted type");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
RenderInvocation::releaseBuffer (BuffHandle& bh)
|
||||
{
|
||||
UNIMPLEMENTED ("free a buffer");
|
||||
}
|
||||
|
||||
|
||||
|
||||
BuffHandle
|
||||
RenderInvocation::fetch (FrameID const& fID)
|
||||
{
|
||||
UNIMPLEMENTED ("fetch a buffer with input data");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
RenderInvocation::is_calculated (BuffHandle const& bh)
|
||||
{
|
||||
UNIMPLEMENTED ("declare a buffer as fully calculated and done");
|
||||
}
|
||||
|
||||
|
||||
|
||||
FrameID const&
|
||||
RenderInvocation::genFrameID (NodeID const&, uint chanNo)
|
||||
{
|
||||
UNIMPLEMENTED ("derive/generate an ID to denote this specific fame+Node position in the graph");
|
||||
}
|
||||
|
||||
|
||||
|
||||
BuffTableStorage&
|
||||
RenderInvocation::getBuffTableStorage() /////////////TODO need somehow to denote the specific storage requirements
|
||||
{
|
||||
UNIMPLEMENTED ("allocate a chunk of storage suitable for holding the buffer pointer tables");
|
||||
REQUIRE (theNode_);
|
||||
REQUIRE (channel < size());
|
||||
|
||||
StateProxy invocationState;
|
||||
return theNode_->pull(invocationState, channel);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -34,9 +34,9 @@
|
|||
#define ENGINE_RENDER_INVOCATION_H
|
||||
|
||||
|
||||
#include "proc/state.hpp"
|
||||
//#include "proc/engine/procnode.hpp"
|
||||
//#include "proc/engine/buffhandle.hpp"
|
||||
//#include "proc/state.hpp"
|
||||
#include "proc/engine/procnode.hpp"
|
||||
#include "proc/engine/buffhandle.hpp"
|
||||
//#include "proc/engine/bufftable.hpp"
|
||||
|
||||
|
||||
|
|
@ -49,34 +49,23 @@ namespace engine {
|
|||
* TODO: type comment
|
||||
*/
|
||||
class RenderInvocation
|
||||
: public State
|
||||
{
|
||||
protected:
|
||||
// State& parent_;
|
||||
// State& current_;
|
||||
ProcNode* theNode_;
|
||||
|
||||
RenderInvocation()
|
||||
{ }
|
||||
public:
|
||||
RenderInvocation (ProcNode* exitNode)
|
||||
: theNode_(exitNode)
|
||||
{
|
||||
REQUIRE (theNode_);
|
||||
}
|
||||
|
||||
size_t size() { return theNode_->nrO(); }
|
||||
|
||||
/** pull calculated data from the N-th node output channel */
|
||||
BuffHandle operator[] (size_t channel);
|
||||
|
||||
|
||||
|
||||
private: /* === top-level implementation of the State interface === */
|
||||
|
||||
BuffHandle allocateBuffer (BufferDescriptor const&);
|
||||
|
||||
void releaseBuffer (BuffHandle& bh);
|
||||
|
||||
BuffHandle fetch (FrameID const& fID);
|
||||
|
||||
void is_calculated (BuffHandle const& bh);
|
||||
|
||||
FrameID const& genFrameID (NodeID const&, uint chanNo);
|
||||
|
||||
BuffTableStorage& getBuffTableStorage();
|
||||
|
||||
virtual State& getCurrentImplementation () { return *this; }
|
||||
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////TODO: currently just fleshing out the API
|
||||
|
|
|
|||
|
|
@ -25,8 +25,63 @@
|
|||
|
||||
namespace engine {
|
||||
|
||||
/** */
|
||||
|
||||
namespace { // Details...
|
||||
|
||||
|
||||
} // (END) Details...
|
||||
|
||||
|
||||
// using mobject::Placement;
|
||||
// using mobject::session::Effect;
|
||||
|
||||
|
||||
/** @internal */
|
||||
BuffHandle
|
||||
StateProxy::allocateBuffer (BufferDescriptor const&)
|
||||
{
|
||||
UNIMPLEMENTED ("allocate a suitable buffer to hold a frame of the denoted type");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
StateProxy::releaseBuffer (BuffHandle& bh)
|
||||
{
|
||||
UNIMPLEMENTED ("free a buffer");
|
||||
}
|
||||
|
||||
|
||||
|
||||
BuffHandle
|
||||
StateProxy::fetch (FrameID const& fID)
|
||||
{
|
||||
UNIMPLEMENTED ("fetch a buffer with input data");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
StateProxy::is_calculated (BuffHandle const& bh)
|
||||
{
|
||||
UNIMPLEMENTED ("declare a buffer as fully calculated and done");
|
||||
}
|
||||
|
||||
|
||||
|
||||
FrameID const&
|
||||
StateProxy::genFrameID (NodeID const&, uint chanNo)
|
||||
{
|
||||
UNIMPLEMENTED ("derive/generate an ID to denote this specific fame+Node position in the graph");
|
||||
}
|
||||
|
||||
|
||||
|
||||
BuffTableStorage&
|
||||
StateProxy::getBuffTableStorage() /////////////TODO need somehow to denote the specific storage requirements
|
||||
{
|
||||
UNIMPLEMENTED ("allocate a chunk of storage suitable for holding the buffer pointer tables");
|
||||
}
|
||||
|
||||
|
||||
} // namespace engine
|
||||
|
|
|
|||
|
|
@ -35,7 +35,21 @@ namespace engine {
|
|||
class StateProxy
|
||||
: public proc_interface::State
|
||||
{
|
||||
protected:
|
||||
|
||||
private: /* === top-level implementation of the State interface === */
|
||||
|
||||
BuffHandle allocateBuffer (BufferDescriptor const&);
|
||||
|
||||
void releaseBuffer (BuffHandle& bh);
|
||||
|
||||
BuffHandle fetch (FrameID const& fID);
|
||||
|
||||
void is_calculated (BuffHandle const& bh);
|
||||
|
||||
FrameID const& genFrameID (NodeID const&, uint chanNo);
|
||||
|
||||
BuffTableStorage& getBuffTableStorage();
|
||||
|
||||
virtual State& getCurrentImplementation () { return *this; }
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@
|
|||
//#include "lib/util.hpp"
|
||||
#include "proc/engine/nodefactory.hpp"
|
||||
#include "proc/engine/nodewiring.hpp"
|
||||
#include "proc/engine/render-invocation.hpp"
|
||||
#include "proc/engine/stateproxy.hpp"
|
||||
#include "proc/engine/buffhandle.hpp"
|
||||
#include "proc/mobject/session/effect.hpp"
|
||||
#include "lib/allocationcluster.hpp"
|
||||
|
||||
|
|
@ -54,7 +55,7 @@ namespace test {
|
|||
* happening in correct order.
|
||||
*/
|
||||
class TestContext
|
||||
: public RenderInvocation
|
||||
: public StateProxy
|
||||
{
|
||||
|
||||
//////////////TODO: facility to verify the right access operations get called
|
||||
|
|
@ -83,8 +84,9 @@ namespace test {
|
|||
ASSERT (pNode);
|
||||
|
||||
TestContext simulatedInvocation;
|
||||
pNode->pull(simulatedInvocation, 0);
|
||||
BuffHandle result = pNode->pull(simulatedInvocation, 0);
|
||||
|
||||
ASSERT (result);
|
||||
// ASSERT we got calculated data in the result buffer
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2237,12 +2237,12 @@ So, when creating a clip out of such a compound media asset, the clip has to be
|
|||
In the most general case the render network may be just a DAG (not just a tree). Especially, multiple exit points may lead down to the same node, and following each of this possible paths the node may be at a different depth on each. This rules out a simple counter starting from the exit level, leaving us with the possibility of either employing a rather convoluted addressing scheme or using arbitrary ID numbers.{{red{...which is what we do for now}}}
|
||||
</pre>
|
||||
</div>
|
||||
<div title="NodeOperationProtocol" modifier="Ichthyostega" modified="200807072147" created="200806010251" tags="Rendering dynamic" changecount="15">
|
||||
<div title="NodeOperationProtocol" modifier="Ichthyostega" modified="200909031217" created="200806010251" tags="Rendering dynamic" changecount="16">
|
||||
<pre>The [[nodes|ProcNode]] are wired to form a "Directed Acyclic Graph"; each node knows its predecessor(s), but not its successor(s). The RenderProcess is organized according to the ''pull principle'', thus we find an operation {{{pull()}}} at the core of this process. There is no such thing as an "engine object" calling nodes iteratively or table driven, rather, the nodes themselves issue recursive calls to their predecessor(s). For this to work, we need the nodes to adhere to a specific protocol:
|
||||
# Node is pulled, with a StateProxy object as parameter (encapsulating the access to the frames or buffers)
|
||||
# Node may now access current parameter values, using the state accessible via the StateProxy
|
||||
# using it's //input-output and wiring descriptor,// the Node creates a StateAdapter wrapping the StateProxy for allocating buffers and accessing the required input
|
||||
# StateAdapter first tries to get the output frames from the Cache in the Backend. In case of failure, a {{{process()}}} call is prepared by generating {{{pull()}}} call(s) for the input
|
||||
# StateAdapter might first try to get the output frames from the Cache in the Backend. In case of failure, a {{{process()}}} call is prepared by generating {{{pull()}}} call(s) for the input
|
||||
# as late as possible, typically on return, these recursive pull-calls have allocated a buffer containing the input data.
|
||||
# when input is ready prior to the {{{process()}}} call, output buffers will be allocated, either from the cache, or (if not caching) from the "parent" StateAdapter up the callstack.
|
||||
# after all buffers are available, the StateAdapter issues the {{{process()}}} call back to the originating node, which now may dereference the frame pointers and do its calculations
|
||||
|
|
|
|||
Loading…
Reference in a new issue