summaryrefslogtreecommitdiff
path: root/thirdparty/embree/kernels/bvh/bvh_builder_twolevel.h
blob: dc7ec7d27859cbc3b1f13424ec25495ab1bb9529 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include <type_traits>

#include "bvh_builder_twolevel_internal.h"
#include "bvh.h"
#include "../common/primref.h"
#include "../builders/priminfo.h"
#include "../builders/primrefgen.h"

/* new open/merge builder */
#define ENABLE_DIRECT_SAH_MERGE_BUILDER 1
#define ENABLE_OPEN_SEQUENTIAL 0
#define SPLIT_MEMORY_RESERVE_FACTOR 1000
#define SPLIT_MEMORY_RESERVE_SCALE 2
#define SPLIT_MIN_EXT_SPACE 1000

namespace embree
{
  namespace isa
  {
    template<int N, typename Mesh, typename Primitive>
    class BVHNBuilderTwoLevel : public Builder
    {
      typedef BVHN<N> BVH;
      typedef typename BVH::AABBNode AABBNode;
      typedef typename BVH::NodeRef NodeRef;

      __forceinline static bool isSmallGeometry(Mesh* mesh) {
        return mesh->size() <= 4;
      }

    public:

      typedef void (*createMeshAccelTy)(Scene* scene, unsigned int geomID, AccelData*& accel, Builder*& builder);

      struct BuildRef : public PrimRef
      {
      public:
        __forceinline BuildRef () {}

        __forceinline BuildRef (const BBox3fa& bounds, NodeRef node)
          : PrimRef(bounds,(size_t)node), node(node)
        {
          if (node.isLeaf())
            bounds_area = 0.0f;
          else
            bounds_area = area(this->bounds());
        }

        /* used by the open/merge bvh builder */
        __forceinline BuildRef (const BBox3fa& bounds, NodeRef node, const unsigned int geomID, const unsigned int numPrimitives)
          : PrimRef(bounds,geomID,numPrimitives), node(node)
        {
          /* important for relative buildref ordering */
          if (node.isLeaf())
            bounds_area = 0.0f;
          else
            bounds_area = area(this->bounds());
        }

        __forceinline size_t size() const {
          return primID();
        }

        friend bool operator< (const BuildRef& a, const BuildRef& b) {
          return a.bounds_area < b.bounds_area;
        }

        friend __forceinline embree_ostream operator<<(embree_ostream cout, const BuildRef& ref) {
          return cout << "{ lower = " << ref.lower << ", upper = " << ref.upper << ", center2 = " << ref.center2() << ", geomID = " << ref.geomID() << ", numPrimitives = " << ref.numPrimitives() << ", bounds_area = " << ref.bounds_area << " }";
        }

        __forceinline unsigned int numPrimitives() const { return primID(); }

      public:
        NodeRef node;
        float bounds_area;
      };


      __forceinline size_t openBuildRef(BuildRef &bref, BuildRef *const refs) {
        if (bref.node.isLeaf())
        {
          refs[0] = bref;
          return 1;
        }
        NodeRef ref = bref.node;
        unsigned int geomID   = bref.geomID();
        unsigned int numPrims = max((unsigned int)bref.numPrimitives() / N,(unsigned int)1);
        AABBNode* node = ref.getAABBNode();
        size_t n = 0;
        for (size_t i=0; i<N; i++) {
          if (node->child(i) == BVH::emptyNode) continue;
          refs[i] = BuildRef(node->bounds(i),node->child(i),geomID,numPrims);
          n++;
        }
        assert(n > 1);
        return n;        
      }
      
      /*! Constructor. */
      BVHNBuilderTwoLevel (BVH* bvh, Scene* scene, Geometry::GTypeMask gtype = Mesh::geom_type, bool useMortonBuilder = false, const size_t singleThreadThreshold = DEFAULT_SINGLE_THREAD_THRESHOLD);
      
      /*! Destructor */
      ~BVHNBuilderTwoLevel ();
      
      /*! builder entry point */
      void build();
      void deleteGeometry(size_t geomID);
      void clear();

      void open_sequential(const size_t extSize);
      
    private:

      class RefBuilderBase {
      public:
        virtual ~RefBuilderBase () {}
        virtual void attachBuildRefs (BVHNBuilderTwoLevel* builder) = 0;
        virtual bool meshQualityChanged (RTCBuildQuality currQuality) = 0;
      };

      class RefBuilderSmall : public RefBuilderBase {
      public:

        RefBuilderSmall (size_t objectID)
          : objectID_ (objectID) {}

