Fix: Memory leak and race condition with particle effector RNG

Store RNG on per thread data, instead of the effector itself which may
be used by multiple objects evaluated in different threads.

This has been causing the blendfile_versioning test to fail randomly.
Thanks Ray and Aras for helping track this down.

Pull Request: https://projects.blender.org/blender/blender/pulls/119967
This commit is contained in:
Brecht Van Lommel 2024-03-27 18:06:31 +01:00 committed by Brecht Van Lommel
parent d2b38a475f
commit 8682ad1908
5 changed files with 11 additions and 22 deletions

View File

@ -16,6 +16,7 @@ extern "C" {
struct Collection;
struct Depsgraph;
struct ListBase;
struct RNG;
struct Object;
struct ParticleData;
struct ParticleKey;
@ -78,6 +79,9 @@ typedef struct EffectorCache {
struct PartDeflect *pd;
/** Random noise generator for e.g. wind. */
struct RNG *rng;
/* precalculated for guides */
struct GuideEffectorData *guide_data;
float guide_loc[4], guide_dir[3], guide_radius;

View File

@ -113,9 +113,6 @@ PartDeflect *BKE_partdeflect_copy(const PartDeflect *pd_src)
return nullptr;
}
PartDeflect *pd_dst = static_cast<PartDeflect *>(MEM_dupallocN(pd_src));
if (pd_dst->rng != nullptr) {
pd_dst->rng = BLI_rng_copy(pd_dst->rng);
}
return pd_dst;
}
@ -124,9 +121,6 @@ void BKE_partdeflect_free(PartDeflect *pd)
if (!pd) {
return;
}
if (pd->rng) {
BLI_rng_free(pd->rng);
}
MEM_freeN(pd);
}
@ -136,12 +130,8 @@ static void precalculate_effector(Depsgraph *depsgraph, EffectorCache *eff)
{
float ctime = DEG_get_ctime(depsgraph);
uint cfra = uint(ctime >= 0 ? ctime : -ctime);
if (!eff->pd->rng) {
eff->pd->rng = BLI_rng_new(eff->pd->seed + cfra);
}
else {
BLI_rng_srandom(eff->pd->rng, eff->pd->seed + cfra);
}
eff->rng = BLI_rng_new(eff->pd->seed + cfra);
if (eff->pd->forcefield == PFIELD_GUIDE && eff->ob->type == OB_CURVES_LEGACY) {
Curve *cu = static_cast<Curve *>(eff->ob->data);
@ -375,6 +365,9 @@ void BKE_effectors_free(ListBase *lb)
{
if (lb) {
LISTBASE_FOREACH (EffectorCache *, eff, lb) {
if (eff->rng) {
BLI_rng_free(eff->rng);
}
if (eff->guide_data) {
MEM_freeN(eff->guide_data);
}
@ -960,7 +953,7 @@ static void do_physical_effector(EffectorCache *eff,
float *total_force)
{
PartDeflect *pd = eff->pd;
RNG *rng = pd->rng;
RNG *rng = eff->rng;
float force[3] = {0, 0, 0};
float temp[3];
float fac;

View File

@ -245,9 +245,6 @@ static void object_copy_data(Main *bmain,
if (ob_src->pd) {
ob_dst->pd = (PartDeflect *)MEM_dupallocN(ob_src->pd);
if (ob_dst->pd->rng) {
ob_dst->pd->rng = (RNG *)MEM_dupallocN(ob_src->pd->rng);
}
}
BKE_rigidbody_object_copy(bmain, ob_dst, ob_src, flag_subdata);

View File

@ -313,11 +313,8 @@ static void particle_settings_blend_write(BlendWriter *writer, ID *id, const voi
}
}
void BKE_particle_partdeflect_blend_read_data(BlendDataReader * /*reader*/, PartDeflect *pd)
void BKE_particle_partdeflect_blend_read_data(BlendDataReader * /*reader*/, PartDeflect * /*pd*/)
{
if (pd) {
pd->rng = nullptr;
}
}
static void particle_settings_blend_read_data(BlendDataReader *reader, ID *id)

View File

@ -131,8 +131,6 @@ typedef struct PartDeflect {
struct Tex *tex;
/* effector noise */
/** Random noise generator for e.g. wind. */
struct RNG *rng;
/** Noise of force. */
float f_noise;
/** Noise random seed. */