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 | |