Blender V5.0
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
36
37#include "BLI_function_ref.hh"
39#include "BLI_string_ref.hh"
40#include "BLI_vector.hh"
41#include "BLI_vector_set.hh"
42
43#include "FN_multi_function.hh"
44
45namespace blender::fn {
46
47class FieldInput;
48struct FieldInputs;
49
59
63class FieldNode {
64 private:
65 FieldNodeType node_type_;
66
67 protected:
74 std::shared_ptr<const FieldInputs> field_inputs_;
75
76 public:
78 virtual ~FieldNode();
79
80 virtual const CPPType &output_cpp_type(int output_index) const = 0;
81
83 bool depends_on_input() const;
84
85 const std::shared_ptr<const FieldInputs> &field_inputs() const;
86
87 virtual uint64_t hash() const;
88 virtual bool is_equal_to(const FieldNode &other) const;
89
94 virtual void for_each_field_input_recursive(FunctionRef<void(const FieldInput &)> fn) const;
95};
96
100template<typename NodePtr> class GFieldBase {
101 protected:
102 NodePtr node_ = nullptr;
104
107 {
108 }
109
110 public:
111 GFieldBase() = default;
112
113 operator bool() const
114 {
115 return node_ != nullptr;
116 }
117
118 friend bool operator==(const GFieldBase &a, const GFieldBase &b)
119 {
120 /* Two nodes can compare equal even when their pointer is not the same. For example, two
121 * "Position" nodes are the same. */
122 return *a.node_ == *b.node_ && a.node_output_index_ == b.node_output_index_;
123 }
124
126 {
128 }
129
130 const CPPType &cpp_type() const
131 {
132 return node_->output_cpp_type(node_output_index_);
133 }
134
135 const FieldNode &node() const
136 {
137 return *node_;
138 }
139
141 {
142 return node_output_index_;
143 }
144};
145
149class GField : public GFieldBase<std::shared_ptr<FieldNode>> {
150 public:
151 GField() = default;
152
153 GField(std::shared_ptr<FieldNode> node, const int node_output_index = 0)
154 : GFieldBase<std::shared_ptr<FieldNode>>(std::move(node), node_output_index)
155 {
156 }
157};
158
163class GFieldRef : public GFieldBase<const FieldNode *> {
164 public:
165 GFieldRef() = default;
166
167 GFieldRef(const GField &field)
168 : GFieldBase<const FieldNode *>(&field.node(), field.node_output_index())
169 {
170 }
171
174 {
175 }
176};
177
178namespace detail {
179/* Utility class to make #is_field_v work. */
181} // namespace detail
182
186template<typename T> class Field : public GField, detail::TypedFieldBase {
187 public:
188 using base_type = T;
189
190 Field() = default;
191
192 Field(GField field) : GField(std::move(field))
193 {
194 BLI_assert(this->cpp_type().template is<T>());
195 }
196
202 template<typename U> Field(Field<U> field) : GField(std::move(field))
203 {
204 static_assert(std::is_same_v<T, U>);
205 }
206
207 Field(std::shared_ptr<FieldNode> node, const int node_output_index = 0)
208 : Field(GField(std::move(node), node_output_index))
209 {
210 }
211};
212
214template<typename T>
215static constexpr bool is_field_v = std::is_base_of_v<detail::TypedFieldBase, T> &&
216 !std::is_same_v<detail::TypedFieldBase, T>;
217
221class FieldOperation : public FieldNode {
226 std::shared_ptr<const mf::MultiFunction> owned_function_;
227 const mf::MultiFunction *function_;
228
231
232 public:
233 FieldOperation(std::shared_ptr<const mf::MultiFunction> function, Vector<GField> inputs = {});
234 FieldOperation(const mf::MultiFunction &function, Vector<GField> inputs = {});
235 ~FieldOperation() override;
236
237 Span<GField> inputs() const;
238 const mf::MultiFunction &multi_function() const;
239
240 const CPPType &output_cpp_type(int output_index) const override;
241
242 static std::shared_ptr<FieldOperation> from(std::shared_ptr<const mf::MultiFunction> function,
244 {
245 return std::make_shared<FieldOperation>(FieldOperation(std::move(function), inputs));
246 }
247 static std::shared_ptr<FieldOperation> from(const mf::MultiFunction &function,
249 {
250 return std::make_shared<FieldOperation>(FieldOperation(function, inputs));
251 }
252};
253
254class FieldContext;
255
259class FieldInput : public FieldNode {
260 public:
261 /* The order is also used for sorting in socket inspection. */
268
269 protected:
271 std::string debug_name_;
273
274 public:
275 FieldInput(const CPPType &type, std::string debug_name = "");
276 ~FieldInput() override;
277
283 const IndexMask &mask,
284 ResourceScope &scope) const = 0;
285
286 virtual std::string socket_inspection_name() const;
288 const CPPType &cpp_type() const;
289 Category category() const;
290
291 const CPPType &output_cpp_type(int output_index) const override;
292};
293
294class FieldConstant : public FieldNode {
295 private:
296 const CPPType &type_;
297 void *value_;
298
299 public:
300 FieldConstant(const CPPType &type, const void *value);
301 ~FieldConstant() override;
302
303 const CPPType &output_cpp_type(int output_index) const override;
304 const CPPType &type() const;
305 GPointer value() const;
306};
307
320
325 public:
326 virtual ~FieldContext() = default;
327
328 virtual GVArray get_varray_for_input(const FieldInput &field_input,
329 const IndexMask &mask,
330 ResourceScope &scope) const;
331};
332
337 struct OutputPointerInfo {
338 void *dst = nullptr;
339 /* When a destination virtual array is provided for an input, this is
340 * unnecessary, otherwise this is used to construct the required virtual array. */
341 void (*set)(void *dst, const GVArray &varray, ResourceScope &scope) = nullptr;
342 };
343
344 ResourceScope scope_;
345 const FieldContext &context_;
346 const IndexMask &mask_;
347 Vector<GField> fields_to_evaluate_;
348 Vector<GVMutableArray> dst_varrays_;
349 Vector<GVArray> evaluated_varrays_;
350 Vector<OutputPointerInfo> output_pointer_infos_;
351 bool is_evaluated_ = false;
352
353 Field<bool> selection_field_;
354 IndexMask selection_mask_;
355
356 public:
359 : context_(context), mask_(*mask)
360 {
361 }
362
365 : context_(context), mask_(scope_.construct<IndexMask>(size))
366 {
367 }
368
370 {
371 /* While this assert isn't strictly necessary, and could be replaced with a warning,
372 * it will catch cases where someone forgets to call #evaluate(). */
373 BLI_assert(is_evaluated_);
374 }
375
384 {
385 selection_field_ = std::move(selection);
386 }
387
393
395 template<typename T> int add_with_destination(Field<T> field, VMutableArray<T> dst)
396 {
397 return this->add_with_destination(GField(std::move(field)), GVMutableArray(std::move(dst)));
398 }
399
407
414 template<typename T> int add_with_destination(Field<T> field, MutableSpan<T> dst)
415 {
416 return this->add_with_destination(std::move(field), VMutableArray<T>::from_span(dst));
417 }
418
419 int add(GField field, GVArray *varray_ptr);
420
427 template<typename T> int add(Field<T> field, VArray<T> *varray_ptr)
428 {
429 const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field));
430 dst_varrays_.append({});
431 output_pointer_infos_.append(OutputPointerInfo{
432 varray_ptr, [](void *dst, const GVArray &varray, ResourceScope & /*scope*/) {
433 *(VArray<T> *)dst = varray.typed<T>();
434 }});
435 return field_index;
436 }
437
441 int add(GField field);
442
446 void evaluate();
447
448 const GVArray &get_evaluated(const int field_index) const
449 {
450 BLI_assert(is_evaluated_);
451 return evaluated_varrays_[field_index];
452 }
453
454 template<typename T> VArray<T> get_evaluated(const int field_index)
455 {
456 return this->get_evaluated(field_index).typed<T>();
457 }
458
460
466 IndexMask get_evaluated_as_mask(int field_index);
467};
468
488 Span<GFieldRef> fields_to_evaluate,
489 const IndexMask &mask,
490 const FieldContext &context,
491 Span<GVMutableArray> dst_varrays = {});
492
493/* -------------------------------------------------------------------- */
496
497void evaluate_constant_field(const GField &field, void *r_value);
498
499template<typename T> T evaluate_constant_field(const Field<T> &field)
500{
501 T value;
502 value.~T();
503 evaluate_constant_field(field, &value);
504 return value;
505}
506
507Field<bool> invert_boolean_field(const Field<bool> &field);
508
509GField make_constant_field(const CPPType &type, const void *value);
510
511template<typename T> Field<T> make_constant_field(T value)
512{
513 return make_constant_field(CPPType::get<T>(), &value);
514}
515
525GField make_field_constant_if_possible(GField field);
526
528 public:
530
531 static GVArray get_index_varray(const IndexMask &mask);
532
534 const IndexMask &mask,
535 ResourceScope &scope) const final;
536
537 uint64_t hash() const override;
538 bool is_equal_to(const fn::FieldNode &other) const override;
539};
540
542
543/* -------------------------------------------------------------------- */
546
548
550{
551 return node_type_;
552}
553
555{
556 return field_inputs_ && !field_inputs_->nodes.is_empty();
557}
558
559inline const std::shared_ptr<const FieldInputs> &FieldNode::field_inputs() const
560{
561 return field_inputs_;
562}
563
565{
566 return get_default_hash(this);
567}
568
569inline bool FieldNode::is_equal_to(const FieldNode &other) const
570{
571 return this == &other;
572}
573
574inline bool operator==(const FieldNode &a, const FieldNode &b)
575{
576 return a.is_equal_to(b);
577}
578
579inline bool operator!=(const FieldNode &a, const FieldNode &b)
580{
581 return !(a == b);
582}
583
585
586/* -------------------------------------------------------------------- */
589
591{
592 return inputs_;
593}
594
595inline const mf::MultiFunction &FieldOperation::multi_function() const
596{
597 return *function_;
598}
599
600inline const CPPType &FieldOperation::output_cpp_type(int output_index) const
601{
602 int output_counter = 0;
603 for (const int param_index : function_->param_indices()) {
604 mf::ParamType param_type = function_->param_type(param_index);
605 if (param_type.is_output()) {
606 if (output_counter == output_index) {
607 return param_type.data_type().single_type();
608 }
609 output_counter++;
610 }
611 }
613 return CPPType::get<float>();
614}
615
617
618/* -------------------------------------------------------------------- */
621
622inline std::string FieldInput::socket_inspection_name() const
623{
624 return debug_name_;
625}
626
628{
629 return debug_name_;
630}
631
632inline const CPPType &FieldInput::cpp_type() const
633{
634 return *type_;
635}
636
638{
639 return category_;
640}
641
642inline const CPPType &FieldInput::output_cpp_type(int output_index) const
643{
644 BLI_assert(output_index == 0);
645 UNUSED_VARS_NDEBUG(output_index);
646 return *type_;
647}
648
650
651} // namespace blender::fn
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define final(a, b, c)
Definition BLI_hash.h:19
#define UNUSED_VARS_NDEBUG(...)
long long int int64_t
unsigned long long int uint64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static const CPPType & get()
NonCopyable(const NonCopyable &other)=delete
NonMovable(NonMovable &&other)=delete
static VMutableArray from_span(MutableSpan< T > values)
FieldConstant(const CPPType &type, const void *value)
Definition field.cc:695
const CPPType & type() const
Definition field.cc:715
const CPPType & output_cpp_type(int output_index) const override
Definition field.cc:708
~FieldConstant() override
Definition field.cc:702
GPointer value() const
Definition field.cc:720
virtual GVArray get_varray_for_input(const FieldInput &field_input, const IndexMask &mask, ResourceScope &scope) const
Definition field.cc:534
virtual ~FieldContext()=default
FieldEvaluator(const FieldContext &context, const int64_t size)
Definition FN_field.hh:364
FieldEvaluator(const FieldContext &context, const IndexMask *mask)
Definition FN_field.hh:358
void set_selection(Field< bool > selection)
Definition FN_field.hh:383
int add(GField field, GVArray *varray_ptr)
Definition field.cc:751
IndexMask get_evaluated_as_mask(int field_index)
Definition field.cc:804
int add(Field< T > field, VArray< T > *varray_ptr)
Definition FN_field.hh:427
IndexMask get_evaluated_selection_as_mask() const
Definition field.cc:817
int add_with_destination(Field< T > field, MutableSpan< T > dst)
Definition FN_field.hh:414
VArray< T > get_evaluated(const int field_index)
Definition FN_field.hh:454
int add_with_destination(GField field, GVMutableArray dst)
Definition field.cc:738
const GVArray & get_evaluated(const int field_index) const
Definition FN_field.hh:448
int add_with_destination(Field< T > field, VMutableArray< T > dst)
Definition FN_field.hh:395
FieldInput(const CPPType &type, std::string debug_name="")
Definition field.cc:677
std::string debug_name_
Definition FN_field.hh:271
Category category() const
Definition FN_field.hh:637
const CPPType * type_
Definition FN_field.hh:270
const CPPType & cpp_type() const
Definition FN_field.hh:632
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:622
const CPPType & output_cpp_type(int output_index) const override
Definition FN_field.hh:642
blender::StringRef debug_name() const
Definition FN_field.hh:627
FieldNodeType node_type() const
Definition FN_field.hh:549
virtual void for_each_field_input_recursive(FunctionRef< void(const FieldInput &)> fn) const
Definition field.cc:582
std::shared_ptr< const FieldInputs > field_inputs_
Definition FN_field.hh:74
virtual bool is_equal_to(const FieldNode &other) const
Definition FN_field.hh:569
virtual uint64_t hash() const
Definition FN_field.hh:564
virtual const CPPType & output_cpp_type(int output_index) const =0
FieldNode(FieldNodeType node_type)
Definition FN_field.hh:547
bool depends_on_input() const
Definition FN_field.hh:554
const std::shared_ptr< const FieldInputs > & field_inputs() const
Definition FN_field.hh:559
Span< GField > inputs() const
Definition FN_field.hh:590
static std::shared_ptr< FieldOperation > from(const mf::MultiFunction &function, Vector< GField > inputs={})
Definition FN_field.hh:247
FieldOperation(std::shared_ptr< const mf::MultiFunction > function, Vector< GField > inputs={})
Definition field.cc:600
static std::shared_ptr< FieldOperation > from(std::shared_ptr< const mf::MultiFunction > function, Vector< GField > inputs={})
Definition FN_field.hh:242
const CPPType & output_cpp_type(int output_index) const override
Definition FN_field.hh:600
const mf::MultiFunction & multi_function() const
Definition FN_field.hh:595
Field(Field< U > field)
Definition FN_field.hh:202
Field(std::shared_ptr< FieldNode > node, const int node_output_index=0)
Definition FN_field.hh:207
Field(GField field)
Definition FN_field.hh:192
GFieldBase(NodePtr node, const int node_output_index)
Definition FN_field.hh:105
const CPPType & cpp_type() const
Definition FN_field.hh:130
uint64_t hash() const
Definition FN_field.hh:125
const FieldNode & node() const
Definition FN_field.hh:135
int node_output_index() const
Definition FN_field.hh:140
friend bool operator==(const GFieldBase &a, const GFieldBase &b)
Definition FN_field.hh:118
GFieldRef(const FieldNode &node, const int node_output_index=0)
Definition FN_field.hh:172
GFieldRef(const GField &field)
Definition FN_field.hh:167
GField(std::shared_ptr< FieldNode > node, const int node_output_index=0)
Definition FN_field.hh:153
static GVArray get_index_varray(const IndexMask &mask)
Definition field.cc:548
GVArray get_varray_for_context(const FieldContext &context, const IndexMask &mask, ResourceScope &scope) const final
Definition field.cc:554
uint64_t hash() const override
Definition field.cc:562
bool is_equal_to(const fn::FieldNode &other) const override
Definition field.cc:568
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
#define T
bool operator==(const FieldNode &a, const FieldNode &b)
Definition FN_field.hh:574
bool operator!=(const FieldNode &a, const FieldNode &b)
Definition FN_field.hh:579
GField make_constant_field(const CPPType &type, const void *value)
Definition field.cc:528
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:507
Field< bool > invert_boolean_field(const Field< bool > &field)
Definition field.cc:520
void evaluate_constant_field(const GField &field, void *r_value)
Definition field.cc:493
static constexpr bool is_field_v
Definition FN_field.hh:215
uint64_t get_default_hash(const T &v, const Args &...args)
Definition BLI_hash.hh:233
static blender::bke::bNodeSocketTemplate inputs[]
VectorSet< const FieldInput * > nodes
Definition FN_field.hh:313
VectorSet< std::reference_wrapper< const FieldInput > > deduplicated_nodes
Definition FN_field.hh:318