[Bf-blender-cvs] [e3b80d62025] strand_editmode: Multithreading support for the mesh sampling library.

Lukas Tönne noreply at git.blender.org
Sun Aug 20 19:57:53 CEST 2017


Commit: e3b80d620250b3229359efe7e195fa8e7886f57a
Author: Lukas Tönne
Date:   Sun Aug 20 18:50:58 2017 +0100
Branches: strand_editmode
https://developer.blender.org/rBe3b80d620250b3229359efe7e195fa8e7886f57a

Multithreading support for the mesh sampling library.

Samples can be generated either one-by-one using the existing "make_sample"
function (which uses a default context), or use the more efficient batch
generation functions. These optionally support threading via the task scheduler
now.

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

M	source/blender/blenkernel/BKE_mesh_sample.h
M	source/blender/blenkernel/intern/mesh_sample.c
M	source/blender/editors/hair/hair_stroke.c

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

diff --git a/source/blender/blenkernel/BKE_mesh_sample.h b/source/blender/blenkernel/BKE_mesh_sample.h
index 377f0c2c182..4721e0aae2d 100644
--- a/source/blender/blenkernel/BKE_mesh_sample.h
+++ b/source/blender/blenkernel/BKE_mesh_sample.h
@@ -36,7 +36,9 @@ struct MeshSampleGenerator;
 
 typedef struct MeshSampleGenerator MeshSampleGenerator;
 typedef float (*MeshSampleVertexWeightFp)(struct DerivedMesh *dm, struct MVert *vert, unsigned int index, void *userdata);
-typedef bool (*MeshSampleRayFp)(void *userdata, float ray_start[3], float ray_end[3]);
+typedef void* (*MeshSampleThreadContextCreateFp)(void *userdata, int start);
+typedef void (*MeshSampleThreadContextFreeFp)(void *userdata, void *thread_ctx);
+typedef bool (*MeshSampleRayFp)(void *userdata, void *thread_ctx, float ray_start[3], float ray_end[3]);
 
 /* ==== Evaluate ==== */
 
@@ -55,16 +57,33 @@ struct MeshSampleGenerator *BKE_mesh_sample_gen_surface_vertices(struct DerivedM
 /* face_weights is optional */
 struct MeshSampleGenerator *BKE_mesh_sample_gen_surface_random(struct DerivedMesh *dm, unsigned int seed);
 struct MeshSampleGenerator *BKE_mesh_sample_gen_surface_random_ex(struct DerivedMesh *dm, unsigned int seed,
-                                                                      MeshSampleVertexWeightFp vertex_weight_cb, void *userdata, bool use_facearea);
+                                                                  MeshSampleVertexWeightFp vertex_weight_cb, void *userdata, bool use_facearea);
 
-struct MeshSampleGenerator *BKE_mesh_sample_gen_surface_raycast(struct DerivedMesh *dm, MeshSampleRayFp ray_cb, void *userdata);
+struct MeshSampleGenerator *BKE_mesh_sample_gen_surface_raycast(
+        struct DerivedMesh *dm,
+        MeshSampleThreadContextCreateFp thread_context_create_cb,
+        MeshSampleThreadContextFreeFp thread_context_free_cb,
+        MeshSampleRayFp ray_cb,
+        void *userdata);
 
 struct MeshSampleGenerator *BKE_mesh_sample_gen_volume_random_bbray(struct DerivedMesh *dm, unsigned int seed, float density);
 
 void BKE_mesh_sample_free_generator(struct MeshSampleGenerator *gen);
 
+/* Generate a single sample.
+ * Not threadsafe!
+ */
 bool BKE_mesh_sample_generate(struct MeshSampleGenerator *gen, struct MeshSample *sample);
 
+/* Generate a large number of samples.
+ */
+int BKE_mesh_sample_generate_batch_ex(struct MeshSampleGenerator *gen,
+                                      void *output_buffer, int output_stride, int count,
+                                      bool use_threads);
+
+int BKE_mesh_sample_generate_batch(struct MeshSampleGenerator *gen,
+                                   MeshSample *output_buffer, int count);
+
 /* ==== Utilities ==== */
 
 struct ParticleSystem;
diff --git a/source/blender/blenkernel/intern/mesh_sample.c b/source/blender/blenkernel/intern/mesh_sample.c
index 9f8541d4dfb..f0c91e5d465 100644
--- a/source/blender/blenkernel/intern/mesh_sample.c
+++ b/source/blender/blenkernel/intern/mesh_sample.c
@@ -33,6 +33,7 @@
 #include "BLI_utildefines.h"
 #include "BLI_math.h"
 #include "BLI_rand.h"
