Commit: f65ea4cfbe80c22004cf3212abf363c9b9dff46c Author: Omar Emara Date: Mon Feb 14 13:57:11 2022 +0200 Branches: temp-viewport-compositor-compiler https://developer.blender.org/rBf65ea4cfbe80c22004cf3212abf363c9b9dff46c
Viewport Compositor: Publicly expose compiler class This patch adds the compiler class to the public header file to be used by the compositor engine. =================================================================== M source/blender/nodes/NOD_compositor_execute.hh M source/blender/nodes/intern/node_compositor_execute.cc =================================================================== diff --git a/source/blender/nodes/NOD_compositor_execute.hh b/source/blender/nodes/NOD_compositor_execute.hh index ff93b5954f4..de257629d4f 100644 --- a/source/blender/nodes/NOD_compositor_execute.hh +++ b/source/blender/nodes/NOD_compositor_execute.hh @@ -19,11 +19,15 @@ #include "BLI_hash.hh" #include "BLI_map.hh" #include "BLI_vector.hh" +#include "BLI_vector_set.hh" +#include "DNA_node_types.h" #include "DNA_scene_types.h" #include "GPU_texture.h" +#include "NOD_derived_node_tree.hh" + namespace blender::compositor { /* -------------------------------------------------------------------- @@ -112,4 +116,46 @@ class CompositorContext { virtual GPUTexture *get_pass_texture(int view_layer, eScenePassType pass_type) = 0; }; +using namespace nodes::derived_node_tree_types; + +class Compiler { + private: + /* The derived and reference node trees representing the compositor setup. */ + NodeTreeRefMap tree_ref_map_; + DerivedNodeTree tree_; + /* The output node whose result should be computed and drawn. */ + DNode output_node_; + /* Stores a heuristic estimation of the number of needed intermediate buffers + * to compute every node and all of its dependencies. */ + Map<DNode, int> needed_buffers_; + /* An ordered set of nodes defining the schedule of node execution. */ + VectorSet<DNode> node_schedule_; + + public: + Compiler(bNodeTree *scene_node_tree); + + void compile(); + + void dump_schedule(); + + private: + /* Computes the output node whose result should be computed and drawn, then store the result in + * output_node_. The output node is the node marked as NODE_DO_OUTPUT. If multiple types of + * output nodes are marked, then the preference will be CMP_NODE_COMPOSITE > CMP_NODE_VIEWER > + * CMP_NODE_SPLITVIEWER. */ + void compute_output_node(); + + /* Computes a heuristic estimation of the number of needed intermediate buffers to compute this + * node and all of its dependencies. The method recursively computes the needed buffers for all + * node dependencies and stores them in the needed_buffers_ map. So the root/output node can be + * provided to compute the needed buffers for all nodes. */ + int compute_needed_buffers(DNode node); + + /* Computes the execution schedule of the nodes and stores the schedule in node_schedule_. This + * is essentially a post-order depth first traversal of the node tree from the output node to the + * leaf input nodes, with informed order of traversal of children based on a heuristic estimation + * of the number of needed_buffers. */ + void compute_schedule(DNode node); +}; + } // namespace blender::compositor diff --git a/source/blender/nodes/intern/node_compositor_execute.cc b/source/blender/nodes/intern/node_compositor_execute.cc index 854bdfc180e..f341a2be8ef 100644 --- a/source/blender/nodes/intern/node_compositor_execute.cc +++ b/source/blender/nodes/intern/node_compositor_execute.cc @@ -15,8 +15,6 @@ */ #include "BLI_map.hh" -#include "BLI_set.hh" -#include "BLI_string_ref.hh" #include "BLI_utildefines.h" #include "BLI_vector.hh" #include "BLI_vector_set.hh" @@ -64,174 +62,144 @@ void TexturePool::release(GPUTexture *texture) * Compiler. */ -class Compiler { - public: - private: - /* The derived and reference node trees repressing the compositor setup. */ - NodeTreeRefMap tree_ref_map_; - DerivedNodeTree tree_; - /* The output node whose result should be computed and drawn. */ - DNode output_node_; - /* Stores a heuristic estimation of the number of needed intermediate buffers - * to compute every node and all of its dependencies. */ - Map<DNode, int> needed_buffers_; - /* An ordered set of nodes defining the schedule of node execution. */ - VectorSet<DNode> node_schedule_; - - public: - Compiler(bNodeTree *scene_node_tree) : tree_(*scene_node_tree, tree_ref_map_){}; - - void compile() - { - compute_output_node(); - compute_needed_buffers(output_node_); - compute_schedule(output_node_); +Compiler::Compiler(bNodeTree *scene_node_tree) : tree_(*scene_node_tree, tree_ref_map_){}; + +void Compiler::compile() +{ + compute_output_node(); + compute_needed_buffers(output_node_); + compute_schedule(output_node_); +} + +void Compiler::dump_schedule() +{ + for (const DNode &node : node_schedule_) { + std::cout << node->name() << std::endl; } +} - void dump_schedule() - { - for (const DNode &node : node_schedule_) { - std::cout << node->name() << std::endl; +void Compiler::compute_output_node() +{ + const NodeTreeRef &root_tree = tree_.root_context().tree(); + for (const NodeRef *node : root_tree.nodes_by_type("CompositorNodeComposite")) { + if (node->bnode()->flag & NODE_DO_OUTPUT) { + output_node_ = DNode(&tree_.root_context(), node); + return; } } - - private: - /* Computes the output node whose result should be computed and drawn. The output node is the - * node marked as NODE_DO_OUTPUT. If multiple types of output nodes are marked, then the - * preference will be CMP_NODE_COMPOSITE > CMP_NODE_VIEWER > CMP_NODE_SPLITVIEWER. */ - void compute_output_node() - { - const NodeTreeRef &root_tree = tree_.root_context().tree(); - for (const NodeRef *node : root_tree.nodes_by_type("CompositorNodeComposite")) { - if (node->bnode()->flag & NODE_DO_OUTPUT) { - output_node_ = DNode(&tree_.root_context(), node); - return; - } + for (const NodeRef *node : root_tree.nodes_by_type("CompositorNodeViewer")) { + if (node->bnode()->flag & NODE_DO_OUTPUT) { + output_node_ = DNode(&tree_.root_context(), node); + return; } - for (const NodeRef *node : root_tree.nodes_by_type("CompositorNodeViewer")) { - if (node->bnode()->flag & NODE_DO_OUTPUT) { - output_node_ = DNode(&tree_.root_context(), node); - return; - } + } + for (const NodeRef *node : root_tree.nodes_by_type("CompositorNodeSplitViewer")) { + if (node->bnode()->flag & NODE_DO_OUTPUT) { + output_node_ = DNode(&tree_.root_context(), node); + return; } - for (const NodeRef *node : root_tree.nodes_by_type("CompositorNodeSplitViewer")) { - if (node->bnode()->flag & NODE_DO_OUTPUT) { - output_node_ = DNode(&tree_.root_context(), node); + } +} + +/* Consider a node that takes n number of buffers as an input from a number of node dependencies, + * which we shall call the input nodes. The node also computes and outputs m number of buffers. + * In order for the node to compute its output, a number of intermediate buffers will be needed. + * Since the node takes n buffers and outputs m buffers, then the number of buffers directly + * needed by the node is (n + m). But each of the input buffers are computed by a node that, in + * turn, needs a number of buffers to compute its output. So the total number of buffers needed + * to compute the output of the node is max(n + m, d) where d is the number of buffers needed by + * the input node that needs the largest number of buffers. We only consider the input node that + * needs the largest number of buffers, because those buffers can be reused by any input node + * that needs a lesser number of buffers. + * + * If the node tree was, in fact, a tree, then this would be an accurate computation. However, + * the node tree is in fact a graph that allows output sharing, so the computation in this case + * is merely a heuristic estimation that works well in most cases. */ +int Compiler::compute_needed_buffers(DNode node) +{ + /* Compute the number of buffers that the node takes as an input as well as the number of + * buffers needed to compute the most demanding dependency node. */ + int input_buffers = 0; + int buffers_needed_by_dependencies = 0; + for (const InputSocketRef *input_ref : node->inputs()) { + const DInputSocket input{node.context(), input_ref}; + /* Only consider inputs that are linked, that is, those that take a buffer. */ + input.foreach_origin_socket([&](const DSocket origin) { + input_buffers++; + /* The origin node was already computed before, so skip it. */ + if (needed_buffers_.contains(origin.node())) { return; } - } + /* Recursively compute the number of buffers needed to compute this dependency node. */ + const int buffers_needed_by_origin = compute_needed_buffers(origin.node()); + if (buffers_needed_by_origin > buffers_needed_by_dependencies) { + buffers_needed_by_dependencies = buffers_needed_by_origin; + } + }); } - /* Computes a heuristic estimation of the number of needed intermediate buffers to compute this - * node and all of its dependencies. The method recursively computes the needed buffers for all - * node dependencies and stores them in the needed_buffers_ map. So the root/output node can be - * provided to compute the needed buffers for all nodes. - * - * Consider a node that takes n number of buffers as an input from a number of node dependencies, - * which we shall call the input nodes. The node also computes and outputs m number of buffers. - * In order for the node to compute its output, a number of intermediate buffers will be needed. - * Since the node takes n buffers and outputs m buffers, then the number of buffers directly - * needed by the node is (n + m). But each of the input buffers are computed by a node that, in - * turn, needs a number of buffers to compute its output. So the total number of buffers needed - * to compute the output of the node is max(n + m, d) where d is the number of buffers needed by - * the input node that needs the largest number of buffers. We only consider the input node that - * needs the largest number of buffers, because those buffers can be reused by any input node - * that needs a lesser number of buffers. - * - * If the node tree was, in fact, a tree, then this would be an accurate computation. However, - * the node tree is in fact a graph that allows output sharing, so the computation in this case - * is merely a heuristic estimation that works well in most cases. */ - int compute_needed_buffers(DNode node) - { - /* Compute the number of buffers that the node takes as an input as well a @@ Diff output truncated at 10240 characters. @@ _______________________________________________ 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