48 if (handled_fields.
add(field)) {
49 fields_to_check.
push(field);
53 while (!fields_to_check.
is_empty()) {
65 field_tree_info.
field_users.add(operation_input, field);
66 if (handled_fields.
add(operation_input)) {
67 fields_to_check.
push(operation_input);
78 return field_tree_info;
88 const Span<std::reference_wrapper<const FieldInput>> field_inputs)
91 for (
const FieldInput &field_input : field_inputs) {
97 field_context_inputs.
append(varray);
99 return field_context_inputs;
115 for (
const int i : field_context_inputs.
index_range()) {
116 const GVArray &varray = field_context_inputs[i];
121 const GFieldRef field_input_field{field_input, 0};
124 if (found_fields.
add(field)) {
125 fields_to_check.
push(field);
129 while (!fields_to_check.
is_empty()) {
133 if (found_fields.
add(field)) {
134 fields_to_check.
push(field);
155 MFVariable &variable = builder.add_input_parameter(
157 variable_by_field.
add_new({field_input, 0}, &variable);
161 struct FieldWithIndex {
163 int current_input_index = 0;
170 fields_to_check.
push({field, 0});
171 while (!fields_to_check.
is_empty()) {
172 FieldWithIndex &field_with_index = fields_to_check.
peek();
173 const GFieldRef &field = field_with_index.field;
174 if (variable_by_field.
contains(field)) {
176 fields_to_check.
pop();
189 if (field_with_index.current_input_index < operation_inputs.
size()) {
192 fields_to_check.
push({operation_inputs[field_with_index.current_input_index]});
193 field_with_index.current_input_index++;
201 int param_input_index = 0;
202 int param_output_index = 0;
203 for (
const int param_index : multi_function.
param_indices()) {
207 const GField &input_field = operation_inputs[param_input_index];
208 variables[param_index] = variable_by_field.
lookup(input_field);
212 const GFieldRef output_field{operation_node, param_output_index};
213 const bool output_is_ignored =
214 field_tree_info.
field_users.lookup(output_field).is_empty() &&
215 !output_fields.
contains(output_field);
216 if (output_is_ignored) {
218 variables[param_index] =
nullptr;
223 variables[param_index] = &new_variable;
224 variable_by_field.
add_new(output_field, &new_variable);
226 param_output_index++;
232 builder.add_call_with_all_variables(multi_function, variables);
239 constant_node.
type(), constant_node.
value().
get(),
false);
240 MFVariable &new_variable = *builder.add_call<1>(fn)[0];
241 variable_by_field.
add_new(field, &new_variable);
250 for (
const GFieldRef &field : output_fields) {
252 if (!already_output_variables.
add(variable)) {
256 variable = builder.add_call<1>(copy_fn, {variable})[0];
258 builder.add_output_parameter(*variable);
262 for (
const GFieldRef &field : output_fields) {
263 variable_by_field.
remove(field);
267 builder.add_destruct(*variable);
285 Array<bool> is_output_written_to_dst(fields_to_evaluate.
size(),
false);
286 const int array_size =
mask.min_array_size();
288 if (
mask.is_empty()) {
289 for (
const int i : fields_to_evaluate.
index_range()) {
290 const CPPType &
type = fields_to_evaluate[i].cpp_type();
317 for (
const int out_index : fields_to_evaluate.
index_range()) {
318 const GFieldRef &field = fields_to_evaluate[out_index];
325 const GVArray &varray = field_context_inputs[field_input_index];
326 r_varrays[out_index] = varray;
332 field_constant.
type(),
mask.min_array_size(), field_constant.
value().
get());
349 for (
const int i : fields_to_evaluate.
index_range()) {
355 if (varying_fields.
contains(field)) {
356 varying_fields_to_evaluate.
append(field);
357 varying_field_indices.
append(i);
360 constant_fields_to_evaluate.
append(field);
361 constant_field_indices.
append(i);
366 if (!varying_fields_to_evaluate.
is_empty()) {
370 procedure, scope, field_tree_info, varying_fields_to_evaluate);
377 for (
const GVArray &varray : field_context_inputs) {
378 mf_params.add_readonly_single_input(varray);
381 for (
const int i : varying_fields_to_evaluate.
index_range()) {
382 const GFieldRef &field = varying_fields_to_evaluate[i];
384 const int out_index = varying_field_indices[i];
389 if (!dst_varray || !dst_varray.
is_span()) {
393 if (!
type.is_trivially_destructible()) {
405 r_varrays[out_index] = dst_varray;
406 is_output_written_to_dst[out_index] =
true;
411 mf_params.add_uninitialized_single_output(span);
414 procedure_executor.call_auto(
mask, mf_params, mf_context);
418 if (!constant_fields_to_evaluate.
is_empty()) {
422 procedure, scope, field_tree_info, constant_fields_to_evaluate);
428 for (
const GVArray &varray : field_context_inputs) {
429 mf_params.add_readonly_single_input(varray);
432 for (
const int i : constant_fields_to_evaluate.
index_range()) {
433 const GFieldRef &field = constant_fields_to_evaluate[i];
438 if (!
type.is_trivially_destructible()) {
444 mf_params.add_uninitialized_single_output({
type,
buffer, 1});
447 const int out_index = constant_field_indices[i];
451 procedure_executor.call(
IndexRange(1), mf_params, mf_context);
457 for (
const int out_index : fields_to_evaluate.
index_range()) {
463 const GVArray &computed_varray = r_varrays[out_index];
465 if (is_output_written_to_dst[out_index]) {
473 computed_varray.materialize_to_uninitialized(mask.slice(range),
474 dst_varray.get_internal_span().data());
481 BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
482 for (const int i : mask.slice(range)) {
483 computed_varray.get_to_uninitialized(i, buffer);
484 dst_varray.set_by_relocate(i, buffer);
488 r_varrays[out_index] = dst_varray;
498 type.value_initialize(r_value);
505 varrays[0].get_to_uninitialized(0, r_value);
525 auto not_op = std::make_shared<FieldOperation>(
FieldOperation(not_fn, {field}));
531 auto constant_node = std::make_shared<FieldConstant>(
type, value);
532 return GField{std::move(constant_node)};
551 auto index_func = [](
int i) {
return i; };
589 owned_function_ = std::move(
function);
602 const std::shared_ptr<const FieldInputs> *field_inputs_candidate =
nullptr;
603 for (
const GField &field : fields) {
604 const std::shared_ptr<const FieldInputs> &field_inputs = field.node().field_inputs();
606 if (field_inputs && !field_inputs->nodes.is_empty()) {
607 if (field_inputs_candidate ==
nullptr) {
608 field_inputs_candidate = &field_inputs;
610 else if ((*field_inputs_candidate)->nodes.size() < field_inputs->nodes.size()) {
612 field_inputs_candidate = &field_inputs;
616 if (field_inputs_candidate ==
nullptr) {
622 for (
const GField &field : fields) {
623 const std::shared_ptr<const FieldInputs> &field_inputs = field.node().field_inputs();
627 if (&field_inputs == field_inputs_candidate) {
630 for (
const FieldInput *field_input : field_inputs->nodes) {
631 if (!(*field_inputs_candidate)->nodes.contains(field_input)) {
632 inputs_not_in_candidate.
append(field_input);
636 if (inputs_not_in_candidate.
is_empty()) {
638 return *field_inputs_candidate;
641 std::shared_ptr<FieldInputs> new_field_inputs = std::make_shared<FieldInputs>(
642 **field_inputs_candidate);
643 for (
const FieldInput *field_input : inputs_not_in_candidate) {
644 new_field_inputs->nodes.add(field_input);
645 new_field_inputs->deduplicated_nodes.add(*field_input);
647 return new_field_inputs;
663 std::shared_ptr<FieldInputs>
field_inputs = std::make_shared<FieldInputs>();
703 return {type_, value_};
720 const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field));
721 dst_varrays_.append(dst);
722 output_pointer_infos_.
append({});
733 const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field));
734 dst_varrays_.append(
nullptr);
735 output_pointer_infos_.
append(OutputPointerInfo{
744 const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field));
745 dst_varrays_.append(
nullptr);
746 output_pointer_infos_.
append({});
755 if (selection_field) {
770 for (
const int i : fields_to_evaluate_.index_range()) {
771 fields[i] = fields_to_evaluate_[i];
773 evaluated_varrays_ =
evaluate_fields(scope_, fields, selection_mask_, context_, dst_varrays_);
774 BLI_assert(fields_to_evaluate_.size() == evaluated_varrays_.size());
775 for (
const int i : fields_to_evaluate_.index_range()) {
776 OutputPointerInfo &info = output_pointer_infos_[i];
777 if (info.dst !=
nullptr) {
778 info.set(info.dst, evaluated_varrays_[i], scope_);
781 is_evaluated_ =
true;
800 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(...)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
void copy_construct(const void *src, void *dst) const
void destruct(void *ptr) const
int64_t alignment() 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)
ValueIterator values() const
const Value & lookup(const Key &key) 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
IndexMask get_evaluated_selection_as_mask()
int add(GField field, GVArray *varray_ptr)
IndexMask get_evaluated_as_mask(int field_index)
const GVArray & get_evaluated(const int field_index) const
int add_with_destination(GField field, GVMutableArray dst)
FieldNodeType node_type() const
std::shared_ptr< const FieldInputs > field_inputs_
bool depends_on_input() const
const std::shared_ptr< const FieldInputs > & field_inputs() const
const MultiFunction & multi_function() const
Span< GField > inputs() const
FieldOperation(std::shared_ptr< const MultiFunction > function, Vector< GField > inputs={})
const FieldNode & node() const
const CPPType & cpp_type() const
static MFDataType ForSingle()
MFDataType data_type() const
InterfaceType interface_type() const
MFVariable & new_variable(MFDataType data_type, std::string name="")
const MultiFunction & construct_function(Args &&...args)
MFDataType data_type() const
MFParamType param_type(int param_index) const
IndexRange param_indices() const
ccl_global float * buffer
void(* MEM_freeN)(void *vmemh)
void *(* MEM_mallocN_aligned)(size_t len, size_t alignment, const char *str)
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
void move_destructs_up(MFProcedure &procedure, MFInstruction &block_end_instr)
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 void build_multi_function_procedure_for_fields(MFProcedure &procedure, ResourceScope &scope, const FieldTreeInfo &field_tree_info, Span< GFieldRef > output_fields)
static Set< GFieldRef > find_varying_fields(const FieldTreeInfo &field_tree_info, Span< GVArray > field_context_inputs)
static Vector< GVArray > get_field_context_inputs(ResourceScope &scope, const IndexMask mask, const FieldContext &context, const Span< std::reference_wrapper< const FieldInput >> field_inputs)
static FieldTreeInfo preprocess_field_tree(Span< GFieldRef > entry_fields)
static std::shared_ptr< const FieldInputs > combine_field_inputs(Span< GField > fields)
GField make_field_constant_if_possible(GField field)
Vector< GVArray > evaluate_fields(ResourceScope &scope, Span< GFieldRef > fields_to_evaluate, IndexMask mask, const FieldContext &context, Span< GVMutableArray > dst_varrays={})
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)
IndexMask find_indices_from_virtual_array(IndexMask indices_to_check, const VArray< bool > &virtual_array, int64_t parallel_grain_size, Vector< int64_t > &r_indices)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
static bNodeSocketTemplate inputs[]
unsigned __int64 uint64_t
VectorSet< std::reference_wrapper< const FieldInput > > deduplicated_field_inputs
MultiValueMap< GFieldRef, GFieldRef > field_users