mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-05-23 05:56:36 +02:00
[graph] limit scope of graph update to outdated nodes
Don't update every nodes in the graph on each modification. Instead, use dfs visit to find nodes impacted by a change (of value or of topology) and limit the update to those nodes.
This commit is contained in:
parent
b67fae013b
commit
1f223ccc54
1 changed files with 43 additions and 18 deletions
|
@ -184,10 +184,14 @@ class Attribute(BaseObject):
|
||||||
# which is why we don't trigger any update in this case
|
# which is why we don't trigger any update in this case
|
||||||
# TODO: update only the nodes impacted by this change
|
# TODO: update only the nodes impacted by this change
|
||||||
# TODO: only update the graph if this attribute participates to a UID
|
# TODO: only update the graph if this attribute participates to a UID
|
||||||
if self.node.graph and self.isInput:
|
if self.isInput:
|
||||||
self.node.graph.update()
|
self.requestGraphUpdate()
|
||||||
self.valueChanged.emit()
|
self.valueChanged.emit()
|
||||||
|
|
||||||
|
def requestGraphUpdate(self):
|
||||||
|
if self.node.graph and self.attributeDesc.uid:
|
||||||
|
self.node.graph.markNodesDirty(self.node)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def isOutput(self):
|
def isOutput(self):
|
||||||
return self._isOutput
|
return self._isOutput
|
||||||
|
@ -285,7 +289,9 @@ class ListAttribute(Attribute):
|
||||||
|
|
||||||
def _set_value(self, value):
|
def _set_value(self, value):
|
||||||
self._value.clear()
|
self._value.clear()
|
||||||
self.extend(value)
|
if value:
|
||||||
|
self.extend(value)
|
||||||
|
self.requestGraphUpdate()
|
||||||
|
|
||||||
def append(self, value):
|
def append(self, value):
|
||||||
self.extend([value])
|
self.extend([value])
|
||||||
|
@ -295,18 +301,13 @@ class ListAttribute(Attribute):
|
||||||
attrs = [attribute_factory(self.attributeDesc.elementDesc, v, self.isOutput, self.node, self) for v in values]
|
attrs = [attribute_factory(self.attributeDesc.elementDesc, v, self.isOutput, self.node, self) for v in values]
|
||||||
self._value.insert(index, attrs)
|
self._value.insert(index, attrs)
|
||||||
self._applyExpr()
|
self._applyExpr()
|
||||||
if self.node.graph:
|
self.requestGraphUpdate()
|
||||||
self.node.graph.update()
|
|
||||||
|
|
||||||
def index(self, item):
|
def index(self, item):
|
||||||
return self._value.indexOf(item)
|
return self._value.indexOf(item)
|
||||||
|
|
||||||
def extend(self, values):
|
def extend(self, values):
|
||||||
values = [attribute_factory(self.attributeDesc.elementDesc, v, self.isOutput, self.node, self) for v in values]
|
self.insert(len(self._value), values)
|
||||||
self._value.extend(values)
|
|
||||||
self._applyExpr()
|
|
||||||
if self.node.graph:
|
|
||||||
self.node.graph.update()
|
|
||||||
|
|
||||||
def remove(self, index, count=1):
|
def remove(self, index, count=1):
|
||||||
if self.node.graph:
|
if self.node.graph:
|
||||||
|
@ -315,8 +316,7 @@ class ListAttribute(Attribute):
|
||||||
if attr.isLink:
|
if attr.isLink:
|
||||||
self.node.graph.removeEdge(attr) # delete edge if the attribute is linked
|
self.node.graph.removeEdge(attr) # delete edge if the attribute is linked
|
||||||
self._value.removeAt(index, count)
|
self._value.removeAt(index, count)
|
||||||
if self.node.graph:
|
self.requestGraphUpdate()
|
||||||
self.node.graph.update()
|
|
||||||
|
|
||||||
def uid(self, uidIndex):
|
def uid(self, uidIndex):
|
||||||
uids = []
|
uids = []
|
||||||
|
@ -713,6 +713,7 @@ class Node(BaseObject):
|
||||||
|
|
||||||
self._name = None # type: str
|
self._name = None # type: str
|
||||||
self.graph = None # type: Graph
|
self.graph = None # type: Graph
|
||||||
|
self.dirty = True # whether this node's outputs must be re-evaluated on next Graph update
|
||||||
self._chunks = ListModel(parent=self)
|
self._chunks = ListModel(parent=self)
|
||||||
self._cmdVars = {}
|
self._cmdVars = {}
|
||||||
self._size = 0
|
self._size = 0
|
||||||
|
@ -1329,6 +1330,7 @@ class Graph(BaseObject):
|
||||||
raise RuntimeError('Destination attribute "{}" is already connected.'.format(dstAttr.fullName()))
|
raise RuntimeError('Destination attribute "{}" is already connected.'.format(dstAttr.fullName()))
|
||||||
edge = Edge(srcAttr, dstAttr)
|
edge = Edge(srcAttr, dstAttr)
|
||||||
self.edges.add(edge)
|
self.edges.add(edge)
|
||||||
|
self.markNodesDirty(dstAttr.node)
|
||||||
dstAttr.valueChanged.emit()
|
dstAttr.valueChanged.emit()
|
||||||
dstAttr.isLinkChanged.emit()
|
dstAttr.isLinkChanged.emit()
|
||||||
return edge
|
return edge
|
||||||
|
@ -1343,6 +1345,7 @@ class Graph(BaseObject):
|
||||||
if dstAttr not in self.edges.keys():
|
if dstAttr not in self.edges.keys():
|
||||||
raise RuntimeError('Attribute "{}" is not connected'.format(dstAttr.fullName()))
|
raise RuntimeError('Attribute "{}" is not connected'.format(dstAttr.fullName()))
|
||||||
self.edges.pop(dstAttr)
|
self.edges.pop(dstAttr)
|
||||||
|
self.markNodesDirty(dstAttr.node)
|
||||||
dstAttr.valueChanged.emit()
|
dstAttr.valueChanged.emit()
|
||||||
dstAttr.isLinkChanged.emit()
|
dstAttr.isLinkChanged.emit()
|
||||||
|
|
||||||
|
@ -1610,14 +1613,16 @@ class Graph(BaseObject):
|
||||||
self.cacheDir = os.path.join(os.path.abspath(os.path.dirname(filepath)), meshroom.core.cacheFolderName)
|
self.cacheDir = os.path.join(os.path.abspath(os.path.dirname(filepath)), meshroom.core.cacheFolderName)
|
||||||
self.filepathChanged.emit()
|
self.filepathChanged.emit()
|
||||||
|
|
||||||
def updateInternals(self, startNodes=None):
|
def updateInternals(self, startNodes=None, force=False):
|
||||||
nodes, edges = self.dfsOnFinish(startNodes=startNodes)
|
nodes, edges = self.dfsOnFinish(startNodes=startNodes)
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
node.updateInternals()
|
if node.dirty or force:
|
||||||
|
node.updateInternals()
|
||||||
|
|
||||||
def updateStatusFromCache(self):
|
def updateStatusFromCache(self, force=False):
|
||||||
for node in self._nodes:
|
for node in self._nodes:
|
||||||
node.updateStatusFromCache()
|
if node.dirty or force:
|
||||||
|
node.updateStatusFromCache()
|
||||||
|
|
||||||
def updateStatisticsFromCache(self):
|
def updateStatisticsFromCache(self):
|
||||||
for node in self._nodes:
|
for node in self._nodes:
|
||||||
|
@ -1638,8 +1643,28 @@ class Graph(BaseObject):
|
||||||
self.updateInternals()
|
self.updateInternals()
|
||||||
if os.path.exists(self._cacheDir):
|
if os.path.exists(self._cacheDir):
|
||||||
self.updateStatusFromCache()
|
self.updateStatusFromCache()
|
||||||
|
for node in self.nodes:
|
||||||
|
node.dirty = False
|
||||||
|
|
||||||
self.updated.emit()
|
self.updated.emit()
|
||||||
|
|
||||||
|
def markNodesDirty(self, fromNode):
|
||||||
|
"""
|
||||||
|
Mark all nodes following 'fromNode' as dirty, and request a graph update.
|
||||||
|
All nodes marked as dirty will get their outputs to be re-evaluated
|
||||||
|
during the next graph update.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fromNode (Node): the node to start the invalidation from
|
||||||
|
|
||||||
|
See Also:
|
||||||
|
Graph.update, Graph.updateInternals, Graph.updateStatusFromCache
|
||||||
|
"""
|
||||||
|
nodes, edges = self.nodesFromNode(fromNode)
|
||||||
|
for node in nodes:
|
||||||
|
node.dirty = True
|
||||||
|
self.update()
|
||||||
|
|
||||||
def stopExecution(self):
|
def stopExecution(self):
|
||||||
""" Request graph execution to be stopped by terminating running chunks"""
|
""" Request graph execution to be stopped by terminating running chunks"""
|
||||||
for chunk in self.iterChunksByStatus(Status.RUNNING):
|
for chunk in self.iterChunksByStatus(Status.RUNNING):
|
||||||
|
@ -1696,8 +1721,8 @@ class Graph(BaseObject):
|
||||||
if self._cacheDir == value:
|
if self._cacheDir == value:
|
||||||
return
|
return
|
||||||
self._cacheDir = value
|
self._cacheDir = value
|
||||||
self.updateInternals()
|
self.updateInternals(force=True)
|
||||||
self.updateStatusFromCache()
|
self.updateStatusFromCache(force=True)
|
||||||
self.cacheDirChanged.emit()
|
self.cacheDirChanged.emit()
|
||||||
|
|
||||||
nodes = Property(BaseObject, nodes.fget, constant=True)
|
nodes = Property(BaseObject, nodes.fget, constant=True)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue