Cycles: Avoid having duplication of BVH arrays during build
authorSergey Sharybin <sergey.vfx@gmail.com>
Sun, 28 Jun 2015 16:07:48 +0000 (18:07 +0200)
committerSergey Sharybin <sergey.vfx@gmail.com>
Sun, 28 Jun 2015 16:15:25 +0000 (18:15 +0200)
Previous idea behind having vector during building and array for actual storage
was needed in order to minimize amount of re-allocations happening during the
build, but it lead to double memory overhead used by those arrays at the vector
to array conversion stage.

Issue with such approach was that for BVH without spatial split size of arrays
is known in advance and it never changes, which made vector to array conversion
totally redundant.

Also after testing with several rather complex from spatial split scenes (such
as trees) it seems even conservative approach of reallocation (when we perform
re-allocation when leaf does not fit into the memory) doesn't give measurable
difference in time.

This makes it so we can switch to array, which will avoid unneeded memory
re-allocations when spatial split is disabled without harming other cases.

it's a bit difficult to measure exact benefit of this change on our production
files here, but depending on the scene it might give quite reasonable memory
save.

intern/cycles/bvh/bvh.cpp
intern/cycles/bvh/bvh_build.cpp
intern/cycles/bvh/bvh_build.h

index 0d9412a5712d9f53b4641c08520f1f98880a016e..350ca16f6e2c858b97761f35792bf6310bb17bfa 100644 (file)
@@ -190,11 +190,12 @@ void BVH::build(Progress& progress)
        }
 
        /* build nodes */
-       vector<int> prim_type;
-       vector<int> prim_index;
-       vector<int> prim_object;
-
-       BVHBuild bvh_build(objects, prim_type, prim_index, prim_object, params, progress);
+       BVHBuild bvh_build(objects,
+                          pack.prim_type,
+                          pack.prim_index,
+                          pack.prim_object,
+                          params,
+                          progress);
        BVHNode *root = bvh_build.run();
 
        if(progress.get_cancel()) {
@@ -202,14 +203,6 @@ void BVH::build(Progress& progress)
                return;
        }
 
-       /* todo: get rid of this copy */
-       pack.prim_type = prim_type;
-       pack.prim_index = prim_index;
-       pack.prim_object = prim_object;
-       prim_type.free_memory();
-       prim_index.free_memory();
-       prim_object.free_memory();
-
        /* compute SAH */
        if(!params.top_level)
                pack.SAH = root->computeSubtreeSAHCost(params);
index 5baf94918b4a00b9d5933f8f02cba29c6b527b1f..a44ad6563160db82108ec6eb38ea31d720877e0d 100644 (file)
@@ -65,15 +65,18 @@ public:
 /* Constructor / Destructor */
 
 BVHBuild::BVHBuild(const vector<Object*>& objects_,
-       vector<int>& prim_type_, vector<int>& prim_index_, vector<int>& prim_object_,
-       const BVHParams& params_, Progress& progress_)
-: objects(objects_),
-  prim_type(prim_type_),
-  prim_index(prim_index_),
-  prim_object(prim_object_),
-  params(params_),
-  progress(progress_),
-  progress_start_time(0.0)
+                   array<int>& prim_type_,
+                   array<int>& prim_index_,
+                   array<int>& prim_object_,
+                   const BVHParams& params_,
+                   Progress& progress_)
+ : objects(objects_),
+   prim_type(prim_type_),
+   prim_index(prim_index_),
+   prim_object(prim_object_),
+   params(params_),
+   progress(progress_),
+   progress_start_time(0.0)
 {
        spatial_min_overlap = 0.0f;
 }
@@ -446,18 +449,10 @@ BVHNode *BVHBuild::create_object_leaf_nodes(const BVHReference *ref, int start,
                return new LeafNode(bounds, 0, 0, 0);
        }
        else if(num == 1) {
-               if(start == prim_index.size()) {
-                       assert(params.use_spatial_split);
-
-                       prim_type.push_back(ref->prim_type());
-                       prim_index.push_back(ref->prim_index());
-                       prim_object.push_back(ref->prim_object());
-               }
-               else {
-                       prim_type[start] = ref->prim_type();
-                       prim_index[start] = ref->prim_index();
-                       prim_object[start] = ref->prim_object();
-               }
+               assert(start < prim_type.size());
+               prim_type[start] = ref->prim_type();
+               prim_index[start] = ref->prim_index();
+               prim_object[start] = ref->prim_object();
 
                uint visibility = objects[ref->prim_object()]->visibility;
                return new LeafNode(ref->bounds(), visibility, start, start+1);
@@ -484,17 +479,9 @@ BVHNode *BVHBuild::create_primitive_leaf_node(const int *p_type,
                                               int num)
 {
        for(int i = 0; i < num; ++i) {
-               if(start + i == prim_index.size()) {
-                       assert(params.use_spatial_split);
-                       prim_type.push_back(p_type[i]);
-                       prim_index.push_back(p_index[i]);
-                       prim_object.push_back(p_object[i]);
-               }
-               else {
-                       prim_type[start + i] = p_type[i];
-                       prim_index[start + i] = p_index[i];
-                       prim_object[start + i] = p_object[i];
-               }
+               prim_type[start + i] = p_type[i];
+               prim_index[start + i] = p_index[i];
+               prim_object[start + i] = p_object[i];
        }
        return new LeafNode(bounds, visibility, start, start + num);
 }
@@ -535,6 +522,19 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range)
                }
        }
 
+       /* Extend an array when needed. */
+       if(prim_type.size() < range.end()) {
+               assert(params.use_spatial_split);
+               /* TODO(sergey): We might want to look into different policies of
+                * re-allocation here, so on the one hand we would not do as much
+                * re-allocations and on the other hand will have small memory
+                * overhead.
+                */
+               prim_type.resize(range.end());
+               prim_index.resize(range.end());
+               prim_object.resize(range.end());
+       }
+
        /* Create leaf nodes for every existing primitive. */
        BVHNode *leaves[PRIMITIVE_NUM_TOTAL + 1] = {NULL};
        int num_leaves = 0;
index 294c5a1758db991309fadf0db740a64ae56fb76b..eefb7b60f7c0d362869afe9e85c6e48d098add10 100644 (file)
@@ -42,13 +42,12 @@ class BVHBuild
 {
 public:
        /* Constructor/Destructor */
-       BVHBuild(
-               const vector<Object*>& objects,
-               vector<int>& prim_type,
-               vector<int>& prim_index,
-               vector<int>& prim_object,
-               const BVHParams& params,
-               Progress& progress);
+       BVHBuild(const vector<Object*>& objects,
+                array<int>& prim_type,
+                array<int>& prim_index,
+                array<int>& prim_object,
+                const BVHParams& params,
+                Progress& progress);
        ~BVHBuild();
 
        BVHNode *run();
@@ -99,9 +98,9 @@ protected:
        int num_original_references;
 
        /* output primitive indexes and objects */
-       vector<int>& prim_type;
-       vector<int>& prim_index;
-       vector<int>& prim_object;
+       array<int>& prim_type;
+       array<int>& prim_index;
+       array<int>& prim_object;
 
        /* build parameters */
        BVHParams params;