46using namespace nodes::derived_node_tree_types;
53 this->build_procedure();
54 procedure_executor_ = std::make_unique<mf::ProcedureExecutor>(procedure_);
62 mf::ParamsBuilder parameter_builder{*procedure_executor_, &
mask};
64 const bool is_single_value = this->is_single_value_operation();
68 for (
int i = 0;
i < procedure_.params().
size();
i++) {
69 if (procedure_.params()[
i].type == mf::ParamType::InterfaceType::Input) {
71 if (
input.is_single_value()) {
72 parameter_builder.add_readonly_single_input(
input.single_value());
75 parameter_builder.add_readonly_single_input(
input.cpu_data());
80 if (is_single_value) {
81 output.allocate_single_value();
82 parameter_builder.add_uninitialized_single_output(
86 output.allocate_texture(domain);
87 parameter_builder.add_uninitialized_single_output(
output.cpu_data());
92 mf::ContextBuilder context_builder;
93 procedure_executor_->call_auto(
mask, parameter_builder, context_builder);
96 if (is_single_value) {
97 for (
int i = 0;
i < procedure_.params().
size();
i++) {
98 if (procedure_.params()[
i].type == mf::ParamType::InterfaceType::Output) {
100 output.update_single_value_data();
106void MultiFunctionProcedureOperation::build_procedure()
110 auto &multi_function_builder = *node_multi_functions_.lookup_or_add_cb(node, [&]() {
111 return std::make_unique<nodes::NodeMultiFunctionBuilder>(*node.bnode(),
112 node.context()->btree());
114 node->typeinfo->build_multi_function(multi_function_builder);
115 const mf::MultiFunction &multi_function = multi_function_builder.function();
127 this->assign_output_variables(node, output_variables);
131 for (
const auto &item : output_to_variable_map_.
items()) {
133 if (!output_variables_.
contains(item.value)) {
134 procedure_builder_.add_destruct(*item.value);
137 for (mf::Variable *variable : implicit_variables_) {
139 if (!output_variables_.contains(variable)) {
140 procedure_builder_.add_destruct(*variable);
143 for (mf::Variable *variable : implicit_input_to_variable_map_.values()) {
144 procedure_builder_.add_destruct(*variable);
147 mf::ReturnInstruction &return_instruction = procedure_builder_.add_return();
148 mf::procedure_optimization::move_destructs_up(procedure_, return_instruction);
152Vector<mf::Variable *> MultiFunctionProcedureOperation::get_input_variables(
153 DNode node,
const mf::MultiFunction &multi_function)
155 int available_inputs_index = 0;
156 Vector<mf::Variable *> input_variables;
157 for (
int i = 0;
i < node->input_sockets().
size();
i++) {
158 const DInputSocket
input{node.context(), node->input_sockets()[
i]};
166 if (origin->is_input()) {
172 input_variables.
append(this->get_constant_input_variable(DInputSocket(origin)));
175 input_variables.
append(this->get_implicit_input_variable(
input, DInputSocket(origin)));
180 const DOutputSocket
output = DOutputSocket(origin);
185 input_variables.
append(output_to_variable_map_.lookup(
output));
203 const mf::DataType expected_type = mf::DataType::ForSingle(
204 CPPType::get<ColorSceneLinear4f<eAlpha::Premultiplied>>());
205 input_variables.
last() = this->convert_variable(input_variables.
last(), expected_type);
209 const mf::ParamType parameter_type = multi_function.param_type(available_inputs_index);
210 input_variables.
last() = this->convert_variable(input_variables.
last(),
211 parameter_type.data_type());
213 available_inputs_index++;
216 return input_variables;
219mf::Variable *MultiFunctionProcedureOperation::get_constant_input_variable(
DInputSocket input)
221 const mf::MultiFunction *constant_function =
nullptr;
222 switch (
input->type) {
225 constant_function = &procedure_.construct_function<mf::CustomMF_Constant<float>>(value);
230 constant_function = &procedure_.construct_function<mf::CustomMF_Constant<int32_t>>(value);
235 constant_function = &procedure_.construct_function<mf::CustomMF_Constant<bool>>(value);
240 constant_function = &procedure_.construct_function<mf::CustomMF_Constant<float3>>(value);
245 constant_function = &procedure_.construct_function<mf::CustomMF_Constant<float4>>(value);
253 mf::Variable *constant_variable = procedure_builder_.add_call<1>(*constant_function)[0];
254 implicit_variables_.
append(constant_variable);
255 return constant_variable;
258mf::Variable *MultiFunctionProcedureOperation::get_implicit_input_variable(
262 const ImplicitInput implicit_input = origin_descriptor.implicit_input;
267 input_descriptor.type = origin_descriptor.type;
268 input_descriptor.implicit_input = implicit_input;
272 if (implicit_input_to_variable_map_.contains(implicit_input)) {
279 existing_input_descriptor.domain_priority =
math::min(
280 existing_input_descriptor.domain_priority, input_descriptor.domain_priority);
282 return implicit_input_to_variable_map_.lookup(implicit_input);
286 const std::string input_identifier =
"implicit_input" + std::to_string(implicit_input_index);
292 mf::Variable &variable = procedure_builder_.add_input_parameter(
293 mf::DataType::ForSingle(
Result::cpp_type(input_descriptor.type)), input_identifier);
294 parameter_identifiers_.append(input_identifier);
297 implicit_input_to_variable_map_.add(implicit_input, &variable);
302mf::Variable *MultiFunctionProcedureOperation::get_multi_function_input_variable(
307 if (output_to_variable_map_.contains(output_socket)) {
314 input_descriptor.domain_priority =
math::min(
315 input_descriptor.domain_priority,
321 return output_to_variable_map_.lookup(output_socket);
325 const std::string input_identifier =
"input" + std::to_string(input_index);
334 mf::Variable &variable = procedure_builder_.add_input_parameter(
335 mf::DataType::ForSingle(
Result::cpp_type(input_descriptor.type)), input_identifier);
336 parameter_identifiers_.append(input_identifier);
339 output_to_variable_map_.add(output_socket, &variable);
354void MultiFunctionProcedureOperation::assign_output_variables(
DNode node,
355 Vector<mf::Variable *> &variables)
359 int available_outputs_index = 0;
360 for (
int i = 0;
i < node->output_sockets().
size();
i++) {
361 const DOutputSocket
output{node.context(), node->output_sockets()[
i]};
367 mf::Variable *output_variable = variables[available_outputs_index];
368 output_to_variable_map_.add_new(
output, output_variable);
379 const bool is_preview_output =
output == preview_output;
380 if (is_preview_output) {
384 if (is_operation_output || is_preview_output) {
385 this->populate_operation_result(
output, output_variable);
388 available_outputs_index++;
392void MultiFunctionProcedureOperation::populate_operation_result(
DOutputSocket output_socket,
393 mf::Variable *variable)
396 const std::string output_identifier =
"output" + std::to_string(output_id);
406 const mf::DataType expected_type = mf::DataType::ForSingle(
result.get_cpp_type());
407 mf::Variable *converted_variable = this->convert_variable(variable, expected_type);
409 procedure_builder_.add_output_parameter(*converted_variable);
410 output_variables_.add_new(converted_variable);
411 parameter_identifiers_.append(output_identifier);
414mf::Variable *MultiFunctionProcedureOperation::convert_variable(mf::Variable *variable,
415 const mf::DataType expected_type)
417 const mf::DataType variable_type = variable->data_type();
418 if (variable_type == expected_type) {
423 const mf::MultiFunction *function = conversion_table.get_conversion_multi_function(
424 variable_type, expected_type);
426 mf::Variable *converted_variable = procedure_builder_.add_call<1>(*function, {variable})[0];
427 implicit_variables_.append(converted_variable);
428 return converted_variable;
431bool MultiFunctionProcedureOperation::is_single_value_operation()
434 for (
int i = 0;
i < procedure_.params().
size();
i++) {
435 if (procedure_.params()[
i].type == mf::ParamType::InterfaceType::Input) {
437 if (!
input.is_single_value()) {
#define BLI_assert_unreachable()
struct bNodeSocketValueFloat bNodeSocketValueFloat
struct bNodeSocketValueInt bNodeSocketValueInt
struct bNodeSocketValueRGBA bNodeSocketValueRGBA
struct bNodeSocketValueVector bNodeSocketValueVector
struct bNodeSocketValueBoolean bNodeSocketValueBoolean
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
ItemIterator items() const &
bool contains(const Key &key) const
void append(const T &value)
const T & last(const int64_t n=0) const
static const CPPType & get()
Result create_result(ResultType type, ResultPrecision precision)
MultiFunctionProcedureOperation(Context &context, PixelCompileUnit &compile_unit, const Schedule &schedule)
Result & get_result(StringRef identifier)
void populate_result(StringRef identifier, Result result)
Context & context() const
Result & get_input(StringRef identifier) const
virtual Domain compute_domain()
InputDescriptor & get_input_descriptor(StringRef identifier)
void declare_input_descriptor(StringRef identifier, InputDescriptor descriptor)
Map< DOutputSocket, std::string > outputs_to_declared_inputs_map_
Map< std::string, DOutputSocket > inputs_to_linked_outputs_map_
Map< std::string, int > inputs_to_reference_counts_map_
const Schedule & schedule_
VectorSet< DOutputSocket > preview_outputs_
Map< DOutputSocket, std::string > output_sockets_to_output_identifiers_map_
PixelOperation(Context &context, PixelCompileUnit &compile_unit, const Schedule &schedule)
PixelCompileUnit compile_unit_
Map< ImplicitInput, std::string > implicit_inputs_to_input_identifiers_map_
static const CPPType & cpp_type(const ResultType type)
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
const DataTypeConversions & get_implicit_type_conversions()
bool is_output_linked_to_node_conditioned(DOutputSocket output, FunctionRef< bool(DNode)> condition)
DSocket get_input_origin_socket(DInputSocket input)
VectorSet< DNode > Schedule
VectorSet< DNode > PixelCompileUnit
DOutputSocket find_preview_output_socket(const DNode &node)
ResultType get_node_socket_result_type(const bNodeSocket *socket)
InputDescriptor input_descriptor_from_input_socket(const bNodeSocket *socket)
bool is_socket_available(const bNodeSocket *socket)
T min(const T &a, const T &b)
VecBase< float, 4 > float4
VecBase< float, 3 > float3