[Bf-blender-cvs] [cb1d57f0f7e] soc-2018-npr: Added a multithreaded variant of split ff bb

Sebastian Parborg noreply at git.blender.org
Thu Aug 9 09:41:59 CEST 2018


Commit: cb1d57f0f7e950afd4fda46637ca4832f79752bd
Author: Sebastian Parborg
Date:   Mon Aug 6 23:57:43 2018 +0200
Branches: soc-2018-npr
https://developer.blender.org/rBcb1d57f0f7e950afd4fda46637ca4832f79752bd

Added a multithreaded variant of split ff bb

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

M	source/blender/modifiers/intern/MOD_mybmesh.c

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

diff --git a/source/blender/modifiers/intern/MOD_mybmesh.c b/source/blender/modifiers/intern/MOD_mybmesh.c
index e67070ae7dc..f5ad53fdb4e 100644
--- a/source/blender/modifiers/intern/MOD_mybmesh.c
+++ b/source/blender/modifiers/intern/MOD_mybmesh.c
@@ -48,6 +48,8 @@
 #include "BLI_gsqueue.h"
 #include "BLI_memarena.h"
 #include "BLI_rand.h"
+#include "BLI_listbase.h"
+#include "BLI_threads.h"
 
 #include "BKE_library_query.h"
 #include "BKE_modifier.h"
@@ -420,6 +422,211 @@ static void get_uv_point(BMFace *face, float uv[2], const float point_v2[2], con
 
 }
 
