| 1 | // Copyright 2009-2021 Intel Corporation | 
| 2 | // SPDX-License-Identifier: Apache-2.0 | 
| 3 |  | 
| 4 | #include "bvh.h" | 
| 5 | #include "bvh_builder.h" | 
| 6 | #include "../builders/primrefgen.h" | 
| 7 | #include "../builders/splitter.h" | 
| 8 |  | 
| 9 | #include "../geometry/linei.h" | 
| 10 | #include "../geometry/triangle.h" | 
| 11 | #include "../geometry/trianglev.h" | 
| 12 | #include "../geometry/trianglev_mb.h" | 
| 13 | #include "../geometry/trianglei.h" | 
| 14 | #include "../geometry/quadv.h" | 
| 15 | #include "../geometry/quadi.h" | 
| 16 | #include "../geometry/object.h" | 
| 17 | #include "../geometry/instance.h" | 
| 18 | #include "../geometry/subgrid.h" | 
| 19 |  | 
| 20 | #include "../common/state.h" | 
| 21 | #include "../../common/algorithms/parallel_for_for.h" | 
| 22 | #include "../../common/algorithms/parallel_for_for_prefix_sum.h" | 
| 23 |  | 
| 24 | #define PROFILE 0 | 
| 25 | #define PROFILE_RUNS 20 | 
| 26 |  | 
| 27 | namespace embree | 
| 28 | { | 
| 29 |   namespace isa | 
| 30 |   { | 
| 31 |     template<int N, typename Primitive> | 
| 32 |     struct CreateLeaf | 
| 33 |     { | 
| 34 |       typedef BVHN<N> BVH; | 
| 35 |       typedef typename BVH::NodeRef NodeRef; | 
| 36 |  | 
| 37 |       __forceinline CreateLeaf (BVH* bvh) : bvh(bvh) {} | 
| 38 |  | 
| 39 |       __forceinline NodeRef operator() (const PrimRef* prims, const range<size_t>& set, const FastAllocator::CachedAllocator& alloc) const | 
| 40 |       { | 
| 41 |         size_t n = set.size(); | 
| 42 |         size_t items = Primitive::blocks(n); | 
| 43 |         size_t start = set.begin(); | 
| 44 |         Primitive* accel = (Primitive*) alloc.malloc1(bytes: items*sizeof(Primitive),align: BVH::byteAlignment); | 
| 45 |         typename BVH::NodeRef node = BVH::encodeLeaf((char*)accel,items); | 
| 46 |         for (size_t i=0; i<items; i++) { | 
| 47 |           accel[i].fill(prims,start,set.end(),bvh->scene); | 
| 48 |         } | 
| 49 |         return node; | 
| 50 |       } | 
| 51 |  | 
| 52 |       BVH* bvh; | 
| 53 |     }; | 
| 54 |  | 
| 55 |  | 
| 56 |     template<int N, typename Primitive> | 
| 57 |     struct CreateLeafQuantized | 
| 58 |     { | 
| 59 |       typedef BVHN<N> BVH; | 
| 60 |       typedef typename BVH::NodeRef NodeRef; | 
| 61 |  | 
| 62 |       __forceinline CreateLeafQuantized (BVH* bvh) : bvh(bvh) {} | 
| 63 |  | 
| 64 |       __forceinline NodeRef operator() (const PrimRef* prims, const range<size_t>& set, const FastAllocator::CachedAllocator& alloc) const | 
| 65 |       { | 
| 66 |         size_t n = set.size(); | 
| 67 |         size_t items = Primitive::blocks(n); | 
| 68 |         size_t start = set.begin(); | 
| 69 |         Primitive* accel = (Primitive*) alloc.malloc1(bytes: items*sizeof(Primitive),align: BVH::byteAlignment); | 
| 70 |         typename BVH::NodeRef node = BVH::encodeLeaf((char*)accel,items); | 
| 71 |         for (size_t i=0; i<items; i++) { | 
| 72 |           accel[i].fill(prims,start,set.end(),bvh->scene); | 
| 73 |         } | 
| 74 |         return node; | 
| 75 |       } | 
| 76 |  | 
| 77 |       BVH* bvh; | 
| 78 |     }; | 
| 79 |  | 
| 80 |     /************************************************************************************/ | 
| 81 |     /************************************************************************************/ | 
| 82 |     /************************************************************************************/ | 
| 83 |     /************************************************************************************/ | 
| 84 |  | 
| 85 |     template<int N, typename Primitive> | 
| 86 |     struct BVHNBuilderSAH : public Builder | 
| 87 |     { | 
| 88 |       typedef BVHN<N> BVH; | 
| 89 |       typedef typename BVHN<N>::NodeRef NodeRef; | 
| 90 |  | 
| 91 |       BVH* bvh; | 
| 92 |       Scene* scene; | 
| 93 |       Geometry* mesh; | 
| 94 |       mvector<PrimRef> prims; | 
| 95 |       GeneralBVHBuilder::Settings settings; | 
| 96 |       Geometry::GTypeMask gtype_; | 
| 97 |       unsigned int geomID_ = std::numeric_limits<unsigned int>::max (); | 
| 98 |       bool primrefarrayalloc; | 
| 99 |       unsigned int numPreviousPrimitives = 0; | 
| 100 |  | 
| 101 |       BVHNBuilderSAH (BVH* bvh, Scene* scene, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, | 
| 102 |                       const Geometry::GTypeMask gtype, bool primrefarrayalloc = false) | 
| 103 |         : bvh(bvh), scene(scene), mesh(nullptr), prims(scene->device,0), | 
| 104 |           settings(sahBlockSize, minLeafSize, min(maxLeafSize,Primitive::max_size()*BVH::maxLeafBlocks), travCost, intCost, DEFAULT_SINGLE_THREAD_THRESHOLD), gtype_(gtype), primrefarrayalloc(primrefarrayalloc) {} | 
| 105 |  | 
| 106 |       BVHNBuilderSAH (BVH* bvh, Geometry* mesh, unsigned int geomID, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const Geometry::GTypeMask gtype) | 
| 107 |         : bvh(bvh), scene(nullptr), mesh(mesh), prims(bvh->device,0), settings(sahBlockSize, minLeafSize, min(maxLeafSize,Primitive::max_size()*BVH::maxLeafBlocks), travCost, intCost, DEFAULT_SINGLE_THREAD_THRESHOLD), gtype_(gtype), geomID_(geomID), primrefarrayalloc(false) {} | 
| 108 |  | 
| 109 |       // FIXME: shrink bvh->alloc in destructor here and in other builders too | 
| 110 |  | 
| 111 |       void build() | 
| 112 |       { | 
| 113 |         /* we reset the allocator when the mesh size changed */ | 
| 114 |         if (mesh && mesh->numPrimitives != numPreviousPrimitives) { | 
| 115 |           bvh->alloc.clear(); | 
| 116 |         } | 
| 117 |  | 
| 118 |         /* if we use the primrefarray for allocations we have to take it back from the BVH */ | 
| 119 |         if (settings.primrefarrayalloc != size_t(inf)) | 
| 120 |           bvh->alloc.unshare(prims); | 
| 121 |  | 
| 122 | 	/* skip build for empty scene */ | 
| 123 |         const size_t numPrimitives = mesh ? mesh->size() : scene->getNumPrimitives(mask: gtype_,mblur: false); | 
| 124 |         numPreviousPrimitives = numPrimitives; | 
| 125 |         if (numPrimitives == 0) { | 
| 126 |           bvh->clear(); | 
| 127 |           prims.clear(); | 
| 128 |           return; | 
| 129 |         } | 
| 130 |  | 
| 131 |         double t0 = bvh->preBuild(mesh ? ""  : TOSTRING(isa) "::BVH"  + toString(value: N) + "BuilderSAH" ); | 
| 132 |  | 
| 133 | #if PROFILE | 
| 134 |         profile(2,PROFILE_RUNS,numPrimitives,[&] (ProfileTimer& timer) { | 
| 135 | #endif | 
| 136 |  | 
| 137 |             /* create primref array */ | 
| 138 |             if (primrefarrayalloc) { | 
| 139 |               settings.primrefarrayalloc = numPrimitives/1000; | 
| 140 |               if (settings.primrefarrayalloc < 1000) | 
| 141 |                 settings.primrefarrayalloc = inf; | 
| 142 |             } | 
| 143 |  | 
| 144 |             /* enable os_malloc for two level build */ | 
| 145 |             if (mesh) | 
| 146 |               bvh->alloc.setOSallocation(true); | 
| 147 |  | 
| 148 |             /* initialize allocator */ | 
| 149 |             const size_t node_bytes = numPrimitives*sizeof(typename BVH::AABBNodeMB)/(4*N); | 
| 150 |             const size_t leaf_bytes = size_t(1.2*Primitive::blocks(numPrimitives)*sizeof(Primitive)); | 
| 151 |             bvh->alloc.init_estimate(node_bytes+leaf_bytes); | 
| 152 |             settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,numPrimitives,node_bytes+leaf_bytes); | 
| 153 |             prims.resize(new_size: numPrimitives);  | 
| 154 |  | 
| 155 |             PrimInfo pinfo = mesh ? | 
| 156 |               createPrimRefArray(mesh,geomID_,numPrimitives,prims,bvh->scene->progressInterface) : | 
| 157 |               createPrimRefArray(scene,gtype_,false,numPrimitives,prims,bvh->scene->progressInterface); | 
| 158 |  | 
| 159 |             /* pinfo might has zero size due to invalid geometry */ | 
| 160 |             if (unlikely(pinfo.size() == 0)) | 
| 161 |             { | 
| 162 |               bvh->clear(); | 
| 163 |               prims.clear(); | 
| 164 |               return; | 
| 165 |             } | 
| 166 |  | 
| 167 |             /* call BVH builder */ | 
| 168 |             NodeRef root = BVHNBuilderVirtual<N>::build(&bvh->alloc,CreateLeaf<N,Primitive>(bvh),bvh->scene->progressInterface,prims.data(),pinfo,settings); | 
| 169 |             bvh->set(root,LBBox3fa(pinfo.geomBounds),pinfo.size()); | 
| 170 |             bvh->layoutLargeNodes(size_t(pinfo.size()*0.005f)); | 
| 171 |  | 
| 172 | #if PROFILE | 
| 173 |           }); | 
| 174 | #endif | 
| 175 |  | 
| 176 |         /* if we allocated using the primrefarray we have to keep it alive */ | 
| 177 |         if (settings.primrefarrayalloc != size_t(inf)) | 
| 178 |           bvh->alloc.share(prims); | 
| 179 |  | 
| 180 |         /* for static geometries we can do some cleanups */ | 
| 181 |         else if (scene && scene->isStaticAccel()) { | 
| 182 |           prims.clear(); | 
| 183 |         } | 
| 184 | 	bvh->cleanup(); | 
| 185 |         bvh->postBuild(t0); | 
| 186 |       } | 
| 187 |  | 
| 188 |       void clear() { | 
| 189 |         prims.clear(); | 
| 190 |       } | 
| 191 |     }; | 
| 192 |  | 
| 193 |     /************************************************************************************/ | 
| 194 |     /************************************************************************************/ | 
| 195 |     /************************************************************************************/ | 
| 196 |     /************************************************************************************/ | 
| 197 |  | 
| 198 |     template<int N, typename Primitive> | 
| 199 |     struct BVHNBuilderSAHQuantized : public Builder | 
| 200 |     { | 
| 201 |       typedef BVHN<N> BVH; | 
| 202 |       typedef typename BVHN<N>::NodeRef NodeRef; | 
| 203 |  | 
| 204 |       BVH* bvh; | 
| 205 |       Scene* scene; | 
| 206 |       Geometry* mesh; | 
| 207 |       mvector<PrimRef> prims; | 
| 208 |       GeneralBVHBuilder::Settings settings; | 
| 209 |       Geometry::GTypeMask gtype_; | 
| 210 |       unsigned int geomID_ = std::numeric_limits<unsigned int>::max(); | 
| 211 |       unsigned int numPreviousPrimitives = 0; | 
| 212 |  | 
| 213 |       BVHNBuilderSAHQuantized (BVH* bvh, Scene* scene, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const Geometry::GTypeMask gtype) | 
| 214 |         : bvh(bvh), scene(scene), mesh(nullptr), prims(scene->device,0), settings(sahBlockSize, minLeafSize, min(maxLeafSize,Primitive::max_size()*BVH::maxLeafBlocks), travCost, intCost, DEFAULT_SINGLE_THREAD_THRESHOLD), gtype_(gtype) {} | 
| 215 |  | 
| 216 |       BVHNBuilderSAHQuantized (BVH* bvh, Geometry* mesh, unsigned int geomID, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const Geometry::GTypeMask gtype) | 
| 217 |         : bvh(bvh), scene(nullptr), mesh(mesh), prims(bvh->device,0), settings(sahBlockSize, minLeafSize, min(maxLeafSize,Primitive::max_size()*BVH::maxLeafBlocks), travCost, intCost, DEFAULT_SINGLE_THREAD_THRESHOLD), gtype_(gtype), geomID_(geomID) {} | 
| 218 |  | 
| 219 |       // FIXME: shrink bvh->alloc in destructor here and in other builders too | 
| 220 |  | 
| 221 |       void build() | 
| 222 |       { | 
| 223 |         /* we reset the allocator when the mesh size changed */ | 
| 224 |         if (mesh && mesh->numPrimitives != numPreviousPrimitives) { | 
| 225 |           bvh->alloc.clear(); | 
| 226 |         } | 
| 227 |  | 
| 228 | 	/* skip build for empty scene */ | 
| 229 |         const size_t numPrimitives = mesh ? mesh->size() : scene->getNumPrimitives(mask: gtype_,mblur: false); | 
| 230 |         numPreviousPrimitives = numPrimitives; | 
| 231 |         if (numPrimitives == 0) { | 
| 232 |           prims.clear(); | 
| 233 |           bvh->clear(); | 
| 234 |           return; | 
| 235 |         } | 
| 236 |  | 
| 237 |         double t0 = bvh->preBuild(mesh ? ""  : TOSTRING(isa) "::QBVH"  + toString(value: N) + "BuilderSAH" ); | 
| 238 |  | 
| 239 | #if PROFILE | 
| 240 |         profile(2,PROFILE_RUNS,numPrimitives,[&] (ProfileTimer& timer) { | 
| 241 | #endif | 
| 242 |             /* create primref array */ | 
| 243 |             prims.resize(new_size: numPrimitives); | 
| 244 |             PrimInfo pinfo = mesh ? | 
| 245 |               createPrimRefArray(mesh,geomID_,numPrimitives,prims,bvh->scene->progressInterface) : | 
| 246 | 	      createPrimRefArray(scene,gtype_,false,numPrimitives,prims,bvh->scene->progressInterface); | 
| 247 |  | 
| 248 |             /* enable os_malloc for two level build */ | 
| 249 |             if (mesh) | 
| 250 |               bvh->alloc.setOSallocation(true); | 
| 251 |  | 
| 252 |             /* call BVH builder */ | 
| 253 |             const size_t node_bytes = numPrimitives*sizeof(typename BVH::QuantizedNode)/(4*N); | 
| 254 |             const size_t leaf_bytes = size_t(1.2*Primitive::blocks(numPrimitives)*sizeof(Primitive)); | 
| 255 |             bvh->alloc.init_estimate(node_bytes+leaf_bytes); | 
| 256 |             settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,numPrimitives,node_bytes+leaf_bytes); | 
| 257 |             NodeRef root = BVHNBuilderQuantizedVirtual<N>::build(&bvh->alloc,CreateLeafQuantized<N,Primitive>(bvh),bvh->scene->progressInterface,prims.data(),pinfo,settings); | 
| 258 |             bvh->set(root,LBBox3fa(pinfo.geomBounds),pinfo.size()); | 
| 259 |             //bvh->layoutLargeNodes(pinfo.size()*0.005f); // FIXME: COPY LAYOUT FOR LARGE NODES !!! | 
| 260 | #if PROFILE | 
| 261 |           }); | 
| 262 | #endif | 
| 263 |  | 
| 264 | 	/* clear temporary data for static geometry */ | 
| 265 | 	if (scene && scene->isStaticAccel()) { | 
| 266 |           prims.clear(); | 
| 267 |         } | 
| 268 | 	bvh->cleanup(); | 
| 269 |         bvh->postBuild(t0); | 
| 270 |       } | 
| 271 |  | 
| 272 |       void clear() { | 
| 273 |         prims.clear(); | 
| 274 |       } | 
| 275 |     }; | 
| 276 |  | 
| 277 |     /************************************************************************************/ | 
| 278 |     /************************************************************************************/ | 
| 279 |     /************************************************************************************/ | 
| 280 |     /************************************************************************************/ | 
| 281 |  | 
| 282 |  | 
| 283 |     template<int N, typename Primitive> | 
| 284 |     struct CreateLeafGrid | 
| 285 |     { | 
| 286 |       typedef BVHN<N> BVH; | 
| 287 |       typedef typename BVH::NodeRef NodeRef; | 
| 288 |  | 
| 289 |       __forceinline CreateLeafGrid (BVH* bvh, const SubGridBuildData * const sgrids) : bvh(bvh),sgrids(sgrids) {} | 
| 290 |  | 
| 291 |       __forceinline NodeRef operator() (const PrimRef* prims, const range<size_t>& set, const FastAllocator::CachedAllocator& alloc) const | 
| 292 |       { | 
| 293 |         const size_t items = set.size(); //Primitive::blocks(n); | 
| 294 |         const size_t start = set.begin(); | 
| 295 |  | 
| 296 |         /* collect all subsets with unique geomIDs */ | 
| 297 |         assert(items <= N); | 
| 298 |         unsigned int geomIDs[N]; | 
| 299 |         unsigned int num_geomIDs = 1; | 
| 300 |         geomIDs[0] = prims[start].geomID(); | 
| 301 |  | 
| 302 |         for (size_t i=1;i<items;i++) | 
| 303 |         { | 
| 304 |           bool found = false; | 
| 305 |           const unsigned int new_geomID = prims[start+i].geomID(); | 
| 306 |           for (size_t j=0;j<num_geomIDs;j++) | 
| 307 |             if (new_geomID == geomIDs[j]) | 
| 308 |             { found = true; break; } | 
| 309 |           if (!found)  | 
| 310 |             geomIDs[num_geomIDs++] = new_geomID; | 
| 311 |         } | 
| 312 |  | 
| 313 |         /* allocate all leaf memory in one single block */ | 
| 314 |         SubGridQBVHN<N>* accel = (SubGridQBVHN<N>*) alloc.malloc1(bytes: num_geomIDs*sizeof(SubGridQBVHN<N>),align: BVH::byteAlignment); | 
| 315 |         typename BVH::NodeRef node = BVH::encodeLeaf((char*)accel,num_geomIDs); | 
| 316 |  | 
| 317 |         for (size_t g=0;g<num_geomIDs;g++) | 
| 318 |         { | 
| 319 |           unsigned int x[N]; | 
| 320 |           unsigned int y[N]; | 
| 321 |           unsigned int primID[N]; | 
| 322 |           BBox3fa bounds[N]; | 
| 323 |           unsigned int pos = 0; | 
| 324 |           for (size_t i=0;i<items;i++) | 
| 325 |           { | 
| 326 |             if (unlikely(prims[start+i].geomID() != geomIDs[g])) continue; | 
| 327 |  | 
| 328 |             const SubGridBuildData& sgrid_bd = sgrids[prims[start+i].primID()]; | 
| 329 |             x[pos] = sgrid_bd.sx; | 
| 330 |             y[pos] = sgrid_bd.sy; | 
| 331 |             primID[pos] = sgrid_bd.primID; | 
| 332 |             bounds[pos] = prims[start+i].bounds(); | 
| 333 |             pos++; | 
| 334 |           } | 
| 335 |           assert(pos <= N); | 
| 336 |           new (&accel[g]) SubGridQBVHN<N>(x,y,primID,bounds,geomIDs[g],pos); | 
| 337 |         } | 
| 338 |  | 
| 339 |         return node; | 
| 340 |       } | 
| 341 |  | 
| 342 |       BVH* bvh; | 
| 343 |       const SubGridBuildData * const sgrids; | 
| 344 |     }; | 
| 345 |  | 
| 346 |  | 
| 347 |     template<int N> | 
| 348 |     struct BVHNBuilderSAHGrid : public Builder | 
| 349 |     { | 
| 350 |       typedef BVHN<N> BVH; | 
| 351 |       typedef typename BVHN<N>::NodeRef NodeRef; | 
| 352 |        | 
| 353 |       BVH* bvh; | 
| 354 |       Scene* scene; | 
| 355 |       GridMesh* mesh; | 
| 356 |       mvector<PrimRef> prims; | 
| 357 |       mvector<SubGridBuildData> sgrids; | 
| 358 |       GeneralBVHBuilder::Settings settings; | 
| 359 |       const unsigned int geomID_ = std::numeric_limits<unsigned int>::max(); | 
| 360 |       unsigned int numPreviousPrimitives = 0; | 
| 361 |  | 
| 362 |       BVHNBuilderSAHGrid (BVH* bvh, Scene* scene, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const size_t mode) | 
| 363 |         : bvh(bvh), scene(scene), mesh(nullptr), prims(scene->device,0), sgrids(scene->device,0), settings(sahBlockSize, minLeafSize, min(maxLeafSize,BVH::maxLeafBlocks), travCost, intCost, DEFAULT_SINGLE_THREAD_THRESHOLD) {} | 
| 364 |  | 
| 365 |       BVHNBuilderSAHGrid (BVH* bvh, GridMesh* mesh, unsigned int geomID, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const size_t mode) | 
| 366 |         : bvh(bvh), scene(nullptr), mesh(mesh), prims(bvh->device,0), sgrids(scene->device,0), settings(sahBlockSize, minLeafSize, min(maxLeafSize,BVH::maxLeafBlocks), travCost, intCost, DEFAULT_SINGLE_THREAD_THRESHOLD), geomID_(geomID) {} | 
| 367 |  | 
| 368 |       void build() | 
| 369 |       { | 
| 370 |         /* we reset the allocator when the mesh size changed */ | 
| 371 |         if (mesh && mesh->numPrimitives != numPreviousPrimitives) { | 
| 372 |           bvh->alloc.clear(); | 
| 373 |         } | 
| 374 |          | 
| 375 |         /* if we use the primrefarray for allocations we have to take it back from the BVH */ | 
| 376 |         if (settings.primrefarrayalloc != size_t(inf)) | 
| 377 |           bvh->alloc.unshare(prims); | 
| 378 |  | 
| 379 |         const size_t numGridPrimitives = mesh ? mesh->size() : scene->getNumPrimitives(mask: GridMesh::geom_type,mblur: false); | 
| 380 |         numPreviousPrimitives = numGridPrimitives; | 
| 381 |  | 
| 382 |  | 
| 383 |         PrimInfo pinfo = mesh ? createPrimRefArrayGrids(mesh,prims,sgrids) : createPrimRefArrayGrids(scene,prims,sgrids); | 
| 384 |         const size_t numPrimitives = pinfo.size(); | 
| 385 |         /* no primitives */ | 
| 386 |         if (numPrimitives == 0) { | 
| 387 |           bvh->clear(); | 
| 388 |           prims.clear(); | 
| 389 |           sgrids.clear(); | 
| 390 |           return; | 
| 391 |         } | 
| 392 |  | 
| 393 |         double t0 = bvh->preBuild(mesh ? ""  : TOSTRING(isa) "::BVH"  + toString(value: N) + "BuilderSAH" ); | 
| 394 |  | 
| 395 |         /* create primref array */ | 
| 396 |         settings.primrefarrayalloc = numPrimitives/1000; | 
| 397 |         if (settings.primrefarrayalloc < 1000) | 
| 398 |           settings.primrefarrayalloc = inf; | 
| 399 |  | 
| 400 |         /* enable os_malloc for two level build */ | 
| 401 |         if (mesh) | 
| 402 |           bvh->alloc.setOSallocation(true); | 
| 403 |  | 
| 404 |         /* initialize allocator */ | 
| 405 |         const size_t node_bytes = numPrimitives*sizeof(typename BVH::AABBNodeMB)/(4*N); | 
| 406 |         const size_t leaf_bytes = size_t(1.2*(float)numPrimitives/N * sizeof(SubGridQBVHN<N>)); | 
| 407 |  | 
| 408 |         bvh->alloc.init_estimate(node_bytes+leaf_bytes); | 
| 409 |         settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,numPrimitives,node_bytes+leaf_bytes); | 
| 410 |  | 
| 411 |         /* pinfo might has zero size due to invalid geometry */ | 
| 412 |         if (unlikely(pinfo.size() == 0)) | 
| 413 |         { | 
| 414 |           bvh->clear(); | 
| 415 |           sgrids.clear(); | 
| 416 |           prims.clear(); | 
| 417 |           return; | 
| 418 |         } | 
| 419 |  | 
| 420 |         /* call BVH builder */ | 
| 421 |         NodeRef root = BVHNBuilderVirtual<N>::build(&bvh->alloc,CreateLeafGrid<N,SubGridQBVHN<N>>(bvh,sgrids.data()),bvh->scene->progressInterface,prims.data(),pinfo,settings); | 
| 422 |         bvh->set(root,LBBox3fa(pinfo.geomBounds),pinfo.size()); | 
| 423 |         bvh->layoutLargeNodes(size_t(pinfo.size()*0.005f)); | 
| 424 |  | 
| 425 |         /* clear temporary array */ | 
| 426 |         sgrids.clear(); | 
| 427 |  | 
| 428 |         /* if we allocated using the primrefarray we have to keep it alive */ | 
| 429 |         if (settings.primrefarrayalloc != size_t(inf)) | 
| 430 |           bvh->alloc.share(prims); | 
| 431 |  | 
| 432 |         /* for static geometries we can do some cleanups */ | 
| 433 |         else if (scene && scene->isStaticAccel()) { | 
| 434 |           prims.clear(); | 
| 435 |         } | 
| 436 | 	bvh->cleanup(); | 
| 437 |         bvh->postBuild(t0); | 
| 438 |       } | 
| 439 |  | 
| 440 |       void clear() { | 
| 441 |         prims.clear(); | 
| 442 |       } | 
| 443 |     }; | 
| 444 |  | 
| 445 |     /************************************************************************************/ | 
| 446 |     /************************************************************************************/ | 
| 447 |     /************************************************************************************/ | 
| 448 |     /************************************************************************************/ | 
| 449 |  | 
| 450 |      | 
| 451 | #if defined(EMBREE_GEOMETRY_TRIANGLE) | 
| 452 |     Builder* BVH4Triangle4MeshBuilderSAH  (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<4,Triangle4>((BVH4*)bvh,mesh,geomID,4,1.0f,4,inf,TriangleMesh::geom_type); } | 
| 453 |     Builder* BVH4Triangle4vMeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<4,Triangle4v>((BVH4*)bvh,mesh,geomID,4,1.0f,4,inf,TriangleMesh::geom_type); } | 
| 454 |     Builder* BVH4Triangle4iMeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<4,Triangle4i>((BVH4*)bvh,mesh,geomID,4,1.0f,4,inf,TriangleMesh::geom_type); } | 
| 455 |  | 
| 456 |     Builder* BVH4Triangle4SceneBuilderSAH  (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<4,Triangle4>((BVH4*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type); } | 
| 457 |     Builder* BVH4Triangle4vSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<4,Triangle4v>((BVH4*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type); } | 
| 458 |     Builder* BVH4Triangle4iSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<4,Triangle4i>((BVH4*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type,true); } | 
| 459 |  | 
| 460 |     Builder* BVH4QuantizedTriangle4iSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHQuantized<4,Triangle4i>((BVH4*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type); } | 
| 461 | #if defined(__AVX__) | 
| 462 |     Builder* BVH8Triangle4MeshBuilderSAH  (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<8,Triangle4>((BVH8*)bvh,mesh,geomID,4,1.0f,4,inf,TriangleMesh::geom_type); } | 
| 463 |     Builder* BVH8Triangle4vMeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<8,Triangle4v>((BVH8*)bvh,mesh,geomID,4,1.0f,4,inf,TriangleMesh::geom_type); } | 
| 464 |     Builder* BVH8Triangle4iMeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<8,Triangle4i>((BVH8*)bvh,mesh,geomID,4,1.0f,4,inf,TriangleMesh::geom_type); } | 
| 465 |  | 
| 466 |     Builder* BVH8Triangle4SceneBuilderSAH  (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<8,Triangle4>((BVH8*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type); } | 
| 467 |     Builder* BVH8Triangle4vSceneBuilderSAH  (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<8,Triangle4v>((BVH8*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type); } | 
| 468 |     Builder* BVH8Triangle4iSceneBuilderSAH     (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<8,Triangle4i>((BVH8*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type,true); } | 
| 469 |     Builder* BVH8QuantizedTriangle4iSceneBuilderSAH  (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHQuantized<8,Triangle4i>((BVH8*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type); } | 
| 470 |     Builder* BVH8QuantizedTriangle4SceneBuilderSAH  (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHQuantized<8,Triangle4>((BVH8*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type); } | 
| 471 |  | 
| 472 |      | 
| 473 |  | 
| 474 | #endif | 
| 475 | #endif | 
| 476 |  | 
| 477 | #if defined(EMBREE_GEOMETRY_QUAD) | 
| 478 |     Builder* BVH4Quad4vMeshBuilderSAH     (void* bvh, QuadMesh* mesh, unsigned int geomID, size_t mode)     { return new BVHNBuilderSAH<4,Quad4v>((BVH4*)bvh,mesh,geomID,4,1.0f,4,inf,QuadMesh::geom_type); } | 
| 479 |     Builder* BVH4Quad4iMeshBuilderSAH     (void* bvh, QuadMesh* mesh, unsigned int geomID, size_t mode)     { return new BVHNBuilderSAH<4,Quad4i>((BVH4*)bvh,mesh,geomID,4,1.0f,4,inf,QuadMesh::geom_type); } | 
| 480 |     Builder* BVH4Quad4vSceneBuilderSAH     (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<4,Quad4v>((BVH4*)bvh,scene,4,1.0f,4,inf,QuadMesh::geom_type); } | 
| 481 |     Builder* BVH4Quad4iSceneBuilderSAH     (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<4,Quad4i>((BVH4*)bvh,scene,4,1.0f,4,inf,QuadMesh::geom_type,true); } | 
| 482 |     Builder* BVH4QuantizedQuad4vSceneBuilderSAH     (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHQuantized<4,Quad4v>((BVH4*)bvh,scene,4,1.0f,4,inf,QuadMesh::geom_type); } | 
| 483 |     Builder* BVH4QuantizedQuad4iSceneBuilderSAH     (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHQuantized<4,Quad4i>((BVH4*)bvh,scene,4,1.0f,4,inf,QuadMesh::geom_type); } | 
| 484 |  | 
| 485 | #if defined(__AVX__) | 
| 486 |     Builder* BVH8Quad4vSceneBuilderSAH     (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<8,Quad4v>((BVH8*)bvh,scene,4,1.0f,4,inf,QuadMesh::geom_type); } | 
| 487 |     Builder* BVH8Quad4iSceneBuilderSAH     (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<8,Quad4i>((BVH8*)bvh,scene,4,1.0f,4,inf,QuadMesh::geom_type,true); } | 
| 488 |     Builder* BVH8QuantizedQuad4vSceneBuilderSAH     (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHQuantized<8,Quad4v>((BVH8*)bvh,scene,4,1.0f,4,inf,QuadMesh::geom_type); } | 
| 489 |     Builder* BVH8QuantizedQuad4iSceneBuilderSAH     (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHQuantized<8,Quad4i>((BVH8*)bvh,scene,4,1.0f,4,inf,QuadMesh::geom_type); } | 
| 490 |     Builder* BVH8Quad4vMeshBuilderSAH     (void* bvh, QuadMesh* mesh, unsigned int geomID, size_t mode)     { return new BVHNBuilderSAH<8,Quad4v>((BVH8*)bvh,mesh,geomID,4,1.0f,4,inf,QuadMesh::geom_type); } | 
| 491 |  | 
| 492 | #endif | 
| 493 | #endif | 
| 494 |  | 
| 495 | #if defined(EMBREE_GEOMETRY_USER) | 
| 496 |  | 
| 497 |     Builder* BVH4VirtualSceneBuilderSAH    (void* bvh, Scene* scene, size_t mode) { | 
| 498 |       int minLeafSize = scene->device->object_accel_min_leaf_size; | 
| 499 |       int maxLeafSize = scene->device->object_accel_max_leaf_size; | 
| 500 |       return new BVHNBuilderSAH<4,Object>((BVH4*)bvh,scene,4,1.0f,minLeafSize,maxLeafSize,UserGeometry::geom_type); | 
| 501 |     } | 
| 502 |  | 
| 503 |     Builder* BVH4VirtualMeshBuilderSAH    (void* bvh, UserGeometry* mesh, unsigned int geomID, size_t mode) { | 
| 504 |       return new BVHNBuilderSAH<4,Object>((BVH4*)bvh,mesh,geomID,4,1.0f,1,inf,UserGeometry::geom_type); | 
| 505 |     } | 
| 506 | #if defined(__AVX__) | 
| 507 |  | 
| 508 |     Builder* BVH8VirtualSceneBuilderSAH    (void* bvh, Scene* scene, size_t mode) { | 
| 509 |       int minLeafSize = scene->device->object_accel_min_leaf_size; | 
| 510 |       int maxLeafSize = scene->device->object_accel_max_leaf_size; | 
| 511 |       return new BVHNBuilderSAH<8,Object>((BVH8*)bvh,scene,8,1.0f,minLeafSize,maxLeafSize,UserGeometry::geom_type); | 
| 512 |     } | 
| 513 |  | 
| 514 |     Builder* BVH8VirtualMeshBuilderSAH    (void* bvh, UserGeometry* mesh, unsigned int geomID, size_t mode) { | 
| 515 |       return new BVHNBuilderSAH<8,Object>((BVH8*)bvh,mesh,geomID,8,1.0f,1,inf,UserGeometry::geom_type); | 
| 516 |     } | 
| 517 | #endif | 
| 518 | #endif | 
| 519 |  | 
| 520 | #if defined(EMBREE_GEOMETRY_INSTANCE) | 
| 521 |     Builder* BVH4InstanceSceneBuilderSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype) { return new BVHNBuilderSAH<4,InstancePrimitive>((BVH4*)bvh,scene,4,1.0f,1,1,gtype); } | 
| 522 |     Builder* BVH4InstanceMeshBuilderSAH (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { | 
| 523 |       return new BVHNBuilderSAH<4,InstancePrimitive>((BVH4*)bvh,mesh,geomID,4,1.0f,1,inf,gtype); | 
| 524 |     } | 
| 525 | #if defined(__AVX__) | 
| 526 |     Builder* BVH8InstanceSceneBuilderSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype) { return new BVHNBuilderSAH<8,InstancePrimitive>((BVH8*)bvh,scene,8,1.0f,1,1,gtype); } | 
| 527 |     Builder* BVH8InstanceMeshBuilderSAH (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { | 
| 528 |       return new BVHNBuilderSAH<8,InstancePrimitive>((BVH8*)bvh,mesh,geomID,8,1.0f,1,inf,gtype); | 
| 529 |     } | 
| 530 | #endif | 
| 531 | #endif | 
| 532 |  | 
| 533 | #if defined(EMBREE_GEOMETRY_GRID) | 
| 534 |     Builder* BVH4GridMeshBuilderSAH  (void* bvh, GridMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAHGrid<4>((BVH4*)bvh,mesh,geomID,4,1.0f,4,4,mode); } | 
| 535 |     Builder* BVH4GridSceneBuilderSAH (void* bvh, Scene* scene, size_t mode)   { return new BVHNBuilderSAHGrid<4>((BVH4*)bvh,scene,4,1.0f,4,4,mode); } // FIXME: check whether cost factors are correct | 
| 536 |  | 
| 537 | #if defined(__AVX__) | 
| 538 |     Builder* BVH8GridMeshBuilderSAH  (void* bvh, GridMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAHGrid<8>((BVH8*)bvh,mesh,geomID,8,1.0f,8,8,mode); } | 
| 539 |     Builder* BVH8GridSceneBuilderSAH (void* bvh, Scene* scene, size_t mode)   { return new BVHNBuilderSAHGrid<8>((BVH8*)bvh,scene,8,1.0f,8,8,mode); } // FIXME: check whether cost factors are correct | 
| 540 | #endif | 
| 541 | #endif | 
| 542 |   } | 
| 543 | } | 
| 544 |  |