Browse Source

Reduce redundant preparation of nodes when executing tree

Joseph Brandenburg 6 months ago
parent
commit
4466a8383b
2 changed files with 21 additions and 17 deletions
  1. 10 4
      base_definitions.py
  2. 11 13
      readtree.py

+ 10 - 4
base_definitions.py

@@ -108,17 +108,19 @@ class MantisTree(NodeTree):
         if (bpy.app.version >= (4,4,0)):
         if (bpy.app.version >= (4,4,0)):
             fix_reroute_colors(self)
             fix_reroute_colors(self)
 
 
-    def update_tree(self, context = None):
+    def update_tree(self, context = None, force=False):
         if self.is_exporting:
         if self.is_exporting:
             return
             return
         my_hash = str( hash_tree(self) )
         my_hash = str( hash_tree(self) )
-        if my_hash != self.hash:
+        if my_hash != self.hash or force:
             self.hash = my_hash
             self.hash = my_hash
             self.is_executing = True
             self.is_executing = True
             from . import readtree
             from . import readtree
             prGreen("Validating Tree: %s" % self.name)
             prGreen("Validating Tree: %s" % self.name)
             try:
             try:
-                scene = context.scene
+                import bpy # I am importing here so that the context passed in
+                # is used for display update... but I always want to do this
+                scene = bpy.context.scene
                 scene.render.use_lock_interface = True
                 scene.render.use_lock_interface = True
                 self.parsed_tree = readtree.parse_tree(self)
                 self.parsed_tree = readtree.parse_tree(self)
                 if context:
                 if context:
@@ -681,6 +683,9 @@ class MantisNode:
         self.hierarchy_connections, self.connections = [], []
         self.hierarchy_connections, self.connections = [], []
         self.hierarchy_dependencies, self.dependencies = [], []
         self.hierarchy_dependencies, self.dependencies = [], []
         self.prepared, self.executed = False, False
         self.prepared, self.executed = False, False
+        self.execution_prepared = False
+        # the above is for tracking prep state in execution, so that I can avoid preparing nodes
+        #  again without changing the readtree code much.
         self.socket_templates = socket_templates
         self.socket_templates = socket_templates
         self.mContext = None # for now I am gonna set this at runtime
         self.mContext = None # for now I am gonna set this at runtime
         # I know it isn't "beautiful OOP" or whatever, but it is just easier
         # I know it isn't "beautiful OOP" or whatever, but it is just easier
@@ -693,7 +698,8 @@ class MantisNode:
     def reset_execution(self) -> None:
     def reset_execution(self) -> None:
         """ Reset the node for additional execution without re-building the tree."""
         """ Reset the node for additional execution without re-building the tree."""
         self.drivers={}; self.bObject=None
         self.drivers={}; self.bObject=None
-        self.prepared, self.executed = False, False
+        self.executed = False
+        self.execution_prepared = False
 
 
     def init_sockets(self) -> None:
     def init_sockets(self) -> None:
         self.inputs.init_sockets(self.socket_templates)
         self.inputs.init_sockets(self.socket_templates)

+ 11 - 13
readtree.py

@@ -471,10 +471,6 @@ def execute_tree(nodes, base_tree, context, error_popups = False):
         if not mContext: # just grab one of these. this is a silly way to do this.
         if not mContext: # just grab one of these. this is a silly way to do this.
             mContext = nc.mContext
             mContext = nc.mContext
         nc.reset_execution()
         nc.reset_execution()
-        # in future, execute_tree only cares about node.executed; parse_tree does node.prepared
-        # will need much testing to get it working; for now continue to reset node.prepared here
-        # Once execute_tree is ready, I can remove this line and things will continue to work.
-        nc.prepared=False # TODO remove this line to avoid repeating work!
         check_and_add_root(nc, xForm_pass)
         check_and_add_root(nc, xForm_pass)
 
 
     executed = []
     executed = []
@@ -501,26 +497,27 @@ def execute_tree(nodes, base_tree, context, error_popups = False):
                 raise GraphError("There is a probably a cycle in the graph somewhere. Fix it!")
                 raise GraphError("There is a probably a cycle in the graph somewhere. Fix it!")
                 # we're trying to solve the halting problem at this point.. don't do that.
                 # we're trying to solve the halting problem at this point.. don't do that.
                 # TODO find a better way! there are algo's for this but they will require using a different solving algo, too
                 # TODO find a better way! there are algo's for this but they will require using a different solving algo, too
-            if n.prepared:
+            if n.execution_prepared:
                 continue
                 continue
             if n.node_type not in ['XFORM', 'UTILITY']:
             if n.node_type not in ['XFORM', 'UTILITY']:
                 for dep in n.hierarchy_dependencies:
                 for dep in n.hierarchy_dependencies:
-                    if not dep.prepared:
+                    if not dep.execution_prepared:
                         xForm_pass.appendleft(n) # hold it
                         xForm_pass.appendleft(n) # hold it
                         break
                         break
                 else:
                 else:
-                    n.prepared=True
+                    n.execution_prepared=True
                     executed.append(n)
                     executed.append(n)
                     for conn in n.hierarchy_connections:
                     for conn in n.hierarchy_connections:
-                        if  not conn.prepared:
+                        if  not conn.execution_prepared:
                             xForm_pass.appendleft(conn)
                             xForm_pass.appendleft(conn)
             else:
             else:
                 for dep in n.hierarchy_dependencies:
                 for dep in n.hierarchy_dependencies:
-                    if not dep.prepared:
+                    if not dep.execution_prepared:
                         break
                         break
                 else:
                 else:
                     try:
                     try:
-                        n.bPrepare(context)
+                        if not n.prepared:
+                            n.bPrepare(context)
                         if not n.executed:
                         if not n.executed:
                             n.bExecute(context)
                             n.bExecute(context)
                         if (n.__class__.__name__ == "xFormArmature" ):
                         if (n.__class__.__name__ == "xFormArmature" ):
@@ -536,10 +533,10 @@ def execute_tree(nodes, base_tree, context, error_popups = False):
                             raise execution_error_cleanup(n, e,)
                             raise execution_error_cleanup(n, e,)
                         else:
                         else:
                             raise e
                             raise e
-                    n.prepared=True
+                    n.execution_prepared=True
                     executed.append(n)
                     executed.append(n)
                     for conn in n.hierarchy_connections:
                     for conn in n.hierarchy_connections:
-                        if  not conn.prepared:
+                        if  not conn.execution_prepared:
                             xForm_pass.appendleft(conn)
                             xForm_pass.appendleft(conn)
         
         
 
 
@@ -550,7 +547,8 @@ def execute_tree(nodes, base_tree, context, error_popups = False):
 
 
         for n in executed:
         for n in executed:
             try:
             try:
-                n.bPrepare(context)
+                if not n.prepared:
+                    n.bPrepare(context)
                 if not n.executed:
                 if not n.executed:
                     n.bExecute(context)
                     n.bExecute(context)
             except Exception as e:
             except Exception as e: