Sverchok update system RFC
Created by: ly29
A description about how updates happens in Sverchok since I know people wonder about it. Please ask questions.
Update events
Update can happen in the following ways:
- Editor changes
- Value change in a node
- Frame change
- Update button
What happens when each event is issued.
Editor changes
The whole node group is evaluated and a list of nodes is created. Then the update function is called on each node in a safe order. The update event from blender is issued to the class SverchCustomTree(NodeTree):
Since the it is hard to know what has changed between two editor change updates the whole list rebuilt, the socket cache cleared and update is called for the whole node group.
def update(self):
makeTreeUpdate2(tree_name = self.name)
speedUpdate(tree_name = self.name)
Value change in a node
If a numeric value in for example a float node is changed the following code is run.
def updateNode(self, context):
speedUpdate(start_node = self.name,tree_name =self.id_data.name)
Note These list should be cached but at the moment they are not. Done!
Animation update
Animation updates are issued from a frame change handler.
def update_ani(self):
if self.sv_animate:
speedUpdate(tree_name = self.name)
@persistent
def sv_update_handler(scene):
'''Sverchok update handler'''
for name,tree in bpy.data.node_groups.items():
if tree.bl_idname =='SverchCustomTreeType' and tree.nodes:
try:
tree.update_ani()
except Exception as e:
print('Failed to update:',name,str(e))
Update buttons
The various update buttons use the following operator.
class SverchokUpdateAll(bpy.types.Operator):
def execute(self, context):
makeTreeUpdate2()
speedUpdate()
return {'FINISHED'}
Note Perhaps we should separate this to have a update All and update current node tree now that we can show more than one node tree at the same time.
Functions
speedUpdate()
speedUpdate is the master update function which calls the update system and dispatches the various calls. It has several modes.
- Partial update only part of a node group starting in a named node
- Update a named node group
- Update all Sverchok node group
- Update an Animation tree (not used yet)
Note It needs some cleaning to be honest.
makeTreeUpdate2()
If tree_name is passed an update list is created for that node group is stored in a update list cache. Without tree_name all node groups are processed.
Note The name comes since this is rewrite of the original update makeTreeUpdate2() function.
Building update lists
There are some function the can be used to create update lists. The list are flat and for the whole tree.
Make update list
Create an update list for a node group or a specified subset of node group. The node_set options is used by the next partial updates but can also be used for creating animation trees and other partial update trees.
Gives the following list:
- Float
- List Series
- Vectors in
- List Length
- Vectors out
- List Series.001 7 Vectors in.001 8 Text Output
def make_update_list(node_tree,node_set = None):
""" Makes a list for updates from a node_group
if a node set is passed only the subtree defined by the node set is used. Otherwise
the complete node tree is used.
"""
A short description of the algorithm used:
- Select nodes that have inputs or outputs.
- Create a dict of {nodeA :[nodeB, nodeC nodeD]} where the nodes in the list are the nodes that needs be updated before nodeA.
- Select the wifi nodes and crete dependecies for them if needed.
- Start with nodes without outputs and try to satisfy the dependecies while maintaining a stack of nodes and creating the output list for each node where the dependencies are satisfied.
It does some error checking on the way and the whole system fails without notifying the user. Because there are many fail invalid node trees states created during normal editing. For example every time you drag a noodle from one node to another 2 updates event are issued and one socket is connected and the other is not.
make_tree_from_nodes
Create an update list of nodes affected by a change by a set of nodes.
def make_tree_from_nodes(node_names,tree_name):
"""
Create a partial update list from a sub-tree, node_names is a list of nodes that
drives change for the tree
Only nodes downtree from node_names are updated
"""
Future issues.
Some issued for the future.
Node state and Error handling
Node need a way to mark that they are not ready and in such cases they will not be updated. Also they need should be able to be marked as failed. I think 3 node states are needed.
- Not ready
- Ready
- Failed
Separating UI and execute
Right now the ui changes and data processing events are not separated. They should be since editor changes might affect the node function and cause incorrect states. Also the other types of events (frame change and value change) do not need the UI update code to run.
I propose the following.
def update(self):
handle sockets
set state
def execute(self):
process data
Animation node trees
Detect driven, animated etc nodes and update only update the parts of the node tree that are needed. Low priority.
Cache animation states
Not sure about how to do this. Low priority.