+#include "BLI_task.h"
 
 #include "BKE_bvhutils.h"
 #include "BKE_mesh_sample.h"
@@ -41,6 +42,8 @@
 
 #include "BLI_strict_flags.h"
 
+#define DEFAULT_TASK_SIZE 1024
+
 /* ==== Evaluate ==== */
 
 bool BKE_mesh_sample_is_volume_sample(const MeshSample *sample)
@@ -174,18 +177,34 @@ BLI_INLINE void mesh_sample_weights_from_loc(MeshSample *sample, DerivedMesh *dm
 /* ==== Sampling ==== */
 
 typedef void (*GeneratorFreeFp)(struct MeshSampleGenerator *gen);
-typedef bool (*GeneratorMakeSampleFp)(struct MeshSampleGenerator *gen, struct MeshSample *sample);
+typedef void* (*GeneratorThreadContextCreateFp)(const struct MeshSampleGenerator *gen, int start);
+typedef void (*GeneratorThreadContextFreeFp)(const struct MeshSampleGenerator *gen, void *thread_ctx);
+typedef bool (*GeneratorMakeSampleFp)(const struct MeshSampleGenerator *gen, void *thread_ctx, struct MeshSample *sample);
 
 typedef struct MeshSampleGenerator
 {
 	GeneratorFreeFp free;
+	GeneratorThreadContextCreateFp thread_context_create;
+	GeneratorThreadContextFreeFp thread_context_free;
 	GeneratorMakeSampleFp make_sample;
+	
+	void *default_ctx;
+	int task_size;
 } MeshSampleGenerator;
 
-static void sample_generator_init(MeshSampleGenerator *gen, GeneratorFreeFp free, GeneratorMakeSampleFp make_sample)
+static void sample_generator_init(MeshSampleGenerator *gen,
+                                  GeneratorFreeFp free,
+                                  GeneratorThreadContextCreateFp thread_context_create,
+                                  GeneratorThreadContextFreeFp thread_context_free,
+                                  GeneratorMakeSampleFp make_sample)
 {
 	gen->free = free;
+	gen->thread_context_create = thread_context_create;
+	gen->thread_context_free = thread_context_free;
 	gen->make_sample = make_sample;
+	
+	gen->default_ctx = NULL;
+	gen->task_size = DEFAULT_TASK_SIZE;
 }
 
 /* ------------------------------------------------------------------------- */
@@ -195,7 +214,6 @@ typedef struct MSurfaceSampleGenerator_Vertices {
 	
 	DerivedMesh *dm;
 	int (*vert_loop_map)[3];
-	int cur_vert;
 } MSurfaceSampleGenerator_Vertices;
 
 static void generator_vertices_free(MSurfaceSampleGenerator_Vertices *gen)
@@ -206,14 +224,28 @@ static void generator_vertices_free(MSurfaceSampleGenerator_Vertices *gen)
 	MEM_freeN(gen);
 }
 
