[Bf-blender-cvs] [a0f644d] temp_merge_gooseberry_hair: Use the generic task scheduler for threaded particle tasks, i.e. distribution and path caching for child particles.

Lukas Tönne noreply at git.blender.org
Mon Jan 19 20:49:57 CET 2015


Commit: a0f644d1c548727ecbbc6bdfcea1332a90ba106b
Author: Lukas Tönne
Date:   Mon Oct 6 18:58:41 2014 +0200
Branches: temp_merge_gooseberry_hair
https://developer.blender.org/rBa0f644d1c548727ecbbc6bdfcea1332a90ba106b

Use the generic task scheduler for threaded particle tasks, i.e.
distribution and path caching for child particles.

This gives a significant improvement of viewport playback performance
with higher child particle counts. Particles previously used their own
threads and had a rather high limit for threading. Also threading
apparently was disabled because only 1 thread was being used ...

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

M	source/blender/blenkernel/BKE_particle.h
M	source/blender/blenkernel/intern/particle.c
M	source/blender/blenkernel/intern/particle_system.c

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

diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index 204fbbf..2aefc53 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -160,11 +160,11 @@ typedef struct ParticleThreadContext {
 	float *vg_effector;
 } ParticleThreadContext;
 
-typedef struct ParticleThread {
+typedef struct ParticleTask {
 	ParticleThreadContext *ctx;
 	struct RNG *rng, *rng_path;
-	int num, tot;
-} ParticleThread;
+	int begin, end;
+} ParticleTask;
 
 typedef struct ParticleBillboardData {
 	struct Object *ob;
@@ -347,8 +347,9 @@ void psys_get_dupli_texture(struct ParticleSystem *psys, struct ParticleSettings
 void psys_get_dupli_path_transform(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ChildParticle *cpa,
                                    struct ParticleCacheKey *cache, float mat[4][4], float *scale);
 
-ParticleThread *psys_threads_create(struct ParticleSimulationData *sim);
-void psys_threads_free(ParticleThread *threads);
+void psys_thread_context_init(struct ParticleThreadContext *ctx, struct ParticleSimulationData *sim);
+void psys_tasks_create(struct ParticleThreadContext *ctx, int totpart, struct ParticleTask **r_tasks, int *r_numtasks);
+void psys_tasks_free(struct ParticleTask *tasks, int numtasks);
 
 void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3], float zvec[3], float center[3]);
 void psys_apply_hair_lattice(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys);
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 300288a..ac4de54 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -53,6 +53,7 @@
 #include "BLI_utildefines.h"
 #include "BLI_kdtree.h"
 #include "BLI_rand.h"
+#include "BLI_task.h"
 #include "BLI_threads.h"
 #include "BLI_linklist.h"
 
@@ -2440,17 +2441,15 @@ static void get_strand_normal(Material *ma, const float surfnor[3], float surfdi
 	copy_v3_v3(nor, vnor);
 }
 