        void attachBuildRefs (BVHNBuilderTwoLevel* topBuilder) {

          Mesh* mesh = topBuilder->scene->template getSafe<Mesh>(objectID_);
          size_t meshSize = mesh->size();
          assert(isSmallGeometry(mesh));
          
          mvector<PrimRef> prefs(topBuilder->scene->device, meshSize);
          auto pinfo = createPrimRefArray(mesh,objectID_,meshSize,prefs,topBuilder->bvh->scene->progressInterface);

          size_t begin=0;
          while (begin < pinfo.size())
          {
            Primitive* accel = (Primitive*) topBuilder->bvh->alloc.getCachedAllocator().malloc1(sizeof(Primitive),BVH::byteAlignment);
            typename BVH::NodeRef node = BVH::encodeLeaf((char*)accel,1);
            accel->fill(prefs.data(),begin,pinfo.size(),topBuilder->bvh->scene);
            
            /* create build primitive */
#if ENABLE_DIRECT_SAH_MERGE_BUILDER
            topBuilder->refs[topBuilder->nextRef++] = BVHNBuilderTwoLevel::BuildRef(pinfo.geomBounds,node,(unsigned int)objectID_,1);
#else
            topBuilder->refs[topBuilder->nextRef++] = BVHNBuilderTwoLevel::BuildRef(pinfo.geomBounds,node);
#endif
          }
          assert(begin == pinfo.size());
        }

        bool meshQualityChanged (RTCBuildQuality /*currQuality*/) {
          return false;
        }
        
        size_t  objectID_;
      };

      class RefBuilderLarge : public RefBuilderBase {
      public:
        
        RefBuilderLarge (size_t objectID, const Ref<Builder>& builder, RTCBuildQuality quality)
        : objectID_ (objectID), builder_ (builder), quality_ (quality) {}

        void attachBuildRefs (BVHNBuilderTwoLevel* topBuilder)
        {
          BVH* object  = topBuilder->getBVH(objectID_); assert(object);
          
          /* build object if it got modified */
          if (topBuilder->isGeometryModified(objectID_))
            builder_->build();

          /* create build primitive */
          if (!object->getBounds().empty())
          {
#if ENABLE_DIRECT_SAH_MERGE_BUILDER
            Mesh* mesh = topBuilder->getMesh(objectID_);
            topBuilder->refs[topBuilder->nextRef++] = BVHNBuilderTwoLevel::BuildRef(object->getBounds(),object->root,(unsigned int)objectID_,(unsigned int)mesh->size());
#else
            topBuilder->refs[topBuilder->nextRef++] = BVHNBuilderTwoLevel::BuildRef(object->getBounds(),object->root);
#endif
          }
        }

        bool meshQualityChanged (RTCBuildQuality currQuality) {
          return currQuality != quality_;
        }

      private:
        size_t          objectID_;
        Ref<Builder>    builder_;
        RTCBuildQuality quality_;
      };

      void setupLargeBuildRefBuilder (size_t objectID, Mesh const * const mesh);
      void setupSmallBuildRefBuilder (size_t objectID, Mesh const * const mesh);

      BVH*  getBVH (size_t objectID) {
        return this->bvh->objects[objectID];
      }
      Mesh* getMesh (size_t objectID) {
        return this->scene->template getSafe<Mesh>(objectID);
      }
      bool  isGeometryModified (size_t objectID) {
        return this->scene->isGeometryModified(objectID);
      }

      void resizeRefsList ()
      {
        size_t num = parallel_reduce (size_t(0), scene->size(), size_t(0), 
          [this](const range<size_t>& r)->size_t {
            size_t c = 0;
            for (auto i=r.begin(); i<r.end(); ++i) {
              Mesh* mesh = scene->getSafe<Mesh>(i);
              if (mesh == nullptr || mesh->numTimeSteps != 1)
                continue;
              size_t meshSize = mesh->size();
              c += isSmallGeometry(mesh) ? Primitive::blocks(meshSize) : 1;
            }
            return c;
          },
          std::plus<size_t>()
        );

        if (refs.size() < num) {
          refs.resize(num);
        }
      }

      void createMeshAccel (size_t geomID, Builder*& builder)
      {
        bvh->objects[geomID] = new BVH(Primitive::type,scene);
        BVH* accel = bvh->objects[geomID];
        auto mesh = scene->getSafe<Mesh>(geomID);
        if (nullptr == mesh) {
          throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"geomID does not return correct type");
          return;
        }

        __internal_two_level_builder__::MeshBuilder<N,Mesh,Primitive>()(accel, mesh, geomID, this->gtype, this->useMortonBuilder_, builder);
      }      

      using BuilderList = std::vector<std::unique_ptr<RefBuilderBase>>;

      BuilderList         builders;
      BVH*                bvh;
      Scene*              scene;      
      mvector<BuildRef>   refs;
      mvector<PrimRef>    prims;
      std::atomic<int>    nextRef;
      const size_t        singleThreadThreshold;
      Geometry::GTypeMask gtype;
      bool                useMortonBuilder_ = false;
    };
  }
}