mirror of
https://github.com/blender/blender
synced 2026-09-29 04:37:17 +03:00
Fix: Geometry Nodes: crash when capturing group input geometry in some cases
The crash requires a fairly specific setup that I noticed when working on #150852. The setup is included here in form of a regression test. The issue happened because the closure currently assumes that the Group Input geometry can be part of the output because it is captured due to being a border link. In another pass when computing the final propagate-relations (data that can propagate from the group input to group output) it is detected that this can't actually happen. So there was some inconsistency in the final required reference lifetimes. There might be a cleaner fix that doesn't require a post-processing step, but I haven't found one yet. Might need some more investigation or refactoring later. Pull Request: https://projects.blender.org/blender/blender/pulls/151390
This commit is contained in:
parent
6eae38e08d
commit
17945ce420
4 changed files with 78 additions and 5 deletions
|
|
@ -993,6 +993,32 @@ static aal::RelationsInNode get_tree_relations(
|
|||
return tree_relations;
|
||||
}
|
||||
|
||||
/**
|
||||
* After creating detecting the final propagate-relations, we can detect some input geometry that
|
||||
* looked like it was passed to the output actually is not. So we can update
|
||||
* #required_data_by_socket to never use the corresponding #ReferenceSetInfo.
|
||||
*/
|
||||
static void disable_unused_group_output_propagation(
|
||||
const Span<ReferenceSetInfo> reference_sets,
|
||||
const Span<aal::PropagateRelation> &propagate_relations,
|
||||
BitGroupVector<> &required_data_by_socket)
|
||||
{
|
||||
Vector<int> propagate_targets;
|
||||
for (const auto relation : propagate_relations) {
|
||||
propagate_targets.append(relation.to_geometry_output);
|
||||
}
|
||||
BitVector<> reference_sets_mask(reference_sets.size(), true);
|
||||
for (const int i : reference_sets.index_range()) {
|
||||
const ReferenceSetInfo &reference_set = reference_sets[i];
|
||||
if (reference_set.type == ReferenceSetType::GroupOutputData) {
|
||||
if (!propagate_targets.contains(reference_set.index)) {
|
||||
reference_sets_mask[i].reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
required_data_by_socket.foreach_and(reference_sets_mask);
|
||||
}
|
||||
|
||||
static std::unique_ptr<ReferenceLifetimesInfo> make_reference_lifetimes_info(const bNodeTree &tree)
|
||||
{
|
||||
tree.ensure_topology_cache();
|
||||
|
|
@ -1049,6 +1075,16 @@ static std::unique_ptr<ReferenceLifetimesInfo> make_reference_lifetimes_info(con
|
|||
/* Make sure that all required data is also potentially available. */
|
||||
required_data_by_socket.all_bits() &= potential_data_by_socket.all_bits();
|
||||
|
||||
reference_lifetimes_info->tree_relations = get_tree_relations(tree,
|
||||
reference_sets,
|
||||
potential_data_by_socket,
|
||||
potential_reference_by_socket,
|
||||
required_data_by_socket);
|
||||
disable_unused_group_output_propagation(
|
||||
reference_sets,
|
||||
reference_lifetimes_info->tree_relations.propagate_relations,
|
||||
required_data_by_socket);
|
||||
|
||||
/* Only useful when debugging the reference lifetimes analysis. */
|
||||
#if 0
|
||||
std::cout << "\n\n"
|
||||
|
|
@ -1060,11 +1096,6 @@ static std::unique_ptr<ReferenceLifetimesInfo> make_reference_lifetimes_info(con
|
|||
<< "\n\n";
|
||||
#endif
|
||||
|
||||
reference_lifetimes_info->tree_relations = get_tree_relations(tree,
|
||||
reference_sets,
|
||||
potential_data_by_socket,
|
||||
potential_reference_by_socket,
|
||||
required_data_by_socket);
|
||||
reference_lifetimes_info->required_data_by_socket = std::move(required_data_by_socket);
|
||||
return reference_lifetimes_info;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_bit_span_ops.hh"
|
||||
#include "BLI_bit_vector.hh"
|
||||
|
||||
namespace blender::bits {
|
||||
|
|
@ -138,6 +139,20 @@ class BitGroupVector {
|
|||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates each group by computing the bitwise-and with the given bits.
|
||||
*/
|
||||
void foreach_and(const BoundedBitSpan bits)
|
||||
{
|
||||
/* This can still be optimized due to the additional knowledge we have how consecutive groups
|
||||
* are layed out in memory. It is possible to updated multiple small groups at once. */
|
||||
BLI_assert(bits.size() == group_size_);
|
||||
for (const int64_t i : this->index_range()) {
|
||||
MutableBoundedBitSpan group = (*this)[i];
|
||||
group &= bits;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender::bits
|
||||
|
|
|
|||
|
|
@ -48,4 +48,28 @@ TEST(bit_group_vector, CopyConstruct)
|
|||
}
|
||||
}
|
||||
|
||||
TEST(bit_group_vector, foreachAnd)
|
||||
{
|
||||
BitGroupVector<> groups(3, 4);
|
||||
groups.all_bits().set_all();
|
||||
|
||||
BitVector<> mask{Span<bool>{false, false, true, false}};
|
||||
groups.foreach_and(mask);
|
||||
|
||||
EXPECT_FALSE(groups[0][0].test());
|
||||
EXPECT_FALSE(groups[0][1].test());
|
||||
EXPECT_TRUE(groups[0][2].test());
|
||||
EXPECT_FALSE(groups[0][3].test());
|
||||
|
||||
EXPECT_FALSE(groups[1][0].test());
|
||||
EXPECT_FALSE(groups[1][1].test());
|
||||
EXPECT_TRUE(groups[1][2].test());
|
||||
EXPECT_FALSE(groups[1][3].test());
|
||||
|
||||
EXPECT_FALSE(groups[2][0].test());
|
||||
EXPECT_FALSE(groups[2][1].test());
|
||||
EXPECT_TRUE(groups[2][2].test());
|
||||
EXPECT_FALSE(groups[2][3].test());
|
||||
}
|
||||
|
||||
} // namespace blender::bits::tests
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1002a6af45f3f0fc0e0cffe03edbb9d9fdf47ea48cb02307d50cabf3198f7980
|
||||
size 97081
|
||||
Loading…
Add table
Add a link
Reference in a new issue