diff options
Diffstat (limited to 'source/blender/functions/FN_multi_function_params.hh')
-rw-r--r-- | source/blender/functions/FN_multi_function_params.hh | 68 |
1 files changed, 63 insertions, 5 deletions
diff --git a/source/blender/functions/FN_multi_function_params.hh b/source/blender/functions/FN_multi_function_params.hh index 5af86c7c284..cae105e7c19 100644 --- a/source/blender/functions/FN_multi_function_params.hh +++ b/source/blender/functions/FN_multi_function_params.hh @@ -38,6 +38,7 @@ class MFParamsBuilder { private: ResourceScope scope_; const MFSignature *signature_; + IndexMask mask_; int64_t min_array_size_; Vector<const GVArray *> virtual_arrays_; Vector<GMutableSpan> mutable_spans_; @@ -46,13 +47,18 @@ class MFParamsBuilder { friend class MFParams; - public: - MFParamsBuilder(const MFSignature &signature, int64_t min_array_size) - : signature_(&signature), min_array_size_(min_array_size) + MFParamsBuilder(const MFSignature &signature, const IndexMask mask) + : signature_(&signature), mask_(mask), min_array_size_(mask.min_array_size()) { } - MFParamsBuilder(const class MultiFunction &fn, int64_t min_array_size); + public: + MFParamsBuilder(const class MultiFunction &fn, int64_t size); + /** + * The indices referenced by the #mask has to live longer than the params builder. This is + * because the it might have to destruct elements for all masked indices in the end. + */ + MFParamsBuilder(const class MultiFunction &fn, const IndexMask *mask); template<typename T> void add_readonly_single_input_value(T value, StringRef expected_name = "") { @@ -112,6 +118,17 @@ class MFParamsBuilder { BLI_assert(ref.size() >= min_array_size_); mutable_spans_.append(ref); } + void add_ignored_single_output(StringRef expected_name = "") + { + this->assert_current_param_name(expected_name); + const int param_index = this->current_param_index(); + const MFParamType ¶m_type = signature_->param_types[param_index]; + BLI_assert(param_type.category() == MFParamType::SingleOutput); + const CPPType &type = param_type.data_type().single_type(); + /* An empty span indicates that this is ignored. */ + const GMutableSpan dummy_span{type}; + mutable_spans_.append(dummy_span); + } void add_vector_output(GVectorArray &vector_array, StringRef expected_name = "") { @@ -176,6 +193,19 @@ class MFParamsBuilder { #endif } + void assert_current_param_name(StringRef expected_name) + { + UNUSED_VARS_NDEBUG(expected_name); +#ifdef DEBUG + if (expected_name.is_empty()) { + return; + } + const int param_index = this->current_param_index(); + StringRef actual_name = signature_->param_names[param_index]; + BLI_assert(actual_name == expected_name); +#endif + } + int current_param_index() const { return virtual_arrays_.size() + mutable_spans_.size() + virtual_vector_arrays_.size() + @@ -204,6 +234,19 @@ class MFParams { return *builder_->virtual_arrays_[data_index]; } + /** + * \return True when the caller provided a buffer for this output parameter. This allows the + * called multi-function to skip some computation. It is still valid to call + * #uninitialized_single_output when this returns false. In this case a new temporary buffer is + * allocated. + */ + bool single_output_is_required(int param_index, StringRef name = "") + { + this->assert_correct_param(param_index, name, MFParamType::SingleOutput); + int data_index = builder_->signature_->data_index(param_index); + return !builder_->mutable_spans_[data_index].is_empty(); + } + template<typename T> MutableSpan<T> uninitialized_single_output(int param_index, StringRef name = "") { @@ -213,7 +256,22 @@ class MFParams { { this->assert_correct_param(param_index, name, MFParamType::SingleOutput); int data_index = builder_->signature_->data_index(param_index); - return builder_->mutable_spans_[data_index]; + GMutableSpan span = builder_->mutable_spans_[data_index]; + if (span.is_empty()) { + /* The output is ignored by the caller, but the multi-function does not handle this case. So + * create a temporary buffer that the multi-function can write to. */ + const CPPType &type = span.type(); + void *buffer = builder_->scope_.linear_allocator().allocate( + builder_->min_array_size_ * type.size(), type.alignment()); + if (!type.is_trivially_destructible()) { + /* Make sure the temporary elements will be destructed in the end. */ + builder_->scope_.add_destruct_call( + [&type, buffer, mask = builder_->mask_]() { type.destruct_indices(buffer, mask); }, + __func__); + } + span = GMutableSpan{type, buffer, builder_->min_array_size_}; + } + return span; } template<typename T> |