Path: blob/master/thirdparty/embree/kernels/bvh/bvh_builder_twolevel.cpp
9913 views
// Copyright 2009-2021 Intel Corporation1// SPDX-License-Identifier: Apache-2.023#if !defined(_CRT_SECURE_NO_WARNINGS)4#define _CRT_SECURE_NO_WARNINGS5#endif67#include "bvh_builder_twolevel.h"8#include "bvh_statistics.h"9#include "../builders/bvh_builder_sah.h"10#include "../common/scene_line_segments.h"11#include "../common/scene_triangle_mesh.h"12#include "../common/scene_quad_mesh.h"1314#define PROFILE 01516namespace embree17{18namespace isa19{20template<int N, typename Mesh, typename Primitive>21BVHNBuilderTwoLevel<N,Mesh,Primitive>::BVHNBuilderTwoLevel (BVH* bvh, Scene* scene, Geometry::GTypeMask gtype, bool useMortonBuilder, const size_t singleThreadThreshold)22: bvh(bvh), scene(scene), refs(scene->device,0), prims(scene->device,0), singleThreadThreshold(singleThreadThreshold), gtype(gtype), useMortonBuilder_(useMortonBuilder) {}2324template<int N, typename Mesh, typename Primitive>25BVHNBuilderTwoLevel<N,Mesh,Primitive>::~BVHNBuilderTwoLevel () {26}2728// ===========================================================================29// ===========================================================================30// ===========================================================================3132template<int N, typename Mesh, typename Primitive>33void BVHNBuilderTwoLevel<N,Mesh,Primitive>::build()34{35/* delete some objects */36size_t num = scene->size();37if (num < bvh->objects.size()) {38parallel_for(num, bvh->objects.size(), [&] (const range<size_t>& r) {39for (size_t i=r.begin(); i<r.end(); i++) {40builders[i].reset();41delete bvh->objects[i]; bvh->objects[i] = nullptr;42}43});44}4546#if PROFILE47while(1)48#endif49{50/* reset memory allocator */51bvh->alloc.reset();5253/* skip build for empty scene */54const size_t numPrimitives = scene->getNumPrimitives(gtype,false);5556if (numPrimitives == 0) {57prims.resize(0);58bvh->set(BVH::emptyNode,empty,0);59return;60}6162/* calculate the size of the entire BVH */63const size_t numLeafBlocks = Primitive::blocks(numPrimitives);64const size_t node_bytes = 2*numLeafBlocks*sizeof(typename BVH::AABBNode)/N;65const size_t leaf_bytes = size_t(1.2*numLeafBlocks*sizeof(Primitive));66bvh->alloc.init_estimate(node_bytes+leaf_bytes);6768double t0 = bvh->preBuild(TOSTRING(isa) "::BVH" + toString(N) + "BuilderTwoLevel");6970/* resize object array if scene got larger */71if (bvh->objects.size() < num) bvh->objects.resize(num);72if (builders.size() < num) builders.resize(num);73resizeRefsList ();74nextRef.store(0);7576/* create acceleration structures */77parallel_for(size_t(0), num, [&] (const range<size_t>& r)78{79for (size_t objectID=r.begin(); objectID<r.end(); objectID++)80{81Mesh* mesh = scene->getSafe<Mesh>(objectID);8283/* ignore meshes we do not support */84if (mesh == nullptr || mesh->numTimeSteps != 1)85continue;8687if (isSmallGeometry(mesh)) {88setupSmallBuildRefBuilder (objectID, mesh);89} else {90setupLargeBuildRefBuilder (objectID, mesh);91}92}93});9495/* parallel build of acceleration structures */96parallel_for(size_t(0), num, [&] (const range<size_t>& r)97{98for (size_t objectID=r.begin(); objectID<r.end(); objectID++)99{100/* ignore if no triangle mesh or not enabled */101Mesh* mesh = scene->getSafe<Mesh>(objectID);102if (mesh == nullptr || !mesh->isEnabled() || mesh->numTimeSteps != 1)103continue;104105builders[objectID]->attachBuildRefs (this);106}107});108109110#if PROFILE111double d0 = getSeconds();112#endif113/* fast path for single geometry scenes */114if (nextRef == 1) {115bvh->set(refs[0].node,LBBox3fa(refs[0].bounds()),numPrimitives);116}117118else119{120/* open all large nodes */121refs.resize(nextRef);122123/* this probably needs some more tuning */124const size_t extSize = max(max((size_t)SPLIT_MIN_EXT_SPACE,refs.size()*SPLIT_MEMORY_RESERVE_SCALE),size_t((float)numPrimitives / SPLIT_MEMORY_RESERVE_FACTOR));125126#if !ENABLE_DIRECT_SAH_MERGE_BUILDER127128#if ENABLE_OPEN_SEQUENTIAL129open_sequential(extSize);130#endif131/* compute PrimRefs */132prims.resize(refs.size());133#endif134135{136#if ENABLE_DIRECT_SAH_MERGE_BUILDER137138const PrimInfo pinfo = parallel_reduce(size_t(0), refs.size(), PrimInfo(empty), [&] (const range<size_t>& r) -> PrimInfo {139140PrimInfo pinfo(empty);141for (size_t i=r.begin(); i<r.end(); i++) {142pinfo.add_center2(refs[i]);143}144return pinfo;145}, [] (const PrimInfo& a, const PrimInfo& b) { return PrimInfo::merge(a,b); });146147#else148const PrimInfo pinfo = parallel_reduce(size_t(0), refs.size(), PrimInfo(empty), [&] (const range<size_t>& r) -> PrimInfo {149150PrimInfo pinfo(empty);151for (size_t i=r.begin(); i<r.end(); i++) {152pinfo.add_center2(refs[i]);153prims[i] = PrimRef(refs[i].bounds(),(size_t)refs[i].node);154}155return pinfo;156}, [] (const PrimInfo& a, const PrimInfo& b) { return PrimInfo::merge(a,b); });157#endif158159/* skip if all objects where empty */160if (pinfo.size() == 0)161bvh->set(BVH::emptyNode,empty,0);162163/* otherwise build toplevel hierarchy */164else165{166/* settings for BVH build */167GeneralBVHBuilder::Settings settings;168settings.branchingFactor = N;169settings.maxDepth = BVH::maxBuildDepthLeaf;170settings.logBlockSize = bsr(N);171settings.minLeafSize = 1;172settings.maxLeafSize = 1;173settings.travCost = 1.0f;174settings.intCost = 1.0f;175settings.singleThreadThreshold = singleThreadThreshold;176177#if ENABLE_DIRECT_SAH_MERGE_BUILDER178179refs.resize(extSize);180181NodeRef root = BVHBuilderBinnedOpenMergeSAH::build<NodeRef,BuildRef>(182typename BVH::CreateAlloc(bvh),183typename BVH::AABBNode::Create2(),184typename BVH::AABBNode::Set2(),185186[&] (const BuildRef* refs, const range<size_t>& range, const FastAllocator::CachedAllocator& alloc) -> NodeRef {187assert(range.size() == 1);188return (NodeRef) refs[range.begin()].node;189},190[&] (BuildRef &bref, BuildRef *refs) -> size_t {191return openBuildRef(bref,refs);192},193[&] (size_t dn) { bvh->scene->progressMonitor(0); },194refs.data(),extSize,pinfo,settings);195#else196NodeRef root = BVHBuilderBinnedSAH::build<NodeRef>(197typename BVH::CreateAlloc(bvh),198typename BVH::AABBNode::Create2(),199typename BVH::AABBNode::Set2(),200201[&] (const PrimRef* prims, const range<size_t>& range, const FastAllocator::CachedAllocator& alloc) -> NodeRef {202assert(range.size() == 1);203return (NodeRef) prims[range.begin()].ID();204},205[&] (size_t dn) { bvh->scene->progressMonitor(0); },206prims.data(),pinfo,settings);207#endif208209210bvh->set(root,LBBox3fa(pinfo.geomBounds),numPrimitives);211}212}213}214215bvh->alloc.cleanup();216bvh->postBuild(t0);217#if PROFILE218double d1 = getSeconds();219std::cout << "TOP_LEVEL OPENING/REBUILD TIME " << 1000.0*(d1-d0) << " ms" << std::endl;220#endif221}222223}224225template<int N, typename Mesh, typename Primitive>226void BVHNBuilderTwoLevel<N,Mesh,Primitive>::deleteGeometry(size_t geomID)227{228if (geomID >= bvh->objects.size()) return;229if (builders[geomID]) builders[geomID].reset();230delete bvh->objects [geomID]; bvh->objects [geomID] = nullptr;231}232233template<int N, typename Mesh, typename Primitive>234void BVHNBuilderTwoLevel<N,Mesh,Primitive>::clear()235{236for (size_t i=0; i<bvh->objects.size(); i++)237if (bvh->objects[i]) bvh->objects[i]->clear();238239for (size_t i=0; i<builders.size(); i++)240if (builders[i]) builders[i].reset();241242refs.clear();243}244245template<int N, typename Mesh, typename Primitive>246void BVHNBuilderTwoLevel<N,Mesh,Primitive>::open_sequential(const size_t extSize)247{248if (refs.size() == 0)249return;250251refs.reserve(extSize);252253#if 1254for (size_t i=0;i<refs.size();i++)255{256NodeRef ref = refs[i].node;257if (ref.isAABBNode())258BVH::prefetch(ref);259}260#endif261262std::make_heap(refs.begin(),refs.end());263while (refs.size()+N-1 <= extSize)264{265std::pop_heap (refs.begin(),refs.end());266NodeRef ref = refs.back().node;267if (ref.isLeaf()) break;268refs.pop_back();269270AABBNode* node = ref.getAABBNode();271for (size_t i=0; i<N; i++) {272if (node->child(i) == BVH::emptyNode) continue;273refs.push_back(BuildRef(node->bounds(i),node->child(i)));274275#if 1276NodeRef ref_pre = node->child(i);277if (ref_pre.isAABBNode())278ref_pre.prefetch();279#endif280std::push_heap (refs.begin(),refs.end());281}282}283}284285template<int N, typename Mesh, typename Primitive>286void BVHNBuilderTwoLevel<N,Mesh,Primitive>::setupSmallBuildRefBuilder (size_t objectID, Mesh const * const /*mesh*/)287{288if (builders[objectID] == nullptr || // new mesh289dynamic_cast<RefBuilderSmall*>(builders[objectID].get()) == nullptr) // size change resulted in large->small change290{291builders[objectID].reset (new RefBuilderSmall(objectID));292}293}294295template<int N, typename Mesh, typename Primitive>296void BVHNBuilderTwoLevel<N,Mesh,Primitive>::setupLargeBuildRefBuilder (size_t objectID, Mesh const * const mesh)297{298if (bvh->objects[objectID] == nullptr || // new mesh299builders[objectID]->meshQualityChanged (mesh->quality) || // changed build quality300dynamic_cast<RefBuilderLarge*>(builders[objectID].get()) == nullptr) // size change resulted in small->large change301{302Builder* builder = nullptr;303delete bvh->objects[objectID];304createMeshAccel(objectID, builder);305builders[objectID].reset (new RefBuilderLarge(objectID, builder, mesh->quality));306}307}308309#if defined(EMBREE_GEOMETRY_TRIANGLE)310Builder* BVH4BuilderTwoLevelTriangle4MeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) {311return new BVHNBuilderTwoLevel<4,TriangleMesh,Triangle4>((BVH4*)bvh,scene,TriangleMesh::geom_type,useMortonBuilder);312}313Builder* BVH4BuilderTwoLevelTriangle4vMeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) {314return new BVHNBuilderTwoLevel<4,TriangleMesh,Triangle4v>((BVH4*)bvh,scene,TriangleMesh::geom_type,useMortonBuilder);315}316Builder* BVH4BuilderTwoLevelTriangle4iMeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) {317return new BVHNBuilderTwoLevel<4,TriangleMesh,Triangle4i>((BVH4*)bvh,scene,TriangleMesh::geom_type,useMortonBuilder);318}319#endif320321#if defined(EMBREE_GEOMETRY_QUAD)322Builder* BVH4BuilderTwoLevelQuadMeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) {323return new BVHNBuilderTwoLevel<4,QuadMesh,Quad4v>((BVH4*)bvh,scene,QuadMesh::geom_type,useMortonBuilder);324}325#endif326327#if defined(EMBREE_GEOMETRY_USER)328Builder* BVH4BuilderTwoLevelVirtualSAH (void* bvh, Scene* scene, bool useMortonBuilder) {329return new BVHNBuilderTwoLevel<4,UserGeometry,Object>((BVH4*)bvh,scene,UserGeometry::geom_type,useMortonBuilder);330}331#endif332333#if defined(EMBREE_GEOMETRY_INSTANCE)334Builder* BVH4BuilderTwoLevelInstanceSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype, bool useMortonBuilder) {335return new BVHNBuilderTwoLevel<4,Instance,InstancePrimitive>((BVH4*)bvh,scene,gtype,useMortonBuilder);336}337#endif338339#if defined(EMBREE_GEOMETRY_INSTANCE_ARRAY)340Builder* BVH4BuilderTwoLevelInstanceArraySAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype, bool useMortonBuilder) {341return new BVHNBuilderTwoLevel<4,InstanceArray,InstanceArrayPrimitive>((BVH4*)bvh,scene,gtype,useMortonBuilder);342}343#endif344345#if defined(__AVX__)346#if defined(EMBREE_GEOMETRY_TRIANGLE)347Builder* BVH8BuilderTwoLevelTriangle4MeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) {348return new BVHNBuilderTwoLevel<8,TriangleMesh,Triangle4>((BVH8*)bvh,scene,TriangleMesh::geom_type,useMortonBuilder);349}350Builder* BVH8BuilderTwoLevelTriangle4vMeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) {351return new BVHNBuilderTwoLevel<8,TriangleMesh,Triangle4v>((BVH8*)bvh,scene,TriangleMesh::geom_type,useMortonBuilder);352}353Builder* BVH8BuilderTwoLevelTriangle4iMeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) {354return new BVHNBuilderTwoLevel<8,TriangleMesh,Triangle4i>((BVH8*)bvh,scene,TriangleMesh::geom_type,useMortonBuilder);355}356#endif357358#if defined(EMBREE_GEOMETRY_QUAD)359Builder* BVH8BuilderTwoLevelQuadMeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) {360return new BVHNBuilderTwoLevel<8,QuadMesh,Quad4v>((BVH8*)bvh,scene,QuadMesh::geom_type,useMortonBuilder);361}362#endif363364#if defined(EMBREE_GEOMETRY_USER)365Builder* BVH8BuilderTwoLevelVirtualSAH (void* bvh, Scene* scene, bool useMortonBuilder) {366return new BVHNBuilderTwoLevel<8,UserGeometry,Object>((BVH8*)bvh,scene,UserGeometry::geom_type,useMortonBuilder);367}368#endif369370#if defined(EMBREE_GEOMETRY_INSTANCE)371Builder* BVH8BuilderTwoLevelInstanceSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype, bool useMortonBuilder) {372return new BVHNBuilderTwoLevel<8,Instance,InstancePrimitive>((BVH8*)bvh,scene,gtype,useMortonBuilder);373}374#endif375376#if defined(EMBREE_GEOMETRY_INSTANCE_ARRAY)377Builder* BVH8BuilderTwoLevelInstanceArraySAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype, bool useMortonBuilder) {378return new BVHNBuilderTwoLevel<8,InstanceArray,InstanceArrayPrimitive>((BVH8*)bvh,scene,gtype,useMortonBuilder);379}380#endif381382#endif383}384}385386387