Blender V4.3
FN_field.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#pragma once
6
37#include <iostream>
38
39#include "BLI_function_ref.hh"
41#include "BLI_string_ref.hh"
42#include "BLI_vector.hh"
43#include "BLI_vector_set.hh"
44
45#include "FN_multi_function.hh"
46
47namespace blender::fn {
48
49class FieldInput;
50struct FieldInputs;
51
56enum class FieldNodeType {
57 Input,
60};
61
65class FieldNode {
66 private:
67 FieldNodeType node_type_;
68
69 protected:
76 std::shared_ptr<const FieldInputs> field_inputs_;
77
78 public:
80 virtual ~FieldNode();
81
82 virtual const CPPType &output_cpp_type(int output_index) const = 0;
83
85 bool depends_on_input() const;
86
87 const std::shared_ptr<const FieldInputs> &field_inputs() const;
88
89 virtual uint64_t hash() const;
90 virtual bool is_equal_to(const FieldNode &other) const;
91
96 virtual void for_each_field_input_recursive(FunctionRef<void(const FieldInput &)> fn) const;
97};
98
102template<typename NodePtr> class GFieldBase {
103 protected:
104 NodePtr node_ = nullptr;
106
107 GFieldBase(NodePtr node, const int node_output_index)
108 : node_(std::move(node)), node_output_index_(node_output_index)
109 {
110 }
111
112 public:
113 GFieldBase() = default;
114
115 operator bool() const
116 {
117 return node_ != nullptr;
118 }
119
120 friend bool operator==(const GFieldBase &a, const GFieldBase &b)
121 {
122 /* Two nodes can compare equal even when their pointer is not the same. For example, two
123 * "Position" nodes are the same. */
124 return *a.node_ == *b.node_ && a.node_output_index_ == b.node_output_index_;
125 }
126
128 {
130 }
131
132 const CPPType &cpp_type() const
133 {
134 return node_->output_cpp_type(node_output_index_);
135 }
136
137 const FieldNode &node() const
138 {
139 return *node_;
140 }
141
143 {
144 return node_output_index_;
145 }
146};
147
151class GField : public GFieldBase<std::shared_ptr<FieldNode>> {
152 public:
153 GField() = default;
154
155 GField(std::shared_ptr<FieldNode> node, const int node_output_index = 0)
156 : GFieldBase<std::shared_ptr<FieldNode>>(std::move(node), node_output_index)
157 {
158 }
159};
160
165class GFieldRef : public GFieldBase<const FieldNode *> {
166 public:
167 GFieldRef() = default;
168
169 GFieldRef(const GField &field)
170 : GFieldBase<const FieldNode *>(&field.node(), field.node_output_index())
171 {
172 }
173
174 GFieldRef(const FieldNode &node, const int node_output_index = 0)
175 : GFieldBase<const FieldNode *>(&node, node_output_index)
176 {
177 }
178};
179
180namespace detail {
181/* Utility class to make #is_field_v work. */
183} // namespace detail
184
188template<typename T> class Field : public GField, detail::TypedFieldBase {
189 public:
190 using base_type = T;
191
192 Field() = default;
193
194 Field(GField field) : GField(std::move(field))
195 {
196 BLI_assert(this->cpp_type().template is<T>());
197 }
198
204 template<typename U> Field(Field<U> field) : GField(std::move(field))
205 {
206 static_assert(std::is_same_v<T, U>);
207 }
208
209 Field(std::shared_ptr<FieldNode> node, const int node_output_index = 0)
210 : Field(GField(std::move(node), node_output_index))
211 {
212 }
213};
214
216template<typename T>
217static constexpr bool is_field_v = std::is_base_of_v<detail::TypedFieldBase, T> &&
218 !std::is_same_v<detail::TypedFieldBase, T>;
219
223class FieldOperation : public FieldNode {
228 std::shared_ptr<const mf::MultiFunction> owned_function_;
229 const mf::MultiFunction *function_;
230
233
234 public:
235 FieldOperation(std::shared_ptr<const mf::MultiFunction> function, Vector<GField> inputs = {});
236 FieldOperation(const mf::MultiFunction &function, Vector<GField> inputs = {});
238
239 Span<GField> inputs() const;
240 const mf::MultiFunction &multi_function() const;
241
242 const CPPType &output_cpp_type(int output_index) const override;
243
244 static std::shared_ptr<FieldOperation> Create(std::shared_ptr<const mf::MultiFunction> function,
245 Vector<GField> inputs = {})
246 {
247 return std::make_shared<FieldOperation>(FieldOperation(std::move(function), inputs));
248 }
249 static std::shared_ptr<FieldOperation> Create(const mf::MultiFunction &function,
250 Vector<GField> inputs = {})
251 {
252 return std::make_shared<FieldOperation>(FieldOperation(function, inputs));
253 }
254};
255
256class FieldContext;
257
261class FieldInput : public FieldNode {
262 public:
263 /* The order is also used for sorting in socket inspection. */
264 enum class Category {
265 NamedAttribute = 0,
266 Generated = 1,
268 Unknown,
269 };
270
271 protected:
273 std::string debug_name_;
275
276 public:
277 FieldInput(const CPPType &type, std::string debug_name = "");
279
285 const IndexMask &mask,
286 ResourceScope &scope) const = 0;
287
288 virtual std::string socket_inspection_name() const;
290 const CPPType &cpp_type() const;
291 Category category() const;
292
293 const CPPType &output_cpp_type(int output_index) const override;
294};
295
296class FieldConstant : public FieldNode {
297 private:
298 const CPPType &type_;
299 void *value_;
300
301 public:
302 FieldConstant(const CPPType &type, const void *value);
304
305 const CPPType &output_cpp_type(int output_index) const override;
306 const CPPType &type() const;
307 GPointer value() const;
308};
309
322
327 public:
328 virtual ~FieldContext() = default;
329
330 virtual GVArray get_varray_for_input(const FieldInput &field_input,
331 const IndexMask &mask,
332 ResourceScope &scope) const;
333};
334
339 struct OutputPointerInfo {
340 void *dst = nullptr;
341 /* When a destination virtual array is provided for an input, this is
342 * unnecessary, otherwise this is used to construct the required virtual array. */
343 void (*set)(void *dst, const GVArray &varray, ResourceScope &scope) = nullptr;
344 };
345
346 ResourceScope scope_;
347 const FieldContext &context_;
348 const IndexMask &mask_;
349 Vector<GField> fields_to_evaluate_;
350 Vector<GVMutableArray> dst_varrays_;
351 Vector<GVArray> evaluated_varrays_;
352 Vector<OutputPointerInfo> output_pointer_infos_;
353 bool is_evaluated_ = false;
354
355 Field<bool> selection_field_;
356 IndexMask selection_mask_;
357
358 public:
360 FieldEvaluator(const FieldContext &context, const IndexMask *mask)
361 : context_(context), mask_(*mask)
362 {
363 }
364
366 FieldEvaluator(const FieldContext &context, const int64_t size)
367 : context_(context), mask_(scope_.construct<IndexMask>(size))
368 {
369 }
370
372 {
373 /* While this assert isn't strictly necessary, and could be replaced with a warning,
374 * it will catch cases where someone forgets to call #evaluate(). */
375 BLI_assert(is_evaluated_);
376 }
377
386 {
387 selection_field_ = std::move(selection);
388 }
389
395
397 template<typename T> int add_with_destination(Field<T> field, VMutableArray<T> dst)
398 {
399 return this->add_with_destination(GField(std::move(field)), GVMutableArray(std::move(dst)));
400 }
401
409
416 template<typename T> int add_with_destination(Field<T> field, MutableSpan<T> dst)
417 {
418 return this->add_with_destination(std::move(field), VMutableArray<T>::ForSpan(dst));
419 }
420
421 int add(GField field, GVArray *varray_ptr);
422
429 template<typename T> int add(Field<T> field, VArray<T> *varray_ptr)
430 {
431 const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field));
432 dst_varrays_.append({});
433 output_pointer_infos_.append(OutputPointerInfo{
434 varray_ptr, [](void *dst, const GVArray &varray, ResourceScope & /*scope*/) {
435 *(VArray<T> *)dst = varray.typed<T>();
436 }});
437 return field_index;
438 }
439
443 int add(GField field);
444
448 void evaluate();
449
450 const GVArray &get_evaluated(const int field_index) const
451 {
452 BLI_assert(is_evaluated_);
453 return evaluated_varrays_[field_index];
454 }
455
456 template<typename T> VArray<T> get_evaluated(const int field_index)
457 {
458 return this->get_evaluated(field_index).typed<T>();
459 }
460
462
468 IndexMask get_evaluated_as_mask(int field_index);
469};
470
490 Span<GFieldRef> fields_to_evaluate,
491 const IndexMask &mask,
492 const FieldContext &context,
493 Span<GVMutableArray> dst_varrays = {});
494
495/* -------------------------------------------------------------------- */
499void evaluate_constant_field(const GField &field, void *r_value);
500
501template<typename T> T evaluate_constant_field(const Field<T> &field)
502{
503 T value;
504 value.~T();
505 evaluate_constant_field(field, &value);
506 return value;
507}
508
509Field<bool> invert_boolean_field(const Field<bool> &field);
510
511GField make_constant_field(const CPPType &type, const void *value);
512
513template<typename T> Field<T> make_constant_field(T value)
514{
515 return make_constant_field(CPPType::get<T>(), &value);
516}
517
527GField make_field_constant_if_possible(GField field);
528
529class IndexFieldInput final : public FieldInput {
530 public:
532
533 static GVArray get_index_varray(const IndexMask &mask);
534
536 const IndexMask &mask,
537 ResourceScope &scope) const final;
538
539 uint64_t hash() const override;
540 bool is_equal_to(const fn::FieldNode &other) const override;
541};
542
545/* -------------------------------------------------------------------- */
549inline FieldNode::FieldNode(const FieldNodeType node_type) : node_type_(node_type) {}
550
552{
553 return node_type_;
554}
555
557{
558 return field_inputs_ && !field_inputs_->nodes.is_empty();
559}
560
561inline const std::shared_ptr<const FieldInputs> &FieldNode::field_inputs() const
562{
563 return field_inputs_;
564}
565
567{
568 return get_default_hash(this);
569}
570
571inline bool FieldNode::is_equal_to(const FieldNode &other) const
572{
573 return this == &other;
574}
575
576inline bool operator==(const FieldNode &a, const FieldNode &b)
577{
578 return a.is_equal_to(b);
579}
580
581inline bool operator!=(const FieldNode &a, const FieldNode &b)
582{
583 return !(a == b);
584}
585
588/* -------------------------------------------------------------------- */
593{
594 return inputs_;
595}
596
598{
599 return *function_;
600}
601
602inline const CPPType &FieldOperation::output_cpp_type(int output_index) const
603{
604 int output_counter = 0;
605 for (const int param_index : function_->param_indices()) {
606 mf::ParamType param_type = function_->param_type(param_index);
607 if (param_type.is_output()) {
608 if (output_counter == output_index) {
609 return param_type.data_type().single_type();
610 }
611 output_counter++;
612 }
613 }
615 return CPPType::get<float>();
616}
617
620/* -------------------------------------------------------------------- */
624inline std::string FieldInput::socket_inspection_name() const
625{
626 return debug_name_;
627}
628
630{
631 return debug_name_;
632}
633
634inline const CPPType &FieldInput::cpp_type() const
635{
636 return *type_;
637}
638
640{
641 return category_;
642}
643
644inline const CPPType &FieldInput::output_cpp_type(int output_index) const
645{
646 BLI_assert(output_index == 0);
647 UNUSED_VARS_NDEBUG(output_index);
648 return *type_;
649}
650
653} // namespace blender::fn
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define UNUSED_VARS_NDEBUG(...)
static const CPPType & get()
int64_t append_and_get_index(const T &value)
void append(const T &value)
FieldConstant(const CPPType &type, const void *value)
Definition field.cc:700
const CPPType & type() const
Definition field.cc:720
const CPPType & output_cpp_type(int output_index) const override
Definition field.cc:713
GPointer value() const
Definition field.cc:725
virtual GVArray get_varray_for_input(const FieldInput &field_input, const IndexMask &mask, ResourceScope &scope) const
Definition field.cc:539
virtual ~FieldContext()=default
FieldEvaluator(const FieldContext &context, const int64_t size)
Definition FN_field.hh:366
FieldEvaluator(const FieldContext &context, const IndexMask *mask)
Definition FN_field.hh:360
void set_selection(Field< bool > selection)
Definition FN_field.hh:385
int add(GField field, GVArray *varray_ptr)
Definition field.cc:756
IndexMask get_evaluated_as_mask(int field_index)
Definition field.cc:809
int add(Field< T > field, VArray< T > *varray_ptr)
Definition FN_field.hh:429
IndexMask get_evaluated_selection_as_mask() const
Definition field.cc:822
int add_with_destination(Field< T > field, MutableSpan< T > dst)
Definition FN_field.hh:416
VArray< T > get_evaluated(const int field_index)
Definition FN_field.hh:456
int add_with_destination(GField field, GVMutableArray dst)
Definition field.cc:743
const GVArray & get_evaluated(const int field_index) const
Definition FN_field.hh:450
int add_with_destination(Field< T > field, VMutableArray< T > dst)
Definition FN_field.hh:397
FieldInput(const CPPType &type, std::string debug_name="")
Definition field.cc:682
std::string debug_name_
Definition FN_field.hh:273
Category category() const
Definition FN_field.hh:639
const CPPType * type_
Definition FN_field.hh:272
const CPPType & cpp_type() const
Definition FN_field.hh:634
virtual GVArray get_varray_for_context(const FieldContext &context, const IndexMask &mask, ResourceScope &scope) const =0
virtual std::string socket_inspection_name() const
Definition FN_field.hh:624
const CPPType & output_cpp_type(int output_index) const override
Definition FN_field.hh:644
blender::StringRef debug_name() const
Definition FN_field.hh:629
FieldNodeType node_type() const
Definition FN_field.hh:551
virtual void for_each_field_input_recursive(FunctionRef< void(const FieldInput &)> fn) const
Definition field.cc:587
std::shared_ptr< const FieldInputs > field_inputs_
Definition FN_field.hh:76
virtual bool is_equal_to(const FieldNode &other) const
Definition FN_field.hh:571
virtual uint64_t hash() const
Definition FN_field.hh:566
virtual const CPPType & output_cpp_type(int output_index) const =0
FieldNode(FieldNodeType node_type)
Definition FN_field.hh:549
bool depends_on_input() const
Definition FN_field.hh:556
const std::shared_ptr< const FieldInputs > & field_inputs() const
Definition FN_field.hh:561
static std::shared_ptr< FieldOperation > Create(std::shared_ptr< const mf::MultiFunction > function, Vector< GField > inputs={})
Definition FN_field.hh:244
Span< GField > inputs() const
Definition FN_field.hh:592
static std::shared_ptr< FieldOperation > Create(const mf::MultiFunction &function, Vector< GField > inputs={})
Definition FN_field.hh:249
FieldOperation(std::shared_ptr< const mf::MultiFunction > function, Vector< GField > inputs={})
Definition field.cc:605
const CPPType & output_cpp_type(int output_index) const override
Definition FN_field.hh:602
const mf::MultiFunction & multi_function() const
Definition FN_field.hh:597
Field(Field< U > field)
Definition FN_field.hh:204
Field(std::shared_ptr< FieldNode > node, const int node_output_index=0)
Definition FN_field.hh:209
Field(GField field)
Definition FN_field.hh:194
GFieldBase(NodePtr node, const int node_output_index)
Definition FN_field.hh:107
const CPPType & cpp_type() const
Definition FN_field.hh:132
uint64_t hash() const
Definition FN_field.hh:127
const FieldNode & node() const
Definition FN_field.hh:137
int node_output_index() const
Definition FN_field.hh:142
friend bool operator==(const GFieldBase &a, const GFieldBase &b)
Definition FN_field.hh:120
GFieldRef(const FieldNode &node, const int node_output_index=0)
Definition FN_field.hh:174
GFieldRef(const GField &field)
Definition FN_field.hh:169
GField(std::shared_ptr< FieldNode > node, const int node_output_index=0)
Definition FN_field.hh:155
static GVArray get_index_varray(const IndexMask &mask)
Definition field.cc:553
GVArray get_varray_for_context(const FieldContext &context, const IndexMask &mask, ResourceScope &scope) const final
Definition field.cc:559
uint64_t hash() const override
Definition field.cc:567
bool is_equal_to(const fn::FieldNode &other) const override
Definition field.cc:573
ParamType param_type(int param_index) const
local_group_size(16, 16) .push_constant(Type b
#define T
bool operator==(const FieldNode &a, const FieldNode &b)
Definition FN_field.hh:576
bool operator!=(const FieldNode &a, const FieldNode &b)
Definition FN_field.hh:581
GField make_constant_field(const CPPType &type, const void *value)
Definition field.cc:533
Vector< GVArray > evaluate_fields(ResourceScope &scope, Span< GFieldRef > fields_to_evaluate, const IndexMask &mask, const FieldContext &context, Span< GVMutableArray > dst_varrays={})
Definition field.cc:281
GField make_field_constant_if_possible(GField field)
Definition field.cc:512
Field< bool > invert_boolean_field(const Field< bool > &field)
Definition field.cc:525
void evaluate_constant_field(const GField &field, void *r_value)
Definition field.cc:498
static constexpr bool is_field_v
Definition FN_field.hh:217
uint64_t get_default_hash(const T &v)
Definition BLI_hash.hh:219
__int64 int64_t
Definition stdint.h:89
unsigned __int64 uint64_t
Definition stdint.h:90
VectorSet< const FieldInput * > nodes
Definition FN_field.hh:315
VectorSet< std::reference_wrapper< const FieldInput > > deduplicated_nodes
Definition FN_field.hh:320