[Bf-blender-cvs] [6974b69] master: Cycles: optimization for hair BVH build, allow max 2 hair curves per leaf.

Brecht Van Lommel noreply at git.blender.org
Tue Apr 22 17:25:30 CEST 2014


Commit: 6974b69c61729cc80a72d78f02eb137c5097b129
Author: Brecht Van Lommel
Date:   Tue Apr 22 16:54:02 2014 +0200
https://developer.blender.org/rB6974b69c61729cc80a72d78f02eb137c5097b129

Cycles: optimization for hair BVH build, allow max 2 hair curves per leaf.

This gives me 14% reduction in render time for koro_final.blend.

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

M	intern/cycles/bvh/bvh_build.cpp
M	intern/cycles/bvh/bvh_build.h
M	intern/cycles/bvh/bvh_params.h
M	intern/cycles/bvh/bvh_split.cpp
M	intern/cycles/bvh/bvh_split.h

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

diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp
index 9367e7b..eb4cca9 100644
--- a/intern/cycles/bvh/bvh_build.cpp
+++ b/intern/cycles/bvh/bvh_build.cpp
@@ -298,18 +298,41 @@ void BVHBuild::thread_build_node(InnerNode *inner, int child, BVHObjectBinning *
 	}
 }
 
+bool BVHBuild::range_within_max_leaf_size(const BVHRange& range)
+{
+	size_t size = range.size();
+	size_t max_leaf_size = max(params.max_triangle_leaf_size, params.max_curve_leaf_size);
+
+	if(size > max_leaf_size)
+		return false;
+	
+	size_t num_triangles = 0;
+	size_t num_curves = 0;
+
+	for(int i = 0; i < size; i++) {
+		BVHReference& ref = references[range.start() + i];
+
+		if(ref.prim_type() & PRIMITIVE_ALL_CURVE)
+			num_curves++;
+		else if(ref.prim_type() & PRIMITIVE_ALL_TRIANGLE)
+			num_triangles++;
+	}
+
+	return (num_triangles < params.max_triangle_leaf_size) && (num_curves < params.max_curve_leaf_size);
+}
+
 /* multithreaded binning builder */
 BVHNode* BVHBuild::build_node(const BVHObjectBinning& range, int level)
 {
 	size_t size = range.size();
-	float leafSAH = params.sah_triangle_cost * range.leafSAH;
-	float splitSAH = params.sah_node_cost * range.bounds().half_area() + params.sah_triangle_cost * range.splitSAH;
+	float leafSAH = params.sah_primitive_cost * range.leafSAH;
+	float splitSAH = params.sah_node_cost * range.bounds().half_area() + params.sah_primitive_cost * range.splitSAH;
 
 	/* have at least one inner node on top level, for performance and correct
 	 * visibility tests, since object instances do not check visibility flag */
 	if(!(range.size() > 0 && params.top_level && level == 0)) {
 		/* make leaf node when threshold reached or SAH tells us */
-		if(params.small_enough_for_leaf(size, level) || (size <= params.max_leaf_size && leafSAH < splitSAH))
+		if(params.small_enough_for_leaf(size, level) || (range_within_max_leaf_size(range) && leafSAH < splitSAH))
 			return create_leaf_node(range);
 	}
 
diff --git a/intern/cycles/bvh/bvh_build.h b/intern/cycles/bvh/bvh_build.h
index ba10eb4..a6b9916 100644
--- a/intern/cycles/bvh/bvh_build.h
+++ b/intern/cycles/bvh/bvh_build.h
@@ -70,6 +70,8 @@ protected:
 	BVHNode *create_leaf_node(const BVHRange& range);
 	BVHNode *create_object_leaf_nodes(const BVHReference *ref, int start, int num);
 
+	bool range_within_max_leaf_size(const BVHRange& range);
+
 	/* threads */
 	enum { THREAD_TASK_SIZE = 4096 };
 	void thread_build_node(InnerNode *node, int child, BVHObjectBinning *range, int level);
diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h
index 3e93c0c..ed67690 100644
--- a/intern/cycles/bvh/bvh_params.h
+++ b/intern/cycles/bvh/bvh_params.h
@@ -33,11 +33,12 @@ public:
 
 	/* SAH costs */
 	float sah_node_cost;
-	float sah_triangle_cost;
+	float sah_primitive_cost;
 
-	/* number of triangles in leaf */
+	/* number of primitives in leaf */
 	int min_leaf_size;
-	int max_leaf_size;
+	int max_triangle_leaf_size;
+	int max_curve_leaf_size;
 
 	/* object or mesh level bvh */
 	int top_level;
@@ -62,11 +63,14 @@ public:
 		use_spatial_split = true;
 		spatial_split_alpha = 1e-5f;
 
+		/* todo: see if splitting up primitive cost to be separate for triangles
+		 * and curves can help. so far in tests it doesn't help, but why? */
 		sah_node_cost = 1.0f;
-		sah_triangle_cost = 1.0f;
+		sah_primitive_cost = 1.0f;
 
 		min_leaf_size = 1;
-		max_leaf_size = 8;
+		max_triangle_leaf_size = 8;
+		max_curve_leaf_size = 2;
 
 		top_level = false;
 		use_cache = false;
@@ -75,11 +79,11 @@ public:
 	}
 
 	/* SAH costs */
