Path: blob/master/thirdparty/embree/kernels/bvh/bvh_builder_twolevel.h
9906 views
// Copyright 2009-2021 Intel Corporation1// SPDX-License-Identifier: Apache-2.023#pragma once45#include <type_traits>67#include "bvh_builder_twolevel_internal.h"8#include "bvh.h"9#include "../builders/priminfo.h"10#include "../builders/primrefgen.h"1112/* new open/merge builder */13#define ENABLE_DIRECT_SAH_MERGE_BUILDER 114#define ENABLE_OPEN_SEQUENTIAL 015#define SPLIT_MEMORY_RESERVE_FACTOR 100016#define SPLIT_MEMORY_RESERVE_SCALE 217#define SPLIT_MIN_EXT_SPACE 10001819namespace embree20{21namespace isa22{23template<int N, typename Mesh, typename Primitive>24class BVHNBuilderTwoLevel : public Builder25{26typedef BVHN<N> BVH;27typedef typename BVH::AABBNode AABBNode;28typedef typename BVH::NodeRef NodeRef;2930__forceinline static bool isSmallGeometry(Mesh* mesh) {31return mesh->size() <= 4;32}3334public:3536typedef void (*createMeshAccelTy)(Scene* scene, unsigned int geomID, AccelData*& accel, Builder*& builder);3738struct BuildRef : public PrimRef39{40public:41__forceinline BuildRef () {}4243__forceinline BuildRef (const BBox3fa& bounds, NodeRef node)44: PrimRef(bounds,(size_t)node), node(node)45{46if (node.isLeaf())47bounds_area = 0.0f;48else49bounds_area = area(this->bounds());50}5152/* used by the open/merge bvh builder */53__forceinline BuildRef (const BBox3fa& bounds, NodeRef node, const unsigned int geomID, const unsigned int numPrimitives)54: PrimRef(bounds,geomID,numPrimitives), node(node)55{56/* important for relative buildref ordering */57if (node.isLeaf())58bounds_area = 0.0f;59else60bounds_area = area(this->bounds());61}6263__forceinline size_t size() const {64return primID();65}6667friend bool operator< (const BuildRef& a, const BuildRef& b) {68return a.bounds_area < b.bounds_area;69}7071friend __forceinline embree_ostream operator<<(embree_ostream cout, const BuildRef& ref) {72return cout << "{ lower = " << ref.lower << ", upper = " << ref.upper << ", center2 = " << ref.center2() << ", geomID = " << ref.geomID() << ", numPrimitives = " << ref.numPrimitives() << ", bounds_area = " << ref.bounds_area << " }";73}7475__forceinline unsigned int numPrimitives() const { return primID(); }7677public:78NodeRef node;79float bounds_area;80};818283__forceinline size_t openBuildRef(BuildRef &bref, BuildRef *const refs) {84if (bref.node.isLeaf())85{86refs[0] = bref;87return 1;88}89NodeRef ref = bref.node;90unsigned int geomID = bref.geomID();91unsigned int numPrims = max((unsigned int)bref.numPrimitives() / N,(unsigned int)1);92AABBNode* node = ref.getAABBNode();93size_t n = 0;94for (size_t i=0; i<N; i++) {95if (node->child(i) == BVH::emptyNode) continue;96refs[i] = BuildRef(node->bounds(i),node->child(i),geomID,numPrims);97n++;98}99assert(n > 1);100return n;101}102103/*! Constructor. */104BVHNBuilderTwoLevel (BVH* bvh, Scene* scene, Geometry::GTypeMask gtype = Mesh::geom_type, bool useMortonBuilder = false, const size_t singleThreadThreshold = DEFAULT_SINGLE_THREAD_THRESHOLD);105106/*! Destructor */107~BVHNBuilderTwoLevel ();108109/*! builder entry point */110void build();111void deleteGeometry(size_t geomID);112void clear();113114void open_sequential(const size_t extSize);115116private:117118class RefBuilderBase {119public:120virtual ~RefBuilderBase () {}121virtual void attachBuildRefs (BVHNBuilderTwoLevel* builder) = 0;122virtual bool meshQualityChanged (RTCBuildQuality currQuality) = 0;123};124125class RefBuilderSmall : public RefBuilderBase {126public:127128RefBuilderSmall (size_t objectID)129: objectID_ (objectID) {}130131void attachBuildRefs (BVHNBuilderTwoLevel* topBuilder) {132133Mesh* mesh = topBuilder->scene->template getSafe<Mesh>(objectID_);134size_t meshSize = mesh->size();135assert(isSmallGeometry(mesh));136137mvector<PrimRef> prefs(topBuilder->scene->device, meshSize);138auto pinfo = createPrimRefArray(mesh,objectID_,meshSize,prefs,topBuilder->bvh->scene->progressInterface);139140size_t begin=0;141while (begin < pinfo.size())142{143Primitive* accel = (Primitive*) topBuilder->bvh->alloc.getCachedAllocator().malloc1(sizeof(Primitive),BVH::byteAlignment);144typename BVH::NodeRef node = BVH::encodeLeaf((char*)accel,1);145accel->fill(prefs.data(),begin,pinfo.size(),topBuilder->bvh->scene);146147/* create build primitive */148#if ENABLE_DIRECT_SAH_MERGE_BUILDER149topBuilder->refs[topBuilder->nextRef++] = BVHNBuilderTwoLevel::BuildRef(pinfo.geomBounds,node,(unsigned int)objectID_,1);150#else151topBuilder->refs[topBuilder->nextRef++] = BVHNBuilderTwoLevel::BuildRef(pinfo.geomBounds,node);152#endif153}154assert(begin == pinfo.size());155}156157bool meshQualityChanged (RTCBuildQuality /*currQuality*/) {158return false;159}160161size_t objectID_;162};163164class RefBuilderLarge : public RefBuilderBase {165public:166167RefBuilderLarge (size_t objectID, const Ref<Builder>& builder, RTCBuildQuality quality)168: objectID_ (objectID), builder_ (builder), quality_ (quality) {}169170void attachBuildRefs (BVHNBuilderTwoLevel* topBuilder)171{172BVH* object = topBuilder->getBVH(objectID_); assert(object);173174/* build object if it got modified */175if (topBuilder->isGeometryModified(objectID_))176builder_->build();177178/* create build primitive */179if (!object->getBounds().empty())180{181#if ENABLE_DIRECT_SAH_MERGE_BUILDER182Mesh* mesh = topBuilder->getMesh(objectID_);183topBuilder->refs[topBuilder->nextRef++] = BVHNBuilderTwoLevel::BuildRef(object->getBounds(),object->root,(unsigned int)objectID_,(unsigned int)mesh->size());184#else185topBuilder->refs[topBuilder->nextRef++] = BVHNBuilderTwoLevel::BuildRef(object->getBounds(),object->root);186#endif187}188}189190bool meshQualityChanged (RTCBuildQuality currQuality) {191return currQuality != quality_;192}193194private:195size_t objectID_;196Ref<Builder> builder_;197RTCBuildQuality quality_;198};199200void setupLargeBuildRefBuilder (size_t objectID, Mesh const * const mesh);201void setupSmallBuildRefBuilder (size_t objectID, Mesh const * const mesh);202203BVH* getBVH (size_t objectID) {204return this->bvh->objects[objectID];205}206Mesh* getMesh (size_t objectID) {207return this->scene->template getSafe<Mesh>(objectID);208}209bool isGeometryModified (size_t objectID) {210return this->scene->isGeometryModified(objectID);211}212213void resizeRefsList ()214{215size_t num = parallel_reduce (size_t(0), scene->size(), size_t(0),216[this](const range<size_t>& r)->size_t {217size_t c = 0;218for (auto i=r.begin(); i<r.end(); ++i) {219Mesh* mesh = scene->getSafe<Mesh>(i);220if (mesh == nullptr || mesh->numTimeSteps != 1)221continue;222size_t meshSize = mesh->size();223c += isSmallGeometry(mesh) ? Primitive::blocks(meshSize) : 1;224}225return c;226},227std::plus<size_t>()228);229230if (refs.size() < num) {231refs.resize(num);232}233}234235void createMeshAccel (size_t geomID, Builder*& builder)236{237bvh->objects[geomID] = new BVH(Primitive::type,scene);238BVH* accel = bvh->objects[geomID];239auto mesh = scene->getSafe<Mesh>(geomID);240if (nullptr == mesh) {241throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"geomID does not return correct type");242return;243}244245__internal_two_level_builder__::MeshBuilder<N,Mesh,Primitive>()(accel, mesh, geomID, this->gtype, this->useMortonBuilder_, builder);246}247248using BuilderList = std::vector<std::unique_ptr<RefBuilderBase>>;249250BuilderList builders;251BVH* bvh;252Scene* scene;253mvector<BuildRef> refs;254mvector<PrimRef> prims;255std::atomic<int> nextRef;256const size_t singleThreadThreshold;257Geometry::GTypeMask gtype;258bool useMortonBuilder_ = false;259};260}261}262263264