소스 검색

execute only passes that nodes define

this is a very minor optimization that doesn't really save an appreciable amount of time
but it reduces function calls by a few thousand, and branching on a set is faster than
calling a no-op function, even if it is only marginally so
Joseph Brandenburg 2 주 전
부모
커밋
d87c7eff33
8개의 변경된 파일과 53개의 추가작업 그리고 28개의 파일을 삭제
  1. 1 0
      base_definitions.py
  2. 6 0
      deformer_nodes.py
  3. 25 22
      execution/readtree.py
  4. 1 0
      link_nodes.py
  5. 3 0
      math_nodes.py
  6. 12 2
      misc_nodes.py
  7. 2 1
      primitives_nodes.py
  8. 3 3
      xForm_nodes.py

+ 1 - 0
base_definitions.py

@@ -935,6 +935,7 @@ class MantisNode:
     node_type = 'UNINITIALIZED'
     socket_templates = None
     property_socket_map = {}
+    passes=frozenset({})
     def __init__(self, signature : tuple,
                  base_tree : bpy.types.NodeTree,
                  socket_templates : list[MantisSocketTemplate]=[],

+ 6 - 0
deformer_nodes.py

@@ -37,6 +37,8 @@ def trace_xForm_back(mantis_node, socket):
 class MantisDeformerNode(MantisNode):
     node_type = 'LINK'
     __slots__ = ()
+    passes=frozenset({'bRelationship', 'bFinalize',})
+
     def __init__(self, signature : tuple,
                  base_tree : NodeTree,
                  socket_templates : list[MantisSocketTemplate]=[]):
@@ -415,6 +417,7 @@ class DeformerMorphTarget(MantisDeformerNode):
     '''A node representing an armature deformer'''
     __slots__ = ()
     socket_templates = MorphTargetSockets
+    passes=frozenset({'bRelationship',})
     
     def GetxForm(self, trace_input="Object"):
         trace = trace_single_line(self, trace_input)
@@ -451,6 +454,7 @@ class DeformerMorphTargetDeform(MantisDeformerNode):
     '''A node representing an armature deformer'''
     __slots__ = ()
     socket_templates = MorphTargetDeformSockets
+    passes=frozenset({'bFinalize',})
 
     def __init__(self, signature, base_tree):
         super().__init__(signature, base_tree, self.socket_templates)
@@ -676,6 +680,7 @@ class DeformerSurfaceDeform(MantisDeformerNode):
     '''A node representing an surface deform modifier'''
     __slots__ = ()
     socket_templates = SurfaceDeformSockets
+    passes=frozenset({'bRelationship', 'bFinalize', 'bModifierApply'})
 
     def GetxForm(self, socket="Deformer"):
         if socket == "Deformer":
@@ -707,6 +712,7 @@ class DeformerMeshDeform(MantisDeformerNode):
     '''A node representing a mesh deform modifier'''
     __slots__ = ()
     socket_templates = MeshDeformSockets
+    passes=frozenset({'bRelationship', 'bFinalize', 'bModifierApply'})
 
     def GetxForm(self, socket="Deformer"):
         if socket == "Deformer":

+ 25 - 22
execution/readtree.py

@@ -129,6 +129,7 @@ def data_from_tree(base_tree, tree_path, mContext, dummy_nodes, all_mantis_nodes
     local_mantis_nodes, group_nodes = {}, []
     tree_path_names = [tree.name for tree in tree_path if hasattr(tree, "name")]
     if tree_path[-1]:
+        
         current_tree = tree_path[-1].node_tree # this may be None.
     else:
         current_tree = base_tree
@@ -686,7 +687,7 @@ def execute_tree(nodes, base_tree, context, error_popups = False, profile=False)
     assert nodes is not None, "Failed to parse tree."
     assert len(nodes) > 0, "No parsed nodes for execution."\
                            " Mantis probably failed to parse the tree."
-    import bpy
+    from bpy.types import Object as bpy_object
     from time import time
     original_active = context.view_layer.objects.active
     start_execution_time = time()
@@ -735,10 +736,10 @@ def execute_tree(nodes, base_tree, context, error_popups = False, profile=False)
             if execution_failed: break
             try:
                 check_and_apply_overlay(n)
-                if not n.prepared:
+                if not n.prepared and 'bPrepare' in n.passes:
                     if profiler: profiler.record(n, "bPrepare", context)
                     else: n.bPrepare(context)
-                if not n.executed:
+                if not n.executed and 'bTransform' in n.passes:
                     if profiler: profiler.record(n, "bTransformPass", context)
                     else: n.bTransformPass(context)
                 if (n.__class__.__name__ == "xFormArmature" ):
@@ -747,7 +748,7 @@ def execute_tree(nodes, base_tree, context, error_popups = False, profile=False)
                     active = ob
                 if not (n.__class__.__name__ == "xFormBone" ) and hasattr(n, "bGetObject"):
                     ob = n.bGetObject()
-                    if isinstance(ob, bpy.types.Object):
+                    if isinstance(ob, bpy_object):
                         select_me.append(ob)
             except Exception as e:
                 e = execution_error_cleanup(n, e, show_error=error_popups)
@@ -760,10 +761,10 @@ def execute_tree(nodes, base_tree, context, error_popups = False, profile=False)
         for n in sorted_nodes:
             try:
                 check_and_apply_overlay(n)
-                if not n.prepared:
+                if not n.prepared and 'bPrepare' in n.passes:
                     if profiler: profiler.record(n, "bPrepare", context)
                     else: n.bPrepare(context)
-                if not n.executed:
+                if not n.executed and 'bRelationship' in n.passes:
                     if profiler: profiler.record(n, "bRelationshipPass", context)
                     else: n.bRelationshipPass(context)
             except Exception as e:
@@ -780,14 +781,15 @@ def execute_tree(nodes, base_tree, context, error_popups = False, profile=False)
             ob.data.pose_position = 'POSE'
 
         for n in sorted_nodes:
-            try:
-                if profiler: profiler.record(n, "bFinalize", context)
-                else: n.bFinalize(context)
-            except Exception as e:
-                e = execution_error_cleanup(n, e, show_error=error_popups)
-                if error_popups == False:
-                    raise e
-                execution_failed = True; break
+            if 'bFinalize' in n.passes:
+                try:
+                    if profiler: profiler.record(n, "bFinalize", context)
+                    else: n.bFinalize(context)
+                except Exception as e:
+                    e = execution_error_cleanup(n, e, show_error=error_popups)
+                    if error_popups == False:
+                        raise e
+                    execution_failed = True; break
 
         # REST pose for deformer bind, so everything is in the rest position
         for ob in switch_me:
@@ -795,14 +797,15 @@ def execute_tree(nodes, base_tree, context, error_popups = False, profile=False)
 
         # finally, apply modifiers and bind stuff
         for n in sorted_nodes:
-            try:
-                if profiler: profiler.record(n, "bModifierApply", context)
-                else: n.bModifierApply(context)
-            except Exception as e:
-                e = execution_error_cleanup(n, e, show_error=error_popups)
-                if error_popups == False:
-                    raise e
-                execution_failed = True; break
+            if 'bModifierApply' in n.passes:
+                try:
+                    if profiler: profiler.record(n, "bModifierApply", context)
+                    else: n.bModifierApply(context)
+                except Exception as e:
+                    e = execution_error_cleanup(n, e, show_error=error_popups)
+                    if error_popups == False:
+                        raise e
+                    execution_failed = True; break
 
         for ob in switch_me:
             ob.data.pose_position = 'POSE'

+ 1 - 0
link_nodes.py

@@ -54,6 +54,7 @@ set_constraint_name = lambda mantis_node : mantis_node.evaluate_input("Name") if
 class MantisLinkNode(MantisNode):
     __slots__ = ()
     node_type = 'LINK'
+    passes=frozenset({'bRelationship', 'bTransform', 'bFinalize',})
     def __init__(self, signature : tuple,
                  base_tree : NodeTree,):
         super().__init__(signature, base_tree, self.socket_templates,

+ 3 - 0
math_nodes.py

@@ -55,6 +55,7 @@ class MathStaticInt(MantisNode):
     __slots__ = ()
     socket_templates = StaticIntSockets
     node_type = "UTILITY"
+    passes=frozenset({'bPrepare',})
 
     def bPrepare(self, bContext = None,):
         a = self.evaluate_input("Int A"); b = self.evaluate_input("Int B")
@@ -67,6 +68,7 @@ class MathStaticFloat(MantisNode):
     __slots__ = ()
     socket_templates = StaticFloatSockets
     node_type = "UTILITY"
+    passes=frozenset({'bPrepare',})
 
     def bPrepare(self, bContext = None,):
         a = self.evaluate_input("Float A"); b = self.evaluate_input("Float B")
@@ -79,6 +81,7 @@ class MathStaticVector(MantisNode):
     __slots__ = ()
     socket_templates = StaticVectorSockets
     node_type = "UTILITY"
+    passes=frozenset({'bPrepare',})
 
     def bPrepare(self, bContext = None,):
         from mathutils import Vector

+ 12 - 2
misc_nodes.py

@@ -205,10 +205,12 @@ def bpy_object_get_guarded(get_name, node=None):
 class MantisMiscNode(MantisNode):
     __slots__ = ()
     node_type='UTILITY'
+    passes=frozenset({'bPrepare',})
 
 class SimpleInputNode(MantisMiscNode):
     __slots__ = ()
     node_type = 'UTILITY'
+    passes=frozenset({})
     def __init__(self, signature, base_tree, socket_templates=[], additional_parameters={}):
         super().__init__(signature, base_tree, socket_templates, additional_parameters)
         self.prepared, self.executed = True, True
@@ -373,6 +375,7 @@ class UtilityMatrixFromCurve(MantisMiscNode):
     '''Get a matrix from a curve'''
     __slots__ = ()
     socket_templates = MatrixFromCurveSockets
+    passes=frozenset({'bPrepare', 'bFinalize'})
 
     def bPrepare(self, bContext = None,):
         from mathutils import Matrix
@@ -455,6 +458,7 @@ class UtilityPointFromCurve(MantisMiscNode):
     '''Get a point from a curve'''
     __slots__ = ()
     socket_templates = PointFromCurveSockets
+    passes=frozenset({'bPrepare', 'bFinalize'})
 
     def bPrepare(self, bContext = None,):
         import bpy
@@ -486,6 +490,7 @@ class UtilityMatricesFromCurve(MantisMiscNode):
     '''Get matrices from a curve'''
     __slots__ = ()
     socket_templates = MatricesFromCurveSockets
+    passes=frozenset({'bPrepare', 'bFinalize'})
 
     def bPrepare(self, bContext = None,):
         import time
@@ -576,6 +581,7 @@ class UtilityNumberOfSplines(MantisMiscNode):
 class UtilityMatrixFromCurveSegment(MantisMiscNode):
     __slots__ = ()
     socket_templates = MatrixFromCurveSegmentSockets
+    passes=frozenset({'bPrepare', 'bFinalize'})
 
     def bPrepare(self, bContext = None,):
         import bpy
@@ -789,12 +795,12 @@ class UtilityBoneProperties(SimpleInputNode):
     def fill_parameters(self, ui_node=None):
         return
 
-# TODO this should probably be moved to Links
 class UtilityDriverVariable(MantisMiscNode):
     '''A node representing an armature object'''
     __slots__ = ()
     socket_templates = DriverVariableSockets
     node_type = "DRIVER"
+    passes=frozenset({'bPrepare', 'bRelationship'})
 
     def reset_execution(self):
         super().reset_execution()
@@ -866,7 +872,6 @@ class UtilityDriverVariable(MantisMiscNode):
         self.parameters["Driver Variable"] = my_var
         self.prepared = True
         
-
     def bRelationshipPass(self, bContext = None,):
         prepare_parameters(self)
         xF1 = self.GetxForm(index = 1)
@@ -929,6 +934,7 @@ class UtilityDriver(MantisMiscNode):
     __slots__ = ()
     socket_templates = DriverSockets
     node_type = "DRIVER" # MUST be run in Pose mode
+    passes=frozenset({'bRelationship'})
     def __init__(self, signature, base_tree):
         from .utilities.drivers import MantisDriver
         super().__init__(signature, base_tree, self.socket_templates,
@@ -982,6 +988,7 @@ class UtilitySwitch(MantisMiscNode):
     __slots__ = ()
     socket_templates = SwitchSockets
     node_type = "DRIVER" # MUST be run in Pose mode
+    passes=frozenset({'bRelationship'})
     def __init__(self, signature, base_tree):
         from .utilities.drivers import MantisDriver
         super().__init__(signature, base_tree, self.socket_templates,
@@ -1234,6 +1241,7 @@ class InputExistingGeometryData(MantisMiscNode):
     '''A node representing existing object data'''
     __slots__ = ()
     socket_templates = InputExistingGeometrySockets
+    passes=frozenset({})
 
     def __init__(self, signature, base_tree):
         super().__init__(signature, base_tree, self.socket_templates)
@@ -1261,6 +1269,7 @@ class UtilityDeclareCollections(MantisMiscNode):
     '''A node to help manage bone collections'''
     __slots__ = ()
     socket_templates = None
+    passes=frozenset({})
     def __init__(self, signature, base_tree):
         # NOTE this one does not use socket template because it is special.
         # The user creates all the sockets for this one.
@@ -1339,6 +1348,7 @@ class UtilityGeometryOfXForm(MantisMiscNode):
     '''A node representing existing object data'''
     __slots__ = ()
     socket_templates = GeometryOfXFormSockets
+    passes=frozenset({})
     def __init__(self, signature, base_tree):
         super().__init__(signature, base_tree, self.socket_templates)
         self.prepared = True; self.executed = True

+ 2 - 1
primitives_nodes.py

@@ -31,6 +31,7 @@ class CirclePrimitive(PrimitiveNode):
     '''A node representing a Circle Primitive mesh'''
     __slots__ = ()
     socket_templates = CirclePrimitiveSockets
+    passes=frozenset({'bPrepare',})
 
     # mode is unused but needed for interface consistency
     def bGetObject(self, mode=''):
@@ -41,7 +42,7 @@ class CirclePrimitive(PrimitiveNode):
             bObject = data.meshes.get(self.evaluate_input("Name"))
         return bObject
         
-    def bTransformPass(self, bContext = None,):
+    def bPrepare(self, bContext = None,):
         # Get the datablock
         data = self.bGetObject()
         import bpy

+ 3 - 3
xForm_nodes.py

@@ -69,6 +69,7 @@ def set_object_parent(node):
 class xFormNode(MantisNode):
     __slots__ = ()
     node_type = 'XFORM'
+    passes=frozenset({'bPrepare', 'bTransform', 'bFinalize'})
     def __init__(self, signature, base_tree, socket_templates=[],
                  additional_parameters={}):
         super().__init__(signature, base_tree, socket_templates,
@@ -431,7 +432,6 @@ class xFormBone(xFormNode):
             b.color.custom.normal=color_normal
             b.color.custom.select=color_select
 
-
     def bFinalize(self, bContext = None):
 
         b = self.bGetParentArmature().data.bones[self.bObject]
@@ -609,7 +609,6 @@ class xFormGeometryObject(xFormNode):
         self.setup_custom_props(self.bGetObject(), "Custom Properties")
         finish_drivers(self)
 
-
     def bGetObject(self, mode = 'POSE'):
         return self.bObject
 
@@ -711,11 +710,11 @@ class xFormObjectInstance(xFormNode):
     def bGetObject(self, mode = 'POSE'):
         return self.bObject
 
-
 class xFormCurvePin(xFormNode):
     """An xForm pinned to a specific location on a curve."""
     __slots__ = ()
     socket_templates = xFormCurvePinSockets
+    passes=frozenset({'bPrepare', 'bFinalize'})
     def __init__(self, signature, base_tree):
         super().__init__(signature, base_tree, self.socket_templates,
             additional_parameters={"Matrix":None})
@@ -857,6 +856,7 @@ class xFormGetBone(xFormNode):
     """Represents an instance of an existing geometry object."""
     __slots__ = ()
     socket_templates = xFormGetBoneSockets
+    passes=frozenset({})
     def __init__(self, signature, base_tree):
         super().__init__(signature, base_tree, self.socket_templates)
         # this is just a getter