From 6974b69c61729cc80a72d78f02eb137c5097b129 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 22 Apr 2014 16:54:02 +0200 Subject: 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. --- intern/cycles/bvh/bvh_build.cpp | 29 ++++++++++++++++++++++++++--- intern/cycles/bvh/bvh_build.h | 2 ++ intern/cycles/bvh/bvh_params.h | 22 +++++++++++++--------- intern/cycles/bvh/bvh_split.cpp | 22 ++++++++++++---------- intern/cycles/bvh/bvh_split.h | 4 ++-- 5 files changed, 55 insertions(+), 24 deletions(-) diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index 9367e7b86b4..eb4cca92b6b 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 ba10eb49412..a6b9916de9b 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 3e93c0c56a0..ed67690a07f 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 e293e8f4c3f..07c35c08c18 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 1f4befbe8e2..5b739311e5f 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) -- cgit v1.2.3