| 1 | // Copyright 2009-2021 Intel Corporation | 
| 2 | // SPDX-License-Identifier: Apache-2.0 | 
| 3 |  | 
| 4 | #include "bvh_refit.h" | 
| 5 | #include "bvh_statistics.h" | 
| 6 |  | 
| 7 | #include "../geometry/linei.h" | 
| 8 | #include "../geometry/triangle.h" | 
| 9 | #include "../geometry/trianglev.h" | 
| 10 | #include "../geometry/trianglei.h" | 
| 11 | #include "../geometry/quadv.h" | 
| 12 | #include "../geometry/object.h" | 
| 13 | #include "../geometry/instance.h" | 
| 14 |  | 
| 15 | namespace embree | 
| 16 | { | 
| 17 |   namespace isa | 
| 18 |   { | 
| 19 |     static const size_t SINGLE_THREAD_THRESHOLD = 4*1024; | 
| 20 |      | 
| 21 |     template<int N> | 
| 22 |     __forceinline bool compare(const typename BVHN<N>::NodeRef* a, const typename BVHN<N>::NodeRef* b) | 
| 23 |     { | 
| 24 |       size_t sa = *(size_t*)&a->node()->lower_x; | 
| 25 |       size_t sb = *(size_t*)&b->node()->lower_x; | 
| 26 |       return sa < sb; | 
| 27 |     } | 
| 28 |  | 
| 29 |     template<int N> | 
| 30 |     BVHNRefitter<N>::BVHNRefitter (BVH* bvh, const LeafBoundsInterface& leafBounds) | 
| 31 |       : bvh(bvh), leafBounds(leafBounds), numSubTrees(0) | 
| 32 |     { | 
| 33 |     } | 
| 34 |  | 
| 35 |     template<int N> | 
| 36 |     void BVHNRefitter<N>::refit() | 
| 37 |     { | 
| 38 |       if (bvh->numPrimitives <= SINGLE_THREAD_THRESHOLD) { | 
| 39 |         bvh->bounds = LBBox3fa(recurse_bottom(ref&: bvh->root)); | 
| 40 |       } | 
| 41 |       else | 
| 42 |       { | 
| 43 |         BBox3fa subTreeBounds[MAX_NUM_SUB_TREES]; | 
| 44 |         numSubTrees = 0; | 
| 45 |         gather_subtree_refs(ref&: bvh->root,subtrees&: numSubTrees,depth: 0); | 
| 46 |         if (numSubTrees) | 
| 47 |           parallel_for(size_t(0), numSubTrees, size_t(1), [&](const range<size_t>& r) { | 
| 48 |               for (size_t i=r.begin(); i<r.end(); i++) { | 
| 49 |                 NodeRef& ref = subTrees[i]; | 
| 50 |                 subTreeBounds[i] = recurse_bottom(ref); | 
| 51 |               } | 
| 52 |             }); | 
| 53 |  | 
| 54 |         numSubTrees = 0;         | 
| 55 |         bvh->bounds = LBBox3fa(refit_toplevel(ref&: bvh->root,subtrees&: numSubTrees,subTreeBounds,depth: 0)); | 
| 56 |       }     | 
| 57 |   } | 
| 58 |  | 
| 59 |     template<int N> | 
| 60 |     void BVHNRefitter<N>::gather_subtree_refs(NodeRef& ref, | 
| 61 |                                               size_t &subtrees, | 
| 62 |                                               const size_t depth) | 
| 63 |     { | 
| 64 |       if (depth >= MAX_SUB_TREE_EXTRACTION_DEPTH)  | 
| 65 |       { | 
| 66 |         assert(subtrees < MAX_NUM_SUB_TREES); | 
| 67 |         subTrees[subtrees++] = ref; | 
| 68 |         return; | 
| 69 |       } | 
| 70 |  | 
| 71 |       if (ref.isAABBNode()) | 
| 72 |       { | 
| 73 |         AABBNode* node = ref.getAABBNode(); | 
| 74 |         for (size_t i=0; i<N; i++) { | 
| 75 |           NodeRef& child = node->child(i); | 
| 76 |           if (unlikely(child == BVH::emptyNode)) continue; | 
| 77 |           gather_subtree_refs(ref&: child,subtrees,depth: depth+1);  | 
| 78 |         } | 
| 79 |       } | 
| 80 |     } | 
| 81 |  | 
| 82 |     template<int N> | 
| 83 |     BBox3fa BVHNRefitter<N>::refit_toplevel(NodeRef& ref, | 
| 84 |                                             size_t &subtrees, | 
| 85 | 											const BBox3fa *const subTreeBounds, | 
| 86 |                                             const size_t depth) | 
| 87 |     { | 
| 88 |       if (depth >= MAX_SUB_TREE_EXTRACTION_DEPTH)  | 
| 89 |       { | 
| 90 |         assert(subtrees < MAX_NUM_SUB_TREES); | 
| 91 |         assert(subTrees[subtrees] == ref); | 
| 92 |         return subTreeBounds[subtrees++]; | 
| 93 |       } | 
| 94 |  | 
| 95 |       if (ref.isAABBNode()) | 
| 96 |       { | 
| 97 |         AABBNode* node = ref.getAABBNode(); | 
| 98 |         BBox3fa bounds[N]; | 
| 99 |  | 
| 100 |         for (size_t i=0; i<N; i++) | 
| 101 |         { | 
| 102 |           NodeRef& child = node->child(i); | 
| 103 |  | 
| 104 |           if (unlikely(child == BVH::emptyNode))  | 
| 105 |             bounds[i] = BBox3fa(empty); | 
| 106 |           else | 
| 107 |             bounds[i] = refit_toplevel(ref&: child,subtrees,subTreeBounds,depth: depth+1);  | 
| 108 |         } | 
| 109 |          | 
| 110 |         BBox3vf<N> boundsT = transpose<N>(bounds); | 
| 111 |        | 
| 112 |         /* set new bounds */ | 
| 113 |         node->lower_x = boundsT.lower.x; | 
| 114 |         node->lower_y = boundsT.lower.y; | 
| 115 |         node->lower_z = boundsT.lower.z; | 
| 116 |         node->upper_x = boundsT.upper.x; | 
| 117 |         node->upper_y = boundsT.upper.y; | 
| 118 |         node->upper_z = boundsT.upper.z; | 
| 119 |          | 
| 120 |         return merge<N>(bounds); | 
| 121 |       } | 
| 122 |       else | 
| 123 |         return leafBounds.leafBounds(ref); | 
| 124 |     } | 
| 125 |  | 
| 126 |     // ========================================================= | 
| 127 |     // ========================================================= | 
| 128 |     // ========================================================= | 
| 129 |  | 
| 130 |      | 
| 131 |     template<int N> | 
| 132 |     BBox3fa BVHNRefitter<N>::recurse_bottom(NodeRef& ref) | 
| 133 |     { | 
| 134 |       /* this is a leaf node */ | 
| 135 |       if (unlikely(ref.isLeaf())) | 
| 136 |         return leafBounds.leafBounds(ref); | 
| 137 |        | 
| 138 |       /* recurse if this is an internal node */ | 
| 139 |       AABBNode* node = ref.getAABBNode(); | 
| 140 |  | 
| 141 |       /* enable exclusive prefetch for >= AVX platforms */       | 
| 142 | #if defined(__AVX__)       | 
| 143 |       BVH::prefetchW(ref); | 
| 144 | #endif       | 
| 145 |       BBox3fa bounds[N]; | 
| 146 |  | 
| 147 |       for (size_t i=0; i<N; i++) | 
| 148 |         if (unlikely(node->child(i) == BVH::emptyNode)) | 
| 149 |         { | 
| 150 |           bounds[i] = BBox3fa(empty);           | 
| 151 |         } | 
| 152 |       else | 
| 153 |         bounds[i] = recurse_bottom(ref&: node->child(i)); | 
| 154 |        | 
| 155 |       /* AOS to SOA transform */ | 
| 156 |       BBox3vf<N> boundsT = transpose<N>(bounds); | 
| 157 |        | 
| 158 |       /* set new bounds */ | 
| 159 |       node->lower_x = boundsT.lower.x; | 
| 160 |       node->lower_y = boundsT.lower.y; | 
| 161 |       node->lower_z = boundsT.lower.z; | 
| 162 |       node->upper_x = boundsT.upper.x; | 
| 163 |       node->upper_y = boundsT.upper.y; | 
| 164 |       node->upper_z = boundsT.upper.z; | 
| 165 |  | 
| 166 |       return merge<N>(bounds); | 
| 167 |     } | 
| 168 |  | 
| 169 |     template<int N, typename Mesh, typename Primitive> | 
| 170 |     BVHNRefitT<N,Mesh,Primitive>::BVHNRefitT (BVH* bvh, Builder* builder, Mesh* mesh, size_t mode) | 
| 171 |       : bvh(bvh), builder(builder), refitter(new BVHNRefitter<N>(bvh,*(typename BVHNRefitter<N>::LeafBoundsInterface*)this)), mesh(mesh), topologyVersion(0) {} | 
| 172 |  | 
| 173 |     template<int N, typename Mesh, typename Primitive> | 
| 174 |     void BVHNRefitT<N,Mesh,Primitive>::clear() | 
| 175 |     { | 
| 176 |       if (builder)  | 
| 177 |         builder->clear(); | 
| 178 |     } | 
| 179 |      | 
| 180 |     template<int N, typename Mesh, typename Primitive> | 
| 181 |     void BVHNRefitT<N,Mesh,Primitive>::build() | 
| 182 |     { | 
| 183 |       if (mesh->topologyChanged(topologyVersion)) { | 
| 184 |         topologyVersion = mesh->getTopologyVersion(); | 
| 185 |         builder->build(); | 
| 186 |       } | 
| 187 |       else | 
| 188 |         refitter->refit(); | 
| 189 |     } | 
| 190 |  | 
| 191 |     template class BVHNRefitter<4>; | 
| 192 | #if defined(__AVX__) | 
| 193 |     template class BVHNRefitter<8>; | 
| 194 | #endif | 
| 195 |      | 
| 196 | #if defined(EMBREE_GEOMETRY_TRIANGLE) | 
| 197 |     Builder* BVH4Triangle4MeshBuilderSAH  (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode); | 
| 198 |     Builder* BVH4Triangle4vMeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode); | 
| 199 |     Builder* BVH4Triangle4iMeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode); | 
| 200 |  | 
| 201 |     Builder* BVH4Triangle4MeshRefitSAH  (void* accel, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<4,TriangleMesh,Triangle4> ((BVH4*)accel,BVH4Triangle4MeshBuilderSAH (bvh: accel,mesh,geomID,mode),mesh,mode); } | 
| 202 |     Builder* BVH4Triangle4vMeshRefitSAH (void* accel, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<4,TriangleMesh,Triangle4v>((BVH4*)accel,BVH4Triangle4vMeshBuilderSAH(bvh: accel,mesh,geomID,mode),mesh,mode); } | 
| 203 |     Builder* BVH4Triangle4iMeshRefitSAH (void* accel, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<4,TriangleMesh,Triangle4i>((BVH4*)accel,BVH4Triangle4iMeshBuilderSAH(bvh: accel,mesh,geomID,mode),mesh,mode); } | 
| 204 | #if  defined(__AVX__) | 
| 205 |     Builder* BVH8Triangle4MeshBuilderSAH  (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode); | 
| 206 |     Builder* BVH8Triangle4vMeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode); | 
| 207 |     Builder* BVH8Triangle4iMeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode); | 
| 208 |  | 
| 209 |     Builder* BVH8Triangle4MeshRefitSAH  (void* accel, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<8,TriangleMesh,Triangle4> ((BVH8*)accel,BVH8Triangle4MeshBuilderSAH (accel,mesh,geomID,mode),mesh,mode); } | 
| 210 |     Builder* BVH8Triangle4vMeshRefitSAH (void* accel, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<8,TriangleMesh,Triangle4v>((BVH8*)accel,BVH8Triangle4vMeshBuilderSAH(accel,mesh,geomID,mode),mesh,mode); } | 
| 211 |     Builder* BVH8Triangle4iMeshRefitSAH (void* accel, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<8,TriangleMesh,Triangle4i>((BVH8*)accel,BVH8Triangle4iMeshBuilderSAH(accel,mesh,geomID,mode),mesh,mode); } | 
| 212 | #endif | 
| 213 | #endif | 
| 214 |  | 
| 215 | #if defined(EMBREE_GEOMETRY_QUAD) | 
| 216 |     Builder* BVH4Quad4vMeshBuilderSAH (void* bvh, QuadMesh* mesh, unsigned int geomID, size_t mode); | 
| 217 |     Builder* BVH4Quad4vMeshRefitSAH (void* accel, QuadMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<4,QuadMesh,Quad4v>((BVH4*)accel,BVH4Quad4vMeshBuilderSAH(accel,mesh,geomID,mode),mesh,mode); } | 
| 218 |  | 
| 219 | #if  defined(__AVX__) | 
| 220 |     Builder* BVH8Quad4vMeshBuilderSAH (void* bvh, QuadMesh* mesh, unsigned int geomID, size_t mode); | 
| 221 |     Builder* BVH8Quad4vMeshRefitSAH (void* accel, QuadMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<8,QuadMesh,Quad4v>((BVH8*)accel,BVH8Quad4vMeshBuilderSAH(accel,mesh,geomID,mode),mesh,mode); } | 
| 222 | #endif | 
| 223 |  | 
| 224 | #endif | 
| 225 |  | 
| 226 | #if defined(EMBREE_GEOMETRY_USER) | 
| 227 |     Builder* BVH4VirtualMeshBuilderSAH (void* bvh, UserGeometry* mesh, unsigned int geomID, size_t mode); | 
| 228 |     Builder* BVH4VirtualMeshRefitSAH (void* accel, UserGeometry* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<4,UserGeometry,Object>((BVH4*)accel,BVH4VirtualMeshBuilderSAH(accel,mesh,geomID,mode),mesh,mode); } | 
| 229 |  | 
| 230 | #if  defined(__AVX__) | 
| 231 |     Builder* BVH8VirtualMeshBuilderSAH (void* bvh, UserGeometry* mesh, unsigned int geomID, size_t mode); | 
| 232 |     Builder* BVH8VirtualMeshRefitSAH (void* accel, UserGeometry* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<8,UserGeometry,Object>((BVH8*)accel,BVH8VirtualMeshBuilderSAH(accel,mesh,geomID,mode),mesh,mode); } | 
| 233 | #endif | 
| 234 | #endif | 
| 235 |  | 
| 236 | #if defined(EMBREE_GEOMETRY_INSTANCE) | 
| 237 |     Builder* BVH4InstanceMeshBuilderSAH (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode); | 
| 238 |     Builder* BVH4InstanceMeshRefitSAH (void* accel, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { return new BVHNRefitT<4,Instance,InstancePrimitive>((BVH4*)accel,BVH4InstanceMeshBuilderSAH(accel,mesh,gtype,geomID,mode),mesh,mode); } | 
| 239 |  | 
| 240 | #if  defined(__AVX__) | 
| 241 |     Builder* BVH8InstanceMeshBuilderSAH (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode); | 
| 242 |     Builder* BVH8InstanceMeshRefitSAH (void* accel, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { return new BVHNRefitT<8,Instance,InstancePrimitive>((BVH8*)accel,BVH8InstanceMeshBuilderSAH(accel,mesh,gtype,geomID,mode),mesh,mode); } | 
| 243 | #endif | 
| 244 | #endif | 
| 245 |  | 
| 246 |   } | 
| 247 | } | 
| 248 |  |