Commit: 079b38f8def1143f1319d367fa32661926ecc8b0 Author: Jacques Lucke Date: Thu Sep 8 16:37:35 2022 +0200 Branches: temp-geometry-nodes-evaluator-refactor https://developer.blender.org/rB079b38f8def1143f1319d367fa32661926ecc8b0
comments =================================================================== M source/blender/functions/FN_lazy_function_graph_executor.hh M source/blender/functions/intern/lazy_function_graph_executor.cc =================================================================== diff --git a/source/blender/functions/FN_lazy_function_graph_executor.hh b/source/blender/functions/FN_lazy_function_graph_executor.hh index cabc69f34ac..ad4098aeee6 100644 --- a/source/blender/functions/FN_lazy_function_graph_executor.hh +++ b/source/blender/functions/FN_lazy_function_graph_executor.hh @@ -4,6 +4,9 @@ /** \file * \ingroup fn + * + * This file provides means to create a #LazyFunction from #Graph (which could then e.g. be used in + * another #Graph again). */ #include "BLI_vector.hh" @@ -13,6 +16,9 @@ namespace blender::fn::lazy_function { +/** + * Can be implemented to log values produced during graph evaluation. + */ class GraphExecutorLogger { public: virtual ~GraphExecutorLogger() = default; @@ -22,6 +28,11 @@ class GraphExecutorLogger { GPointer value) const; }; +/** + * Has to be implemented when some of the nodes in the graph may have side effects. The + * #GraphExecutor has to know about that to make sure that these nodes will be executed even though + * their outputs are not needed. + */ class GraphExecutorSideEffectProvider { public: virtual ~GraphExecutorSideEffectProvider() = default; diff --git a/source/blender/functions/intern/lazy_function_graph_executor.cc b/source/blender/functions/intern/lazy_function_graph_executor.cc index 97393b04f8e..b6b3ca591bc 100644 --- a/source/blender/functions/intern/lazy_function_graph_executor.cc +++ b/source/blender/functions/intern/lazy_function_graph_executor.cc @@ -1,5 +1,43 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +/** + * This file implements the evaluation of a lazy-function graph. It's main objectices are: + * - Only compute values that are actually used. + * - Allow to spread the work over an arbitrary number of CPU cores. + * + * Other (simpler) executors with different main objectives could be implemented in the future. For + * some scenarios those could be simpler when many nodes do very little work or most nodes have to + * be processed sequentially. Those assumptions make the first and second objective less important + * respectively. + * + * The design implemented in this executor requires *no* main thread that coordinates everything. + * Instead, one thread will trigger some initial work and then many threads coordinate themselves + * in a distributed fashion. In an ideal situation, every thread ends up processing a separate part + * of the graph which results in less communication overhead. The way TBB schedules tasks helps + * with that: a thread will next process the task that it added to a task pool just before. + * + * Communication between threads is synchronized by using a mutex in every node. When a thread + * wants to access the state of a node, its mutex has to be locked first (there some documented + * exceptions) to that. The assumption here is that most nodes are only ever touched by a single + * thread and therefore the lock contention is reduced the more nodes there are. + * + * Similar to how a #LazyFunction can be thought of as a state machine (see `FN_lazy_function.hh`), + * each node can also be thought of as a state machine. The state of a node contains the evaluation + * state of its inputs and outputs. Every time a node is executed, it has to advance its state in + * some way (e.g. it requests a new input or computes a new output). + * + * At the core of the executor is a task pool. Every task in that pool represents a node execution. + * When a node is executed it may send notifications to other nodes which may in turn add those + * nodes to the task pool. For example, the current node has computed one of its outputs, then the + * computed value is forwarded to all linked inputs, changing their node states in the process. If + * this input was the last missing required input, the node will be added to the task pool so that + * it is executed next. + * + * When the task pool is empty, the executor gives back control to the caller which may later + * provide new inputs to the graph which in turn adds new nodes to the task pool and the process + * starts again. + */ + #include <mutex> #include "BLI_enumerable_thread_specific.hh" _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs