From 95288eba5965ce92a04864040ff088f40c18ada2 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 2 Sep 2021 12:41:19 +0200 Subject: improve field evaluator and add geometry context --- source/blender/functions/FN_field.hh | 123 +++++++++++++++++-------------- source/blender/functions/intern/field.cc | 11 ++- 2 files changed, 76 insertions(+), 58 deletions(-) (limited to 'source/blender/functions') diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh index 76ffb0225ab..744345fd339 100644 --- a/source/blender/functions/FN_field.hh +++ b/source/blender/functions/FN_field.hh @@ -185,9 +185,15 @@ class OperationFieldSource : public FieldSource { } }; +class ContextFieldSource; + class FieldContext { public: ~FieldContext() = default; + + virtual const GVArray *try_get_varray_for_context(const ContextFieldSource &context_source, + IndexMask mask, + ResourceScope &scope) const; }; class ContextFieldSource : public FieldSource { @@ -218,6 +224,7 @@ class ContextFieldSource : public FieldSource { const CPPType &cpp_type_of_output_index(int output_index) const override { BLI_assert(output_index == 0); + UNUSED_VARS_NDEBUG(output_index); return *type_; } @@ -255,39 +262,20 @@ template Field make_constant_field(T value) return Field{GField{std::move(operation), 0}}; } -class FieldEvaluator; - -class GFieldOutputHandle { - protected: - FieldEvaluator *evaluator_; - int field_index_; - - public: - GFieldOutputHandle(FieldEvaluator &evaluator, int field_index) - : evaluator_(&evaluator), field_index_(field_index) - { - } - - const GVArray &get(); -}; - -template class FieldOutputHandle : GFieldOutputHandle { - public: - explicit FieldOutputHandle(const GFieldOutputHandle &other) : GFieldOutputHandle(other) - { - } - - const VArray &get(); -}; - class FieldEvaluator : NonMovable, NonCopyable { private: + struct OutputPointerInfo { + void *dst = nullptr; + void (*set)(void *dst, const GVArray &varray, ResourceScope &scope) = nullptr; + }; + ResourceScope scope_; const FieldContext &context_; const IndexMask mask_; Vector fields_to_evaluate_; Vector dst_hints_; Vector evaluated_varrays_; + Vector output_pointer_infos_; bool is_evaluated_ = false; public: @@ -297,24 +285,56 @@ class FieldEvaluator : NonMovable, NonCopyable { { } - GFieldOutputHandle add(GField field, GVMutableArray *dst_hint = nullptr) + /** + * \param field: Field to add to the evaluator. + * \param dst: Mutable virtual array that the evaluated result for this field is be written into. + */ + int add_with_destination(GField field, GVMutableArray &dst) { const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field)); - dst_hints_.append(dst_hint); - return GFieldOutputHandle(*this, field_index); + dst_hints_.append(&dst); + output_pointer_infos_.append({}); + return field_index; } - template - FieldOutputHandle add(Field field, VMutableArray *dst_hint = nullptr) + /** Same as above but typed. */ + template int add_with_destination(Field field, VMutableArray &dst) { - GVMutableArray *generic_dst_hint = nullptr; - if (dst_hint != nullptr) { - generic_dst_hint = &scope_.construct>(__func__, - *dst_hint); - } - return FieldOutputHandle(this->add(GField(std::move(field)), generic_dst_hint)); + GVMutableArray &generic_dst_hint = scope_.construct>( + __func__, dst); + return this->add_with_destination(GField(std::move(field)), generic_dst_hint); } + /** + * \param field: Field to add to the evaluator. + * \param varray_ptr: Once #evaluate is called, the resulting virtual array will be will be + * assigned to the given position. + */ + template int add(Field field, const VArray **varray_ptr) + { + const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field)); + dst_hints_.append(nullptr); + output_pointer_infos_.append(OutputPointerInfo{ + varray_ptr, [](void *dst, const GVArray &varray, ResourceScope &scope) { + *(const VArray **)dst = &*scope.construct>(__func__, varray); + }}); + return field_index; + } + + /** + * \return Index of the field in the evaluator. Can be used in the #get_evaluated methods. + */ + int add(GField field) + { + const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field)); + dst_hints_.append(nullptr); + output_pointer_infos_.append({}); + return field_index; + } + + /** + * Evaluate all fields on the evaluator. This can only be called once. + */ void evaluate() { BLI_assert_msg(!is_evaluated_, "Cannot evaluate twice."); @@ -323,39 +343,28 @@ class FieldEvaluator : NonMovable, NonCopyable { fields[i] = &fields_to_evaluate_[i]; } evaluated_varrays_ = evaluate_fields(scope_, fields, mask_, context_, dst_hints_); + BLI_assert(fields_to_evaluate_.size() == evaluated_varrays_.size()); + for (const int i : fields_to_evaluate_.index_range()) { + OutputPointerInfo &info = output_pointer_infos_[i]; + if (info.dst != nullptr) { + info.set(info.dst, *evaluated_varrays_[i], scope_); + } + } is_evaluated_ = true; } - const GVArray &get(const int field_index) const + const GVArray &get_evaluated(const int field_index) const { BLI_assert(is_evaluated_); return *evaluated_varrays_[field_index]; } - template const VArray &get(const int field_index) + template const VArray &get_evaluated(const int field_index) { - const GVArray &varray = this->get(field_index); + const GVArray &varray = this->get_evaluated(field_index); GVArray_Typed &typed_varray = scope_.construct>(__func__, varray); return *typed_varray; } }; -/* -------------------------------------------------------------------- - * GFieldOutputHandle inline methods. - */ - -inline const GVArray &GFieldOutputHandle::get() -{ - return evaluator_->get(field_index_); -} - -/* -------------------------------------------------------------------- - * FieldOutputHandle inline methods. - */ - -template inline const VArray &FieldOutputHandle::get() -{ - return evaluator_->get(field_index_); -} - } // namespace blender::fn diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc index 4a95bc5ef3f..6d8fce07f5a 100644 --- a/source/blender/functions/intern/field.cc +++ b/source/blender/functions/intern/field.cc @@ -93,7 +93,7 @@ static Vector get_field_context_inputs(ResourceScope &scope, { Vector field_context_inputs; for (const ContextFieldSource &context_source : graph_info.deduplicated_context_sources) { - const GVArray *varray = context_source.try_get_varray_for_context(context, mask, scope); + const GVArray *varray = context.try_get_varray_for_context(context_source, mask, scope); if (varray == nullptr) { const CPPType &type = context_source.cpp_type(); varray = &scope.construct( @@ -420,4 +420,13 @@ void evaluate_fields_to_spans(Span fields_to_evaluate, evaluate_fields(scope, fields_to_evaluate, mask, context, varrays); } +const GVArray *FieldContext::try_get_varray_for_context(const ContextFieldSource &context_source, + IndexMask mask, + ResourceScope &scope) const +{ + /* By default ask the context source to create the varray. Another field context might overwrite + * the context here. */ + return context_source.try_get_varray_for_context(*this, mask, scope); +} + } // namespace blender::fn -- cgit v1.2.3