Fix #137145: Crash when enabling Auto Normalize in Weight Paint mode

Caused by d3f84449ad.

The problem was that one SharedCache referenced the data of another,
without using the shared_ptr mechanism that is typically used for that
case. I had forgotten to avoid this-- I already did a similar fix a couple
years ago for curves: b07085fe3c

This time I kept the result as part of the cache to avoid the overhead
of attribute access on every call to `Mesh::face_normals()`.

Pull Request: https://projects.blender.org/blender/blender/pulls/137167
This commit is contained in:
Hans Goudey
2025-04-09 17:57:12 +02:00
committed by Hans Goudey
parent 93f0867ba6
commit 63beb6afb3
2 changed files with 29 additions and 17 deletions

View File

@@ -99,13 +99,19 @@ struct LooseVertCache : public LooseGeomCache {};
/** Similar to #VArraySpan but with the ability to be resized and updated. */
class NormalsCache {
std::variant<Vector<float3>, Span<float3>> data_;
public:
/**
* Signals that the data from the corresponding "true normals" cache can be used instead. Used to
* avoid referencing the data from another shared cache while not still not fetching the custom
* normal attribute on every cache request.
*/
struct UseTrueCache {};
std::variant<UseTrueCache, Vector<float3>, Span<float3>> data;
MutableSpan<float3> ensure_vector_size(const int size);
Span<float3> get_span() const;
/** \note The caller must ensure that the data is valid as long as the cache. */
void store_varray(const VArray<float3> &data);
void store_span(Span<float3> data);
void store_vector(Vector<float3> &&data);
};

View File

@@ -60,41 +60,36 @@ void mesh_vert_normals_assign(Mesh &mesh, Vector<float3> vert_normals)
MutableSpan<float3> NormalsCache::ensure_vector_size(const int size)
{
if (auto *vector = std::get_if<Vector<float3>>(&data_)) {
if (auto *vector = std::get_if<Vector<float3>>(&this->data)) {
vector->resize(size);
}
else {
data_ = Vector<float3>(size);
this->data = Vector<float3>(size);
}
return std::get<Vector<float3>>(data_).as_mutable_span();
return std::get<Vector<float3>>(this->data).as_mutable_span();
}
Span<float3> NormalsCache::get_span() const
{
if (const auto *vector = std::get_if<Vector<float3>>(&data_)) {
if (const auto *vector = std::get_if<Vector<float3>>(&this->data)) {
return vector->as_span();
}
return std::get<Span<float3>>(data_);
return std::get<Span<float3>>(this->data);
}
void NormalsCache::store_varray(const VArray<float3> &data)
{
if (data.is_span()) {
data_ = data.get_internal_span();
this->data = data.get_internal_span();
}
else {
data.materialize(this->ensure_vector_size(data.size()));
}
}
void NormalsCache::store_span(const Span<float3> data)
{
data_ = data;
}
void NormalsCache::store_vector(Vector<float3> &&data)
{
data_ = std::move(data);
this->data = std::move(data);
}
} // namespace blender::bke
@@ -383,8 +378,14 @@ blender::Span<blender::float3> Mesh::vert_normals() const
return;
}
}
r_data.store_span(this->vert_normals_true());
r_data.data = NormalsCache::UseTrueCache();
});
if (std::holds_alternative<NormalsCache::UseTrueCache>(
this->runtime->vert_normals_cache.data().data))
{
return this->vert_normals_true();
}
return this->runtime->vert_normals_cache.data().get_span();
}
@@ -435,8 +436,13 @@ blender::Span<blender::float3> Mesh::face_normals() const
return;
}
}
r_data.store_span(this->face_normals_true());
r_data.data = NormalsCache::UseTrueCache();
});
if (std::holds_alternative<NormalsCache::UseTrueCache>(
this->runtime->face_normals_cache.data().data))
{
return this->face_normals_true();
}
return this->runtime->face_normals_cache.data().get_span();
}