-static bool generator_vertices_make_sample(MSurfaceSampleGenerator_Vertices *gen, MeshSample *sample)
+static void* generator_vertices_thread_context_create(const MSurfaceSampleGenerator_Vertices *UNUSED(gen), int start)
+{
+	int *cur_vert = MEM_callocN(sizeof(int), "generator_vertices_thread_context");
+	*cur_vert = start;
+	return cur_vert;
+}
+
+static void generator_vertices_thread_context_free(const MSurfaceSampleGenerator_Vertices *UNUSED(gen), void *thread_ctx)
+{
+	MEM_freeN(thread_ctx);
+}
+
+static bool generator_vertices_make_sample(const MSurfaceSampleGenerator_Vertices *gen, void *thread_ctx, MeshSample *sample)
 {
 	DerivedMesh *dm = gen->dm;
 	const int num_verts = dm->getNumVerts(dm);
 	const MLoop *mloops = dm->getLoopArray(dm);
 	
-	while (gen->cur_vert < num_verts) {
-		int cur_vert = gen->cur_vert++;
+	int cur_vert = *(int *)thread_ctx;
+	bool found_vert = false;
+	while (cur_vert < num_verts) {
+		++cur_vert;
 		
 		const int *loops = gen->vert_loop_map[cur_vert];
 		if (loops[0] >= 0) {
@@ -231,10 +263,13 @@ static bool generator_vertices_make_sample(MSurfaceSampleGenerator_Vertices *gen
 			sample->orig_weights[1] = 0.0f;
 			sample->orig_weights[2] = 0.0f;
 
-			return true;
+			found_vert = true;
+			break;
 		}
 	}
-	return false;
+	
+	*(int *)thread_ctx = cur_vert;
+	return found_vert;
 }
 
 MeshSampleGenerator *BKE_mesh_sample_gen_surface_vertices(DerivedMesh *dm)
@@ -244,10 +279,13 @@ MeshSampleGenerator *BKE_mesh_sample_gen_surface_vertices(DerivedMesh *dm)
 	DM_ensure_normals(dm);
 	
 	gen = MEM_callocN(sizeof(MSurfaceSampleGenerator_Vertices), "MSurfaceSampleGenerator_Vertices");
-	sample_generator_init(&gen->base, (GeneratorFreeFp)generator_vertices_free, (GeneratorMakeSampleFp)generator_vertices_make_sample);
+	sample_generator_init(&gen->base,
+	                      (GeneratorFreeFp)generator_vertices_free,
+	                      (GeneratorThreadContextCreateFp)generator_vertices_thread_context_create,
+	                      (GeneratorThreadContextFreeFp)generator_vertices_thread_context_free,
+	                      (GeneratorMakeSampleFp)generator_vertices_make_sample);
 	
 	gen->dm = dm;
-	gen->cur_vert = 0;
 	
 	{
 		const int num_verts = dm->getNumVerts(dm);
@@ -292,7 +330,7 @@ typedef struct MSurfaceSampleGenerator_Random {
 	MeshSampleGenerator base;
 	
 	DerivedMesh *dm;
-	RNG *rng;
+	unsigned int seed;
 	float *tri_weights;
 	float *vertex_weights;
 	
@@ -327,11 +365,21 @@ static void generator_random_free(MSurfaceSampleGenerator_Random *gen)
 		MEM_freeN(gen->tri_weights);
 	if (gen->vertex_weights)
 		MEM_freeN(gen->vertex_weights);
-	if (gen->rng)
-		BLI_rng_free(gen->rng);
 	MEM_freeN(gen);
 }
 
+static void* generator_random_thread_context_create(const MSurfaceSampleGenerator_Random *gen, int start)
+{
+	RNG *rng = BLI_rng_new(gen->seed);
+	BLI_rng_skip(rng, start);
+	return rng;
+}
+
+static void generator_random_thread_context_free(const MSurfaceSampleGenerator_Random *UNUSED(gen), void *thread_ctx)
+{
+	BLI_rng_free(thread_ctx);
+}
+
 /* Find the index in "sum" array before "value" is crossed. */
 BLI_INLINE int weight_array_binary_search(const float *sum, int size, float value)
 {
@@ -357,10 +405,10 @@ BLI_INLINE int weight_array_binary_search(const float *sum, int size, float valu
 	return low;
 }
 
-static bool generator_random_make_sample(MSurfaceSampleGenerator_Random *gen, MeshSample *sample)
+static bool generator_random_make_sample(const MSurfaceSampleGenerator_Random *gen, void *thread_ctx, MeshSample *sample)
 {
 	DerivedMesh *dm = gen->dm;
-	RNG *rng = gen->rng;
+	RNG *rng = thread_ctx;
 	const MLoop *mloops = dm->getLoopArray(dm);
 	const MLoopTri *mtris = dm->getLoopTriArray(dm);
 	int tottris = dm->getNumLoopTri(dm);
@@ -430,10 +478,14 @@ MeshSampleGenerator *BKE_mesh_sample_gen_surface_random_ex(DerivedMesh *dm, unsi
 	DM_ensure_normals(dm);
 	
 	gen = MEM_callocN(sizeof(MSurfaceSampleGenerator_Random), "MSurfaceSampleGenerator_Random");
-	sample_generator_init(&gen->base, (GeneratorFreeFp)generator_random_free, (GeneratorMakeSampleFp)generator_random_make_sample);
+	sample_generator_init(&gen->base,
+	                      (GeneratorFreeFp)generator_random_free,
+	                      (GeneratorThreadContextCreateFp)generator_random_thread_context_create,
+	                      (GeneratorThreadContextFreeFp)generator_random_thread_context_free,
+	                      (GeneratorMakeSampleFp)generator_random_make_sample);
 	
 	gen->dm = dm;
-	gen->rng = BLI_rng_new(seed);
+	gen->seed = seed;
 	
 	if (use_facearea) {
 		int numtris = dm->getNumLoopTri(dm);
@@ -488,6 +540,8 @@ typedef struct MSurfaceSampleGenerator_RayCast {
 	BVHTreeFromMesh bvhdata;
 	
 	MeshSampleRayFp ray_cb;
+	MeshSampleThreadContextCreateFp thread_context_create_cb;
+	MeshSampleThreadContex

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list