[Bf-blender-cvs] [79d0e9c] : Removing ParticleSystem->frand arrays to avoid memory corruption issues in threaded depgraph updates and effector list construction.

Lukas Tönne noreply at git.blender.org
Wed Mar 12 18:22:29 CET 2014


Commit: 79d0e9c4f9dad3c13f318d045c806c4cebd40a51
Author: Lukas Tönne
Date:   Fri Mar 7 10:25:56 2014 +0100
https://developer.blender.org/rB79d0e9c4f9dad3c13f318d045c806c4cebd40a51

Removing ParticleSystem->frand arrays to avoid memory corruption issues
in threaded depgraph updates and effector list construction.

Gathering effectors during depgraph updates will call the
psys_check_enabled function. This in turn contained a DNA alloc call
for the psys->frand RNG arrays, which is really bad because data must be
immutable during these effector constructions.

To avoid such allocs the frand array is now global for all particle
systems. To avoid correlation of pseudo-random numbers the psys->seed
value is complemented with random offset and multiplier for the actual
float array. This is not ideal, but work sufficiently well (given that
random numbers were already really limited and show repetition quite
easily for particle counts > PSYS_FRAND_COUNT).

===================================================================

M	source/blender/blenkernel/BKE_particle.h
M	source/blender/blenkernel/intern/boids.c
M	source/blender/blenkernel/intern/object.c
M	source/blender/blenkernel/intern/particle.c
M	source/blender/blenkernel/intern/particle_system.c
M	source/blender/blenloader/intern/readfile.c
M	source/blender/editors/space_view3d/drawobject.c
M	source/blender/makesdna/DNA_particle_types.h
M	source/blender/render/intern/source/convertblender.c
M	source/creator/creator.c

===================================================================

diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index b6be72f..d87b209 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -34,6 +34,8 @@
  *  \ingroup bke
  */
 
+#include "BLI_utildefines.h"
+
 #include "DNA_particle_types.h"
 #include "DNA_object_types.h"
 
@@ -70,9 +72,6 @@ struct EdgeHash;
 /* OpenMP: Can only advance one variable within loop definition. */
 #define LOOP_DYNAMIC_PARTICLES for (p = 0; p < psys->totpart; p++) if ((pa = psys->particles + p)->state.time > 0.0f)
 
-#define PSYS_FRAND_COUNT    1024
-#define PSYS_FRAND(seed)    psys->frand[(seed) % PSYS_FRAND_COUNT]
-
 /* fast but sure way to get the modifier*/
 #define PARTICLE_PSMD ParticleSystemModifierData * psmd = sim->psmd ? sim->psmd : psys_get_modifier(sim->ob, sim->psys)
 
@@ -247,6 +246,34 @@ typedef struct ParticleDrawData {
 
 #define PARTICLE_DRAW_DATA_UPDATED  1
 
+#define PSYS_FRAND_COUNT    1024
+unsigned int PSYS_FRAND_SEED_OFFSET[PSYS_FRAND_COUNT];
+unsigned int PSYS_FRAND_SEED_MULTIPLIER[PSYS_FRAND_COUNT];
+float PSYS_FRAND_BASE[PSYS_FRAND_COUNT];
+
+void psys_init_rng(void);
+
+BLI_INLINE float psys_frand(ParticleSystem *psys, unsigned int seed)
+{
+	/* XXX far from ideal, this simply scrambles particle random numbers a bit
+	 * to avoid obvious correlations.
+	 * Can't use previous psys->frand arrays because these require initialization
+	 * inside psys_check_enabled, which wreaks havok in multithreaded depgraph updates.
+	 */
+	unsigned int offset = PSYS_FRAND_SEED_OFFSET[psys->seed % PSYS_FRAND_COUNT];
+	unsigned int multiplier = PSYS_FRAND_SEED_MULTIPLIER[psys->seed % PSYS_FRAND_COUNT];
+	return PSYS_FRAND_BASE[(offset + seed * multiplier) % PSYS_FRAND_COUNT];
+}
+
+BLI_INLINE void psys_frand_vec(ParticleSystem *psys, unsigned int seed, float vec[3])
+{
+	unsigned int offset = PSYS_FRAND_SEED_OFFSET[psys->seed % PSYS_FRAND_COUNT];
+	unsigned int multiplier = PSYS_FRAND_SEED_MULTIPLIER[psys->seed % PSYS_FRAND_COUNT];
+	vec[0] = PSYS_FRAND_BASE[(offset + (seed + 0) * multiplier) % PSYS_FRAND_COUNT];
+	vec[1] = PSYS_FRAND_BASE[(offset + (seed + 1) * multiplier) % PSYS_FRAND_COUNT];
+	vec[2] = PSYS_FRAND_BASE[(offset + (seed + 2) * multiplier) % PSYS_FRAND_COUNT];
+}
+
 /* ----------- functions needed outside particlesystem ---------------- */
 /* particle.c */
 int count_particles(struct ParticleSystem *psys);
diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c
index a8d64ea..157de3e 100644
--- a/source/blender/blenkernel/intern/boids.c
+++ b/source/blender/blenkernel/intern/boids.c
@@ -970,8 +970,8 @@ void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa)
 	bbd->wanted_speed = 0.0f;
 
 	/* create random seed for every particle & frame */
