50 if (handled_fields.
add(field)) {
51 fields_to_check.
push(field);
55 while (!fields_to_check.
is_empty()) {
57 const FieldNode &field_node = field.node();
67 field_tree_info.
field_users.add(operation_input, field);
68 if (handled_fields.
add(operation_input)) {
69 fields_to_check.
push(operation_input);
80 return field_tree_info;
90 const Span<std::reference_wrapper<const FieldInput>> field_inputs)
93 for (
const FieldInput &field_input : field_inputs) {
94 GVArray varray = context.get_varray_for_input(field_input, mask, scope);
96 const CPPType &type = field_input.cpp_type();
99 field_context_inputs.
append(varray);
101 return field_context_inputs;
117 for (
const int i : field_context_inputs.
index_range()) {
118 const GVArray &varray = field_context_inputs[i];
123 const GFieldRef field_input_field{field_input, 0};
126 if (found_fields.
add(field)) {
127 fields_to_check.
push(field);
131 while (!fields_to_check.
is_empty()) {
135 if (found_fields.
add(field)) {
136 fields_to_check.
push(field);
158 mf::DataType::ForSingle(field_input.cpp_type()), field_input.debug_name());
159 variable_by_field.
add_new({field_input, 0}, &variable);
163 struct FieldWithIndex {
165 int current_input_index = 0;
172 fields_to_check.
push({field, 0});
173 while (!fields_to_check.
is_empty()) {
174 FieldWithIndex &field_with_index = fields_to_check.
peek();
175 const GFieldRef &field = field_with_index.field;
176 if (variable_by_field.
contains(field)) {
178 fields_to_check.
pop();
181 const FieldNode &field_node = field.node();
191 if (field_with_index.current_input_index < operation_inputs.
size()) {
194 fields_to_check.
push({operation_inputs[field_with_index.current_input_index]});
195 field_with_index.current_input_index++;
203 int param_input_index = 0;
204 int param_output_index = 0;
205 for (
const int param_index : multi_function.
param_indices()) {
207 const mf::ParamType::InterfaceType interface_type = param_type.
interface_type();
208 if (interface_type == mf::ParamType::Input) {
209 const GField &input_field = operation_inputs[param_input_index];
210 variables[param_index] = variable_by_field.
lookup(input_field);
213 else if (interface_type == mf::ParamType::Output) {
214 const GFieldRef output_field{operation_node, param_output_index};
215 const bool output_is_ignored =
216 field_tree_info.
field_users.lookup(output_field).is_empty() &&
217 !output_fields.
contains(output_field);
218 if (output_is_ignored) {
220 variables[param_index] =
nullptr;
225 variables[param_index] = &new_variable;
226 variable_by_field.
add_new(output_field, &new_variable);
228 param_output_index++;
234 builder.add_call_with_all_variables(multi_function, variables);
241 constant_node.
type(), constant_node.
value().
get(),
false);
242 mf::Variable &new_variable = *builder.add_call<1>(fn)[0];
243 variable_by_field.
add_new(field, &new_variable);
252 for (
const GFieldRef &field : output_fields) {
254 if (!already_output_variables.
add(variable)) {
258 variable->data_type());
259 variable = builder.add_call<1>(copy_fn, {variable})[0];
261 builder.add_output_parameter(*variable);
265 for (
const GFieldRef &field : output_fields) {
266 variable_by_field.
remove(field);
270 builder.add_destruct(*variable);
275 mf::procedure_optimization::move_destructs_up(procedure, return_instr);
288 Array<bool> is_output_written_to_dst(fields_to_evaluate.
size(),
false);
289 const int array_size = mask.min_array_size();
291 if (mask.is_empty()) {
292 for (
const int i : fields_to_evaluate.
index_range()) {
293 const CPPType &type = fields_to_evaluate[i].cpp_type();
320 for (
const int out_index : fields_to_evaluate.
index_range()) {
321 const GFieldRef &field = fields_to_evaluate[out_index];
322 const FieldNode &field_node = field.node();
328 const GVArray &varray = field_context_inputs[field_input_index];
329 r_varrays[out_index] = varray;
335 field_constant.
type(), mask.min_array_size(), field_constant.
value().
get());
352 for (
const int i : fields_to_evaluate.
index_range()) {
358 if (varying_fields.
contains(field)) {
359 varying_fields_to_evaluate.
append(field);
360 varying_field_indices.
append(i);
363 constant_fields_to_evaluate.
append(field);
364 constant_field_indices.
append(i);
369 if (!varying_fields_to_evaluate.
is_empty()) {
373 procedure, scope, field_tree_info, varying_fields_to_evaluate);
380 for (
const GVArray &varray : field_context_inputs) {
381 mf_params.add_readonly_single_input(varray);
384 for (
const int i : varying_fields_to_evaluate.
index_range()) {
385 const GFieldRef &field = varying_fields_to_evaluate[i];
386 const CPPType &type = field.cpp_type();
387 const int out_index = varying_field_indices[i];
392 if (!dst_varray || !dst_varray.
is_span()) {
396 if (!type.is_trivially_destructible()) {
399 [buffer, mask, &type]() { type.destruct_indices(buffer, mask); });
408 r_varrays[out_index] = dst_varray;
409 is_output_written_to_dst[out_index] =
true;
414 mf_params.add_uninitialized_single_output(span);
417 procedure_executor.call_auto(mask, mf_params, mf_context);
421 if (!constant_fields_to_evaluate.
is_empty()) {
425 procedure, scope, field_tree_info, constant_fields_to_evaluate);
432 for (
const GVArray &varray : field_context_inputs) {
433 mf_params.add_readonly_single_input(varray);
436 for (
const int i : constant_fields_to_evaluate.
index_range()) {
437 const GFieldRef &field = constant_fields_to_evaluate[i];
438 const CPPType &type = field.cpp_type();
442 if (!type.is_trivially_destructible()) {
448 mf_params.add_uninitialized_single_output({type, buffer, 1});
451 const int out_index = constant_field_indices[i];
455 procedure_executor.call(mask, mf_params, mf_context);
461 for (
const int out_index : fields_to_evaluate.
index_range()) {
467 const GVArray &computed_varray = r_varrays[out_index];
469 if (is_output_written_to_dst[out_index]) {
483 BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
484 mask.slice(range).foreach_segment([&](auto segment) {
485 for (const int i : segment) {
486 computed_varray.get_to_uninitialized(i, buffer);
487 dst_varray.set_by_relocate(i, buffer);
492 r_varrays[out_index] = dst_varray;
500 if (field.node().depends_on_input()) {
501 const CPPType &type = field.cpp_type();
509 varrays[0].get_to_uninitialized(0, r_value);
514 if (field.node().depends_on_input()) {
517 const CPPType &type = field.cpp_type();
521 type.destruct(buffer);
527 static auto not_fn = mf::build::SI1_SO<bool, bool>(
528 "Not", [](
bool a) {
return !a; }, mf::build::exec_presets::AllSpanOrSingle());
529 auto not_op = FieldOperation::Create(not_fn, {field});
535 auto constant_node = std::make_shared<FieldConstant>(type, value);
536 return GField{std::move(constant_node)};
555 auto index_func = [](
int i) {
return i; };
592 if (&field_input !=
this) {
593 field_input.for_each_field_input_recursive(fn);
609 owned_function_ = std::move(function);
622 const std::shared_ptr<const FieldInputs> *field_inputs_candidate =
nullptr;
623 for (
const GField &field : fields) {
624 const std::shared_ptr<const FieldInputs> &field_inputs = field.node().field_inputs();
626 if (field_inputs && !field_inputs->nodes.is_empty()) {
627 if (field_inputs_candidate ==
nullptr) {
628 field_inputs_candidate = &field_inputs;
630 else if ((*field_inputs_candidate)->nodes.size() < field_inputs->nodes.size()) {
632 field_inputs_candidate = &field_inputs;
636 if (field_inputs_candidate ==
nullptr) {
642 for (
const GField &field : fields) {
643 const std::shared_ptr<const FieldInputs> &field_inputs = field.node().field_inputs();
647 if (&field_inputs == field_inputs_candidate) {
650 for (
const FieldInput *field_input : field_inputs->nodes) {
651 if (!(*field_inputs_candidate)->nodes.contains(field_input)) {
652 inputs_not_in_candidate.
append(field_input);
656 if (inputs_not_in_candidate.
is_empty()) {
658 return *field_inputs_candidate;
661 std::shared_ptr<FieldInputs> new_field_inputs = std::make_shared<FieldInputs>(
662 **field_inputs_candidate);
663 for (
const FieldInput *field_input : inputs_not_in_candidate) {
664 new_field_inputs->nodes.add(field_input);
665 new_field_inputs->deduplicated_nodes.add(*field_input);
667 return new_field_inputs;
685 std::shared_ptr<FieldInputs>
field_inputs = std::make_shared<FieldInputs>();
704 type.copy_construct(value, value_);
727 return {type_, value_};
745 const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field));
746 dst_varrays_.append(dst);
747 output_pointer_infos_.
append({});
758 const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field));
759 dst_varrays_.append(
nullptr);
760 output_pointer_infos_.
append(OutputPointerInfo{
762 *
static_cast<GVArray *
>(dst) = varray;
769 const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field));
770 dst_varrays_.append(
nullptr);
771 output_pointer_infos_.
append({});
780 if (selection_field) {
782 evaluate_fields(scope, {selection_field}, full_mask, context)[0].typed<bool>();
795 for (
const int i : fields_to_evaluate_.index_range()) {
796 fields[i] = fields_to_evaluate_[i];
798 evaluated_varrays_ =
evaluate_fields(scope_, fields, selection_mask_, context_, dst_varrays_);
799 BLI_assert(fields_to_evaluate_.size() == evaluated_varrays_.size());
800 for (
const int i : fields_to_evaluate_.index_range()) {
801 OutputPointerInfo &info = output_pointer_infos_[i];
802 if (info.dst !=
nullptr) {
803 info.set(info.dst, evaluated_varrays_[i], scope_);
806 is_evaluated_ =
true;
825 return selection_mask_;
#define BLI_assert_unreachable()
#define BLI_assert_msg(a, msg)
#define BUFFER_FOR_CPP_TYPE_VALUE(type, variable_name)
#define UNUSED_VARS_NDEBUG(...)
void destruct(void *ptr) const
void value_initialize(void *ptr) const
GMutableSpan take_front(const int64_t n) const
const CPPType & type() const
static GVArray ForEmpty(const CPPType &type)
static GVArray ForSingleDefault(const CPPType &type, int64_t size)
static GVArray ForSingleRef(const CPPType &type, int64_t size, const void *value)
static GVArray ForSpan(GSpan span)
VArray< T > typed() const
GMutableSpan get_internal_span() const
static GVMutableArray ForSpan(GMutableSpan span)
void * allocate(const int64_t size, const int64_t alignment)
const Value & lookup(const Key &key) const
ValueIterator values() const
void add_new(const Key &key, const Value &value)
bool remove(const Key &key)
bool contains(const Key &key) const
T & construct(Args &&...args)
void add_destruct_call(Func func)
LinearAllocator & linear_allocator()
bool contains(const Key &key) const
constexpr int64_t size() const
constexpr IndexRange index_range() const
constexpr bool is_empty() const
constexpr bool contains(const T &value) const
void push(const T &value)
T get_internal_single() const
static VArray ForFunc(const int64_t size, GetFunc get_func)
void append(const T &value)
IndexRange index_range() const
FieldConstant(const CPPType &type, const void *value)
const CPPType & type() const
const CPPType & output_cpp_type(int output_index) const override
int add(GField field, GVArray *varray_ptr)
IndexMask get_evaluated_as_mask(int field_index)
IndexMask get_evaluated_selection_as_mask() const
int add_with_destination(GField field, GVMutableArray dst)
const GVArray & get_evaluated(const int field_index) const
FieldNodeType node_type() const
virtual void for_each_field_input_recursive(FunctionRef< void(const FieldInput &)> fn) const
std::shared_ptr< const FieldInputs > field_inputs_
const std::shared_ptr< const FieldInputs > & field_inputs() const
Span< GField > inputs() const
FieldOperation(std::shared_ptr< const mf::MultiFunction > function, Vector< GField > inputs={})
const mf::MultiFunction & multi_function() const
ParamType param_type(int param_index) const
IndexRange param_indices() const
const DataType & data_type() const
InterfaceType interface_type() const
const MultiFunction & construct_function(Args &&...args)
Variable & new_variable(DataType data_type, std::string name="")
static IndexMask from_bools(Span< bool > bools, IndexMaskMemory &memory)
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
void * MEM_mallocN_aligned(size_t len, size_t alignment, const char *str)
void MEM_freeN(void *vmemh)
ccl_device_inline float4 mask(const int4 mask, const float4 a)
void copy(const GVArray &src, GMutableSpan dst, int64_t grain_size=4096)
static IndexMask index_mask_from_selection(const IndexMask full_mask, const VArray< bool > &selection, ResourceScope &scope)
GField make_constant_field(const CPPType &type, const void *value)
static std::shared_ptr< const FieldInputs > combine_field_inputs(Span< GField > fields)
static FieldTreeInfo preprocess_field_tree(Span< GFieldRef > entry_fields)
static void build_multi_function_procedure_for_fields(mf::Procedure &procedure, ResourceScope &scope, const FieldTreeInfo &field_tree_info, Span< GFieldRef > output_fields)
Vector< GVArray > evaluate_fields(ResourceScope &scope, Span< GFieldRef > fields_to_evaluate, const IndexMask &mask, const FieldContext &context, Span< GVMutableArray > dst_varrays={})
GField make_field_constant_if_possible(GField field)
static Set< GFieldRef > find_varying_fields(const FieldTreeInfo &field_tree_info, Span< GVArray > field_context_inputs)
Field< bool > invert_boolean_field(const Field< bool > &field)
void evaluate_constant_field(const GField &field, void *r_value)
static IndexMask evaluate_selection(const Field< bool > &selection_field, const FieldContext &context, IndexMask full_mask, ResourceScope &scope)
static Vector< GVArray > get_field_context_inputs(ResourceScope &scope, const IndexMask &mask, const FieldContext &context, const Span< std::reference_wrapper< const FieldInput > > field_inputs)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
unsigned __int64 uint64_t
VectorSet< std::reference_wrapper< const FieldInput > > deduplicated_field_inputs
MultiValueMap< GFieldRef, GFieldRef > field_users