Path: blob/master/thirdparty/embree/kernels/common/rtcore_builder.cpp
9905 views
// Copyright 2009-2021 Intel Corporation1// SPDX-License-Identifier: Apache-2.023#define RTC_EXPORT_API45#include "default.h"6#include "device.h"7#include "scene.h"8#include "context.h"9#include "alloc.h"1011#include "../builders/bvh_builder_sah.h"12#include "../builders/bvh_builder_morton.h"1314namespace embree15{16namespace isa // FIXME: support more ISAs for builders17{18struct BVH : public RefCount19{20BVH (Device* device)21: device(device), allocator(device,true), morton_src(device,0), morton_tmp(device,0)22{23device->refInc();24}2526~BVH() {27device->refDec();28}2930public:31Device* device;32FastAllocator allocator;33mvector<BVHBuilderMorton::BuildPrim> morton_src;34mvector<BVHBuilderMorton::BuildPrim> morton_tmp;35};3637void* rtcBuildBVHMorton(const RTCBuildArguments* arguments)38{39BVH* bvh = (BVH*) arguments->bvh;40RTCBuildPrimitive* prims_i = arguments->primitives;41size_t primitiveCount = arguments->primitiveCount;42RTCCreateNodeFunction createNode = arguments->createNode;43RTCSetNodeChildrenFunction setNodeChildren = arguments->setNodeChildren;44RTCSetNodeBoundsFunction setNodeBounds = arguments->setNodeBounds;45RTCCreateLeafFunction createLeaf = arguments->createLeaf;46RTCProgressMonitorFunction buildProgress = arguments->buildProgress;47void* userPtr = arguments->userPtr;4849std::atomic<size_t> progress(0);5051/* initialize temporary arrays for morton builder */52PrimRef* prims = (PrimRef*) prims_i;53mvector<BVHBuilderMorton::BuildPrim>& morton_src = bvh->morton_src;54mvector<BVHBuilderMorton::BuildPrim>& morton_tmp = bvh->morton_tmp;55morton_src.resize(primitiveCount);56morton_tmp.resize(primitiveCount);5758/* compute centroid bounds */59const BBox3fa centBounds = parallel_reduce ( size_t(0), primitiveCount, BBox3fa(empty), [&](const range<size_t>& r) -> BBox3fa {6061BBox3fa bounds(empty);62for (size_t i=r.begin(); i<r.end(); i++)63bounds.extend(prims[i].bounds().center2());64return bounds;65}, BBox3fa::merge);6667/* compute morton codes */68BVHBuilderMorton::MortonCodeMapping mapping(centBounds);69parallel_for ( size_t(0), primitiveCount, [&](const range<size_t>& r) {70BVHBuilderMorton::MortonCodeGenerator generator(mapping,&morton_src[r.begin()]);71for (size_t i=r.begin(); i<r.end(); i++) {72generator(prims[i].bounds(),(unsigned) i);73}74});7576/* start morton build */77std::pair<void*,BBox3fa> root = BVHBuilderMorton::build<std::pair<void*,BBox3fa>>(7879/* thread local allocator for fast allocations */80[&] () -> FastAllocator::CachedAllocator {81return bvh->allocator.getCachedAllocator();82},8384/* lambda function that allocates BVH nodes */85[&] ( const FastAllocator::CachedAllocator& alloc, size_t N ) -> void* {86return createNode((RTCThreadLocalAllocator)&alloc, (unsigned int)N,userPtr);87},8889/* lambda function that sets bounds */90[&] (void* node, const std::pair<void*,BBox3fa>* children, size_t N) -> std::pair<void*,BBox3fa>91{92BBox3fa bounds = empty;93void* childptrs[BVHBuilderMorton::MAX_BRANCHING_FACTOR];94const RTCBounds* cbounds[BVHBuilderMorton::MAX_BRANCHING_FACTOR];95for (size_t i=0; i<N; i++) {96bounds.extend(children[i].second);97childptrs[i] = children[i].first;98cbounds[i] = (const RTCBounds*)&children[i].second;99}100setNodeBounds(node,cbounds,(unsigned int)N,userPtr);101setNodeChildren(node,childptrs, (unsigned int)N,userPtr);102return std::make_pair(node,bounds);103},104105/* lambda function that creates BVH leaves */106[&]( const range<unsigned>& current, const FastAllocator::CachedAllocator& alloc) -> std::pair<void*,BBox3fa>107{108RTCBuildPrimitive localBuildPrims[RTC_BUILD_MAX_PRIMITIVES_PER_LEAF];109BBox3fa bounds = empty;110for (size_t i=0;i<current.size();i++)111{112const size_t id = morton_src[current.begin()+i].index;113bounds.extend(prims[id].bounds());114localBuildPrims[i] = prims_i[id];115}116void* node = createLeaf((RTCThreadLocalAllocator)&alloc,localBuildPrims,current.size(),userPtr);117return std::make_pair(node,bounds);118},119120/* lambda that calculates the bounds for some primitive */121[&] (const BVHBuilderMorton::BuildPrim& morton) -> BBox3fa {122return prims[morton.index].bounds();123},124125/* progress monitor function */126[&] (size_t dn) {127if (!buildProgress) return true;128const size_t n = progress.fetch_add(dn)+dn;129const double f = std::min(1.0,double(n)/double(primitiveCount));130return buildProgress(userPtr,f);131},132133morton_src.data(),morton_tmp.data(),primitiveCount,134*arguments);135136bvh->allocator.cleanup();137return root.first;138}139140void* rtcBuildBVHBinnedSAH(const RTCBuildArguments* arguments)141{142BVH* bvh = (BVH*) arguments->bvh;143RTCBuildPrimitive* prims = arguments->primitives;144size_t primitiveCount = arguments->primitiveCount;145RTCCreateNodeFunction createNode = arguments->createNode;146RTCSetNodeChildrenFunction setNodeChildren = arguments->setNodeChildren;147RTCSetNodeBoundsFunction setNodeBounds = arguments->setNodeBounds;148RTCCreateLeafFunction createLeaf = arguments->createLeaf;149RTCProgressMonitorFunction buildProgress = arguments->buildProgress;150void* userPtr = arguments->userPtr;151152std::atomic<size_t> progress(0);153154/* calculate priminfo */155auto computeBounds = [&](const range<size_t>& r) -> CentGeomBBox3fa156{157CentGeomBBox3fa bounds(empty);158for (size_t j=r.begin(); j<r.end(); j++)159bounds.extend((BBox3fa&)prims[j]);160return bounds;161};162const CentGeomBBox3fa bounds =163parallel_reduce(size_t(0),primitiveCount,size_t(1024),size_t(1024),CentGeomBBox3fa(empty), computeBounds, CentGeomBBox3fa::merge2);164165const PrimInfo pinfo(0,primitiveCount,bounds);166167/* build BVH */168void* root = BVHBuilderBinnedSAH::build<void*>(169170/* thread local allocator for fast allocations */171[&] () -> FastAllocator::CachedAllocator {172return bvh->allocator.getCachedAllocator();173},174175/* lambda function that creates BVH nodes */176[&](BVHBuilderBinnedSAH::BuildRecord* children, const size_t N, const FastAllocator::CachedAllocator& alloc) -> void*177{178void* node = createNode((RTCThreadLocalAllocator)&alloc, (unsigned int)N,userPtr);179const RTCBounds* cbounds[GeneralBVHBuilder::MAX_BRANCHING_FACTOR];180for (size_t i=0; i<N; i++) cbounds[i] = (const RTCBounds*) &children[i].prims.geomBounds;181setNodeBounds(node,cbounds, (unsigned int)N,userPtr);182return node;183},184185/* lambda function that updates BVH nodes */186[&](const BVHBuilderBinnedSAH::BuildRecord& precord, const BVHBuilderBinnedSAH::BuildRecord* crecords, void* node, void** children, const size_t N) -> void* {187setNodeChildren(node,children, (unsigned int)N,userPtr);188return node;189},190191/* lambda function that creates BVH leaves */192[&](const PrimRef* prims, const range<size_t>& range, const FastAllocator::CachedAllocator& alloc) -> void* {193return createLeaf((RTCThreadLocalAllocator)&alloc,(RTCBuildPrimitive*)(prims+range.begin()),range.size(),userPtr);194},195196/* progress monitor function */197[&] (size_t dn) {198if (!buildProgress) return true;199const size_t n = progress.fetch_add(dn)+dn;200const double f = std::min(1.0,double(n)/double(primitiveCount));201return buildProgress(userPtr,f);202},203204(PrimRef*)prims,pinfo,*arguments);205206bvh->allocator.cleanup();207return root;208}209210static __forceinline const std::pair<CentGeomBBox3fa,unsigned int> mergePair(const std::pair<CentGeomBBox3fa,unsigned int>& a, const std::pair<CentGeomBBox3fa,unsigned int>& b) {211CentGeomBBox3fa centBounds = CentGeomBBox3fa::merge2(a.first,b.first);212unsigned int maxGeomID = max(a.second,b.second);213return std::pair<CentGeomBBox3fa,unsigned int>(centBounds,maxGeomID);214}215216void* rtcBuildBVHSpatialSAH(const RTCBuildArguments* arguments)217{218BVH* bvh = (BVH*) arguments->bvh;219RTCBuildPrimitive* prims = arguments->primitives;220size_t primitiveCount = arguments->primitiveCount;221RTCCreateNodeFunction createNode = arguments->createNode;222RTCSetNodeChildrenFunction setNodeChildren = arguments->setNodeChildren;223RTCSetNodeBoundsFunction setNodeBounds = arguments->setNodeBounds;224RTCCreateLeafFunction createLeaf = arguments->createLeaf;225RTCSplitPrimitiveFunction splitPrimitive = arguments->splitPrimitive;226RTCProgressMonitorFunction buildProgress = arguments->buildProgress;227void* userPtr = arguments->userPtr;228229std::atomic<size_t> progress(0);230231/* calculate priminfo */232233auto computeBounds = [&](const range<size_t>& r) -> std::pair<CentGeomBBox3fa,unsigned int>234{235CentGeomBBox3fa bounds(empty);236unsigned maxGeomID = 0;237for (size_t j=r.begin(); j<r.end(); j++)238{239bounds.extend((BBox3fa&)prims[j]);240maxGeomID = max(maxGeomID,prims[j].geomID);241}242return std::pair<CentGeomBBox3fa,unsigned int>(bounds,maxGeomID);243};244245246const std::pair<CentGeomBBox3fa,unsigned int> pair =247parallel_reduce(size_t(0),primitiveCount,size_t(1024),size_t(1024),std::pair<CentGeomBBox3fa,unsigned int>(CentGeomBBox3fa(empty),0), computeBounds, mergePair);248249CentGeomBBox3fa bounds = pair.first;250const unsigned int maxGeomID = pair.second;251252if (unlikely(maxGeomID >= ((unsigned int)1 << (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS))))253{254/* fallback code for max geomID larger than threshold */255return rtcBuildBVHBinnedSAH(arguments);256}257258const PrimInfo pinfo(0,primitiveCount,bounds);259260/* function that splits a build primitive */261struct Splitter262{263Splitter (RTCSplitPrimitiveFunction splitPrimitive, unsigned geomID, unsigned primID, void* userPtr)264: splitPrimitive(splitPrimitive), geomID(geomID), primID(primID), userPtr(userPtr) {}265266__forceinline void operator() (PrimRef& prim, const size_t dim, const float pos, PrimRef& left_o, PrimRef& right_o) const267{268prim.geomIDref() &= BVHBuilderBinnedFastSpatialSAH::GEOMID_MASK;269splitPrimitive((RTCBuildPrimitive*)&prim,(unsigned)dim,pos,(RTCBounds*)&left_o,(RTCBounds*)&right_o,userPtr);270left_o.geomIDref() = geomID; left_o.primIDref() = primID;271right_o.geomIDref() = geomID; right_o.primIDref() = primID;272}273274__forceinline void operator() (const BBox3fa& box, const size_t dim, const float pos, BBox3fa& left_o, BBox3fa& right_o) const275{276PrimRef prim(box,geomID & BVHBuilderBinnedFastSpatialSAH::GEOMID_MASK,primID);277splitPrimitive((RTCBuildPrimitive*)&prim,(unsigned)dim,pos,(RTCBounds*)&left_o,(RTCBounds*)&right_o,userPtr);278}279280RTCSplitPrimitiveFunction splitPrimitive;281unsigned geomID;282unsigned primID;283void* userPtr;284};285286/* build BVH */287void* root = BVHBuilderBinnedFastSpatialSAH::build<void*>(288289/* thread local allocator for fast allocations */290[&] () -> FastAllocator::CachedAllocator {291return bvh->allocator.getCachedAllocator();292},293294/* lambda function that creates BVH nodes */295[&] (BVHBuilderBinnedFastSpatialSAH::BuildRecord* children, const size_t N, const FastAllocator::CachedAllocator& alloc) -> void*296{297void* node = createNode((RTCThreadLocalAllocator)&alloc, (unsigned int)N,userPtr);298const RTCBounds* cbounds[GeneralBVHBuilder::MAX_BRANCHING_FACTOR];299for (size_t i=0; i<N; i++) cbounds[i] = (const RTCBounds*) &children[i].prims.geomBounds;300setNodeBounds(node,cbounds, (unsigned int)N,userPtr);301return node;302},303304/* lambda function that updates BVH nodes */305[&] (const BVHBuilderBinnedFastSpatialSAH::BuildRecord& precord, const BVHBuilderBinnedFastSpatialSAH::BuildRecord* crecords, void* node, void** children, const size_t N) -> void* {306setNodeChildren(node,children, (unsigned int)N,userPtr);307return node;308},309310/* lambda function that creates BVH leaves */311[&] (const PrimRef* prims, const range<size_t>& range, const FastAllocator::CachedAllocator& alloc) -> void* {312return createLeaf((RTCThreadLocalAllocator)&alloc,(RTCBuildPrimitive*)(prims+range.begin()),range.size(),userPtr);313},314315/* returns the splitter */316[&] ( const PrimRef& prim ) -> Splitter {317return Splitter(splitPrimitive,prim.geomID(),prim.primID(),userPtr);318},319320/* progress monitor function */321[&] (size_t dn) {322if (!buildProgress) return true;323const size_t n = progress.fetch_add(dn)+dn;324const double f = std::min(1.0,double(n)/double(primitiveCount));325return buildProgress(userPtr,f);326},327328(PrimRef*)prims,329arguments->primitiveArrayCapacity,330pinfo,*arguments);331332bvh->allocator.cleanup();333return root;334}335}336}337338using namespace embree;339using namespace embree::isa;340341RTC_NAMESPACE_BEGIN342343RTC_API RTCBVH rtcNewBVH(RTCDevice device)344{345RTC_CATCH_BEGIN;346RTC_TRACE(rtcNewAllocator);347RTC_VERIFY_HANDLE(device);348BVH* bvh = new BVH((Device*)device);349return (RTCBVH) bvh->refInc();350RTC_CATCH_END((Device*)device);351return nullptr;352}353354RTC_API void* rtcBuildBVH(const RTCBuildArguments* arguments)355{356BVH* bvh = (BVH*) arguments->bvh;357RTC_CATCH_BEGIN;358RTC_TRACE(rtcBuildBVH);359RTC_VERIFY_HANDLE(bvh);360RTC_VERIFY_HANDLE(arguments);361RTC_VERIFY_HANDLE(arguments->createNode);362RTC_VERIFY_HANDLE(arguments->setNodeChildren);363RTC_VERIFY_HANDLE(arguments->setNodeBounds);364RTC_VERIFY_HANDLE(arguments->createLeaf);365366if (arguments->primitiveArrayCapacity < arguments->primitiveCount)367throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"primitiveArrayCapacity must be greater or equal to primitiveCount")368369/* initialize the allocator */370bvh->allocator.init_estimate(arguments->primitiveCount*sizeof(BBox3fa));371bvh->allocator.reset();372373/* switch between different builders based on quality level */374if (arguments->buildQuality == RTC_BUILD_QUALITY_LOW)375return rtcBuildBVHMorton(arguments);376else if (arguments->buildQuality == RTC_BUILD_QUALITY_MEDIUM)377return rtcBuildBVHBinnedSAH(arguments);378else if (arguments->buildQuality == RTC_BUILD_QUALITY_HIGH) {379if (arguments->splitPrimitive == nullptr || arguments->primitiveArrayCapacity <= arguments->primitiveCount)380return rtcBuildBVHBinnedSAH(arguments);381else382return rtcBuildBVHSpatialSAH(arguments);383}384else385throw_RTCError(RTC_ERROR_INVALID_OPERATION,"invalid build quality");386387/* if we are in dynamic mode, then do not clear temporary data */388if (!(arguments->buildFlags & RTC_BUILD_FLAG_DYNAMIC))389{390bvh->morton_src.clear();391bvh->morton_tmp.clear();392}393394RTC_CATCH_END(bvh->device);395return nullptr;396}397398RTC_API void* rtcThreadLocalAlloc(RTCThreadLocalAllocator localAllocator, size_t bytes, size_t align)399{400FastAllocator::CachedAllocator* alloc = (FastAllocator::CachedAllocator*) localAllocator;401RTC_CATCH_BEGIN;402RTC_TRACE(rtcThreadLocalAlloc);403return alloc->malloc0(bytes,align);404RTC_CATCH_END(alloc->alloc->getDevice());405return nullptr;406}407408RTC_API void rtcMakeStaticBVH(RTCBVH hbvh)409{410BVH* bvh = (BVH*) hbvh;411RTC_CATCH_BEGIN;412RTC_TRACE(rtcStaticBVH);413RTC_VERIFY_HANDLE(hbvh);414bvh->morton_src.clear();415bvh->morton_tmp.clear();416RTC_CATCH_END(bvh->device);417}418419RTC_API void rtcRetainBVH(RTCBVH hbvh)420{421BVH* bvh = (BVH*) hbvh;422Device* device = bvh ? bvh->device : nullptr;423RTC_CATCH_BEGIN;424RTC_TRACE(rtcRetainBVH);425RTC_VERIFY_HANDLE(hbvh);426bvh->refInc();427RTC_CATCH_END(device);428}429430RTC_API void rtcReleaseBVH(RTCBVH hbvh)431{432BVH* bvh = (BVH*) hbvh;433Device* device = bvh ? bvh->device : nullptr;434RTC_CATCH_BEGIN;435RTC_TRACE(rtcReleaseBVH);436RTC_VERIFY_HANDLE(hbvh);437bvh->refDec();438RTC_CATCH_END(device);439}440441RTC_NAMESPACE_END442443444