Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <jacques@blender.org>2022-04-21 16:29:07 +0300
committerJacques Lucke <jacques@blender.org>2022-04-21 16:29:18 +0300
commitc196ca37407d4dacb832d4c888ac87e66d7094c5 (patch)
tree1e9617668055d5d94163c9d31845be6d3b47a590
parent0178e694b72d32ee9805b2f854d1dc4cc46d481f (diff)
Functions: fix procedure executor not writing output in correct buffer
The issue was that the executor would forget about the caller provided storage if the variable is destructed.
-rw-r--r--source/blender/functions/intern/multi_function_procedure_executor.cc27
-rw-r--r--source/blender/functions/tests/FN_multi_function_procedure_test.cc30
2 files changed, 40 insertions, 17 deletions
diff --git a/source/blender/functions/intern/multi_function_procedure_executor.cc b/source/blender/functions/intern/multi_function_procedure_executor.cc
index 7a0b74d8039..c58ca0bb8fd 100644
--- a/source/blender/functions/intern/multi_function_procedure_executor.cc
+++ b/source/blender/functions/intern/multi_function_procedure_executor.cc
@@ -681,14 +681,9 @@ class VariableState : NonCopyable, NonMovable {
/* Sanity check to make sure that enough indices can be destructed. */
BLI_assert(new_tot_initialized >= 0);
- bool do_destruct_self = false;
-
switch (value_->type) {
case ValueType::GVArray: {
- if (mask.size() == full_mask.size()) {
- do_destruct_self = true;
- }
- else {
+ if (mask.size() < full_mask.size()) {
/* Not all elements are destructed. Since we can't work on the original array, we have to
* create a copy first. */
this->ensure_is_mutable(full_mask, data_type, value_allocator);
@@ -701,16 +696,10 @@ class VariableState : NonCopyable, NonMovable {
case ValueType::Span: {
const CPPType &type = data_type.single_type();
type.destruct_indices(this->value_as<VariableValue_Span>()->data, mask);
- if (new_tot_initialized == 0) {
- do_destruct_self = true;
- }
break;
}
case ValueType::GVVectorArray: {
- if (mask.size() == full_mask.size()) {
- do_destruct_self = true;
- }
- else {
+ if (mask.size() < full_mask.size()) {
/* Not all elements are cleared. Since we can't work on the original vector array, we
* have to create a copy first. A possible future optimization is to create the partial
* copy directly. */
@@ -729,22 +718,26 @@ class VariableState : NonCopyable, NonMovable {
BLI_assert(value_typed->is_initialized);
UNUSED_VARS_NDEBUG(value_typed);
if (mask.size() == tot_initialized_) {
- do_destruct_self = true;
+ const CPPType &type = data_type.single_type();
+ type.destruct(value_typed->data);
+ value_typed->is_initialized = false;
}
break;
}
case ValueType::OneVector: {
auto *value_typed = this->value_as<VariableValue_OneVector>();
- UNUSED_VARS(value_typed);
if (mask.size() == tot_initialized_) {
- do_destruct_self = true;
+ value_typed->data.clear(IndexRange(1));
}
break;
}
}
tot_initialized_ = new_tot_initialized;
- return do_destruct_self;
+
+ const bool should_self_destruct = new_tot_initialized == 0 &&
+ caller_provided_storage_ == nullptr;
+ return should_self_destruct;
}
void indices_split(IndexMask mask, IndicesSplitVectors &r_indices)
diff --git a/source/blender/functions/tests/FN_multi_function_procedure_test.cc b/source/blender/functions/tests/FN_multi_function_procedure_test.cc
index a196d0396ec..e7cedb40f83 100644
--- a/source/blender/functions/tests/FN_multi_function_procedure_test.cc
+++ b/source/blender/functions/tests/FN_multi_function_procedure_test.cc
@@ -378,4 +378,34 @@ TEST(multi_function_procedure, BufferReuse)
EXPECT_EQ(results[4], 53);
}
+TEST(multi_function_procedure, OutputBufferReplaced)
+{
+ MFProcedure procedure;
+ MFProcedureBuilder builder{procedure};
+
+ const int output_value = 42;
+ CustomMF_GenericConstant constant_fn(CPPType::get<int>(), &output_value, false);
+ MFVariable &var_o = procedure.new_variable(MFDataType::ForSingle<int>());
+ builder.add_output_parameter(var_o);
+ builder.add_call_with_all_variables(constant_fn, {&var_o});
+ builder.add_destruct(var_o);
+ builder.add_call_with_all_variables(constant_fn, {&var_o});
+ builder.add_return();
+
+ EXPECT_TRUE(procedure.validate());
+
+ MFProcedureExecutor procedure_fn{procedure};
+
+ Array<int> output(3, 0);
+ fn::MFParamsBuilder params(procedure_fn, output.size());
+ params.add_uninitialized_single_output(output.as_mutable_span());
+
+ fn::MFContextBuilder context;
+ procedure_fn.call(IndexMask(output.size()), params, context);
+
+ EXPECT_EQ(output[0], output_value);
+ EXPECT_EQ(output[1], output_value);
+ EXPECT_EQ(output[2], output_value);
+}
+
} // namespace blender::fn::tests