-static int psys_threads_init_path(ParticleThread *threads, Scene *scene, float cfra, int editupdate)
+static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSimulationData *sim, Scene *scene, float cfra, int editupdate)
 {
-	ParticleThreadContext *ctx = threads[0].ctx;
-/*	Object *ob = ctx->sim.ob; */
-	ParticleSystem *psys = ctx->sim.psys;
+	ParticleSystem *psys = sim->psys;
 	ParticleSettings *part = psys->part;
-/*	ParticleEditSettings *pset = &scene->toolsettings->particle; */
 	int totparent = 0, between = 0;
-	int steps = (int)pow(2.0, (double)part->draw_step);
+	int steps = 1 << part->draw_step;
 	int totchild = psys->totchild;
-	int i, seed, totthread = threads[0].tot;
+
+	psys_thread_context_init(ctx, sim);
 
 	/*---start figuring out what is actually wanted---*/
 	if (psys_in_edit_mode(scene, psys)) {
@@ -2459,7 +2458,7 @@ static int psys_threads_init_path(ParticleThread *threads, Scene *scene, float c
 		if (psys->renderdata == 0 && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0)
 			totchild = 0;
 
-		steps = (int)pow(2.0, (double)pset->draw_step);
+		steps = 1 << pset->draw_step;
 	}
 
 	if (totchild && part->childtype == PART_CHILD_FACES) {
@@ -2479,18 +2478,8 @@ static int psys_threads_init_path(ParticleThread *threads, Scene *scene, float c
 		totparent = MIN2(totparent, totchild);
 	}
 
-	if (totchild == 0) return 0;
-
-	/* init random number generator */
-	seed = 31415926 + ctx->sim.psys->seed;
-	
-	if (ctx->editupdate || totchild < 10000)
-		totthread = 1;
-	
-	for (i = 0; i < totthread; i++) {
-		threads[i].rng_path = BLI_rng_new(seed);
-		threads[i].tot = totthread;
-	}
+	if (totchild == 0)
+		return false;
 
 	/* fill context values */
 	ctx->between = between;
@@ -2513,21 +2502,21 @@ static int psys_threads_init_path(ParticleThread *threads, Scene *scene, float c
 	if (psys->part->flag & PART_CHILD_EFFECT)
 		ctx->vg_effector = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_EFFECTOR);
 
-	/* set correct ipo timing */
-#if 0 // XXX old animation system
-	if (part->flag & PART_ABS_TIME && part->ipo) {
-		calc_ipo(part->ipo, cfra);
-		execute_ipo((ID *)part, part->ipo);
-	}
-#endif // XXX old animation system
+	return true;
+}
 
-	return 1;
+static void psys_task_init_path(ParticleTask *task, ParticleSimulationData *sim)
+{
+	/* init random number generator */
+	int seed = 31415926 + sim->psys->seed;
+	
+	task->rng_path = BLI_rng_new(seed);
 }
 
 /* note: this function must be thread safe, except for branching! */
-static void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, ParticleCacheKey *child_keys, int i)
+static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cpa, ParticleCacheKey *child_keys, int i)
 {
-	ParticleThreadContext *ctx = thread->ctx;
+	ParticleThreadContext *ctx = task->ctx;
 	Object *ob = ctx->sim.ob;
 	ParticleSystem *psys = ctx->sim.psys;
 	ParticleSettings *part = psys->part;
@@ -2793,89 +2782,80 @@ static void psys_thread_create_path(ParticleThread *thread, struct ChildParticle
 		child_keys->steps = -1;
 }
 
-static void *exec_child_path_cache(void *data)
+static void exec_child_path_cache(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
 {
-	ParticleThread *thread = (ParticleThread *)data;
-	ParticleThreadContext *ctx = thread->ctx;
+	ParticleTask *task = taskdata;
+	ParticleThreadContext *ctx = task->ctx;
 	ParticleSystem *psys = ctx->sim.psys;
 	ParticleCacheKey **cache = psys->childcache;
 	ChildParticle *cpa;
-	int i, totchild = ctx->totchild, first = 0;
+	int i;
 
-	if (thread->tot > 1) {
-		first = ctx->parent_pass ? 0 : ctx->totparent;
-		totchild = ctx->parent_pass ? ctx->totparent : ctx->totchild;
+	cpa = psys->child + task->begin;
+	for (i = task->begin; i < task->end; ++i, ++cpa) {
+		psys_thread_create_path(task, cpa, cache[i], i);
 	}
-	
-	cpa = psys->child + first + thread->num;
-	for (i = first + thread->num; i < totchild; i += thread->tot, cpa += thread->tot)
-		psys_thread_create_path(thread, cpa, cache[i], i);
-
-	return 0;
 }
 
 void psys_cache_child_paths(ParticleSimulationData *sim, float cfra, int editupdate)
 {
-	ParticleThread *pthreads;
-	ParticleThreadContext *ctx;
-	ListBase threads;
-	int i, totchild, totparent, totthread;
-
+	TaskScheduler *task_scheduler;
+	TaskPool *task_pool;
+	ParticleThreadContext ctx;
+	ParticleTask *tasks_parent, *tasks_child;
+	int numtasks_parent, numtasks_child;
+	int i, totchild, totparent;
+	
 	if (sim->psys->flag & PSYS_GLOBAL_HAIR)
 		return;
-
-	pthreads = psys_threads_create(sim);
-
-	if (!psys_threads_init_path(pthreads, sim->scene, cfra, editupdate)) {
-		psys_threads_free(pthreads);
+	
+	/* create a task pool for child path tasks */
+	if (!psys_thread_context_init_path(&ctx, sim, sim->scene, cfra, editupdate))
 		return;
-	}
-
-	ctx = pthreads[0].ctx;
-	totchild = ctx->totchild;
-	totparent = ctx->totparent;
-
+	
+	task_scheduler = BLI_task_scheduler_get();
+	task_pool = BLI_task_pool_create(task_scheduler, &ctx);
+	totchild = ctx.totchild;
+	totparent = ctx.totparent;
+	
 	if (editupdate && sim->psys->childcache && totchild == sim->psys->totchildcache) {
 		; /* just overwrite the existing cache */
 	}
 	else {
 		/* clear out old and create new empty path cache */
 		free_child_path_cache(sim->psys);
-		sim->psys->childcache = psys_alloc_path_cache_buffers(&sim->psys->childcachebufs, totchild, ctx->steps + 1);
+		sim->psys->childcache = psys_alloc_path_cache_buffers(&sim->psys->childcachebufs, totchild, ctx.steps + 1);
 		sim->psys->totchildcache = totchild;
 	}
-
-	totthread = pthreads[0].tot;
-
-	if (totthread > 1) {
-
-		/* make virtual child parents thread safe by calculating them first */
-		if (totparent) {
-			BLI_init_threads(&threads, exec_child_path_cache, totthread);
-			
-			for (i = 0; i < totthread; i++) {
-				pthreads[i].ctx->parent_pass = 1;
-				BLI_insert_thread(&threads, &pthreads[i]);
-			}
-
-			BLI_end_threads(&threads);
-
-			for (i = 0; i < totthread; i++)
-				pthreads[i].ctx->parent_pass = 0;
-		}
-
-		BLI_init_threads(&threads, exec_child_path_cache, totthread);
-
-		for (i = 0; i < totthread; i++)
-			BLI_insert_thread(&threads, &pthreads[i]);
-
-		BLI_end_threads(&threads);
+	
+	/* cache parent paths */
+	ctx.parent_pass = 1;
+	psys_tasks_create(&ctx, totparent, &tasks_parent, &numtasks_parent);
+	for (i = 0; i < numtasks_parent; ++i) {
+		ParticleTask *task = &tasks_parent[i];
+		
+		psys_task_init_path(task, sim);
+		BLI_task_pool_push(task_pool, exec_child_path_cache, task, false, TASK_PRIORITY_LOW);
 	}
-	else
-		exec_child_path_cache(&pthreads[0]);
+	BLI_task_pool_work_and_wait(task_pool);
+	
+	/* cache child paths */
+	ctx.parent_pass = 0;
+	psys_tasks_create(&ctx, totchild, &tasks_child, &numtasks_child);
+	for (i = 0; i < numtasks_child; ++i) {
+		ParticleTask *task = &tasks_child[i];
+		
+		psys_task_init_path(task, sim);
+		BLI_task_pool_push(task_pool, exec_child_path_cache, task, false, TASK_PRIORITY_LOW);
+	}
+	BLI_task_pool_work_and_wait(task_pool);
 
-	psys_threads_free(pthreads);
+	BLI_task_pool_free(task_pool);
+	
+	psys_tasks_free(tasks_parent, numtasks_parent);
+	psys_tasks_free(tasks_child, numtasks_child);
 }
+
 /* figure out incremental rotations along path starting from unit quat */
 static void cache_key_incremental_rotation(ParticleCacheKey *key0, ParticleCacheKey *key1, ParticleCacheKey *key2, float *prev_tangent, int i)
 {
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index bb9ab99..d087ae8 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -68,6 +68,7 @@
 #include "BLI_kdtree.h"
 #include "BLI_kdopbvh.h"
 #include "BLI_sort.h"
+#include "BLI_task.h"
 #include "BLI_threads.h"
 #include "BLI_linklist.h"
 
@@ -789,7 +790,7 @@ static int distribute_binary_search(float *sum, int n, float value)
 
 /* note: this function must be thread safe, for from == PART_FROM_CHILD */
 #define ONLY_WORKING_WITH_PA_VERTS 0
-static void distribute_threads_exec(ParticleThread *thread, ParticleData *pa, ChildParticle *cpa,

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list