diff options
author | Jacques Lucke <jacques@blender.org> | 2021-09-02 13:41:19 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2021-09-02 13:41:19 +0300 |
commit | 95288eba5965ce92a04864040ff088f40c18ada2 (patch) | |
tree | 7866fcf0380e3e9645f68a5ffa53185c0b8078a9 | |
parent | 01037308d5d2b0bcf3ec607f8cbd9e48fdd564f6 (diff) |
improve field evaluator and add geometry context
-rw-r--r-- | source/blender/blenkernel/BKE_geometry_set.hh | 43 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/attribute_access.cc | 18 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/customdata.c | 4 | ||||
-rw-r--r-- | source/blender/functions/FN_field.hh | 123 | ||||
-rw-r--r-- | source/blender/functions/intern/field.cc | 11 | ||||
-rw-r--r-- | source/blender/nodes/NOD_geometry_exec.hh | 1 |
6 files changed, 139 insertions, 61 deletions
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index 45e8ab92e41..da758669659 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -35,6 +35,8 @@ #include "BKE_attribute_access.hh" #include "BKE_geometry_set.h" +#include "FN_field.hh" + struct Collection; struct Curve; struct CurveEval; @@ -581,3 +583,44 @@ class VolumeComponent : public GeometryComponent { static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_VOLUME; }; + +namespace blender::bke { + +class GeometryComponentFieldContext : public fn::FieldContext { + private: + const GeometryComponent &component_; + const AttributeDomain domain_; + + public: + GeometryComponentFieldContext(const GeometryComponent &component, const AttributeDomain domain) + : component_(component), domain_(domain) + { + } + + const GeometryComponent &geometry_component() const + { + return component_; + } + + AttributeDomain domain() const + { + return domain_; + } +}; + +class AttributeContextFieldSource : public fn::ContextFieldSource { + private: + std::string name_; + + public: + AttributeContextFieldSource(std::string name, const CPPType &type) + : fn::ContextFieldSource(type, name), name_(std::move(name)) + { + } + + const GVArray *try_get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &scope) const override; +}; + +} // namespace blender::bke diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index 941bfebcc60..bf3756b7bcf 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -1300,3 +1300,21 @@ blender::bke::OutputAttribute GeometryComponent::attribute_try_get_for_output_on { return create_output_attribute(*this, attribute_id, domain, data_type, true, nullptr); } + +namespace blender::bke { + +const GVArray *AttributeContextFieldSource::try_get_varray_for_context( + const fn::FieldContext &context, IndexMask UNUSED(mask), ResourceScope &scope) const +{ + if (const GeometryComponentFieldContext *geometry_context = + dynamic_cast<const GeometryComponentFieldContext *>(&context)) { + const GeometryComponent &component = geometry_context->geometry_component(); + const AttributeDomain domain = geometry_context->domain(); + const CustomDataType data_type = cpp_type_to_custom_data_type(*type_); + GVArrayPtr attribute = component.attribute_try_get_for_read(name_, domain, data_type); + return scope.add(std::move(attribute), __func__); + } + return nullptr; +} + +} // namespace blender::bke diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index a86d0a608d6..311039bac24 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -2848,7 +2848,7 @@ void *CustomData_duplicate_referenced_layer_named(CustomData *data, } void *CustomData_duplicate_referenced_layer_anonymous(CustomData *data, - const int type, + const int UNUSED(type), const AnonymousAttributeID *anonymous_id, const int totelem) { @@ -3564,7 +3564,6 @@ bool CustomData_bmesh_merge(const CustomData *source, BMesh *bm, const char htype) { - if (CustomData_number_of_layers_typemask(source, mask) == 0) { return false; } @@ -4813,7 +4812,6 @@ static void copy_bit_flag(void *dst, const void *src, const size_t data_size, co *((_type *)(_dst)) |= _val; \ } \ (void)0 - switch (data_size) { case 1: COPY_BIT_FLAG(uint8_t, dst, src, flag); 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<typename T> Field<T> make_constant_field(T value) return Field<T>{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<typename T> class FieldOutputHandle : GFieldOutputHandle { - public: - explicit FieldOutputHandle(const GFieldOutputHandle &other) : GFieldOutputHandle(other) - { - } - - const VArray<T> &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<GField> fields_to_evaluate_; Vector<GVMutableArray *> dst_hints_; Vector<const GVArray *> evaluated_varrays_; + Vector<OutputPointerInfo> 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<typename T> - FieldOutputHandle<T> add(Field<T> field, VMutableArray<T> *dst_hint = nullptr) + /** Same as above but typed. */ + template<typename T> int add_with_destination(Field<T> field, VMutableArray<T> &dst) { - GVMutableArray *generic_dst_hint = nullptr; - if (dst_hint != nullptr) { - generic_dst_hint = &scope_.construct<GVMutableArray_For_VMutableArray<T>>(__func__, - *dst_hint); - } - return FieldOutputHandle<T>(this->add(GField(std::move(field)), generic_dst_hint)); + GVMutableArray &generic_dst_hint = scope_.construct<GVMutableArray_For_VMutableArray<T>>( + __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<typename T> int add(Field<T> field, const VArray<T> **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<T> **)dst = &*scope.construct<GVArray_Typed<T>>(__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<typename T> const VArray<T> &get(const int field_index) + template<typename T> const VArray<T> &get_evaluated(const int field_index) { - const GVArray &varray = this->get(field_index); + const GVArray &varray = this->get_evaluated(field_index); GVArray_Typed<T> &typed_varray = scope_.construct<GVArray_Typed<T>>(__func__, varray); return *typed_varray; } }; -/* -------------------------------------------------------------------- - * GFieldOutputHandle inline methods. - */ - -inline const GVArray &GFieldOutputHandle::get() -{ - return evaluator_->get(field_index_); -} - -/* -------------------------------------------------------------------- - * FieldOutputHandle inline methods. - */ - -template<typename T> inline const VArray<T> &FieldOutputHandle<T>::get() -{ - return evaluator_->get<T>(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<const GVArray *> get_field_context_inputs(ResourceScope &scope, { Vector<const GVArray *> 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<GVArray_For_SingleValueRef>( @@ -420,4 +420,13 @@ void evaluate_fields_to_spans(Span<const GField *> 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 diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index 7519cc80572..04307019aec 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -35,6 +35,7 @@ namespace blender::nodes { using bke::AttributeIDRef; using bke::geometry_set_realize_instances; +using bke::GeometryComponentFieldContext; using bke::OutputAttribute; using bke::OutputAttribute_Typed; using bke::ReadAttributeLookup; |