+typedef struct FFBB_thread_data {
+	//Shared data
+	MeshData *m_d;
+	BMEdge **edges;
+	int orig_edges;
+	float *step_arr;
+
+	int cur_e;
+	int tot_e;
+	SpinLock spin;
+} FFBB_thread_data;
+
+static int FFBB_queue_next_e(FFBB_thread_data *queue)
+{
+	int edge_idx = -1;
+
+	BLI_spin_lock(&queue->spin);
+	if (queue->cur_e < queue->tot_e) {
+		edge_idx = queue->cur_e;
+		queue->cur_e++;
+	}
+	BLI_spin_unlock(&queue->spin);
+
+	return edge_idx;
+}
+
+static void split_BB_FF_edges_thread(void *data_v) {
+	//Split BB,FF edges if they have sign crossings
+    FFBB_thread_data *th_data = (FFBB_thread_data *)data_v;
+	MeshData *m_d = th_data->m_d;
+
+	int i, face_index;
+	BMIter iter_f;
+	BMEdge *e;
+	BMFace *f;
+	BMVert *v1, *v2;
+	float v1_u, v1_v, v2_u, v2_v;
+	bool is_B;
+
+	while ((i = FFBB_queue_next_e(th_data)) >= 0) {
+		Vert_buf v_buf;
+		e = th_data->edges[i];
+
+		is_B = calc_if_B_nor(m_d->cam_loc, e->v1->co, e->v1->no);
+
+		if( is_B  != calc_if_B_nor(m_d->cam_loc, e->v2->co, e->v2->no) ){
+			//This is not a FF or BB edge
+			continue;
+		}
+
+		if( i < th_data->orig_edges ){
+			//This edge exists on the original mesh
+			//TODO why do I have to use find? Segfault otherwise...
+			//remember to replace the rest of "at_index"
+			//why is table_ensure not fixing the assert?
+			BMEdge *orig_e = BM_edge_at_index_find(m_d->bm_orig, i);
+
+			//Get face connected to edge from orig mesh
+			//TODO is it wise to use BM_ITER_ELEM here?
+			BM_ITER_ELEM (f, &iter_f, orig_e, BM_FACES_OF_EDGE) {
+				//Get first face
+				break;
+			}
+
+			face_index = BM_elem_index_get(f);
+
+			v1 = orig_e->v1;
+			v2 = orig_e->v2;
+
+			v_buf.orig_edge = orig_e;
+			v_buf.orig_face = f;
+		} else {
+			BMVert *vert_arr[2];
+
+			//This should be safe because the vert count is still the same as the original mesh.
+			v1 = BLI_ghash_lookup(m_d->vert_hash, e->v1);
+			v2 = BLI_ghash_lookup(m_d->vert_hash, e->v2);
+
+			vert_arr[0] = v1;
+			vert_arr[1] = v2;
+
+			//TODO add checks if to hande if there is no face
+			BLI_spin_lock(&th_data->spin);
+			f = BM_face_exists_overlap(vert_arr, 2);
+			face_index = BM_elem_index_get(f);
+			BLI_spin_unlock(&th_data->spin);
+
+			v_buf.orig_edge = NULL;
+			v_buf.orig_face = f;
+		}
+
+		//TODO can I just check each vert once?
+		get_uv_coord(v1, f, &v1_u, &v1_v);
+		get_uv_coord(v2, f, &v2_u, &v2_v);
+		{
+			int i;
+			float u, v;
+			float P[3], du[3], dv[3];
+
+			if( v1_u == v2_u ){
+				u = v1_u;
+
+				for(i=0; i < 10; i++){
+					v = th_data->step_arr[i];
+					m_d->eval->evaluateLimit(m_d->eval, face_index, u, v, P, du, dv);
+					if( calc_if_B(m_d->cam_loc, P, du, dv) != is_B ){
+						BLI_spin_lock(&th_data->spin);
+						split_edge_and_move_vert(m_d->bm, e, P, du, dv);
+						v_buf.u = u;
+						v_buf.v = v;
+						BLI_buffer_append(m_d->new_vert_buffer, Vert_buf, v_buf);
+						BLI_spin_unlock(&th_data->spin);
+						break;
+					}
+				}
+			} else if ( v1_v == v2_v ){
+				v = v1_v;
+
+				for(i=0; i < 10; i++){
+					u = th_data->step_arr[i];
+					m_d->eval->evaluateLimit(m_d->eval, face_index, u, v, P, du, dv);
+					if( calc_if_B(m_d->cam_loc, P, du, dv) != is_B ){
+						BLI_spin_lock(&th_data->spin);
+						split_edge_and_move_vert(m_d->bm, e, P, du, dv);
+						v_buf.u = u;
+						v_buf.v = v;
+						BLI_buffer_append(m_d->new_vert_buffer, Vert_buf, v_buf);
+						BLI_spin_unlock(&th_data->spin);
+						break;
+					}
+				}
+			} else {
+				bool alt_diag;
+				if((v1_u == 0 && v1_v == 0) || (v2_u == 0 && v2_v == 0)){
+					alt_diag = false;
+				} else {
+					alt_diag = true;
+				}
+				for(i=0; i < 10; i++){
+					if(alt_diag){
+						u = 1.0f - th_data->step_arr[i];
+					} else {
+						u = th_data->step_arr[i];
+					}
+
+					v = th_data->step_arr[i];
+					m_d->eval->evaluateLimit(m_d->eval, face_index, u, v, P, du, dv);
+					if( calc_if_B(m_d->cam_loc, P, du, dv) != is_B ){
+						BLI_spin_lock(&th_data->spin);
+						split_edge_and_move_vert(m_d->bm, e, P, du, dv);
+						v_buf.u = u;
+						v_buf.v = v;
+						BLI_buffer_append(m_d->new_vert_buffer, Vert_buf, v_buf);
+						BLI_spin_unlock(&th_data->spin);
+						break;
+					}
+				}
+			}
+		}
+
+	}
+
+}
+
+static void split_BB_FF_edges_thread_start(MeshData *m_d){
+	int orig_edges = BM_mesh_elem_count(m_d->bm_orig, BM_EDGE);
+
+	void    *edge_stack[BM_DEFAULT_ITER_STACK_SIZE];
+	int      edge_len;
+	BMEdge **edges = BM_iter_as_arrayN(m_d->bm, BM_EDGES_OF_MESH, NULL, &edge_len,
+	                                   edge_stack, BM_DEFAULT_ITER_STACK_SIZE);
+
+	//Do 10 samples but don't check end and start point
+	float step = 1.0f/11.0f;
+	float step_arr[] = { step*5.0f, step*6.0f, step*4.0f, step*7.0f, step*3.0f,
+		step*8.0f, step*2.0f, step*9.0f, step*1.0f, step*10.0f };
+
+	FFBB_thread_data th_data;
+	th_data.m_d = m_d;
+	th_data.edges = edges;
+	th_data.orig_edges = orig_edges;
+	th_data.step_arr = step_arr;
+
+	th_data.cur_e = 0;
+	th_data.tot_e = edge_len;
+
+	ListBase threads;
+	int tot_thread = BLI_system_thread_count();
+
+	BLI_threadpool_init(&threads, split_BB_FF_edges_thread, tot_thread);
+
+	BLI_spin_init(&th_data.spin);
+
+	/* fill in threads handles */
+	for (int i = 0; i < tot_thread; i++) {
+		BLI_threadpool_insert(&threads, &th_data);
+	}
+
+	BLI_threadpool_end(&threads);
+
+	BLI_spin_end(&th_data.spin);
+
+	MEM_freeN(edges);
+}
+
 static void split_BB_FF_edges(MeshData *m_d) {
 	//Split BB,FF edges if they have sign crossings
 
@@ -446,8 +653,6 @@ static void split_BB_FF_edges(MeshData *m_d) {
 			break;
 		}
 
-		//TODO perhaps we need to use the limit surface normal
-
 		is_B = calc_if_B_nor(m_d->cam_loc, e->v1->co, e->v1->no);
 
 		if( is_B  != calc_if_B_nor(m_d->cam_loc, e->v2->co, e->v2->no) ){
@@ -498,27 +703,6 @@ static void split_BB_FF_edges(MeshData *m_d) {
 		get_uv_coord(v1, f, &v1_u, &v1_v);
 		get_uv_coord(v2, f, &v2_u, &v2_v);
 
-		//TODO perhaps we need to check the limit normal and not the vertex normal?
-		//EDIT: If we update the vert normals in the step were we move them to their
-		//limit pos, we don't need to relalc it here.
-		//TODO Make sure you can skip the move to vert step later
-		/*
-		{
-			float P1[3], P2[3], du[3], dv[3];
-			//is this a FF or BB edge?
-			m_d->eval->evaluateLimit(m_d->eval, face_index, v1_u, v1_v, P1, du, dv);
-
-			is_B = calc_if_B(m_d->cam_loc, P1, du, dv);
-
-			m_d->eval->evaluateLimit(m_d->eval, face_index, v2_u, v2_v, P2, du, dv);
-
-			if( is_B  != calc_if_B(m_d->cam_loc, P2, du, dv) ){
-				//FB edge, we only want to split FF or BB
-				//Skip to next edge
-				continue;
-			}
-		}
-		*/
 		{
 			int i;
 			float u, v;
@@ -1344,7 +1528,6 @@ static void contour_insertion( MeshData *m_d ) {
 			}
 		}
 
-		//TODO perhaps we need to use the limit surface normal
 		if( calc_if_B_nor(m_d->cam_loc, e->v1->co, e->v1->no) == calc_if_B_nor(m_d->cam_loc, e->v2->co, e->v2->no) ){
 			//This is not a FB or BF edge
 			continue;
@@ -2911,6 +3094,7 @@ static void optimization( MeshData *m_d ){
 				BM_ITER_ELEM (face, &iter_f, vert, BM_FACES_OF_VERT) {
 					//TODO mark inconsistent faces in an other way
 					// and only check each face once
+					// look at BM_face_exists_overlap for marks
 					if(face->mat_nr == 5){
 						//Already added this face to inco_faces
 						continue;
@@ -4254,7 +4438,8 @@ static Mesh *mybmesh_do(Mesh *mesh, MyBMeshModifierData *mmd, float cam_loc[3])
 
 		if (mmd->flag & MOD_MYBMESH_FF_SPLIT) {
 			TIMEIT_START(split_bb_ff);
-			split_BB_FF_edges(&mesh_data);
+			split_BB_FF_edges_thread_start(&mesh_data);
+			//split_BB_FF_edges(&mesh_data);
 			TIMEIT_END(split_bb_ff);
 		}
 		// (6.2) Contour Insertion



More information about the Bf-blender-cvs mailing list