-	__forceinline float cost(int num_nodes, int num_tris) const
-	{ return node_cost(num_nodes) + triangle_cost(num_tris); }
+	__forceinline float cost(int num_nodes, int num_primitives) const
+	{ return node_cost(num_nodes) + primitive_cost(num_primitives); }
 
-	__forceinline float triangle_cost(int n) const
-	{ return n*sah_triangle_cost; }
+	__forceinline float primitive_cost(int n) const
+	{ return n*sah_primitive_cost; }
 
 	__forceinline float node_cost(int n) const
 	{ return n*sah_node_cost; }
diff --git a/intern/cycles/bvh/bvh_split.cpp b/intern/cycles/bvh/bvh_split.cpp
index e293e8f..07c35c0 100644
--- a/intern/cycles/bvh/bvh_split.cpp
+++ b/intern/cycles/bvh/bvh_split.cpp
@@ -54,8 +54,8 @@ BVHObjectSplit::BVHObjectSplit(BVHBuild *builder, const BVHRange& range, float n
 			right_bounds = builder->spatial_right_bounds[i - 1];
 
 			float sah = nodeSAH +
-				left_bounds.safe_area() * builder->params.triangle_cost(i) +
-				right_bounds.safe_area() * builder->params.triangle_cost(range.size() - i);
+				left_bounds.safe_area() * builder->params.primitive_cost(i) +
+				right_bounds.safe_area() * builder->params.primitive_cost(range.size() - i);
 
 			if(sah < min_sah) {
 				min_sah = sah;
@@ -150,8 +150,8 @@ BVHSpatialSplit::BVHSpatialSplit(BVHBuild *builder, const BVHRange& range, float
 			rightNum -= builder->spatial_bins[dim][i - 1].exit;
 
 			float sah = nodeSAH +
-				left_bounds.safe_area() * builder->params.triangle_cost(leftNum) +
-				builder->spatial_right_bounds[i - 1].safe_area() * builder->params.triangle_cost(rightNum);
+				left_bounds.safe_area() * builder->params.primitive_cost(leftNum) +
+				builder->spatial_right_bounds[i - 1].safe_area() * builder->params.primitive_cost(rightNum);
 
 			if(sah < this->sah) {
 				this->sah = sah;
@@ -209,10 +209,10 @@ void BVHSpatialSplit::split(BVHBuild *builder, BVHRange& left, BVHRange& right,
 		ldb.grow(lref.bounds());
 		rdb.grow(rref.bounds());
 
-		float lac = builder->params.triangle_cost(left_end - left_start);
-		float rac = builder->params.triangle_cost(right_end - right_start);
-		float lbc = builder->params.triangle_cost(left_end - left_start + 1);
-		float rbc = builder->params.triangle_cost(right_end - right_start + 1);
+		float lac = builder->params.primitive_cost(left_end - left_start);
+		float rac = builder->params.primitive_cost(right_end - right_start);
+		float lbc = builder->params.primitive_cost(left_end - left_start + 1);
+		float rbc = builder->params.primitive_cost(right_end - right_start + 1);
 
 		float unsplitLeftSAH = lub.safe_area() * lbc + right_bounds.safe_area() * rac;
 		float unsplitRightSAH = left_bounds.safe_area() * lac + rub.safe_area() * rbc;
@@ -284,8 +284,10 @@ void BVHSpatialSplit::split_reference(BVHBuild *builder, BVHReference& left, BVH
 		/* curve split: NOTE - Currently ignores curve width and needs to be fixed.*/
 		const int k0 = mesh->curves[ref.prim_index()].first_key + PRIMITIVE_UNPACK_SEGMENT(ref.prim_type());
 		const int k1 = k0 + 1;
-		const float3 v0 = float4_to_float3(mesh->curve_keys[k0]);
-		const float3 v1 = float4_to_float3(mesh->curve_keys[k1]);
+		const float4 key0 = mesh->curve_keys[k0];
+		const float4 key1 = mesh->curve_keys[k1];
+		const float3 v0 = float4_to_float3(key0);
+		const float3 v1 = float4_to_float3(key1);
 
 		float v0p = v0[dim];
 		float v1p = v1[dim];
diff --git a/intern/cycles/bvh/bvh_split.h b/intern/cycles/bvh/bvh_split.h
index 1f4befb..5b73931 100644
--- a/intern/cycles/bvh/bvh_split.h
+++ b/intern/cycles/bvh/bvh_split.h
@@ -77,7 +77,7 @@ public:
 		/* find split candidates. */
 		float area = range.bounds().safe_area();
 
-		leafSAH = area * builder->params.triangle_cost(range.size());
+		leafSAH = area * builder->params.primitive_cost(range.size());
 		nodeSAH = area * builder->params.node_cost(2);
 
 		object = BVHObjectSplit(builder, range, nodeSAH);
@@ -92,7 +92,7 @@ public:
 
 		/* leaf SAH is the lowest => create leaf. */
 		minSAH = min(min(leafSAH, object.sah), spatial.sah);
-		no_split = (minSAH == leafSAH && range.size() <= builder->params.max_leaf_size);
+		no_split = (minSAH == leafSAH && builder->range_within_max_leaf_size(range));
 	}
 
 	__forceinline void split(BVHBuild *builder, BVHRange& left, BVHRange& right, const BVHRange& range)




More information about the Bf-blender-cvs mailing list