-	rand = (int)(PSYS_FRAND(psys->seed + p) * 1000);
-	rand = (int)(PSYS_FRAND((int)bbd->cfra + rand) * 1000);
+	rand = (int)(psys_frand(psys, psys->seed + p) * 1000);
+	rand = (int)(psys_frand(psys, (int)bbd->cfra + rand) * 1000);
 
 	set_boid_values(&val, bbd->part->boids, pa);
 
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index e4b5905..43dbc34 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -1279,7 +1279,6 @@ static ParticleSystem *copy_particlesystem(ParticleSystem *psys)
 	psysn->pathcache = NULL;
 	psysn->childcache = NULL;
 	psysn->edit = NULL;
-	psysn->frand = NULL;
 	psysn->pdd = NULL;
 	psysn->effectors = NULL;
 	psysn->tree = NULL;
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 3a5b4b5..4f4964c 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -85,6 +85,17 @@
 
 #include "RE_render_ext.h"
 
+void psys_init_rng(void)
+{
+	int i;
+	BLI_srandom(5831); /* arbitrary */
+	for (i = 0; i < PSYS_FRAND_COUNT; ++i) {
+		PSYS_FRAND_BASE[i] = BLI_frand();
+		PSYS_FRAND_SEED_OFFSET[i] = (unsigned int)BLI_rand();
+		PSYS_FRAND_SEED_MULTIPLIER[i] = (unsigned int)BLI_rand();
+	}
+}
+
 static void get_child_modifier_parameters(ParticleSettings *part, ParticleThreadContext *ctx,
                                           ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex);
 static void do_child_modifiers(ParticleSimulationData *sim,
@@ -260,16 +271,6 @@ int psys_in_edit_mode(Scene *scene, ParticleSystem *psys)
 {
 	return (scene->basact && (scene->basact->object->mode & OB_MODE_PARTICLE_EDIT) && psys == psys_get_current((scene->basact)->object) && (psys->edit || psys->pointcache->edit) && !psys->renderdata);
 }
-static void psys_create_frand(ParticleSystem *psys)
-{
-	int i;
-	float *rand = psys->frand = MEM_callocN(PSYS_FRAND_COUNT * sizeof(float), "particle randoms");
-
-	BLI_srandom(psys->seed);
-
-	for (i = 0; i < 1024; i++, rand++)
-		*rand = BLI_frand();
-}
 int psys_check_enabled(Object *ob, ParticleSystem *psys)
 {
 	ParticleSystemModifierData *psmd;
@@ -285,14 +286,6 @@ int psys_check_enabled(Object *ob, ParticleSystem *psys)
 	else if (!(psmd->modifier.mode & eModifierMode_Realtime))
 		return 0;
 
-	/* perhaps not the perfect place, but we have to be sure the rands are there before usage */
-	if (!psys->frand)
-		psys_create_frand(psys);
-	else if (psys->recalc & PSYS_RECALC_RESET) {
-		MEM_freeN(psys->frand);
-		psys_create_frand(psys);
-	}
-	
 	return 1;
 }
 
@@ -579,9 +572,6 @@ void psys_free(Object *ob, ParticleSystem *psys)
 
 		pdEndEffectors(&psys->effectors);
 
-		if (psys->frand)
-			MEM_freeN(psys->frand);
-
 		if (psys->pdd) {
 			psys_free_pdd(psys);
 			MEM_freeN(psys->pdd);
@@ -787,7 +777,7 @@ void psys_render_restore(Object *ob, ParticleSystem *psys)
 		PARTICLE_P;
 
 		LOOP_PARTICLES {
-			if (PSYS_FRAND(p) > disp)
+			if (psys_frand(psys, p) > disp)
 				pa->flag |= PARS_NO_DISP;
 			else
 				pa->flag &= ~PARS_NO_DISP;
@@ -2685,7 +2675,7 @@ static void psys_thread_create_path(ParticleThread *thread, struct ChildParticle
 	/* get different child parameters from textures & vgroups */
 	get_child_modifier_parameters(part, ctx, cpa, cpa_from, cpa_num, cpa_fuv, orco, &ptex);
 
-	if (ptex.exist < PSYS_FRAND(i + 24)) {
+	if (ptex.exist < psys_frand(psys, i + 24)) {
 		child_keys->steps = -1;
 		return;
 	}
@@ -3001,7 +2991,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
 	LOOP_SHOWN_PARTICLES {
 		if (!psys->totchild) {
 			psys_get_texture(sim, pa, &ptex, PAMAP_LENGTH, 0.f);
-			pa_length = ptex.length * (1.0f - part->randlength * PSYS_FRAND(psys->seed + p));
+			pa_length = ptex.length * (1.0f - part->randlength * psys_frand(psys, psys->seed + p));
 			if (vg_length)
 				pa_length *= psys_particle_value_from_verts(psmd->dm, part->from, pa, vg_length);
 		}
@@ -3837,8 +3827,8 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti
 	ptex->gravity = ptex->field = ptex->time = ptex->clump = ptex->kink =
 	ptex->effector = ptex->rough1 = ptex->rough2 = ptex->roughe = 1.0f;
 
-	ptex->length = 1.0f - part->randlength * PSYS_FRAND(child_index + 26);
-	ptex->length *= part->clength_thres < PSYS_FRAND(child_index + 27) ? part->clength : 1.0f;
+	ptex->length = 1.0f - part->randlength * psys_frand(psys, child_index + 26);
+	ptex->length *= part->clength_thres < psys_frand(psys, child_index + 27) ? part->clength : 1.0f;
 
 	for (m = 0; m < MAX_MTEX; m++, mtexp++) {
 		mtex = *mtexp;
@@ -4000,7 +3990,7 @@ float psys_get_child_time(ParticleSystem *psys, ChildParticle *cpa, float cfra,
 			w++;
 		}
 
-		life = part->lifetime * (1.0f - part->randlife * PSYS_FRAND(cpa - psys->child + 25));
+		life = part->lifetime * (1.0f - part->randlife * psys_frand(psys, cpa - psys->child + 25));
 	}
 	else {
 		ParticleData *pa = psys->particles + cpa->parent;
@@ -4029,7 +4019,7 @@ float psys_get_child_size(ParticleSystem *psys, ChildParticle *cpa, float UNUSED
 	size *= part->childsize;
 
 	if (part->childrandsize != 0.0f)
-		size *= 1.0f - part->childrandsize * PSYS_FRAND(cpa - psys->child + 26);
+		size *= 1.0f - part->childrandsize * psys_frand(psys, cpa - psys->child + 26);
 
 	return size;
 }
@@ -4041,7 +4031,7 @@ static void get_child_modifier_parameters(ParticleSettings *part, ParticleThread
 	get_cpa_texture(ctx->dm, psys, part, psys->particles + cpa->pa[0], i, cpa_num, cpa_fuv, orco, ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra);
 
 
-	if (ptex->exist < PSYS_FRAND(i + 24))
+	if (ptex->exist < psys_frand(psys, i + 24))
 		return;
 
 	if (ctx->vg_length)
@@ -4096,11 +4086,17 @@ static void do_child_modifiers(ParticleSimulationData *sim, ParticleTexture *pte
 	if (rough1 > 0.f)
 		do_rough(orco, mat, t, rough1, part->rough1_size, 0.0, state);
 
-	if (rough2 > 0.f)
-		do_rough(sim->psys->frand + ((i + 27) % (PSYS_FRAND_COUNT - 3)), mat, t, rough2, part->rough2_size, part->rough2_thres, state);
+	if (rough2 > 0.f) {
+		float vec[3];
+		psys_frand_vec(sim->psys, i + 27, vec);
+		do_rough(vec, mat, t, rough2, part->rough2_size, part->rough2_thres, state);
+	}
 
-	if (rough_end > 0.f)
-		do_rough_end(sim->psys->frand + ((i + 27) % (PSYS_FRAND_COUNT - 3)), mat, t, rough_end, part->rough_end_shape, state);
+	if (rough_end > 0.f) {
+		float vec[3];
+		psys_frand_vec(sim->psys, i + 27, vec);
+		do_rough_end(vec, mat, t, rough_end, part->rough_end_shape, state);
+	}
 }
 /* get's hair (or keyed) particles state at the "path time" specified in state->time */
 void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *state, int vel)
@@ -4363,7 +4359,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
 				}
 			}
 
-			state->time = (cfra - (part->sta + (part->end - part->sta) * PSYS_FRAND(p + 23))) / (part->lifetime * PSYS_FRAND(p + 24));
+			state->time = (cfra - (part->sta + (part->end - part->sta) * psys_frand(psys, p + 23))) / (part->lifetime * psys_frand(psys, p + 24));
 
 			psys_get_particle_on_path(sim, p, state, 1);
 			return 1;
@@ -4572,7 +4568,7 @@ void psys_get_dupli_path_transform(ParticleSimulationData *sim, ParticleData *pa
 			float q_phase[4];
 			float phasefac = psys->part->phasefac;
 			if (psy

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list