1 // Copyright 2009-2021 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 
4 #pragma once
5 
6 #include <type_traits>
7 
8 #include "bvh_builder_twolevel_internal.h"
9 #include "bvh.h"
10 #include "../common/primref.h"
11 #include "../builders/priminfo.h"
12 #include "../builders/primrefgen.h"
13 
14 /* new open/merge builder */
15 #define ENABLE_DIRECT_SAH_MERGE_BUILDER 1
16 #define ENABLE_OPEN_SEQUENTIAL 0
17 #define SPLIT_MEMORY_RESERVE_FACTOR 1000
18 #define SPLIT_MEMORY_RESERVE_SCALE 2
19 #define SPLIT_MIN_EXT_SPACE 1000
20 
21 namespace embree
22 {
23   namespace isa
24   {
25     template<int N, typename Mesh, typename Primitive>
26     class BVHNBuilderTwoLevel : public Builder
27     {
28       typedef BVHN<N> BVH;
29       typedef typename BVH::AABBNode AABBNode;
30       typedef typename BVH::NodeRef NodeRef;
31 
isSmallGeometry(Mesh * mesh)32       __forceinline static bool isSmallGeometry(Mesh* mesh) {
33         return mesh->size() <= 4;
34       }
35 
36     public:
37 
38       typedef void (*createMeshAccelTy)(Scene* scene, unsigned int geomID, AccelData*& accel, Builder*& builder);
39 
40       struct BuildRef : public PrimRef
41       {
42       public:
BuildRefBuildRef43         __forceinline BuildRef () {}
44 
BuildRefBuildRef45         __forceinline BuildRef (const BBox3fa& bounds, NodeRef node)
46           : PrimRef(bounds,(size_t)node), node(node)
47         {
48           if (node.isLeaf())
49             bounds_area = 0.0f;
50           else
51             bounds_area = area(this->bounds());
52         }
53 
54         /* used by the open/merge bvh builder */
BuildRefBuildRef55         __forceinline BuildRef (const BBox3fa& bounds, NodeRef node, const unsigned int geomID, const unsigned int numPrimitives)
56           : PrimRef(bounds,geomID,numPrimitives), node(node)
57         {
58           /* important for relative buildref ordering */
59           if (node.isLeaf())
60             bounds_area = 0.0f;
61           else
62             bounds_area = area(this->bounds());
63         }
64 
sizeBuildRef65         __forceinline size_t size() const {
66           return primID();
67         }
68 
69         friend bool operator< (const BuildRef& a, const BuildRef& b) {
70           return a.bounds_area < b.bounds_area;
71         }
72 
73         friend __forceinline embree_ostream operator<<(embree_ostream cout, const BuildRef& ref) {
74           return cout << "{ lower = " << ref.lower << ", upper = " << ref.upper << ", center2 = " << ref.center2() << ", geomID = " << ref.geomID() << ", numPrimitives = " << ref.numPrimitives() << ", bounds_area = " << ref.bounds_area << " }";
75         }
76 
numPrimitivesBuildRef77         __forceinline unsigned int numPrimitives() const { return primID(); }
78 
79       public:
80         NodeRef node;
81         float bounds_area;
82       };
83 
84 
openBuildRef(BuildRef & bref,BuildRef * const refs)85       __forceinline size_t openBuildRef(BuildRef &bref, BuildRef *const refs) {
86         if (bref.node.isLeaf())
87         {
88           refs[0] = bref;
89           return 1;
90         }
91         NodeRef ref = bref.node;
92         unsigned int geomID   = bref.geomID();
93         unsigned int numPrims = max((unsigned int)bref.numPrimitives() / N,(unsigned int)1);
94         AABBNode* node = ref.getAABBNode();
95         size_t n = 0;
96         for (size_t i=0; i<N; i++) {
97           if (node->child(i) == BVH::emptyNode) continue;
98           refs[i] = BuildRef(node->bounds(i),node->child(i),geomID,numPrims);
99           n++;
100         }
101         assert(n > 1);
102         return n;
103       }
104 
105       /*! Constructor. */
106       BVHNBuilderTwoLevel (BVH* bvh, Scene* scene, Geometry::GTypeMask gtype = Mesh::geom_type, bool useMortonBuilder = false, const size_t singleThreadThreshold = DEFAULT_SINGLE_THREAD_THRESHOLD);
107 
108       /*! Destructor */
109       ~BVHNBuilderTwoLevel ();
110 
111       /*! builder entry point */
112       void build();
113       void deleteGeometry(size_t geomID);
114       void clear();
115 
116       void open_sequential(const size_t extSize);
117 
118     private:
119 
120       class RefBuilderBase {
121       public:
~RefBuilderBase()122         virtual ~RefBuilderBase () {}
123         virtual void attachBuildRefs (BVHNBuilderTwoLevel* builder) = 0;
124         virtual bool meshQualityChanged (RTCBuildQuality currQuality) = 0;
125       };
126 
127       class RefBuilderSmall : public RefBuilderBase {
128       public:
129 
RefBuilderSmall(size_t objectID)130         RefBuilderSmall (size_t objectID)
131           : objectID_ (objectID) {}
132 
attachBuildRefs(BVHNBuilderTwoLevel * topBuilder)133         void attachBuildRefs (BVHNBuilderTwoLevel* topBuilder) {
134 
135           Mesh* mesh = topBuilder->scene->template getSafe<Mesh>(objectID_);
136           size_t meshSize = mesh->size();
137           assert(isSmallGeometry(mesh));
138 
139           mvector<PrimRef> prefs(topBuilder->scene->device, meshSize);
140           auto pinfo = createPrimRefArray(mesh,objectID_,meshSize,prefs,topBuilder->bvh->scene->progressInterface);
141 
142           size_t begin=0;
143           while (begin < pinfo.size())
144           {
145             Primitive* accel = (Primitive*) topBuilder->bvh->alloc.getCachedAllocator().malloc1(sizeof(Primitive),BVH::byteAlignment);
146             typename BVH::NodeRef node = BVH::encodeLeaf((char*)accel,1);
147             accel->fill(prefs.data(),begin,pinfo.size(),topBuilder->bvh->scene);
148 
149             /* create build primitive */
150 #if ENABLE_DIRECT_SAH_MERGE_BUILDER
151             topBuilder->refs[topBuilder->nextRef++] = BVHNBuilderTwoLevel::BuildRef(pinfo.geomBounds,node,(unsigned int)objectID_,1);
152 #else
153             topBuilder->refs[topBuilder->nextRef++] = BVHNBuilderTwoLevel::BuildRef(pinfo.geomBounds,node);
154 #endif
155           }
156           assert(begin == pinfo.size());
157         }
158 
meshQualityChanged(RTCBuildQuality)159         bool meshQualityChanged (RTCBuildQuality /*currQuality*/) {
160           return false;
161         }
162 
163         size_t  objectID_;
164       };
165 
166       class RefBuilderLarge : public RefBuilderBase {
167       public:
168 
RefBuilderLarge(size_t objectID,const Ref<Builder> & builder,RTCBuildQuality quality)169         RefBuilderLarge (size_t objectID, const Ref<Builder>& builder, RTCBuildQuality quality)
170         : objectID_ (objectID), builder_ (builder), quality_ (quality) {}
171 
attachBuildRefs(BVHNBuilderTwoLevel * topBuilder)172         void attachBuildRefs (BVHNBuilderTwoLevel* topBuilder)
173         {
174           BVH* object  = topBuilder->getBVH(objectID_); assert(object);
175 
176           /* build object if it got modified */
177           if (topBuilder->isGeometryModified(objectID_))
178             builder_->build();
179 
180           /* create build primitive */
181           if (!object->getBounds().empty())
182           {
183 #if ENABLE_DIRECT_SAH_MERGE_BUILDER
184             Mesh* mesh = topBuilder->getMesh(objectID_);
185             topBuilder->refs[topBuilder->nextRef++] = BVHNBuilderTwoLevel::BuildRef(object->getBounds(),object->root,(unsigned int)objectID_,(unsigned int)mesh->size());
186 #else
187             topBuilder->refs[topBuilder->nextRef++] = BVHNBuilderTwoLevel::BuildRef(object->getBounds(),object->root);
188 #endif
189           }
190         }
191 
meshQualityChanged(RTCBuildQuality currQuality)192         bool meshQualityChanged (RTCBuildQuality currQuality) {
193           return currQuality != quality_;
194         }
195 
196       private:
197         size_t          objectID_;
198         Ref<Builder>    builder_;
199         RTCBuildQuality quality_;
200       };
201 
202       void setupLargeBuildRefBuilder (size_t objectID, Mesh const * const mesh);
203       void setupSmallBuildRefBuilder (size_t objectID, Mesh const * const mesh);
204 
getBVH(size_t objectID)205       BVH*  getBVH (size_t objectID) {
206         return this->bvh->objects[objectID];
207       }
getMesh(size_t objectID)208       Mesh* getMesh (size_t objectID) {
209         return this->scene->template getSafe<Mesh>(objectID);
210       }
isGeometryModified(size_t objectID)211       bool  isGeometryModified (size_t objectID) {
212         return this->scene->isGeometryModified(objectID);
213       }
214 
resizeRefsList()215       void resizeRefsList ()
216       {
217         size_t num = parallel_reduce (size_t(0), scene->size(), size_t(0),
218           [this](const range<size_t>& r)->size_t {
219             size_t c = 0;
220             for (auto i=r.begin(); i<r.end(); ++i) {
221               Mesh* mesh = scene->getSafe<Mesh>(i);
222               if (mesh == nullptr || mesh->numTimeSteps != 1)
223                 continue;
224               size_t meshSize = mesh->size();
225               c += isSmallGeometry(mesh) ? Primitive::blocks(meshSize) : 1;
226             }
227             return c;
228           },
229           std::plus<size_t>()
230         );
231 
232         if (refs.size() < num) {
233           refs.resize(num);
234         }
235       }
236 
createMeshAccel(size_t geomID,Builder * & builder)237       void createMeshAccel (size_t geomID, Builder*& builder)
238       {
239         bvh->objects[geomID] = new BVH(Primitive::type,scene);
240         BVH* accel = bvh->objects[geomID];
241         auto mesh = scene->getSafe<Mesh>(geomID);
242         if (nullptr == mesh) {
243           throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"geomID does not return correct type");
244           return;
245         }
246 
247         __internal_two_level_builder__::MeshBuilder<N,Mesh,Primitive>()(accel, mesh, geomID, this->gtype, this->useMortonBuilder_, builder);
248       }
249 
250       using BuilderList = std::vector<std::unique_ptr<RefBuilderBase>>;
251 
252       BuilderList         builders;
253       BVH*                bvh;
254       Scene*              scene;
255       mvector<BuildRef>   refs;
256       mvector<PrimRef>    prims;
257       std::atomic<int>    nextRef;
258       const size_t        singleThreadThreshold;
259       Geometry::GTypeMask gtype;
260       bool                useMortonBuilder_ = false;
261     };
262   }
263 }
264