diff options
Diffstat (limited to 'source/blender/compositor/realtime_compositor/intern/compile_state.cc')
-rw-r--r-- | source/blender/compositor/realtime_compositor/intern/compile_state.cc | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/source/blender/compositor/realtime_compositor/intern/compile_state.cc b/source/blender/compositor/realtime_compositor/intern/compile_state.cc new file mode 100644 index 00000000000..97c1e47e86e --- /dev/null +++ b/source/blender/compositor/realtime_compositor/intern/compile_state.cc @@ -0,0 +1,163 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <limits> + +#include "BLI_math_vec_types.hh" + +#include "DNA_node_types.h" + +#include "NOD_derived_node_tree.hh" + +#include "COM_compile_state.hh" +#include "COM_domain.hh" +#include "COM_input_descriptor.hh" +#include "COM_node_operation.hh" +#include "COM_result.hh" +#include "COM_scheduler.hh" +#include "COM_shader_operation.hh" +#include "COM_utilities.hh" + +namespace blender::realtime_compositor { + +using namespace nodes::derived_node_tree_types; + +CompileState::CompileState(const Schedule &schedule) : schedule_(schedule) +{ +} + +const Schedule &CompileState::get_schedule() +{ + return schedule_; +} + +void CompileState::map_node_to_node_operation(DNode node, NodeOperation *operations) +{ + return node_operations_.add_new(node, operations); +} + +void CompileState::map_node_to_shader_operation(DNode node, ShaderOperation *operations) +{ + return shader_operations_.add_new(node, operations); +} + +Result &CompileState::get_result_from_output_socket(DOutputSocket output) +{ + /* The output belongs to a node that was compiled into a standard node operation, so return a + * reference to the result from that operation using the output identifier. */ + if (node_operations_.contains(output.node())) { + NodeOperation *operation = node_operations_.lookup(output.node()); + return operation->get_result(output->identifier); + } + + /* Otherwise, the output belongs to a node that was compiled into a shader operation, so + * retrieve the internal identifier of that output and return a reference to the result from + * that operation using the retrieved identifier. */ + ShaderOperation *operation = shader_operations_.lookup(output.node()); + return operation->get_result(operation->get_output_identifier_from_output_socket(output)); +} + +void CompileState::add_node_to_shader_compile_unit(DNode node) +{ + shader_compile_unit_.add_new(node); + + /* If the domain of the shader compile unit is not yet determined or was determined to be + * an identity domain, update it to be the computed domain of the node. */ + if (shader_compile_unit_domain_ == Domain::identity()) { + shader_compile_unit_domain_ = compute_shader_node_domain(node); + } +} + +ShaderCompileUnit &CompileState::get_shader_compile_unit() +{ + return shader_compile_unit_; +} + +void CompileState::reset_shader_compile_unit() +{ + return shader_compile_unit_.clear(); +} + +bool CompileState::should_compile_shader_compile_unit(DNode node) +{ + /* If the shader compile unit is empty, then it can't be compiled yet. */ + if (shader_compile_unit_.is_empty()) { + return false; + } + + /* If the node is not a shader node, then it can't be added to the shader compile unit and the + * shader compile unit is considered complete and should be compiled. */ + if (!is_shader_node(node)) { + return true; + } + + /* If the computed domain of the node doesn't matches the domain of the shader compile unit, then + * it can't be added to the shader compile unit and the shader compile unit is considered + * complete and should be compiled. Identity domains are an exception as they are always + * compatible because they represents single values. */ + if (shader_compile_unit_domain_ != Domain::identity() && + shader_compile_unit_domain_ != compute_shader_node_domain(node)) { + return true; + } + + /* Otherwise, the node is compatible and can be added to the compile unit and it shouldn't be + * compiled just yet. */ + return false; +} + +Domain CompileState::compute_shader_node_domain(DNode node) +{ + /* Default to an identity domain in case no domain input was found, most likely because all + * inputs are single values. */ + Domain node_domain = Domain::identity(); + int current_domain_priority = std::numeric_limits<int>::max(); + + /* Go over the inputs and find the domain of the non single value input with the highest domain + * priority. */ + for (const bNodeSocket *input : node->input_sockets()) { + const DInputSocket dinput{node.context(), input}; + + /* Get the output linked to the input. If it is null, that means the input is unlinked, so skip + * it. */ + const DOutputSocket output = get_output_linked_to_input(dinput); + if (!output) { + continue; + } + + const InputDescriptor input_descriptor = input_descriptor_from_input_socket(input); + + /* If the output belongs to a node that is part of the shader compile unit, then the domain of + * the input is the domain of the compile unit itself. */ + if (shader_compile_unit_.contains(output.node())) { + /* Single value inputs can't be domain inputs. */ + if (shader_compile_unit_domain_.size == int2(1)) { + continue; + } + + /* Notice that the lower the domain priority value is, the higher the priority is, hence the + * less than comparison. */ + if (input_descriptor.domain_priority < current_domain_priority) { + node_domain = shader_compile_unit_domain_; + current_domain_priority = input_descriptor.domain_priority; + } + continue; + } + + const Result &result = get_result_from_output_socket(output); + + /* A single value input can't be a domain input. */ + if (result.is_single_value() || input_descriptor.expects_single_value) { + continue; + } + + /* Notice that the lower the domain priority value is, the higher the priority is, hence the + * less than comparison. */ + if (input_descriptor.domain_priority < current_domain_priority) { + node_domain = result.domain(); + current_domain_priority = input_descriptor.domain_priority; + } + } + + return node_domain; +} + +} // namespace blender::realtime_compositor |