void BVHNBuilder<N>::BVHNBuilderV::build(BVH* bvh, BuildProgressMonitor& progress_in, PrimRef* prims, const PrimInfo& pinfo, const size_t blockSize, const size_t minLeafSize, const size_t maxLeafSize, const float travCost, const float intCost) { //bvh->alloc.init_estimate(pinfo.size()*sizeof(PrimRef)); auto progressFunc = [&] (size_t dn) { progress_in(dn); }; auto createLeafFunc = [&] (const BVHBuilderBinnedSAH::BuildRecord& current, Allocator* alloc) -> size_t { return createLeaf(current,alloc); }; NodeRef root; BVHBuilderBinnedSAH::build_reduce<NodeRef> (root,typename BVH::CreateAlloc(bvh),size_t(0),typename BVH::CreateNode(bvh),rotate<N>,createLeafFunc,progressFunc, prims,pinfo,N,BVH::maxBuildDepthLeaf,blockSize,minLeafSize,maxLeafSize,travCost,intCost); bvh->set(root,pinfo.geomBounds,pinfo.size()); #if ROTATE_TREE if (N == 4) { for (int i=0; i<ROTATE_TREE; i++) BVHNRotate<N>::rotate(bvh->root); bvh->clearBarrier(bvh->root); } #endif bvh->layoutLargeNodes(pinfo.size()*0.005f); }
void PrimRefArrayGenFromGeometry<Ty>::generate_parallel(size_t threadIndex, size_t threadCount, LockStepTaskScheduler* scheduler, const Ty* geom, PrimRef* prims_o, PrimInfo& pinfo_o) { PrimRefArrayGenFromGeometry gen(geom,prims_o,pinfo_o); /* calculate initial destination for each thread */ size_t numPrimitives = geom->size(); gen.dst = new size_t[threadCount]; for (size_t i=0; i<threadCount; i++) gen.dst[i] = i*numPrimitives/threadCount; /* first try to generate primref array */ pinfo_o.reset(); scheduler->dispatchTask(task_task_gen_parallel, &gen, threadIndex, threadCount); assert(pinfo_o.size() <= numPrimitives); /* calculate new destinations */ size_t cnt = 0; for (size_t i=0; i<threadCount; i++) { size_t n = gen.dst[i]; gen.dst[i] = cnt; cnt += n; } /* if primitive got filtered out, run again */ if (cnt < numPrimitives) { pinfo_o.reset(); scheduler->dispatchTask(task_task_gen_parallel, &gen, threadIndex, threadCount); assert(pinfo_o.size() == cnt); } delete[] gen.dst; gen.dst = NULL; }
void BVHBuilderSpatial<N>::BVHBuilderV::build(BVH* bvh, BuildProgressMonitor& progress_in, PrimRefList& prims, const PrimInfo& pinfo, const size_t blockSize, const size_t minLeafSize, const size_t maxLeafSize, const float travCost, const float intCost) { //bvh->alloc.init_estimate(pinfo.size()*sizeof(PrimRef)); auto progressFunc = [&] (size_t dn) { progress_in(dn); }; auto splitPrimitiveFunc = [&] (const PrimRef& prim, int dim, float pos, PrimRef& left_o, PrimRef& right_o) -> void { splitPrimitive(prim,dim,pos,left_o,right_o); }; auto createLeafFunc = [&] (BVHBuilderBinnedSpatialSAH::BuildRecord& current, Allocator* alloc) -> size_t { return createLeaf(current,alloc); }; typename BVH::NodeRef root; BVHBuilderBinnedSpatialSAH::build_reduce<typename BVH::NodeRef> (root,typename BVH::CreateAlloc(bvh),size_t(0),typename BVH::CreateNode(bvh),rotate<N>, createLeafFunc,splitPrimitiveFunc,progressFunc, prims,pinfo,BVH::N,BVH::maxBuildDepthLeaf,blockSize,minLeafSize,maxLeafSize,travCost,intCost); bvh->set(root,pinfo.geomBounds,pinfo.size()); #if ROTATE_TREE for (int i=0; i<ROTATE_TREE; i++) BVHRotate::rotate(bvh->root); bvh->clearBarrier(bvh->root); #endif bvh->layoutLargeNodes(pinfo.size()*0.005f); }
void build() { /* we reset the allocator when the mesh size changed */ if (mesh && mesh->numPrimitivesChanged) { bvh->alloc.clear(); } /* skip build for empty scene */ const size_t numOriginalPrimitives = mesh ? mesh->size() : scene->getNumPrimitives<Mesh,false>(); if (numOriginalPrimitives == 0) { prims0.clear(); bvh->clear(); return; } double t0 = bvh->preBuild(mesh ? "" : TOSTRING(isa) "::BVH" + toString(N) + "BuilderFastSpatialSAH"); /* create primref array */ const size_t numSplitPrimitives = max(numOriginalPrimitives,size_t(splitFactor*numOriginalPrimitives)); prims0.resize(numSplitPrimitives); PrimInfo pinfo = mesh ? createPrimRefArray(mesh,prims0,bvh->scene->progressInterface) : createPrimRefArray(scene,Mesh::geom_type,false,prims0,bvh->scene->progressInterface); Splitter splitter(scene); /* enable os_malloc for two level build */ if (mesh) bvh->alloc.setOSallocation(true); const size_t node_bytes = pinfo.size()*sizeof(typename BVH::AlignedNode)/(4*N); const size_t leaf_bytes = size_t(1.2*Primitive::blocks(pinfo.size())*sizeof(Primitive)); bvh->alloc.init_estimate(node_bytes+leaf_bytes); settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,pinfo.size(),node_bytes+leaf_bytes); settings.branchingFactor = N; settings.maxDepth = BVH::maxBuildDepthLeaf; NodeRef root = BVHBuilderBinnedFastSpatialSAH::build<NodeRef>( typename BVH::CreateAlloc(bvh), typename BVH::AlignedNode::Create2(), typename BVH::AlignedNode::Set2(), CreateLeafSpatial<N,Primitive>(bvh), splitter, bvh->scene->progressInterface, prims0.data(), numSplitPrimitives, pinfo,settings); bvh->set(root,LBBox3fa(pinfo.geomBounds),pinfo.size()); bvh->layoutLargeNodes(size_t(pinfo.size()*0.005f)); /* clear temporary data for static geometry */ if (scene && scene->isStaticAccel()) { prims0.clear(); bvh->shrink(); } bvh->cleanup(); bvh->postBuild(t0); }
void BVH2Builder<Heuristic>::recurse(const TaskScheduler::ThreadInfo& thread, BVH2::Base*& node, size_t depth, atomic_set<PrimRefBlock>& prims, const PrimInfo& pinfo, const Split& split) { /* use full single threaded build for small jobs */ if (pinfo.size() < 4*1024) new BuildTask(thread,this,node,depth,prims,pinfo,split); /* use single threaded split for medium size jobs */ else if (pinfo.size() < 128*1024) new SplitTask(thread,this,node,depth,prims,pinfo,split); /* use parallel splitter for big jobs */ else new ParallelSplitTask(thread,this,node,depth,prims,pinfo,split); }
PrimRefArrayGen::PrimRefArrayGen(size_t threadIndex, size_t threadCount, LockStepTaskScheduler* scheduler, const Scene* scene, GeometryTy ty, size_t numTimeSteps, PrimRef* prims_o, PrimInfo& pinfo_o, bool parallel) : dst(NULL), scene(scene), ty(ty), numTimeSteps(numTimeSteps), numPrimitives(0), prims_o(prims_o), pinfo_o(pinfo_o) { /*! calculate number of primitives */ if ((ty & TRIANGLE_MESH) && (numTimeSteps & 1)) numPrimitives += scene->numTriangles; if ((ty & TRIANGLE_MESH) && (numTimeSteps & 2)) numPrimitives += scene->numTriangles2; if ((ty & SUBDIV_MESH ) && (numTimeSteps & 1)) numPrimitives += scene->numSubdivPatches; if ((ty & SUBDIV_MESH ) && (numTimeSteps & 2)) numPrimitives += scene->numSubdivPatches2; if ((ty & BEZIER_CURVES) && (numTimeSteps & 1)) numPrimitives += scene->numBezierCurves; if ((ty & BEZIER_CURVES) && (numTimeSteps & 2)) numPrimitives += scene->numBezierCurves2; if ((ty & USER_GEOMETRY) ) numPrimitives += scene->numUserGeometries1; /*! parallel generation of primref array */ if (parallel) { /* calculate initial destination for each thread */ dst = new size_t[threadCount]; for (size_t i=0; i<threadCount; i++) dst[i] = i*numPrimitives/threadCount; /* first try to generate primref array */ pinfo_o.reset(); scheduler->dispatchTask(task_task_gen_parallel, this, threadIndex, threadCount); assert(pinfo_o.size() <= numPrimitives); /* calculate new destinations */ size_t cnt = 0; for (size_t i=0; i<threadCount; i++) { size_t n = dst[i]; dst[i] = cnt; cnt += n; } /* if primitive got filtered out, run again */ if (cnt < numPrimitives) { pinfo_o.reset(); scheduler->dispatchTask(task_task_gen_parallel, this, threadIndex, threadCount); assert(pinfo_o.size() == cnt); } delete[] dst; dst = NULL; } /*! sequential generation of primref array */ else { pinfo_o.reset(); task_gen_parallel(0,1); assert(pinfo_o.size() <= numPrimitives); } }
void BVHNBuilderQuantized<N>::BVHNBuilderV::build(BVH* bvh, BuildProgressMonitor& progress_in, PrimRef* prims, const PrimInfo& pinfo, const size_t blockSize, const size_t minLeafSize, const size_t maxLeafSize, const float travCost, const float intCost) { //bvh->alloc.init_estimate(pinfo.size()*sizeof(PrimRef)); auto progressFunc = [&] (size_t dn) { progress_in(dn); }; auto createLeafFunc = [&] (const BVHBuilderBinnedSAH::BuildRecord& current, Allocator* alloc) -> size_t { return createLeaf(current,alloc); }; #if ENABLE_32BIT_OFFSETS_FOR_QUANTIZED_NODES == 1 typename BVH::QuantizedNode *first = (typename BVH::QuantizedNode*)bvh->alloc.malloc(sizeof(typename BVH::QuantizedNode), bvh->byteNodeAlignment); NodeRef &root = *(NodeRef*)first; // as the builder assigns current.parent = (size_t*)&root assert(((size_t)first & 0x7) == 0); #else NodeRef root = 0; #endif BVHBuilderBinnedSAH::build_reduce<NodeRef> (root,typename BVH::CreateAlloc(bvh),size_t(0),typename BVH::CreateQuantizedNode(bvh),dummy<N>,createLeafFunc,progressFunc, prims,pinfo,N,BVH::maxBuildDepthLeaf,blockSize,minLeafSize,maxLeafSize,travCost,intCost); #if ENABLE_32BIT_OFFSETS_FOR_QUANTIZED_NODES == 1 NodeRef new_root = ((size_t)first + first->childOffset(0)) | BVH::tyQuantizedNode; #else NodeRef new_root = (size_t)root | BVH::tyQuantizedNode; // todo: COPY LAYOUT FOR LARGE NODES !!! //bvh->layoutLargeNodes(pinfo.size()*0.005f); #endif assert(new_root.isQuantizedNode()); bvh->set(new_root,pinfo.geomBounds,pinfo.size()); }
void PrimRefArrayGenFromGeometry<Ty>::generate_sequential(size_t threadIndex, size_t threadCount, const Ty* geom, PrimRef* prims_o, PrimInfo& pinfo_o) { pinfo_o.reset(); PrimRefArrayGenFromGeometry gen(geom,prims_o,pinfo_o); gen.task_gen_parallel(0,1); assert(pinfo_o.size() <= geom->size()); }
__forceinline BVH2Builder<Heuristic>::ParallelSplitTask::ParallelSplitTask(const TaskScheduler::ThreadInfo& thread, BVH2Builder* parent, BVH2::Base*& node, size_t depth, atomic_set<PrimRefBlock>& prims, const PrimInfo& pinfo, const Split& split) : parent(parent), dst(node), depth(depth), split(split) { /*! compute leaf and split cost */ const float leafSAH = parent->trity.intCost*pinfo.sah(); const float splitSAH = BVH2::travCost*halfArea(pinfo.geomBounds)+parent->trity.intCost*split.sah(); assert(atomic_set<PrimRefBlock>::block_iterator_unsafe(prims).size() == pinfo.size()); assert(leafSAH >= 0 && splitSAH >= 0); /*! create a leaf node when threshold reached or SAH tells us to stop */ if (pinfo.size() <= 1 || depth > BVH2::maxDepth || (pinfo.size() <= parent->bvh->maxLeafTris && leafSAH <= splitSAH)) { dst = parent->createLeaf(thread,prims,pinfo); delete this; return; } /*! start parallel splitting */ new (&splitter) MultiThreadedSplitterNormal(thread, &parent->alloc,parent->triangles,parent->vertices,prims,pinfo,split, (TaskScheduler::completeFunction)_createNode,this); }
FallBackSplit FallBackSplit::find(size_t threadIndex, PrimRefBlockAlloc<PrimRef>& alloc, PrimRefList& prims, PrimRefList& lprims_o, PrimInfo& linfo_o, PrimRefList& rprims_o, PrimInfo& rinfo_o) { size_t num = 0; BBox3fa lbounds = empty, rbounds = empty; PrimRefList::item* lblock = lprims_o.insert(alloc.malloc(threadIndex)); PrimRefList::item* rblock = rprims_o.insert(alloc.malloc(threadIndex)); linfo_o.reset(); rinfo_o.reset(); while (PrimRefList::item* block = prims.take()) { for (size_t i=0; i<block->size(); i++) { const PrimRef& prim = block->at(i); const BBox3fa bounds = prim.bounds(); if ((num++)%2) { linfo_o.add(bounds,prim.center2()); if (likely(lblock->insert(prim))) continue; lblock = lprims_o.insert(alloc.malloc(threadIndex)); lblock->insert(prim); } else { rinfo_o.add(bounds,prim.center2()); if (likely(rblock->insert(prim))) continue; rblock = rprims_o.insert(alloc.malloc(threadIndex)); rblock->insert(prim); } } alloc.free(threadIndex,block); } return FallBackSplit(linfo_o.geomBounds,linfo_o.size(),rinfo_o.geomBounds,rinfo_o.size()); }
void BVHNBuilderMblur<N>::BVHNBuilderV::build(BVH* bvh, BuildProgressMonitor& progress_in, PrimRef* prims, const PrimInfo& pinfo, const size_t blockSize, const size_t minLeafSize, const size_t maxLeafSize, const float travCost, const float intCost) { //bvh->alloc.init_estimate(pinfo.size()*sizeof(PrimRef)); auto progressFunc = [&] (size_t dn) { progress_in(dn); }; auto createLeafFunc = [&] (const BVHBuilderBinnedSAH::BuildRecord& current, Allocator* alloc) -> std::pair<BBox3fa,BBox3fa> { return createLeaf(current,alloc); }; /* reduction function */ auto reduce = [] (NodeMB* node, const std::pair<BBox3fa,BBox3fa>* bounds, const size_t num) -> std::pair<BBox3fa,BBox3fa> { assert(num <= N); BBox3fa bounds0 = empty; BBox3fa bounds1 = empty; for (size_t i=0; i<num; i++) { const BBox3fa b0 = bounds[i].first; const BBox3fa b1 = bounds[i].second; node->set(i,b0,b1); bounds0 = merge(bounds0,b0); bounds1 = merge(bounds1,b1); } return std::pair<BBox3fa,BBox3fa>(bounds0,bounds1); }; auto identity = std::make_pair(BBox3fa(empty),BBox3fa(empty)); NodeRef root; BVHBuilderBinnedSAH::build_reduce<NodeRef> (root,typename BVH::CreateAlloc(bvh),identity,CreateNodeMB<N>(bvh),reduce,createLeafFunc,progressFunc, prims,pinfo,N,BVH::maxBuildDepthLeaf,blockSize,minLeafSize,maxLeafSize,travCost,intCost); bvh->set(root,pinfo.geomBounds,pinfo.size()); #if ROTATE_TREE if (N == 4) { for (int i=0; i<ROTATE_TREE; i++) BVHNRotate<N>::rotate(bvh->root); bvh->clearBarrier(bvh->root); } #endif //bvh->layoutLargeNodes(pinfo.size()*0.005f); // FIXME: implement for Mblur nodes and activate }
void BVH4BuilderTwoLevel::build(size_t threadIndex, size_t threadCount) { /* delete some objects */ size_t N = scene->size(); if (N < objects.size()) { parallel_for(N, objects.size(), [&] (const range<size_t>& r) { for (size_t i=r.begin(); i<r.end(); i++) { delete builders[i]; builders[i] = nullptr; delete objects[i]; objects[i] = nullptr; } }); } /* reset memory allocator */ bvh->alloc.reset(); /* skip build for empty scene */ const size_t numPrimitives = scene->getNumPrimitives<TriangleMesh,1>(); if (numPrimitives == 0) { prims.resize(0); bvh->set(BVH4::emptyNode,empty,0); return; } double t0 = bvh->preBuild(TOSTRING(isa) "::BVH4BuilderTwoLevel"); #if PROFILE profile(2,20,numPrimitives,[&] (ProfileTimer& timer) { #endif /* resize object array if scene got larger */ if (objects.size() < N) objects.resize(N); if (builders.size() < N) builders.resize(N); if (refs.size() < N) refs.resize(N); nextRef = 0; /* create of acceleration structures */ parallel_for(size_t(0), N, [&] (const range<size_t>& r) { for (size_t objectID=r.begin(); objectID<r.end(); objectID++) { TriangleMesh* mesh = scene->getTriangleMeshSafe(objectID); /* verify meshes got deleted properly */ if (mesh == nullptr || mesh->numTimeSteps != 1) { assert(objectID < objects.size () && objects[objectID] == nullptr); assert(objectID < builders.size() && builders[objectID] == nullptr); continue; } /* create BVH and builder for new meshes */ if (objects[objectID] == nullptr) createTriangleMeshAccel(mesh,(AccelData*&)objects[objectID],builders[objectID]); } }); /* parallel build of acceleration structures */ parallel_for(size_t(0), N, [&] (const range<size_t>& r) { for (size_t objectID=r.begin(); objectID<r.end(); objectID++) { /* ignore if no triangle mesh or not enabled */ TriangleMesh* mesh = scene->getTriangleMeshSafe(objectID); if (mesh == nullptr || !mesh->isEnabled() || mesh->numTimeSteps != 1) continue; BVH4* object = objects [objectID]; assert(object); Builder* builder = builders[objectID]; assert(builder); /* build object if it got modified */ #if !PROFILE if (mesh->isModified()) #endif builder->build(0,0); /* create build primitive */ if (!object->bounds.empty()) refs[nextRef++] = BVH4BuilderTwoLevel::BuildRef(object->bounds,object->root); } }); /* fast path for single geometry scenes */ if (nextRef == 1) { bvh->set(refs[0].node,refs[0].bounds(),numPrimitives); return; } /* open all large nodes */ refs.resize(nextRef); open_sequential(numPrimitives); /* fast path for small geometries */ if (refs.size() == 1) { bvh->set(refs[0].node,refs[0].bounds(),numPrimitives); return; } /* compute PrimRefs */ prims.resize(refs.size()); const PrimInfo pinfo = parallel_reduce(size_t(0), refs.size(), size_t(1024), PrimInfo(empty), [&] (const range<size_t>& r) -> PrimInfo { PrimInfo pinfo(empty); for (size_t i=r.begin(); i<r.end(); i++) { pinfo.add(refs[i].bounds()); prims[i] = PrimRef(refs[i].bounds(),(size_t)refs[i].node); } return pinfo; }, [] (const PrimInfo& a, const PrimInfo& b) { return PrimInfo::merge(a,b); }); /* skip if all objects where empty */ if (pinfo.size() == 0) bvh->set(BVH4::emptyNode,empty,0); /* otherwise build toplevel hierarchy */ else { BVH4::NodeRef root; BVHBuilderBinnedSAH::build<BVH4::NodeRef> (root, [&] { return bvh->alloc.threadLocal2(); }, [&] (const isa::BVHBuilderBinnedSAH::BuildRecord& current, BVHBuilderBinnedSAH::BuildRecord* children, const size_t N, FastAllocator::ThreadLocal2* alloc) -> int { BVH4::Node* node = (BVH4::Node*) alloc->alloc0.malloc(sizeof(BVH4::Node)); node->clear(); for (size_t i=0; i<N; i++) { node->set(i,children[i].pinfo.geomBounds); children[i].parent = (size_t*)&node->child(i); } *current.parent = bvh->encodeNode(node); return 0; }, [&] (const BVHBuilderBinnedSAH::BuildRecord& current, FastAllocator::ThreadLocal2* alloc) -> int { assert(current.prims.size() == 1); *current.parent = (BVH4::NodeRef) prims[current.prims.begin()].ID(); return 1; }, [&] (size_t dn) { bvh->scene->progressMonitor(0); }, prims.data(),pinfo,BVH4::N,BVH4::maxBuildDepthLeaf,4,1,1,1.0f,1.0f); bvh->set(root,pinfo.geomBounds,numPrimitives); } #if PROFILE }); #endif bvh->alloc.cleanup(); bvh->postBuild(t0); }
void build(size_t, size_t) { /* progress monitor */ auto progress = [&] (size_t dn) { bvh->scene->progressMonitor(dn); }; auto virtualprogress = BuildProgressMonitorFromClosure(progress); /* fast path for empty BVH */ const size_t numPrimitives = scene->getNumPrimitives<BezierCurves,1>(); if (numPrimitives == 0) { prims.clear(); bvh->set(BVH::emptyNode,empty,0); return; } double t0 = bvh->preBuild(TOSTRING(isa) "::BVH" + toString(N) + "BuilderHairSAH"); //profile(1,5,numPrimitives,[&] (ProfileTimer& timer) { /* create primref array */ bvh->alloc.init_estimate(numPrimitives*sizeof(Primitive)); prims.resize(numPrimitives); const PrimInfo pinfo = createBezierRefArray<1>(scene,prims,virtualprogress); /* build hierarchy */ typename BVH::NodeRef root = bvh_obb_builder_binned_sah<N> ( [&] () { return bvh->alloc.threadLocal2(); }, [&] (const PrimInfo* children, const size_t numChildren, HeuristicArrayBinningSAH<BezierPrim> alignedHeuristic, FastAllocator::ThreadLocal2* alloc) -> Node* { Node* node = (Node*) alloc->alloc0.malloc(sizeof(Node),16); node->clear(); for (size_t i=0; i<numChildren; i++) node->set(i,children[i].geomBounds); return node; }, [&] (const PrimInfo* children, const size_t numChildren, UnalignedHeuristicArrayBinningSAH<BezierPrim> unalignedHeuristic, FastAllocator::ThreadLocal2* alloc) -> UnalignedNode* { UnalignedNode* node = (UnalignedNode*) alloc->alloc0.malloc(sizeof(UnalignedNode),16); node->clear(); for (size_t i=0; i<numChildren; i++) { const LinearSpace3fa space = unalignedHeuristic.computeAlignedSpace(children[i]); const PrimInfo sinfo = unalignedHeuristic.computePrimInfo(children[i],space); node->set(i,OBBox3fa(space,sinfo.geomBounds)); } return node; }, [&] (size_t depth, const PrimInfo& pinfo, FastAllocator::ThreadLocal2* alloc) -> NodeRef { size_t items = pinfo.size(); size_t start = pinfo.begin; Primitive* accel = (Primitive*) alloc->alloc1.malloc(items*sizeof(Primitive)); NodeRef node = bvh->encodeLeaf((char*)accel,items); for (size_t i=0; i<items; i++) { accel[i].fill(prims.data(),start,pinfo.end,bvh->scene,false); } return node; }, progress, prims.data(),pinfo,N,BVH::maxBuildDepthLeaf,1,1,BVH::maxLeafBlocks); bvh->set(root,pinfo.geomBounds,pinfo.size()); //}); /* clear temporary data for static geometry */ if (scene->isStatic()) { prims.clear(); bvh->shrink(); } bvh->cleanup(); bvh->postBuild(t0); }
void build(size_t, size_t) { /* progress monitor */ auto progress = [&] (size_t dn) { bvh->scene->progressMonitor(dn); }; auto virtualprogress = BuildProgressMonitorFromClosure(progress); /* fast path for empty BVH */ const size_t numPrimitives = scene->getNumPrimitives<BezierCurves,2>(); if (numPrimitives == 0) { prims.clear(); bvh->set(BVH4::emptyNode,empty,0); return; } double t0 = bvh->preBuild(TOSTRING(isa) "::BVH4BuilderMBHairSAH"); //profile(1,5,numPrimitives,[&] (ProfileTimer& timer) { /* create primref array */ bvh->alloc.init_estimate(numPrimitives*sizeof(Primitive)); prims.resize(numPrimitives); const PrimInfo pinfo = createBezierRefArray<2>(scene,prims,virtualprogress); BVH4::NodeRef root = bvh_obb_builder_binned_sah ( [&] () { return bvh->alloc.threadLocal2(); }, [&] (const PrimInfo* children, const size_t numChildren, HeuristicArrayBinningSAH<BezierPrim> alignedHeuristic, FastAllocator::ThreadLocal2* alloc) -> BVH4::NodeMB* { BVH4::NodeMB* node = (BVH4::NodeMB*) alloc->alloc0.malloc(sizeof(BVH4::NodeMB),16); node->clear(); for (size_t i=0; i<numChildren; i++) { std::pair<BBox3fa,BBox3fa> bounds = alignedHeuristic.computePrimInfoMB(scene,children[i]); node->set(i,bounds.first,bounds.second); } return node; }, [&] (const PrimInfo* children, const size_t numChildren, UnalignedHeuristicArrayBinningSAH<BezierPrim> unalignedHeuristic, FastAllocator::ThreadLocal2* alloc) -> BVH4::UnalignedNodeMB* { BVH4::UnalignedNodeMB* node = (BVH4::UnalignedNodeMB*) alloc->alloc0.malloc(sizeof(BVH4::UnalignedNodeMB),16); node->clear(); for (size_t i=0; i<numChildren; i++) { const AffineSpace3fa space = unalignedHeuristic.computeAlignedSpaceMB(scene,children[i]); UnalignedHeuristicArrayBinningSAH<BezierPrim>::PrimInfoMB pinfo = unalignedHeuristic.computePrimInfoMB(scene,children[i],space); node->set(i,space,pinfo.s0t0,pinfo.s1t1); } return node; }, [&] (size_t depth, const PrimInfo& pinfo, FastAllocator::ThreadLocal2* alloc) -> BVH4::NodeRef { size_t items = pinfo.size(); size_t start = pinfo.begin; Primitive* accel = (Primitive*) alloc->alloc1.malloc(items*sizeof(Primitive)); BVH4::NodeRef node = bvh->encodeLeaf((char*)accel,items); for (size_t i=0; i<items; i++) { accel[i].fill(prims.data(),start,pinfo.end,bvh->scene,false); } return node; }, progress, prims.data(),pinfo,BVH4::N,BVH4::maxBuildDepthLeaf,1,1,BVH4::maxLeafBlocks); bvh->set(root,pinfo.geomBounds,pinfo.size()); //}); /* clear temporary data for static geometry */ if (scene->isStatic()) prims.clear(); bvh->alloc.cleanup(); bvh->postBuild(t0); }