TuttleOFX
1
|
00001 #ifndef _TUTTLE_HOST_PROCESSVISITORS_HPP_ 00002 #define _TUTTLE_HOST_PROCESSVISITORS_HPP_ 00003 00004 #include "ProcessVertexData.hpp" 00005 00006 #include <tuttle/host/memory/MemoryCache.hpp> 00007 00008 #include <boost/graph/properties.hpp> 00009 #include <boost/graph/visitors.hpp> 00010 #include <boost/graph/depth_first_search.hpp> 00011 #include <boost/graph/breadth_first_search.hpp> 00012 #include <boost/foreach.hpp> 00013 #include <boost/date_time/posix_time/posix_time.hpp> 00014 #include <boost/unordered_map.hpp> 00015 00016 #include <iostream> 00017 #include <fstream> 00018 #include <vector> 00019 00020 namespace tuttle { 00021 namespace host { 00022 namespace graph { 00023 00024 template<class TGraph> 00025 inline void connectClips( TGraph& graph ) 00026 { 00027 BOOST_FOREACH( typename TGraph::edge_descriptor ed, graph.getEdges() ) 00028 { 00029 typename TGraph::Edge& edge = graph.instance( ed ); 00030 typename TGraph::Vertex& vertexOutput = graph.targetInstance( ed ); 00031 typename TGraph::Vertex& vertexInput = graph.sourceInstance( ed ); 00032 00033 TUTTLE_TLOG( TUTTLE_TRACE, "[Connect Clips] " << edge ); 00034 TUTTLE_TLOG( TUTTLE_TRACE, "[Connect Clips] " << vertexOutput << " -> " << vertexInput ); 00035 //TUTTLE_TLOG_VAR( TUTTLE_TRACE, edge.getInAttrName() ); 00036 00037 if( ! vertexOutput.isFake() && ! vertexInput.isFake() ) 00038 { 00039 INode& outputNode = vertexOutput.getProcessNode(); 00040 INode& inputNode = vertexInput.getProcessNode(); 00041 inputNode.connect( outputNode, inputNode.getAttribute( edge.getInAttrName() ) ); 00042 } 00043 } 00044 } 00045 00046 00047 namespace visitor { 00048 00049 00050 00051 template<class TGraph> 00052 class Setup1 : public boost::default_dfs_visitor 00053 { 00054 public: 00055 typedef typename TGraph::GraphContainer GraphContainer; 00056 typedef typename TGraph::Vertex Vertex; 00057 00058 Setup1( TGraph& graph ) 00059 : _graph( graph ) 00060 {} 00061 00062 template<class VertexDescriptor, class Graph> 00063 void finish_vertex( VertexDescriptor v, Graph& g ) 00064 { 00065 Vertex& vertex = _graph.instance( v ); 00066 00067 TUTTLE_TLOG( TUTTLE_TRACE, "[Setup 1] finish vertex " << vertex ); 00068 if( vertex.isFake() ) 00069 return; 00070 00071 vertex.getProcessNode().setup1(); 00072 } 00073 00074 private: 00075 TGraph& _graph; 00076 }; 00077 00078 template<class TGraph> 00079 class Setup2 : public boost::default_dfs_visitor 00080 { 00081 public: 00082 typedef typename TGraph::GraphContainer GraphContainer; 00083 typedef typename TGraph::Vertex Vertex; 00084 00085 Setup2( TGraph& graph ) 00086 : _graph( graph ) 00087 {} 00088 00089 template<class VertexDescriptor, class Graph> 00090 void discover_vertex( VertexDescriptor v, Graph& g ) 00091 { 00092 Vertex& vertex = _graph.instance( v ); 00093 00094 TUTTLE_TLOG( TUTTLE_TRACE, "[Setup 2] discover vertex " << vertex ); 00095 if( vertex.isFake() ) 00096 return; 00097 00098 vertex.getProcessNode().setup2_reverse(); 00099 } 00100 00101 private: 00102 TGraph& _graph; 00103 }; 00104 00105 00106 template<class TGraph> 00107 class Setup3 : public boost::default_dfs_visitor 00108 { 00109 public: 00110 typedef typename TGraph::GraphContainer GraphContainer; 00111 typedef typename TGraph::Vertex Vertex; 00112 00113 Setup3( TGraph& graph ) 00114 : _graph( graph ) 00115 {} 00116 template<class VertexDescriptor, class Graph> 00117 void finish_vertex( VertexDescriptor v, Graph& g ) 00118 { 00119 Vertex& vertex = _graph.instance( v ); 00120 00121 TUTTLE_TLOG( TUTTLE_TRACE, "[Setup 3] finish vertex " << vertex ); 00122 if( vertex.isFake() ) 00123 return; 00124 00125 vertex.getProcessNode().setup3(); 00126 } 00127 00128 private: 00129 TGraph& _graph; 00130 }; 00131 00132 template<class TGraph> 00133 class TimeDomain : public boost::default_dfs_visitor 00134 { 00135 public: 00136 typedef typename TGraph::GraphContainer GraphContainer; 00137 typedef typename TGraph::Vertex Vertex; 00138 00139 TimeDomain( TGraph& graph ) 00140 : _graph( graph ) 00141 {} 00142 00143 template<class VertexDescriptor, class Graph> 00144 void finish_vertex( VertexDescriptor vd, Graph& g ) 00145 { 00146 Vertex& vertex = _graph.instance( vd ); 00147 00148 TUTTLE_TLOG( TUTTLE_TRACE, "[Time Domain] finish vertex " << vertex ); 00149 if( vertex.isFake() ) 00150 return; 00151 00152 vertex.getProcessData()._timeDomain = vertex.getProcessNode().computeTimeDomain(); 00153 TUTTLE_TLOG( TUTTLE_TRACE, "[Time Domain] min: " << vertex.getProcessData()._timeDomain.min << ", max: " << vertex.getProcessData()._timeDomain.max ); 00154 } 00155 00156 private: 00157 TGraph& _graph; 00158 }; 00159 00160 template<class TGraph> 00161 class ComputeHashAtTime : public boost::default_dfs_visitor 00162 { 00163 public: 00164 typedef typename TGraph::GraphContainer GraphContainer; 00165 typedef typename TGraph::Vertex Vertex; 00166 typedef typename TGraph::Edge Edge; 00167 typedef typename TGraph::vertex_descriptor vertex_descriptor; 00168 typedef typename TGraph::edge_descriptor edge_descriptor; 00169 typedef typename TGraph::Vertex::Key VertexKey; 00170 00171 ComputeHashAtTime( TGraph& graph, NodeHashContainer& outNodesHash, const OfxTime time ) 00172 : _graph( graph ) 00173 , _outNodesHash( outNodesHash ) 00174 , _time( time ) 00175 { 00176 //TUTTLE_TLOG( TUTTLE_TRACE, "[ComputeHashAtTime] constructor" ); 00177 } 00178 00179 template<class VertexDescriptor, class Graph> 00180 void finish_vertex( VertexDescriptor vd, Graph& g ) 00181 { 00182 Vertex& vertex = _graph.instance( vd ); 00183 TUTTLE_TLOG( TUTTLE_TRACE, "[Compute Hash At Time] finish vertex " << vertex ); 00184 00185 if( vertex.isFake() ) 00186 return; 00187 00188 const std::size_t localHash = vertex.getProcessNode().getLocalHashAtTime(_time); 00189 00190 typedef std::map<VertexKey, std::size_t> InputsHash; 00191 InputsHash inputsGlobalHash; 00192 BOOST_FOREACH( const edge_descriptor& ed, _graph.getOutEdges( vd ) ) 00193 { 00194 const Edge& edge = _graph.instance( ed ); 00195 vertex_descriptor inputVertexDesc = _graph.target( ed ); 00196 Vertex& inputVertex = _graph.instance( inputVertexDesc ); 00197 00198 const std::size_t inputGlobalHash = _outNodesHash.getHash(inputVertex.getKey()); 00199 // Key is: (clipName, time) 00200 VertexKey k( edge.getInAttrName(), edge.getOutTime() ); 00201 inputsGlobalHash[k] = inputGlobalHash; 00202 } 00203 // inputGlobalHashes is put into a map to be ordered by clip name 00204 // the clipName is unique for each time used 00205 std::size_t seed = localHash; 00206 BOOST_FOREACH( const typename InputsHash::value_type& inputGlobalHash, inputsGlobalHash ) 00207 { 00208 //TUTTLE_TLOG_VAR2( TUTTLE_TRACE, inputGlobalHash.first, inputGlobalHash.second ); 00209 boost::hash_combine( seed, inputGlobalHash.first.getName() ); // name of the input clip connected 00210 boost::hash_combine( seed, inputGlobalHash.second ); 00211 } 00212 _outNodesHash.addHash( vertex.getKey(), seed ); 00213 //TUTTLE_TLOG_VAR( TUTTLE_TRACE, localHash ); 00214 //TUTTLE_TLOG_VAR2( TUTTLE_TRACE, vertex.getKey(), seed ); 00215 } 00216 00217 private: 00218 TGraph& _graph; 00219 NodeHashContainer& _outNodesHash; 00220 OfxTime _time; 00221 }; 00222 00223 00224 /** 00225 * @brief Create a new version of a graph with nodes deployed over time. 00226 * 00227 * Compute kOfxImageEffectActionGetFramesNeeded for each node if kOfxImageEffectPropTemporalClipAccess is true. 00228 */ 00229 template<class TGraph> 00230 class DeployTime : public boost::default_dfs_visitor 00231 { 00232 public: 00233 typedef typename TGraph::GraphContainer GraphContainer; 00234 typedef typename TGraph::Vertex Vertex; 00235 typedef typename TGraph::Edge Edge; 00236 typedef typename TGraph::vertex_descriptor vertex_descriptor; 00237 typedef typename TGraph::edge_descriptor edge_descriptor; 00238 00239 DeployTime( TGraph& graph, const OfxTime time ) 00240 : _graph( graph ) 00241 , _time( time ) 00242 { 00243 // clear all time informations before to fill with new values 00244 BOOST_FOREACH( const vertex_descriptor vd, graph.getVertices() ) 00245 { 00246 Vertex& v = graph.instance( vd ); 00247 v.clearTimeInfo(); 00248 } 00249 BOOST_FOREACH( const edge_descriptor ed, graph.getEdges() ) 00250 { 00251 Edge& e = graph.instance( ed ); 00252 e.clearTimeInfo(); 00253 } 00254 } 00255 00256 template<class VertexDescriptor, class Graph> 00257 void discover_vertex( VertexDescriptor v, Graph& g ) 00258 { 00259 Vertex& vertex = _graph.instance( v ); 00260 00261 00262 00263 TUTTLE_TLOG( TUTTLE_TRACE, "[Deploy Time] " << vertex ); 00264 if( vertex.isFake() ) 00265 { 00266 BOOST_FOREACH( const edge_descriptor& ed, _graph.getOutEdges( v ) ) 00267 { 00268 Edge& e = _graph.instance( ed ); 00269 e._timesNeeded[_time].insert( _time ); 00270 //TUTTLE_TLOG( TUTTLE_TRACE, "--- insert edge: " << _time ); 00271 } 00272 vertex._data._times.insert( _time ); 00273 return; 00274 } 00275 00276 // merge times nedded for all out edges 00277 BOOST_FOREACH( const edge_descriptor& ed, _graph.getInEdges( v ) ) 00278 { 00279 const Edge& edge = _graph.instance( ed ); 00280 //TUTTLE_TLOG( TUTTLE_TRACE, "-- outEdge: " << edge ); 00281 BOOST_FOREACH( const typename Edge::TimeMap::value_type& timesNeeded, edge._timesNeeded ) 00282 { 00283 vertex._data._times.insert( timesNeeded.second.begin(), timesNeeded.second.end() ); 00284 // std::cout << "--- insert vertex: "; 00285 // std::copy( (*timesNeeded).second.begin(), 00286 // (*timesNeeded).second.end(), 00287 // std::ostream_iterator<OfxTime>(std::cout, ",") ); 00288 // std::cout << std::endl; 00289 } 00290 } 00291 00292 // Set all times needed on each input edges 00293 BOOST_FOREACH( const OfxTime t, vertex._data._times ) 00294 { 00295 TUTTLE_TLOG( TUTTLE_TRACE, "[Deploy Time] time: " << boost::lexical_cast< std::string >(t) ); 00296 INode::ClipTimesSetMap mapInputsTimes = vertex.getProcessNode().getTimesNeeded( t ); 00297 // BOOST_FOREACH( const INode::InputsTimeMap::value_type& v, mapInputsTimes ) 00298 // { 00299 // TUTTLE_TLOG_VAR( TUTTLE_TRACE, v.first ); 00300 // } 00301 BOOST_FOREACH( const edge_descriptor& ed, _graph.getOutEdges( v ) ) 00302 { 00303 Edge& edge = _graph.instance( ed ); 00304 // TUTTLE_TLOG( TUTTLE_INFO, "-- inEdge "<<t<<": " << edge ); 00305 // const Vertex& input = _graph.targetInstance( ed ); 00306 // TUTTLE_TLOG_VAR( TUTTLE_TRACE, input.getName() ); 00307 // std::cout << "--- insert edges: "; 00308 // std::copy( mapInputsTimes[input.getName()+"." kOfxOutputAttributeName].begin(), 00309 // mapInputsTimes[input.getName()+"." kOfxOutputAttributeName].end(), 00310 // std::ostream_iterator<OfxTime>(std::cout, ",") ); 00311 edge._timesNeeded[t] = mapInputsTimes[edge.getInAttrName()]; 00312 } 00313 } 00314 } 00315 00316 private: 00317 TGraph& _graph; 00318 OfxTime _time; 00319 }; 00320 00321 template<class TGraph> 00322 struct IdentityNodeConnection 00323 { 00324 typedef typename TGraph::GraphContainer GraphContainer; 00325 typedef typename TGraph::Vertex Vertex; 00326 typedef typename Vertex::Key VertexKey; 00327 typedef typename TGraph::vertex_descriptor vertex_descriptor; 00328 typedef typename TGraph::Edge Edge; 00329 typedef typename TGraph::edge_descriptor edge_descriptor; 00330 00331 VertexKey _identityVertex; ///< the identity node to remove 00332 struct InputClipConnection 00333 { 00334 VertexKey _srcNode; 00335 std::string _inputClip; 00336 }; 00337 struct OutputClipConnection 00338 { 00339 VertexKey _dstNode; 00340 std::string _dstNodeClip; 00341 }; 00342 InputClipConnection _input; 00343 std::vector< OutputClipConnection > _outputs; 00344 }; 00345 00346 /** 00347 * @warning in progress... 00348 */ 00349 template<class TGraph> 00350 class RemoveIdentityNodes : public boost::default_dfs_visitor 00351 { 00352 public: 00353 typedef typename TGraph::GraphContainer GraphContainer; 00354 typedef typename TGraph::Vertex Vertex; 00355 typedef typename Vertex::Key VertexKey; 00356 typedef typename TGraph::vertex_descriptor vertex_descriptor; 00357 typedef typename TGraph::Edge Edge; 00358 typedef typename TGraph::edge_descriptor edge_descriptor; 00359 00360 public: 00361 RemoveIdentityNodes( TGraph& graph, std::vector<IdentityNodeConnection<TGraph> >& toRemove ) 00362 : _graph( graph ) 00363 , _toRemove( toRemove ) 00364 {} 00365 00366 template<class VertexDescriptor, class Graph> 00367 void finish_vertex( VertexDescriptor vd, Graph& g ) 00368 { 00369 Vertex& vertex = _graph.instance( vd ); 00370 00371 TUTTLE_TLOG( TUTTLE_TRACE, "[Remove identity nodes] finish vertex " << vertex ); 00372 if( vertex.isFake() ) 00373 return; 00374 00375 std::string inputClip; 00376 OfxTime atTime; 00377 if( vertex.getProcessNode().isIdentity( vertex.getProcessDataAtTime(), inputClip, atTime ) ) 00378 { 00379 try 00380 { 00381 IdentityNodeConnection<TGraph> reconnect; 00382 reconnect._identityVertex = vertex.getKey(); 00383 reconnect._input._inputClip = inputClip; 00384 00385 if( ! inputClip.empty() ) 00386 { 00387 // The inputClip should not be empty in the OpenFX standard, 00388 // but it's used in TuttleOFX to disable the process of the node 00389 // and all the graph branch behind. 00390 00391 bool clipFound = false; 00392 bool clipFoundAtTime = false; 00393 BOOST_FOREACH( const edge_descriptor& ed, _graph.getOutEdges( vd ) ) 00394 { 00395 const Edge& e = _graph.instance( ed ); 00396 if( e.getInAttrName() == inputClip ) 00397 { 00398 clipFound = true; 00399 if( e.getOutTime() == atTime ) 00400 { 00401 clipFoundAtTime = true; 00402 vertex_descriptor in = _graph.target( ed ); 00403 reconnect._input._srcNode = _graph.instance(in).getKey(); 00404 } 00405 } 00406 } 00407 if( ! clipFound ) 00408 { 00409 std::stringstream existingClips; 00410 BOOST_FOREACH( const edge_descriptor& ed, _graph.getOutEdges( vd ) ) 00411 { 00412 const Edge& e = _graph.instance( ed ); 00413 existingClips << e.getInAttrName() << ", "; 00414 } 00415 BOOST_THROW_EXCEPTION( exception::Bug() 00416 << exception::dev() + "Plugin declares itself as identity, but gives a non existing input clip. " 00417 "(node: " + vertex.getName() + ", input clip:" + inputClip + ", existing clips: (" + existingClips.str() + "))" 00418 ); 00419 } 00420 if( ! clipFoundAtTime ) 00421 { 00422 std::stringstream framesNeeded; 00423 BOOST_FOREACH( const edge_descriptor& ed, _graph.getOutEdges( vd ) ) 00424 { 00425 const Edge& e = _graph.instance( ed ); 00426 if( e.getInAttrName() == inputClip ) 00427 { 00428 framesNeeded << e.getOutTime() << ", "; 00429 } 00430 } 00431 BOOST_THROW_EXCEPTION( exception::Bug() 00432 << exception::dev() + "Plugin declares itself as identity, but gives a time on the input clip different from declared framesNeeded. " 00433 "(node: " + vertex.getName() + ", input clip:" + inputClip + ", time:" + atTime + ", framesNeeded:(" + framesNeeded.str() + "))" 00434 ); 00435 } 00436 00437 BOOST_FOREACH( const edge_descriptor& ed, _graph.getInEdges( vd ) ) 00438 { 00439 const Edge& e = _graph.instance( ed ); 00440 vertex_descriptor out = _graph.source( ed ); 00441 typename IdentityNodeConnection<TGraph>::OutputClipConnection c; 00442 c._dstNode = _graph.instance(out).getKey(); 00443 c._dstNodeClip = e.getInAttrName(); 00444 reconnect._outputs.push_back(c); 00445 } 00446 } 00447 TUTTLE_TLOG( TUTTLE_TRACE, "isIdentity => " << vertex.getName() << " - " << inputClip << " at time " << atTime ); 00448 _toRemove.push_back( reconnect ); 00449 TUTTLE_TLOG_VAR( TUTTLE_TRACE, _toRemove.size() ); 00450 } 00451 catch( boost::exception& e ) 00452 { 00453 e << exception::user() + "Error on the node " + quotes(vertex.getName()) + ". It fails to declare itself as an identity node." 00454 << exception::nodeName( vertex.getName() ) 00455 << exception::time( vertex.getProcessDataAtTime()._time ); 00456 throw; 00457 } 00458 } 00459 } 00460 00461 private: 00462 TGraph& _graph; 00463 std::vector<IdentityNodeConnection<TGraph> >& _toRemove; 00464 00465 }; 00466 00467 /** 00468 * @brief Unconnect identity nodes and re-connect neightbors nodes 00469 * 00470 * //////////////////////////////////////////////////////////////////////////////// 00471 * // Output at time 5 00472 * // | 00473 * // Retime time -2 <-- identity node declare to use Merge at time 3 00474 * // | 00475 * // Merge at time 3 <-- identity node declare to use ReadA at time 3 00476 * // / \ 00477 * // / \ 00478 * // / \ 00479 * // ReadA time 3 ReadB time 3 00480 * // 00481 * //////////////////////////////////////////////////////////////////////////////// 00482 * // After removing identity nodes: 00483 * // 00484 * // Output at time 5 00485 * // | 00486 * // ReadA time 3 00487 * // 00488 * // Retime time -2 <-- leave unconnected 00489 * // Merge at time 3 <-- leave unconnected 00490 * // ReadB time 3 <-- leave unconnected 00491 * //////////////////////////////////////////////////////////////////////////////// 00492 */ 00493 template<class TGraph> 00494 void removeIdentityNodes( TGraph& graph, const std::vector<IdentityNodeConnection<TGraph> >& nodesToRemove ) 00495 { 00496 // TUTTLE_IF_DEBUG( 00497 // TUTTLE_LOG_VAR( TUTTLE_TRACE, toRemove.size() ); 00498 // BOOST_FOREACH( const IdentityNodeConnection<TGraph>& connection, toRemove ) 00499 // { 00500 // TUTTLE_LOG( TUTTLE_TRACE, connection._identityVertex ); 00501 // TUTTLE_LOG( TUTTLE_TRACE, "IN: " 00502 // << connection._identityVertex << "::" << connection._input._inputClip 00503 // << " <<-- " 00504 // << connection._input._srcNode << "::" kOfxOutputAttributeName ); 00505 // 00506 // BOOST_FOREACH( const typename IdentityNodeConnection<TGraph>::OutputClipConnection& outputClipConnection, connection._outputs ) 00507 // { 00508 // TUTTLE_LOG( TUTTLE_TRACE, "OUT: " 00509 // << connection._identityVertex << "::" kOfxOutputAttributeName 00510 // << " -->> " 00511 // << outputClipConnection._dstNode << "::" << outputClipConnection._dstNodeClip ); 00512 // } 00513 // } 00514 // ); 00515 // TUTTLE_LOG( TUTTLE_TRACE, "-- removeIdentityNodes --" ); 00516 typedef typename TGraph::Vertex Vertex; 00517 typedef typename Vertex::Key VertexKey; 00518 00519 typedef boost::unordered_map<VertexKey, const IdentityNodeConnection<TGraph>*> IdentityMap; 00520 IdentityMap identityNodes; 00521 00522 BOOST_FOREACH( const IdentityNodeConnection<TGraph>& connection, nodesToRemove ) 00523 { 00524 identityNodes[connection._identityVertex] = &connection; 00525 } 00526 00527 bool disabledBranch = false; 00528 BOOST_FOREACH( const IdentityNodeConnection<TGraph>& connection, nodesToRemove ) 00529 { 00530 if( connection._input._inputClip.empty() ) 00531 { 00532 // The input clip is empty, this not in the OpenFX standard. 00533 // In Tuttle, it means that the branch is disabled. 00534 disabledBranch = true; 00535 } 00536 else 00537 { 00538 // Create new connections if the input clip name is not empty 00539 TUTTLE_TLOG_TRACE( boost::lexical_cast<std::string>(connection._identityVertex) ); 00540 TUTTLE_TLOG_TRACE( "IN: " 00541 << boost::lexical_cast<std::string>(connection._identityVertex) << "::" << boost::lexical_cast<std::string>(connection._input._inputClip) 00542 << " <<-- " 00543 << boost::lexical_cast<std::string>(connection._input._srcNode) << "::" kOfxOutputAttributeName ); 00544 const typename TGraph::VertexKey* searchIn = &( connection._input._srcNode ); 00545 { 00546 // search a non-identity node to replace the connection 00547 typename IdentityMap::const_iterator it = identityNodes.find( *searchIn ); 00548 typename IdentityMap::const_iterator itEnd = identityNodes.end(); 00549 while( it != itEnd ) 00550 { 00551 searchIn = &( it->second->_input._srcNode ); 00552 it = identityNodes.find( *searchIn ); 00553 } 00554 } 00555 const typename TGraph::VertexKey& in = *searchIn; 00556 const typename TGraph::vertex_descriptor descIn = graph.getVertexDescriptor( in ); 00557 00558 // replace all input/output connections of the identity node by one edge 00559 BOOST_FOREACH( const typename IdentityNodeConnection<TGraph>::OutputClipConnection& outputClipConnection, connection._outputs ) 00560 { 00561 //TUTTLE_TLOG_TRACE( "OUT: " 00562 // << connection._identityVertex << "::" kOfxOutputAttributeName 00563 // << " -->> " 00564 // << outputClipConnection._dstNode << "::" << outputClipConnection._dstNodeClip ); 00565 const typename TGraph::VertexKey& out = outputClipConnection._dstNode; 00566 const std::string inAttr = outputClipConnection._dstNodeClip; 00567 00568 const typename TGraph::vertex_descriptor descOut = graph.getVertexDescriptor( out ); 00569 00570 const typename TGraph::Edge e( in, out, inAttr ); 00571 graph.addEdge( descOut, descIn, e ); 00572 } 00573 } 00574 // Warning: We don't remove the vertex itself to not invalidate vertex_descriptors but only remove edges. 00575 // graph.removeVertex( graph.getVertexDescriptor(connection._identityVertex) ); 00576 // remove all node connections 00577 graph.clearVertex( graph.getVertexDescriptor(connection._identityVertex) ); 00578 } 00579 00580 if( disabledBranch ) 00581 { 00582 // @todo: Remove connections of all vertices not connected to the output. 00583 // These unconnected branches have been created by identity nodes without source clip. 00584 } 00585 } 00586 00587 template<class TGraph> 00588 class PreProcess1 : public boost::default_dfs_visitor 00589 { 00590 public: 00591 typedef typename TGraph::GraphContainer GraphContainer; 00592 typedef typename TGraph::Vertex Vertex; 00593 00594 PreProcess1( TGraph& graph ) 00595 : _graph( graph ) 00596 {} 00597 00598 template<class VertexDescriptor, class Graph> 00599 void finish_vertex( VertexDescriptor v, Graph& g ) 00600 { 00601 Vertex& vertex = _graph.instance( v ); 00602 00603 TUTTLE_TLOG( TUTTLE_TRACE, "[Preprocess 1] finish vertex " << vertex ); 00604 if( vertex.isFake() ) 00605 return; 00606 00607 //TUTTLE_TLOG( TUTTLE_TRACE, vertex.getProcessDataAtTime()._time ); 00608 vertex.getProcessNode().preProcess1( vertex.getProcessDataAtTime() ); 00609 } 00610 00611 private: 00612 TGraph& _graph; 00613 }; 00614 00615 template<class TGraph> 00616 class PreProcess2 : public boost::default_dfs_visitor 00617 { 00618 public: 00619 typedef typename TGraph::GraphContainer GraphContainer; 00620 typedef typename TGraph::Vertex Vertex; 00621 00622 PreProcess2( TGraph& graph ) 00623 : _graph( graph ) 00624 {} 00625 00626 template<class VertexDescriptor, class Graph> 00627 void discover_vertex( VertexDescriptor v, Graph& g ) 00628 { 00629 Vertex& vertex = _graph.instance( v ); 00630 00631 TUTTLE_TLOG( TUTTLE_TRACE, "[Preprocess 2] discover vertex " << vertex ); 00632 if( vertex.isFake() ) 00633 return; 00634 00635 vertex.getProcessNode().preProcess2_reverse( vertex.getProcessDataAtTime() ); 00636 } 00637 00638 private: 00639 TGraph& _graph; 00640 }; 00641 00642 template<class TGraph> 00643 class OptimizeGraph : public boost::default_dfs_visitor 00644 { 00645 public: 00646 typedef typename TGraph::GraphContainer GraphContainer; 00647 typedef typename TGraph::Vertex Vertex; 00648 typedef typename TGraph::Edge Edge; 00649 typedef typename TGraph::vertex_descriptor vertex_descriptor; 00650 typedef typename TGraph::edge_descriptor edge_descriptor; 00651 typedef typename TGraph::in_edge_iterator in_edge_iterator; 00652 typedef typename TGraph::out_edge_iterator out_edge_iterator; 00653 00654 OptimizeGraph( TGraph& graph ) 00655 : _graph( graph ) 00656 { 00657 } 00658 00659 template <class VertexDescriptor, class Graph> 00660 void finish_vertex( VertexDescriptor v, const Graph& g ) 00661 { 00662 using namespace boost; 00663 using namespace boost::graph; 00664 Vertex& vertex = _graph.instance( v ); 00665 00666 ProcessVertexAtTimeData& procOptions = vertex.getProcessDataAtTime(); 00667 if( !vertex.isFake() ) 00668 { 00669 // compute local infos, need to be a real node ! 00670 vertex.getProcessNode().preProcess_infos( vertex.getProcessDataAtTime(), procOptions._time, procOptions._localInfos ); 00671 } 00672 00673 // compute global infos for inputs 00674 00675 // direct dependencies (originally the node inputs) 00676 BOOST_FOREACH( const edge_descriptor& oe, out_edges( v, _graph.getGraph() ) ) 00677 { 00678 // Edge& outEdge = _graph.instance(*oe); 00679 Vertex& outVertex = _graph.targetInstance( oe ); 00680 procOptions._inputsInfos += outVertex.getProcessDataAtTime()._localInfos; 00681 procOptions._globalInfos += outVertex.getProcessDataAtTime()._globalInfos; 00682 } 00683 procOptions._globalInfos += procOptions._localInfos; 00684 00685 // BOOST_FOREACH( const edge_descriptor& ie, in_edges( v, _graph.getGraph() ) ) 00686 // { 00687 // Edge& e = _graph.instance( ie ); 00688 // } 00689 00690 00691 // TUTTLE_TLOG( TUTTLE_TRACE, vertex.getName() ); 00692 // TUTTLE_TLOG( TUTTLE_TRACE, procOptions ); 00693 } 00694 00695 private: 00696 TGraph& _graph; 00697 }; 00698 00699 template<class TGraph> 00700 class Process : public boost::default_dfs_visitor 00701 { 00702 public: 00703 typedef typename TGraph::GraphContainer GraphContainer; 00704 typedef typename TGraph::Vertex Vertex; 00705 00706 Process( TGraph& graph, memory::IMemoryCache& cache ) 00707 : _graph( graph ) 00708 , _cache( cache ) 00709 , _result( NULL ) 00710 { 00711 } 00712 00713 Process( TGraph& graph, memory::IMemoryCache& cache, memory::IMemoryCache& result ) 00714 : _graph( graph ) 00715 , _cache( cache ) 00716 , _result( &result ) 00717 { 00718 } 00719 00720 /** 00721 * Set a MemoryCache object to accumulate output nodes buffers. 00722 */ 00723 void setOutputMemoryCache( memory::IMemoryCache& result ) 00724 { 00725 _result = &result; 00726 } 00727 00728 template<class VertexDescriptor, class Graph> 00729 void finish_vertex( VertexDescriptor v, Graph& g ) 00730 { 00731 Vertex& vertex = _graph.instance( v ); 00732 TUTTLE_TLOG( TUTTLE_TRACE, "[Process] finish_vertex " << vertex ); 00733 00734 // do nothing on the empty output node 00735 // it's just a link to final nodes 00736 if( vertex.isFake() ) 00737 return; 00738 00739 // check if abort ? 00740 00741 // launch the process 00742 boost::posix_time::ptime t1(boost::posix_time::microsec_clock::local_time()); 00743 vertex.getProcessNode().process( vertex.getProcessDataAtTime() ); 00744 boost::posix_time::ptime t2(boost::posix_time::microsec_clock::local_time()); 00745 _cumulativeTime += t2 - t1; 00746 00747 TUTTLE_TLOG( TUTTLE_TRACE, "[Process] " << quotes(vertex._name) << " " << vertex._data._time << " took: " << t2 - t1 << " (cumul: " << _cumulativeTime << ")" << vertex ); 00748 00749 if( _result && vertex.getProcessDataAtTime()._isFinalNode ) 00750 { 00751 memory::CACHE_ELEMENT img = _cache.get( vertex._clipName + "." kOfxOutputAttributeName, vertex._data._time ); 00752 if( ! img.get() ) 00753 { 00754 BOOST_THROW_EXCEPTION( exception::Logic() 00755 << exception::user() + "Output buffer not found in memoryCache at the end of the node process." 00756 << exception::dev() + vertex._clipName + "." kOfxOutputAttributeName + " at time " + vertex._data._time 00757 << exception::nodeName( vertex._name ) 00758 << exception::time( vertex._data._time ) ); 00759 } 00760 _result->put( vertex._clipName, vertex._data._time, img ); 00761 } 00762 } 00763 00764 private: 00765 TGraph& _graph; 00766 memory::IMemoryCache& _cache; 00767 memory::IMemoryCache* _result; 00768 boost::posix_time::time_duration _cumulativeTime; 00769 }; 00770 00771 template<class TGraph> 00772 class PostProcess : public boost::default_dfs_visitor 00773 { 00774 public: 00775 typedef typename TGraph::GraphContainer GraphContainer; 00776 typedef typename TGraph::Vertex Vertex; 00777 00778 PostProcess( TGraph& graph ) 00779 : _graph( graph ) 00780 {} 00781 00782 template<class VertexDescriptor, class Graph> 00783 void initialize_vertex( VertexDescriptor v, Graph& g ) 00784 { 00785 Vertex& vertex = _graph.instance( v ); 00786 00787 TUTTLE_TLOG( TUTTLE_TRACE,"[Post-process] initialize_vertex " << vertex ); 00788 if( vertex.isFake() ) 00789 return; 00790 } 00791 00792 template<class VertexDescriptor, class Graph> 00793 void finish_vertex( VertexDescriptor v, Graph& g ) 00794 { 00795 Vertex& vertex = _graph.instance( v ); 00796 00797 TUTTLE_TLOG( TUTTLE_TRACE, "[Post-process] finish_vertex " << vertex ); 00798 if( vertex.isFake() ) 00799 return; 00800 00801 vertex.getProcessNode().postProcess( vertex.getProcessDataAtTime() ); 00802 } 00803 00804 private: 00805 TGraph& _graph; 00806 }; 00807 00808 00809 template<class TGraph> 00810 class BeforeRenderCallbackVisitor : public boost::default_dfs_visitor 00811 { 00812 public: 00813 typedef typename TGraph::Vertex Vertex; 00814 BeforeRenderCallbackVisitor( TGraph& graph ) 00815 : _graph( graph ) 00816 {} 00817 00818 template<class VertexDescriptor, class Graph> 00819 void finish_vertex( VertexDescriptor v, Graph& g ) 00820 { 00821 Vertex& vertex = _graph.instance( v ); 00822 if( !vertex.isFake() ) 00823 { 00824 vertex.getProcessNode().beforeRenderCallback( vertex.getProcessNode(), vertex.getProcessDataAtTime() ); 00825 } 00826 } 00827 00828 private: 00829 TGraph& _graph; 00830 }; 00831 00832 00833 } 00834 } 00835 } 00836 } 00837 00838 #endif 00839