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.
This commit is contained in:
parent
2108a61691
commit
6974b69c61
Notes:
blender-bot
2023-02-14 05:53:42 +01:00
Referenced by commit 0421ae056d
, Cycles: Change confusing logic of max leaf size check
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue