Cycles: refactor of BVH building to prepare for Optix
authorPatrick Mours <pmours@nvidia.com>
Mon, 26 Aug 2019 15:29:06 +0000 (17:29 +0200)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Mon, 26 Aug 2019 15:39:57 +0000 (17:39 +0200)
Ref D5363

12 files changed:
intern/cycles/bvh/bvh.cpp
intern/cycles/bvh/bvh.h
intern/cycles/bvh/bvh2.cpp
intern/cycles/bvh/bvh2.h
intern/cycles/bvh/bvh4.cpp
intern/cycles/bvh/bvh4.h
intern/cycles/bvh/bvh8.cpp
intern/cycles/bvh/bvh8.h
intern/cycles/bvh/bvh_embree.cpp
intern/cycles/bvh/bvh_embree.h
intern/cycles/render/mesh.cpp
intern/cycles/render/mesh.h

index 53c667779282858a3479668dabf5f31e98231b18..b6a4aba74b5a3bbfd7ef2e5d80dd66638b798c79 100644 (file)
@@ -71,7 +71,11 @@ BVHLayout BVHParams::best_bvh_layout(BVHLayout requested_layout, BVHLayoutMask s
   /* This is a mask of supported BVH layouts which are narrower than the
    * requested one.
    */
-  const BVHLayoutMask allowed_layouts_mask = (supported_layouts & (requested_layout_mask - 1));
+  BVHLayoutMask allowed_layouts_mask = (supported_layouts & (requested_layout_mask - 1));
+  /* If the requested layout is not supported, choose from the supported layouts instead. */
+  if (allowed_layouts_mask == 0) {
+    allowed_layouts_mask = supported_layouts;
+  }
   /* We get widest from allowed ones and convert mask to actual layout. */
   const BVHLayoutMask widest_allowed_layout_mask = __bsr(allowed_layouts_mask);
   return (BVHLayout)(1 << widest_allowed_layout_mask);
@@ -90,23 +94,27 @@ int BVHStackEntry::encodeIdx() const
 
 /* BVH */
 
-BVH::BVH(const BVHParams &params_, const vector<Object *> &objects_)
-    : params(params_), objects(objects_)
+BVH::BVH(const BVHParams &params_, const vector<Mesh *> &meshes_, const vector<Object *> &objects_)
+    : params(params_), meshes(meshes_), objects(objects_)
 {
 }
 
-BVH *BVH::create(const BVHParams &params, const vector<Object *> &objects)
+BVH *BVH::create(const BVHParams &params,
+                 const vector<Mesh *> &meshes,
+                 const vector<Object *> &objects)
 {
   switch (params.bvh_layout) {
     case BVH_LAYOUT_BVH2:
-      return new BVH2(params, objects);
+      return new BVH2(params, meshes, objects);
     case BVH_LAYOUT_BVH4:
-      return new BVH4(params, objects);
+      return new BVH4(params, meshes, objects);
     case BVH_LAYOUT_BVH8:
-      return new BVH8(params, objects);
+      return new BVH8(params, meshes, objects);
     case BVH_LAYOUT_EMBREE:
 #ifdef WITH_EMBREE
-      return new BVHEmbree(params, objects);
+      return new BVHEmbree(params, meshes, objects);
+#else
+      break;
 #endif
     case BVH_LAYOUT_NONE:
     case BVH_LAYOUT_ALL:
@@ -356,26 +364,17 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
   size_t pack_leaf_nodes_offset = leaf_nodes_size;
   size_t object_offset = 0;
 
-  map<Mesh *, int> mesh_map;
-
-  foreach (Object *ob, objects) {
-    Mesh *mesh = ob->mesh;
+  foreach (Mesh *mesh, meshes) {
     BVH *bvh = mesh->bvh;
 
-    if (mesh->need_build_bvh()) {
-      if (mesh_map.find(mesh) == mesh_map.end()) {
-        prim_index_size += bvh->pack.prim_index.size();
-        prim_tri_verts_size += bvh->pack.prim_tri_verts.size();
-        nodes_size += bvh->pack.nodes.size();
-        leaf_nodes_size += bvh->pack.leaf_nodes.size();
-
-        mesh_map[mesh] = 1;
-      }
+    if (mesh->need_build_bvh(params.bvh_layout)) {
+      prim_index_size += bvh->pack.prim_index.size();
+      prim_tri_verts_size += bvh->pack.prim_tri_verts.size();
+      nodes_size += bvh->pack.nodes.size();
+      leaf_nodes_size += bvh->pack.leaf_nodes.size();
     }
   }
 
-  mesh_map.clear();
-
   pack.prim_index.resize(prim_index_size);
   pack.prim_type.resize(prim_index_size);
   pack.prim_object.resize(prim_index_size);
@@ -400,6 +399,8 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
   int4 *pack_leaf_nodes = (pack.leaf_nodes.size()) ? &pack.leaf_nodes[0] : NULL;
   float2 *pack_prim_time = (pack.prim_time.size()) ? &pack.prim_time[0] : NULL;
 
+  map<Mesh *, int> mesh_map;
+
   /* merge */
   foreach (Object *ob, objects) {
     Mesh *mesh = ob->mesh;
@@ -407,7 +408,7 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
     /* We assume that if mesh doesn't need own BVH it was already included
      * into a top-level BVH and no packing here is needed.
      */
-    if (!mesh->need_build_bvh()) {
+    if (!mesh->need_build_bvh(params.bvh_layout)) {
       pack.object_node[object_offset++] = 0;
       continue;
     }
index edce3ca6f2a6d06fbfa96e1dd4c016952bc1de6f..92082e4de867ada6e0ae8533f43e9d3faea3e6ae 100644 (file)
 CCL_NAMESPACE_BEGIN
 
 class Stats;
+class Device;
+class DeviceScene;
 class BVHNode;
 struct BVHStackEntry;
 class BVHParams;
 class BoundBox;
 class LeafNode;
+class Mesh;
 class Object;
 class Progress;
 
@@ -81,18 +84,25 @@ class BVH {
  public:
   PackedBVH pack;
   BVHParams params;
+  vector<Mesh *> meshes;
   vector<Object *> objects;
 
-  static BVH *create(const BVHParams &params, const vector<Object *> &objects);
+  static BVH *create(const BVHParams &params,
+                     const vector<Mesh *> &meshes,
+                     const vector<Object *> &objects);
   virtual ~BVH()
   {
   }
 
   virtual void build(Progress &progress, Stats *stats = NULL);
+  virtual void copy_to_device(Progress & /*progress*/, DeviceScene * /*dscene*/)
+  {
+  }
+
   void refit(Progress &progress);
 
  protected:
-  BVH(const BVHParams &params, const vector<Object *> &objects);
+  BVH(const BVHParams &params, const vector<Mesh *> &meshes, const vector<Object *> &objects);
 
   /* Refit range of primitives. */
   void refit_primitives(int start, int end, BoundBox &bbox, uint &visibility);
index f419d413ef66f2dda28ad30ca1c9499b5d53765f..b1a9148c2974349ed2a5792e91f1f8d577011b0b 100644 (file)
 
 CCL_NAMESPACE_BEGIN
 
-BVH2::BVH2(const BVHParams &params_, const vector<Object *> &objects_) : BVH(params_, objects_)
+BVH2::BVH2(const BVHParams &params_,
+           const vector<Mesh *> &meshes_,
+           const vector<Object *> &objects_)
+    : BVH(params_, meshes_, objects_)
 {
 }
 
index c6a4e6fa73af069e0bbd3794accb3d83cff7cefa..a3eaff9cf653956b2ce21055a13c945d51020d8c 100644 (file)
@@ -46,7 +46,7 @@ class BVH2 : public BVH {
  protected:
   /* constructor */
   friend class BVH;
-  BVH2(const BVHParams &params, const vector<Object *> &objects);
+  BVH2(const BVHParams &params, const vector<Mesh *> &meshes, const vector<Object *> &objects);
 
   /* Building process. */
   virtual BVHNode *widen_children_nodes(const BVHNode *root) override;
index b6df9024ffadb575dcc4e93dfd9e5cee2d86a84c..89b42ee1d2186e378515607edf498de1ca2a64a7 100644 (file)
@@ -31,7 +31,10 @@ CCL_NAMESPACE_BEGIN
  * life easier all over the place.
  */
 
-BVH4::BVH4(const BVHParams &params_, const vector<Object *> &objects_) : BVH(params_, objects_)
+BVH4::BVH4(const BVHParams &params_,
+           const vector<Mesh *> &meshes_,
+           const vector<Object *> &objects_)
+    : BVH(params_, meshes_, objects_)
 {
   params.bvh_layout = BVH_LAYOUT_BVH4;
 }
index 38b0961d3dfadbdbf5cd4260f7e732a87f4672ff..c44f2833c840a286603d6e2c952ede9cce0db008 100644 (file)
@@ -46,7 +46,7 @@ class BVH4 : public BVH {
  protected:
   /* constructor */
   friend class BVH;
-  BVH4(const BVHParams &params, const vector<Object *> &objects);
+  BVH4(const BVHParams &params, const vector<Mesh *> &meshes, const vector<Object *> &objects);
 
   /* Building process. */
   virtual BVHNode *widen_children_nodes(const BVHNode *root) override;
index 10fd01dd8d0e3ca6ba2e3100b785e646a23c424f..d3516525f7860e330219145efe6d26abc46b0a0c 100644 (file)
 
 CCL_NAMESPACE_BEGIN
 
-BVH8::BVH8(const BVHParams &params_, const vector<Object *> &objects_) : BVH(params_, objects_)
+BVH8::BVH8(const BVHParams &params_,
+           const vector<Mesh *> &meshes_,
+           const vector<Object *> &objects_)
+    : BVH(params_, meshes_, objects_)
 {
 }
 
index 6292353c7d44abc5ecf2a783c939b8142481bfa2..5f26fd423e100c41cf064444c5d87c5303fc19dd 100644 (file)
@@ -57,7 +57,7 @@ class BVH8 : public BVH {
  protected:
   /* constructor */
   friend class BVH;
-  BVH8(const BVHParams &params, const vector<Object *> &objects);
+  BVH8(const BVHParams &params, const vector<Mesh *> &meshes, const vector<Object *> &objects);
 
   /* Building process. */
   virtual BVHNode *widen_children_nodes(const BVHNode *root) override;
index b011bc63dbd3eec817a6d4d9e66fbb4893acccb5..d12a0c137ea3d13c97d49ae4417cdd68e98e721c 100644 (file)
@@ -285,8 +285,10 @@ RTCDevice BVHEmbree::rtc_shared_device = NULL;
 int BVHEmbree::rtc_shared_users = 0;
 thread_mutex BVHEmbree::rtc_shared_mutex;
 
-BVHEmbree::BVHEmbree(const BVHParams &params_, const vector<Object *> &objects_)
-    : BVH(params_, objects_),
+BVHEmbree::BVHEmbree(const BVHParams &params_,
+                     const vector<Mesh *> &meshes_,
+                     const vector<Object *> &objects_)
+    : BVH(params_, meshes_, objects_),
       scene(NULL),
       mem_used(0),
       top_level(NULL),
@@ -497,6 +499,11 @@ void BVHEmbree::build(Progress &progress, Stats *stats_)
   stats = NULL;
 }
 
+void BVHEmbree::copy_to_device(Progress & /*progress*/, DeviceScene *dscene)
+{
+  dscene->data.bvh.scene = scene;
+}
+
 BVHNode *BVHEmbree::widen_children_nodes(const BVHNode * /*root*/)
 {
   assert(!"Must not be called.");
@@ -840,7 +847,7 @@ void BVHEmbree::pack_nodes(const BVHNode *)
     Mesh *mesh = ob->mesh;
     BVH *bvh = mesh->bvh;
 
-    if (mesh->need_build_bvh()) {
+    if (mesh->need_build_bvh(BVH_LAYOUT_EMBREE)) {
       if (mesh_map.find(mesh) == mesh_map.end()) {
         prim_index_size += bvh->pack.prim_index.size();
         prim_tri_verts_size += bvh->pack.prim_tri_verts.size();
@@ -872,7 +879,7 @@ void BVHEmbree::pack_nodes(const BVHNode *)
     /* We assume that if mesh doesn't need own BVH it was already included
      * into a top-level BVH and no packing here is needed.
      */
-    if (!mesh->need_build_bvh()) {
+    if (!mesh->need_build_bvh(BVH_LAYOUT_EMBREE)) {
       pack.object_node[object_offset++] = prim_offset;
       continue;
     }
index 60702713583c1cf8f1106c42d64ed79533f56ed7..123e87dd9b03f8fc1a599a2c4b0be66991c52569 100644 (file)
@@ -36,6 +36,7 @@ class Mesh;
 class BVHEmbree : public BVH {
  public:
   virtual void build(Progress &progress, Stats *stats) override;
+  virtual void copy_to_device(Progress &progress, DeviceScene *dscene) override;
   virtual ~BVHEmbree();
   RTCScene scene;
   static void destroy(RTCScene);
@@ -45,7 +46,9 @@ class BVHEmbree : public BVH {
 
  protected:
   friend class BVH;
-  BVHEmbree(const BVHParams &params, const vector<Object *> &objects);
+  BVHEmbree(const BVHParams &params,
+            const vector<Mesh *> &meshes,
+            const vector<Object *> &objects);
 
   virtual void pack_nodes(const BVHNode *) override;
   virtual void refit_nodes() override;
index 6ac6666185909205db7220033e78605141acfe04..c7e0430fe7e84ea2a06167010d9c726f3a5ac650 100644 (file)
@@ -433,6 +433,8 @@ Mesh::Mesh() : Node(node_type)
 
   attr_map_offset = 0;
 
+  prim_offset = 0;
+
   num_subd_verts = 0;
 
   attributes.triangle_mesh = this;
@@ -1013,9 +1015,11 @@ void Mesh::compute_bvh(
 
   compute_bounds();
 
-  if (need_build_bvh()) {
+  const BVHLayout bvh_layout = BVHParams::best_bvh_layout(params->bvh_layout,
+                                                          device->get_bvh_layout_mask());
+  if (need_build_bvh(bvh_layout)) {
     string msg = "Updating Mesh BVH ";
-    if (name == "")
+    if (name.empty())
       msg += string_printf("%u/%u", (uint)(n + 1), (uint)total);
     else
       msg += string_printf("%s %u/%u", name.c_str(), (uint)(n + 1), (uint)total);
@@ -1023,12 +1027,17 @@ void Mesh::compute_bvh(
     Object object;
     object.mesh = this;
 
+    vector<Mesh *> meshes;
+    meshes.push_back(this);
     vector<Object *> objects;
     objects.push_back(&object);
 
     if (bvh && !need_update_rebuild) {
       progress->set_status(msg, "Refitting BVH");
+
+      bvh->meshes = meshes;
       bvh->objects = objects;
+
       bvh->refit(*progress);
     }
     else {
@@ -1036,8 +1045,7 @@ void Mesh::compute_bvh(
 
       BVHParams bparams;
       bparams.use_spatial_split = params->use_bvh_spatial_split;
-      bparams.bvh_layout = BVHParams::best_bvh_layout(params->bvh_layout,
-                                                      device->get_bvh_layout_mask());
+      bparams.bvh_layout = bvh_layout;
       bparams.use_unaligned_nodes = dscene->data.bvh.have_curves &&
                                     params->use_bvh_unaligned_nodes;
       bparams.num_motion_triangle_steps = params->num_bvh_time_steps;
@@ -1047,7 +1055,7 @@ void Mesh::compute_bvh(
       bparams.curve_subdivisions = dscene->data.curve.subdivisions;
 
       delete bvh;
-      bvh = BVH::create(bparams, objects);
+      bvh = BVH::create(bparams, meshes, objects);
       MEM_GUARDED_CALL(progress, bvh->build, *progress);
     }
   }
@@ -1128,7 +1136,7 @@ int Mesh::motion_step(float time) const
   return -1;
 }
 
-bool Mesh::need_build_bvh() const
+bool Mesh::need_build_bvh(BVHLayout) const
 {
   return !transform_applied || has_surface_bssrdf;
 }
@@ -1722,6 +1730,8 @@ void MeshManager::mesh_calc_offset(Scene *scene)
   size_t face_size = 0;
   size_t corner_size = 0;
 
+  size_t prim_size = 0;
+
   foreach (Mesh *mesh, scene->meshes) {
     mesh->vert_offset = vert_size;
     mesh->tri_offset = tri_size;
@@ -1751,6 +1761,9 @@ void MeshManager::mesh_calc_offset(Scene *scene)
     }
     face_size += mesh->subd_faces.size();
     corner_size += mesh->subd_face_corners.size();
+
+    mesh->prim_offset = prim_size;
+    prim_size += mesh->num_primitives();
   }
 }
 
@@ -1929,7 +1942,7 @@ void MeshManager::device_update_bvh(Device *device,
   }
 #endif
 
-  BVH *bvh = BVH::create(bparams, scene->objects);
+  BVH *bvh = BVH::create(bparams, scene->meshes, scene->objects);
   bvh->build(progress, &device->stats);
 
   if (progress.get_cancel()) {
@@ -1994,14 +2007,7 @@ void MeshManager::device_update_bvh(Device *device,
   dscene->data.bvh.bvh_layout = bparams.bvh_layout;
   dscene->data.bvh.use_bvh_steps = (scene->params.num_bvh_time_steps != 0);
 
-#ifdef WITH_EMBREE
-  if (bparams.bvh_layout == BVH_LAYOUT_EMBREE) {
-    dscene->data.bvh.scene = ((BVHEmbree *)bvh)->scene;
-  }
-  else {
-    dscene->data.bvh.scene = NULL;
-  }
-#endif
+  bvh->copy_to_device(progress, dscene);
 
   delete bvh;
 }
@@ -2213,6 +2219,8 @@ void MeshManager::device_update(Device *device,
   /* Update displacement. */
   bool displacement_done = false;
   size_t num_bvh = 0;
+  BVHLayout bvh_layout = BVHParams::best_bvh_layout(scene->params.bvh_layout,
+                                                    device->get_bvh_layout_mask());
 
   foreach (Mesh *mesh, scene->meshes) {
     if (mesh->need_update) {
@@ -2220,7 +2228,7 @@ void MeshManager::device_update(Device *device,
         displacement_done = true;
       }
 
-      if (mesh->need_build_bvh()) {
+      if (mesh->need_build_bvh(bvh_layout)) {
         num_bvh++;
       }
     }
@@ -2245,7 +2253,7 @@ void MeshManager::device_update(Device *device,
     if (mesh->need_update) {
       pool.push(function_bind(
           &Mesh::compute_bvh, mesh, device, dscene, &scene->params, &progress, i, num_bvh));
-      if (mesh->need_build_bvh()) {
+      if (mesh->need_build_bvh(bvh_layout)) {
         i++;
       }
     }
index 5bb6ab328b753862a8e90ab5a502caf108cadefb..50b1f0e69f14a7f85efbc13d78923f09f1ff10ea 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "graph/node.h"
 
+#include "bvh/bvh_params.h"
 #include "render/attribute.h"
 #include "render/shader.h"
 
@@ -94,7 +95,7 @@ class Mesh : public Node {
     int first_key;
     int num_keys;
 
-    int num_segments()
+    int num_segments() const
     {
       return num_keys - 1;
     }
@@ -167,6 +168,16 @@ class Mesh : public Node {
     return curve_first_key.size();
   }
 
+  size_t num_segments() const
+  {
+    return curve_keys.size() - curve_first_key.size();
+  }
+
+  size_t num_primitives() const
+  {
+    return num_triangles() + num_segments();
+  }
+
   /* Mesh SubdFace */
   struct SubdFace {
     int start_corner;
@@ -268,6 +279,8 @@ class Mesh : public Node {
 
   size_t attr_map_offset;
 
+  size_t prim_offset;
+
   size_t num_subd_verts;
 
   /* Functions */
@@ -332,8 +345,9 @@ class Mesh : public Node {
    *   same BVH tree.
    * - Special ray intersection is needed, for example to limit subsurface rays
    *   to only the mesh itself.
+   * - The BVH layout requires the top level to only contain instances.
    */
-  bool need_build_bvh() const;
+  bool need_build_bvh(BVHLayout layout) const;
 
   /* Check if the mesh should be treated as instanced. */
   bool is_instanced() const;