-
Notifications
You must be signed in to change notification settings - Fork 233
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Separate UI and processing #152
Comments
I did some further research and the issue is actually worse than I thought re:editing. Already today we could gain a lot by renaming all update(self) functions so that blender don't call them but only the sverchok update system. Adding a cylinder node triggers the update function 18 times... Code: def init(self, context):
a=self.inputs.new('StringsSocket', "RadTop", "RadTop")
print("Added socket:",a.name) etc def update(self):
print("Cylinder total sockets",len(self.inputs)+len(self.outputs)) Output:
|
Also the blender update system updates nodes in the order given by D.node_groups['NodeTree'].nodes.keys()
['Viewer Draw', 'Circle', 'List Range.001', 'List Range.002', 'List Range', 'Cylinder.001'] and then
Given all of this it sometimes feels like miracle that sverchok is working as well as it is... |
that's great, so a lot less processing seems achievable.. to the point |
Yeah, note that this is only for editor changes but if you click the update button or modify a slider, it works as it should. I am sure we all dealt with side effect of this while bug hunting... Time for some sed and testing... |
Not so happy about renaming all update functions even if seems to be working fine. It feels dangerous somehow. |
|
No we have to rename all The name change is a simple fix to decrease amount of updates on editor changes to 50% since blender ui code call the function. |
Does that mean that sverchok would be responsible for all updates? ..like calling |
so the stuff we used to do in |
If we change the names of all node level |
I did something like this to test but it fails sometimes. sv_isUpdating = BoolProperty( default=False )
def update(self):
'''
Rebuild and update the Sverchok node tree, used at editor changes
'''
if self.sv_isUpdating:
print("Recursion protection!")
return
self.sv_isUpdating = True
try:
makeTreeUpdate2(tree = self)
speedUpdate(tree = self)
except Exception as e:
print(e)
self.sv_isUpdating = False
return
self.sv_isUpdating = False |
is this the same?: sv_isUpdating = BoolProperty( default=False )
def update(self):
'''
Rebuild and update the Sverchok node tree, used at editor changes
'''
if self.sv_isUpdating:
print("Recursion protection!")
return
self.sv_isUpdating = True
try:
makeTreeUpdate2(tree = self)
speedUpdate(tree = self)
except Exception as e:
print(e)
finally:
self.sv_isUpdating = False |
It should be, I try to stay clear of
Needs to be
But please don't look to much around there... there is room for cleaning up. |
I'm also not a fan of using try/except , but speed wise it's OK on code that isn't on a tight loop. |
I might have a read anyway to see if I can understand the mechanics. |
But for some reason it doesn't work like this. Hmm. Well we cut away 50% of the updates with rename alone. A step forward. |
Can't really get recursion check working... However the startup issue is that |
what about simple UI drags of nodes across the canvas, I see blender really takes a hit on my machine when moving nodes. |
I see that sometimes but havn't found out exactly what causes. But our |
We can ask Lukas Tone maybe |
Yes I should try to collect a set of questions and requests. |
Okay I think the way forward here is that I do limited with a couple of test to see if actually works out as well as I think it will and work out issues. |
Now it is possible to dump update list from a tree using this:
For debug reasons. |
NodegroupsI have been thinking about how to make reusable components of nodes. Already today it is kind of possible using wifi nodes, however it they can't be reused. It would be possible to do node groups with only a limited amount of works, however they wouldn't behave as nicely as blender node groups does with editing and so on. They would also have to live on either the same layout or a special layout only for node group since UI and processing is the same. Total separation of processing and uiTo be able to have node groups without them being visible somewhere we need to totally decouple ui and processing, something that needs to be done sooner or later anyway. Does it make sense to do this as two steps or only make a large step? Even the first step would be a step forward and solve many issues. It would also make it easier to get to the next step. Note This is important but some work to get started. But I will try to push forward with this. |
the hidden complexities of this beast scare me a little 👍 |
Yeah it does. I no longer think that a gradual transition is possible but resolved some other issues... Slowly. |
I think we can do something usable without going C/C++ and learn a lot about how we want it to work. There will be limits of how much complex data we can process in real time, some algorithms are very heavy, like spatial search with kdtree, voronoi and others. From there we can make a proposal and try to redo it in C/C++ as a python module. Or somebody else learns from this project. But going this route still has some limits getting data in and out of blender I think, but much more complicated things could be possible. I found this interesting. |
Compiling a module may happen eventually, but multi-core access is a lot more attractive to investigate first (i think). And Numpy is perfect for all this numerical stuff, but I think you mentioned this before -- all data passed around would need to be in np.array([]) form to avoid the overhead of creating it each time. np.array silently optimizes it's containers if it realizes it's holding homogeneous data: https://scipy-lectures.github.io/intro/numpy/array_object.html maybe this is off topic. |
It is slightly off topic, but it does needs to be done also. But too separate ui and processing is very important step that will make later work easier. |
When we do this split we can stop expensive updates on every editor change. Further down the road we keep track of changes in nodes and update only changed nodes, like works like now if you change a slider in a node, only the nodes affected will have to change. |
let me ask some more questions then.
|
Current: def update(self):
inputs = self.inputs
outputs = self.outputs
# outputs, end early.
if not 'Range' in outputs or not outputs['Range'].links:
return
param=[inputs[i].sv_get()[0] for i in range(3)]
f=self.func_dict[self.mode]
out = [f(*args) for args in zip(*match_long_repeat(param))]
self.outputs['Range'].sv_set(out) note the last self there can and should be removed. def update(self):
# last socket created, now we are ready!
if 'Range' in outputs:
self.state='ready'
def process(self):
inputs = self.inputs
outputs = self.outputs
if not outputs['Range'].links:
return
param=[inputs[i].sv_get()[0] for i in range(3)]
f=self.func_dict[self.mode]
out = [f(*args) for args in zip(*match_long_repeat(param))]
outputs['Range'].sv_set(out) The main difference is that Perhaps we can even say the it has to terminate in an output node for it be processed. For example view draw, text out etc. In which case the check that Actually it feels logical to check for |
Yeah the availability of terminating nodes would be the last check before calling |
I think you are saying that even the check for if not outputs['Range'].links:
return might be better suited in in that case perhaps the signature of |
Yes, that we should check that it makes sense to call process. I am not sure, a lot of these issues needs to be resolved while implementing it I guess. |
this may be tangential, but it's not permitted to update .self while inside draw_buttons
i do recall there are overrides for this http://blender.45788.x6.nabble.com/Python-API-change-breaks-Rigify-td104240.html
|
|
Refactoring the update system a bit in preparation. To separate unconnected node groups on the same layout to allow error handling to be for each sub group of nodes.
Also a nice performance boost on the same layout:
5 times quicker, basically by having less |
Note that this rethinking happened because @zeffii posted the python performance tips and that I noted that separate this is very similar to building the list only took a fraction of the time Some further testing and looking at performance problems we are now 100 times faster for a larger test layout (173 nodes)
The point of the new code was make independent groups in the layout separated, this is right now "only" 56 times faster than building a complete layout with old
So how is this speedup possible? By doing less inspection and caring less about absolute order of nodes, only that the nodes they depend on are updated before them. |
good explanation. Good speedup for update in python is limited anyway, but cython or something may help in far future. |
This UI and processing separation could allow for the node window to be an optional external application, even a browser window. This might lead to the node view being rewritten in javascript / coffeescript and it would communicate via sockets with Blender to change the states of nodes. Think about the level of customization that could be implemented into the external nodeview. maybe in the distant future |
Would this mean for the code of the nodes? All processing functions declared outside of the class? or entirely different |
It could be done in many ways. We should just decide. A separate file would be good because it would force separation. I imagine either a compile function that returns either a class or a callable, or a class that can parse the node and extract the needed info. |
A lot of into in this thread isn't up to date with my current thinking about the issue, I think I will have time to tackle this next week and will probably start an new issue about it then. |
Maybe do a demonstration node, something simple, and also a more complicated one that really pushes the node interface. Okay, in your own good time. |
test node as usual. If your look at UI/workingdef separation changed, what changed? |
and my opinion, if no viewer draw/bmeshviewer etc in chain of update, than no update should occure with this nodes... imho. Or even if viewer node not active |
@nortikin Reprocess as little as possible, store as little data in the socket cache as possible but still allow small changes quickly. The big change from what outlined above is to separate the execution completely from the nodes which would allow a simple form of real node groups to exist, the editing wouldn't be as nice as blender but it could be fully functional. |
This is more and more becoming a limitation, therefore closing the issue might seem like the wrong thing to do but it is and old issue I think it better to start over then pretend that is is moving forward right now. I am not sure how to do this the correct way but will outline my ideas and concerns today in a new issue. But there is lot noise here so closing this one. |
What
To introduce a split between code that updates sockets and the code that process data.
Why
To solve these issues:
How
Changed
The
update
function cannot be calledupdate
because blender calls the update function. (see comments)The proposal is to call it
sv_update
.The new
def update(self):
function has the following responsibilities:For a simple node like Circle it could become like this.
For multi in socket it could be like this.
An then we have process that does the actual processing without checking if in sockets exists or are connected. We should still only procduce data that is needed.
etc.
Note the name process could be execute or something else.
States
More?
If any node in connected graph is marked not ready the node graph is not processed.
If any node in a connected graph fails the processing of that node graph is halted, the error node is marked.
Empty input
The question is what should happen on empty input.
Implementation stages:
Since this is big change it would be hard to do it in one step.
node.update()
then if it existsnode.process()
. It would work like today.Limitations
Data cannot drive number of outputs without user interaction (clicking a button for example). There is only one node today that does this, List Separate and that could be done in different way.
The text was updated successfully, but these errors were encountered: