Cycles: Only sort indices when finding a best dimension to split

This reduces amount of data being moved back and forth, which should
have positive effect on the performance.
This commit is contained in:
Sergey Sharybin 2016-02-22 16:25:33 +01:00
parent bbbbe68473
commit d9b729e342
5 changed files with 72 additions and 5 deletions

@ -245,6 +245,8 @@ BVHNode* BVHBuild::run()
foreach(BVHSpatialStorage &storage, spatial_storage) {
storage.spatial_right_bounds.clear();
storage.spatial_right_bounds.resize(num_bins);
storage.spatial_indices.clear();
storage.spatial_indices.reserve(num_bins);
}
}

@ -185,6 +185,7 @@ struct BVHSpatialBin
struct BVHSpatialStorage {
vector<BoundBox> spatial_right_bounds;
BVHSpatialBin spatial_bins[3][BVHParams::NUM_SPATIAL_BINS];
vector<int> spatial_indices;
};
CCL_NAMESPACE_END

@ -65,5 +65,54 @@ void bvh_reference_sort(int start, int end, BVHReference *data, int dim)
sort(data+start, data+end, compare);
}
CCL_NAMESPACE_END
struct BVHReferenceCompareIndexed {
public:
BVHReferenceCompareIndexed(int dim, const BVHReference *data, int start)
: dim_(dim),
start_(start),
data_(data)
{}
bool operator()(const int a, const int b)
{
const BVHReference& ra = data_[start_ + a];
const BVHReference& rb = data_[start_ + b];
NO_EXTENDED_PRECISION float ca = ra.bounds().min[dim_] + ra.bounds().max[dim_];
NO_EXTENDED_PRECISION float cb = rb.bounds().min[dim_] + rb.bounds().max[dim_];
if(ca < cb) return true;
else if(ca > cb) return false;
else if(ra.prim_object() < rb.prim_object()) return true;
else if(ra.prim_object() > rb.prim_object()) return false;
else if(ra.prim_index() < rb.prim_index()) return true;
else if(ra.prim_index() > rb.prim_index()) return false;
else if(ra.prim_type() < rb.prim_type()) return true;
else if(ra.prim_type() > rb.prim_type()) return false;
return false;
}
private:
int dim_, start_;
const BVHReference *data_;
};
/* NOTE: indices are always from 0 to count, even in the cases when start is not
* zero. This is to simplify indexing in the object splitter. Index array is also
* always zero-based index.
*/
void bvh_reference_sort_indices(int start,
int end,
const BVHReference *data,
int *indices,
int dim)
{
const int count = end - start;
for(int i = 0; i < count; ++i) {
indices[i] = i;
}
BVHReferenceCompareIndexed compare(dim, data, start);
sort(indices, indices+count, compare);
}
CCL_NAMESPACE_END

@ -21,6 +21,11 @@
CCL_NAMESPACE_BEGIN
void bvh_reference_sort(int start, int end, BVHReference *data, int dim);
void bvh_reference_sort_indices(int start,
int end,
const BVHReference *data,
int *indices,
int dim);
CCL_NAMESPACE_END

@ -42,15 +42,25 @@ BVHObjectSplit::BVHObjectSplit(BVHBuild *builder,
const BVHReference *ref_ptr = &builder->references[range.start()];
float min_sah = FLT_MAX;
storage->spatial_indices.resize(range.size());
int *indices = &storage->spatial_indices[0];
for(int dim = 0; dim < 3; dim++) {
/* sort references */
bvh_reference_sort(range.start(), range.end(), &builder->references[0], dim);
/* Sort references.
* We only sort indices, to save amount of memory being sent back
* and forth.
*/
bvh_reference_sort_indices(range.start(),
range.end(),
&builder->references[0],
indices,
dim);
/* sweep right to left and determine bounds. */
BoundBox right_bounds = BoundBox::empty;
for(int i = range.size() - 1; i > 0; i--) {
right_bounds.grow(ref_ptr[i].bounds());
right_bounds.grow(ref_ptr[indices[i]].bounds());
storage_->spatial_right_bounds[i - 1] = right_bounds;
}
@ -58,7 +68,7 @@ BVHObjectSplit::BVHObjectSplit(BVHBuild *builder,
BoundBox left_bounds = BoundBox::empty;
for(int i = 1; i < range.size(); i++) {
left_bounds.grow(ref_ptr[i - 1].bounds());
left_bounds.grow(ref_ptr[indices[i - 1]].bounds());
right_bounds = storage_->spatial_right_bounds[i - 1];
float sah = nodeSAH +