1 //============================================================================
2 //  Copyright (c) Kitware, Inc.
3 //  All rights reserved.
4 //  See LICENSE.txt for details.
5 //
6 //  This software is distributed WITHOUT ANY WARRANTY; without even
7 //  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8 //  PURPOSE.  See the above copyright notice for more information.
9 //============================================================================
10 
11 #include <math.h>
12 
13 #include <vtkm/Math.h>
14 #include <vtkm/VectorAnalysis.h>
15 
16 #include <vtkm/cont/Algorithm.h>
17 #include <vtkm/cont/DeviceAdapter.h>
18 #include <vtkm/cont/DeviceAdapterAlgorithm.h>
19 #include <vtkm/cont/Invoker.h>
20 #include <vtkm/cont/RuntimeDeviceTracker.h>
21 #include <vtkm/cont/TryExecute.h>
22 
23 #include <vtkm/cont/AtomicArray.h>
24 
25 #include <vtkm/rendering/raytracing/BoundingVolumeHierarchy.h>
26 #include <vtkm/rendering/raytracing/Logger.h>
27 #include <vtkm/rendering/raytracing/MortonCodes.h>
28 #include <vtkm/rendering/raytracing/RayTracingTypeDefs.h>
29 #include <vtkm/rendering/raytracing/Worklets.h>
30 
31 #include <vtkm/worklet/WorkletMapField.h>
32 
33 #define AABB_EPSILON 0.00001f
34 namespace vtkm
35 {
36 namespace rendering
37 {
38 namespace raytracing
39 {
40 namespace detail
41 {
42 
43 class LinearBVHBuilder
44 {
45 public:
46   class CountingIterator;
47 
48   class GatherFloat32;
49 
50   template <typename Device>
51   class GatherVecCast;
52 
53   class CreateLeafs;
54 
55   class BVHData;
56 
57   class PropagateAABBs;
58 
59   class TreeBuilder;
60 
61   VTKM_CONT
LinearBVHBuilder()62   LinearBVHBuilder() {}
63 
64   VTKM_CONT void SortAABBS(BVHData& bvh, bool);
65 
66   VTKM_CONT void BuildHierarchy(BVHData& bvh);
67 
68   VTKM_CONT void Build(LinearBVH& linearBVH);
69 }; // class LinearBVHBuilder
70 
71 class LinearBVHBuilder::CountingIterator : public vtkm::worklet::WorkletMapField
72 {
73 public:
74   VTKM_CONT
CountingIterator()75   CountingIterator() {}
76   using ControlSignature = void(FieldOut);
77   using ExecutionSignature = void(WorkIndex, _1);
78   VTKM_EXEC
operator ()(const vtkm::Id & index,vtkm::Id & outId) const79   void operator()(const vtkm::Id& index, vtkm::Id& outId) const { outId = index; }
80 }; //class countingIterator
81 
82 class LinearBVHBuilder::GatherFloat32 : public vtkm::worklet::WorkletMapField
83 {
84 public:
85   VTKM_CONT
GatherFloat32()86   GatherFloat32() {}
87   using ControlSignature = void(FieldIn, WholeArrayIn, WholeArrayOut);
88   using ExecutionSignature = void(WorkIndex, _1, _2, _3);
89 
90   template <typename InType, typename OutType>
operator ()(const vtkm::Id & outIndex,const vtkm::Id & inIndex,const InType & inPortal,OutType & outPortal) const91   VTKM_EXEC void operator()(const vtkm::Id& outIndex,
92                             const vtkm::Id& inIndex,
93                             const InType& inPortal,
94                             OutType& outPortal) const
95   {
96     outPortal.Set(outIndex, inPortal.Get(inIndex));
97   }
98 }; //class GatherFloat
99 
100 class LinearBVHBuilder::CreateLeafs : public vtkm::worklet::WorkletMapField
101 {
102 
103 public:
104   VTKM_CONT
CreateLeafs()105   CreateLeafs() {}
106 
107   typedef void ControlSignature(FieldIn, WholeArrayOut);
108   typedef void ExecutionSignature(_1, _2, WorkIndex);
109 
110   template <typename LeafPortalType>
operator ()(const vtkm::Id & dataIndex,LeafPortalType & leafs,const vtkm::Id & index) const111   VTKM_EXEC void operator()(const vtkm::Id& dataIndex,
112                             LeafPortalType& leafs,
113                             const vtkm::Id& index) const
114   {
115     const vtkm::Id offset = index * 2;
116     leafs.Set(offset, 1);             // number of primitives
117     leafs.Set(offset + 1, dataIndex); // number of primitives
118   }
119 }; //class createLeafs
120 
121 template <typename DeviceAdapterTag>
122 class LinearBVHBuilder::GatherVecCast : public vtkm::worklet::WorkletMapField
123 {
124 private:
125   using Vec4IdArrayHandle = typename vtkm::cont::ArrayHandle<vtkm::Id4>;
126   using Vec4IntArrayHandle = typename vtkm::cont::ArrayHandle<vtkm::Vec4i_32>;
127   using PortalConst = typename Vec4IdArrayHandle::ReadPortalType;
128   using Portal = typename Vec4IntArrayHandle::WritePortalType;
129 
130 private:
131   PortalConst InputPortal;
132   Portal OutputPortal;
133 
134 public:
135   VTKM_CONT
GatherVecCast(const Vec4IdArrayHandle & inputPortal,Vec4IntArrayHandle & outputPortal,const vtkm::Id & size)136   GatherVecCast(const Vec4IdArrayHandle& inputPortal,
137                 Vec4IntArrayHandle& outputPortal,
138                 const vtkm::Id& size)
139     : InputPortal(inputPortal.PrepareForInput(DeviceAdapterTag()))
140   {
141     this->OutputPortal = outputPortal.PrepareForOutput(size, DeviceAdapterTag());
142   }
143   using ControlSignature = void(FieldIn);
144   using ExecutionSignature = void(WorkIndex, _1);
145   VTKM_EXEC
operator ()(const vtkm::Id & outIndex,const vtkm::Id & inIndex) const146   void operator()(const vtkm::Id& outIndex, const vtkm::Id& inIndex) const
147   {
148     OutputPortal.Set(outIndex, InputPortal.Get(inIndex));
149   }
150 }; //class GatherVec3Id
151 
152 class LinearBVHBuilder::BVHData
153 {
154 public:
155   vtkm::cont::ArrayHandle<vtkm::UInt32> mortonCodes;
156   vtkm::cont::ArrayHandle<vtkm::Id> parent;
157   vtkm::cont::ArrayHandle<vtkm::Id> leftChild;
158   vtkm::cont::ArrayHandle<vtkm::Id> rightChild;
159   vtkm::cont::ArrayHandle<vtkm::Id> leafs;
160   vtkm::cont::ArrayHandle<vtkm::Bounds> innerBounds;
161   vtkm::cont::ArrayHandleCounting<vtkm::Id> leafOffsets;
162   AABBs& AABB;
163 
BVHData(vtkm::Id numPrimitives,AABBs & aabbs)164   VTKM_CONT BVHData(vtkm::Id numPrimitives, AABBs& aabbs)
165     : leafOffsets(0, 2, numPrimitives)
166     , AABB(aabbs)
167     , NumPrimitives(numPrimitives)
168   {
169     InnerNodeCount = NumPrimitives - 1;
170     vtkm::Id size = NumPrimitives + InnerNodeCount;
171 
172     parent.Allocate(size);
173     leftChild.Allocate(InnerNodeCount);
174     rightChild.Allocate(InnerNodeCount);
175     innerBounds.Allocate(InnerNodeCount);
176     mortonCodes.Allocate(NumPrimitives);
177   }
178 
179   VTKM_CONT
~BVHData()180   ~BVHData() {}
181 
182   VTKM_CONT
GetNumberOfPrimitives() const183   vtkm::Id GetNumberOfPrimitives() const { return NumPrimitives; }
184   VTKM_CONT
GetNumberOfInnerNodes() const185   vtkm::Id GetNumberOfInnerNodes() const { return InnerNodeCount; }
186 
187 private:
188   vtkm::Id NumPrimitives;
189   vtkm::Id InnerNodeCount;
190 
191 }; // class BVH
192 
193 class LinearBVHBuilder::PropagateAABBs : public vtkm::worklet::WorkletMapField
194 {
195 private:
196   vtkm::Int32 LeafCount;
197 
198 public:
199   VTKM_CONT
PropagateAABBs(vtkm::Int32 leafCount)200   PropagateAABBs(vtkm::Int32 leafCount)
201     : LeafCount(leafCount)
202 
203   {
204   }
205   using ControlSignature = void(WholeArrayIn,
206                                 WholeArrayIn,
207                                 WholeArrayIn,
208                                 WholeArrayIn,
209                                 WholeArrayIn,
210                                 WholeArrayIn,
211                                 WholeArrayIn,
212                                 WholeArrayIn,     //Parents
213                                 WholeArrayIn,     //lchild
214                                 WholeArrayIn,     //rchild
215                                 AtomicArrayInOut, //counters
216                                 WholeArrayInOut   // flatbvh
217   );
218   using ExecutionSignature = void(WorkIndex, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12);
219 
220   template <typename InputPortalType,
221             typename OffsetPortalType,
222             typename IdPortalType,
223             typename AtomicType,
224             typename BVHType>
operator ()(const vtkm::Id workIndex,const InputPortalType & xmin,const InputPortalType & ymin,const InputPortalType & zmin,const InputPortalType & xmax,const InputPortalType & ymax,const InputPortalType & zmax,const OffsetPortalType & leafOffsets,const IdPortalType & parents,const IdPortalType & leftChildren,const IdPortalType & rightChildren,AtomicType & counters,BVHType & flatBVH) const225   VTKM_EXEC_CONT void operator()(const vtkm::Id workIndex,
226                                  const InputPortalType& xmin,
227                                  const InputPortalType& ymin,
228                                  const InputPortalType& zmin,
229                                  const InputPortalType& xmax,
230                                  const InputPortalType& ymax,
231                                  const InputPortalType& zmax,
232                                  const OffsetPortalType& leafOffsets,
233                                  const IdPortalType& parents,
234                                  const IdPortalType& leftChildren,
235                                  const IdPortalType& rightChildren,
236                                  AtomicType& counters,
237                                  BVHType& flatBVH) const
238 
239   {
240     //move up into the inner nodes
241     vtkm::Id currentNode = LeafCount - 1 + workIndex;
242     vtkm::Id2 childVector;
243     while (currentNode != 0)
244     {
245       currentNode = parents.Get(currentNode);
246       vtkm::Int32 oldCount = counters.Add(currentNode, 1);
247       if (oldCount == 0)
248       {
249         return;
250       }
251       vtkm::Id currentNodeOffset = currentNode * 4;
252       childVector[0] = leftChildren.Get(currentNode);
253       childVector[1] = rightChildren.Get(currentNode);
254       if (childVector[0] > (LeafCount - 2))
255       {
256         //our left child is a leaf, so just grab the AABB
257         //and set it in the current node
258         childVector[0] = childVector[0] - LeafCount + 1;
259 
260         vtkm::Vec4f_32 first4Vec; // = FlatBVH.Get(currentNode); only this one needs effects this
261 
262         first4Vec[0] = xmin.Get(childVector[0]);
263         first4Vec[1] = ymin.Get(childVector[0]);
264         first4Vec[2] = zmin.Get(childVector[0]);
265         first4Vec[3] = xmax.Get(childVector[0]);
266         flatBVH.Set(currentNodeOffset, first4Vec);
267 
268         vtkm::Vec4f_32 second4Vec = flatBVH.Get(currentNodeOffset + 1);
269         second4Vec[0] = ymax.Get(childVector[0]);
270         second4Vec[1] = zmax.Get(childVector[0]);
271         flatBVH.Set(currentNodeOffset + 1, second4Vec);
272         // set index to leaf
273         vtkm::Id leafIndex = leafOffsets.Get(childVector[0]);
274         childVector[0] = -(leafIndex + 1);
275       }
276       else
277       {
278         //our left child is an inner node, so gather
279         //both AABBs in the child and join them for
280         //the current node left AABB.
281         vtkm::Id child = childVector[0] * 4;
282 
283         vtkm::Vec4f_32 cFirst4Vec = flatBVH.Get(child);
284         vtkm::Vec4f_32 cSecond4Vec = flatBVH.Get(child + 1);
285         vtkm::Vec4f_32 cThird4Vec = flatBVH.Get(child + 2);
286 
287         cFirst4Vec[0] = vtkm::Min(cFirst4Vec[0], cSecond4Vec[2]);
288         cFirst4Vec[1] = vtkm::Min(cFirst4Vec[1], cSecond4Vec[3]);
289         cFirst4Vec[2] = vtkm::Min(cFirst4Vec[2], cThird4Vec[0]);
290         cFirst4Vec[3] = vtkm::Max(cFirst4Vec[3], cThird4Vec[1]);
291         flatBVH.Set(currentNodeOffset, cFirst4Vec);
292 
293         vtkm::Vec4f_32 second4Vec = flatBVH.Get(currentNodeOffset + 1);
294         second4Vec[0] = vtkm::Max(cSecond4Vec[0], cThird4Vec[2]);
295         second4Vec[1] = vtkm::Max(cSecond4Vec[1], cThird4Vec[3]);
296 
297         flatBVH.Set(currentNodeOffset + 1, second4Vec);
298       }
299 
300       if (childVector[1] > (LeafCount - 2))
301       {
302         //our right child is a leaf, so just grab the AABB
303         //and set it in the current node
304         childVector[1] = childVector[1] - LeafCount + 1;
305 
306 
307         vtkm::Vec4f_32 second4Vec = flatBVH.Get(currentNodeOffset + 1);
308 
309         second4Vec[2] = xmin.Get(childVector[1]);
310         second4Vec[3] = ymin.Get(childVector[1]);
311         flatBVH.Set(currentNodeOffset + 1, second4Vec);
312 
313         vtkm::Vec4f_32 third4Vec;
314         third4Vec[0] = zmin.Get(childVector[1]);
315         third4Vec[1] = xmax.Get(childVector[1]);
316         third4Vec[2] = ymax.Get(childVector[1]);
317         third4Vec[3] = zmax.Get(childVector[1]);
318         flatBVH.Set(currentNodeOffset + 2, third4Vec);
319 
320         // set index to leaf
321         vtkm::Id leafIndex = leafOffsets.Get(childVector[1]);
322         childVector[1] = -(leafIndex + 1);
323       }
324       else
325       {
326         //our left child is an inner node, so gather
327         //both AABBs in the child and join them for
328         //the current node left AABB.
329         vtkm::Id child = childVector[1] * 4;
330 
331         vtkm::Vec4f_32 cFirst4Vec = flatBVH.Get(child);
332         vtkm::Vec4f_32 cSecond4Vec = flatBVH.Get(child + 1);
333         vtkm::Vec4f_32 cThird4Vec = flatBVH.Get(child + 2);
334 
335         vtkm::Vec4f_32 second4Vec = flatBVH.Get(currentNodeOffset + 1);
336         second4Vec[2] = vtkm::Min(cFirst4Vec[0], cSecond4Vec[2]);
337         second4Vec[3] = vtkm::Min(cFirst4Vec[1], cSecond4Vec[3]);
338         flatBVH.Set(currentNodeOffset + 1, second4Vec);
339 
340         cThird4Vec[0] = vtkm::Min(cFirst4Vec[2], cThird4Vec[0]);
341         cThird4Vec[1] = vtkm::Max(cFirst4Vec[3], cThird4Vec[1]);
342         cThird4Vec[2] = vtkm::Max(cSecond4Vec[0], cThird4Vec[2]);
343         cThird4Vec[3] = vtkm::Max(cSecond4Vec[1], cThird4Vec[3]);
344         flatBVH.Set(currentNodeOffset + 2, cThird4Vec);
345       }
346       vtkm::Vec4f_32 fourth4Vec{ 0.0f };
347       vtkm::Int32 leftChild =
348         static_cast<vtkm::Int32>((childVector[0] >= 0) ? childVector[0] * 4 : childVector[0]);
349       memcpy(&fourth4Vec[0], &leftChild, 4);
350       vtkm::Int32 rightChild =
351         static_cast<vtkm::Int32>((childVector[1] >= 0) ? childVector[1] * 4 : childVector[1]);
352       memcpy(&fourth4Vec[1], &rightChild, 4);
353       flatBVH.Set(currentNodeOffset + 3, fourth4Vec);
354     }
355   }
356 }; //class PropagateAABBs
357 
358 class LinearBVHBuilder::TreeBuilder : public vtkm::worklet::WorkletMapField
359 {
360 private:
361   vtkm::Id LeafCount;
362   vtkm::Id InnerCount;
363   //TODO: get intrinsic support
364   VTKM_EXEC
CountLeadingZeros(vtkm::UInt32 & x) const365   inline vtkm::Int32 CountLeadingZeros(vtkm::UInt32& x) const
366   {
367     vtkm::UInt32 y;
368     vtkm::UInt32 n = 32;
369     y = x >> 16;
370     if (y != 0)
371     {
372       n = n - 16;
373       x = y;
374     }
375     y = x >> 8;
376     if (y != 0)
377     {
378       n = n - 8;
379       x = y;
380     }
381     y = x >> 4;
382     if (y != 0)
383     {
384       n = n - 4;
385       x = y;
386     }
387     y = x >> 2;
388     if (y != 0)
389     {
390       n = n - 2;
391       x = y;
392     }
393     y = x >> 1;
394     if (y != 0)
395       return vtkm::Int32(n - 2);
396     return vtkm::Int32(n - x);
397   }
398 
399   // returns the count of largest shared prefix between
400   // two morton codes. Ties are broken by the indexes
401   // a and b.
402   //
403   // returns count of the largest binary prefix
404 
405   template <typename MortonType>
delta(const vtkm::Int32 & a,const vtkm::Int32 & b,const MortonType & mortonCodePortal) const406   VTKM_EXEC inline vtkm::Int32 delta(const vtkm::Int32& a,
407                                      const vtkm::Int32& b,
408                                      const MortonType& mortonCodePortal) const
409   {
410     bool tie = false;
411     bool outOfRange = (b < 0 || b > LeafCount - 1);
412     //still make the call but with a valid adderss
413     vtkm::Int32 bb = (outOfRange) ? 0 : b;
414     vtkm::UInt32 aCode = mortonCodePortal.Get(a);
415     vtkm::UInt32 bCode = mortonCodePortal.Get(bb);
416     //use xor to find where they differ
417     vtkm::UInt32 exOr = aCode ^ bCode;
418     tie = (exOr == 0);
419     //break the tie, a and b must always differ
420     exOr = tie ? vtkm::UInt32(a) ^ vtkm::UInt32(bb) : exOr;
421     vtkm::Int32 count = CountLeadingZeros(exOr);
422     if (tie)
423       count += 32;
424     count = (outOfRange) ? -1 : count;
425     return count;
426   }
427 
428 public:
429   VTKM_CONT
TreeBuilder(const vtkm::Id & leafCount)430   TreeBuilder(const vtkm::Id& leafCount)
431     : LeafCount(leafCount)
432     , InnerCount(leafCount - 1)
433   {
434   }
435   using ControlSignature = void(FieldOut, FieldOut, WholeArrayIn, WholeArrayOut);
436   using ExecutionSignature = void(WorkIndex, _1, _2, _3, _4);
437 
438   template <typename MortonType, typename ParentType>
operator ()(const vtkm::Id & index,vtkm::Id & leftChild,vtkm::Id & rightChild,const MortonType & mortonCodePortal,ParentType & parentPortal) const439   VTKM_EXEC void operator()(const vtkm::Id& index,
440                             vtkm::Id& leftChild,
441                             vtkm::Id& rightChild,
442                             const MortonType& mortonCodePortal,
443                             ParentType& parentPortal) const
444   {
445     vtkm::Int32 idx = vtkm::Int32(index);
446     //determine range direction
447     vtkm::Int32 d =
448       0 > (delta(idx, idx + 1, mortonCodePortal) - delta(idx, idx - 1, mortonCodePortal)) ? -1 : 1;
449 
450     //find upper bound for the length of the range
451     vtkm::Int32 minDelta = delta(idx, idx - d, mortonCodePortal);
452     vtkm::Int32 lMax = 2;
453     while (delta(idx, idx + lMax * d, mortonCodePortal) > minDelta)
454       lMax *= 2;
455 
456     //binary search to find the lower bound
457     vtkm::Int32 l = 0;
458     for (int t = lMax / 2; t >= 1; t /= 2)
459     {
460       if (delta(idx, idx + (l + t) * d, mortonCodePortal) > minDelta)
461         l += t;
462     }
463 
464     vtkm::Int32 j = idx + l * d;
465     vtkm::Int32 deltaNode = delta(idx, j, mortonCodePortal);
466     vtkm::Int32 s = 0;
467     vtkm::Float32 divFactor = 2.f;
468     //find the split position using a binary search
469     for (vtkm::Int32 t = (vtkm::Int32)ceil(vtkm::Float32(l) / divFactor);;
470          divFactor *= 2, t = (vtkm::Int32)ceil(vtkm::Float32(l) / divFactor))
471     {
472       if (delta(idx, idx + (s + t) * d, mortonCodePortal) > deltaNode)
473       {
474         s += t;
475       }
476 
477       if (t == 1)
478         break;
479     }
480 
481     vtkm::Int32 split = idx + s * d + vtkm::Min(d, 0);
482     //assign parent/child pointers
483     if (vtkm::Min(idx, j) == split)
484     {
485       //leaf
486       parentPortal.Set(split + InnerCount, idx);
487       leftChild = split + InnerCount;
488     }
489     else
490     {
491       //inner node
492       parentPortal.Set(split, idx);
493       leftChild = split;
494     }
495 
496 
497     if (vtkm::Max(idx, j) == split + 1)
498     {
499       //leaf
500       parentPortal.Set(split + InnerCount + 1, idx);
501       rightChild = split + InnerCount + 1;
502     }
503     else
504     {
505       parentPortal.Set(split + 1, idx);
506       rightChild = split + 1;
507     }
508   }
509 }; // class TreeBuilder
510 
SortAABBS(BVHData & bvh,bool singleAABB)511 VTKM_CONT void LinearBVHBuilder::SortAABBS(BVHData& bvh, bool singleAABB)
512 {
513   //create array of indexes to be sorted with morton codes
514   vtkm::cont::ArrayHandle<vtkm::Id> iterator;
515   iterator.Allocate(bvh.GetNumberOfPrimitives());
516 
517   vtkm::worklet::DispatcherMapField<CountingIterator> iterDispatcher;
518   iterDispatcher.Invoke(iterator);
519 
520   //sort the morton codes
521 
522   vtkm::cont::Algorithm::SortByKey(bvh.mortonCodes, iterator);
523 
524   vtkm::Id arraySize = bvh.GetNumberOfPrimitives();
525   vtkm::cont::ArrayHandle<vtkm::Float32> temp1;
526   vtkm::cont::ArrayHandle<vtkm::Float32> temp2;
527   temp1.Allocate(arraySize);
528 
529   vtkm::worklet::DispatcherMapField<GatherFloat32> gatherDispatcher;
530 
531   //xmins
532   gatherDispatcher.Invoke(iterator, bvh.AABB.xmins, temp1);
533 
534   temp2 = bvh.AABB.xmins;
535   bvh.AABB.xmins = temp1;
536   temp1 = temp2;
537   //ymins
538   gatherDispatcher.Invoke(iterator, bvh.AABB.ymins, temp1);
539 
540   temp2 = bvh.AABB.ymins;
541   bvh.AABB.ymins = temp1;
542   temp1 = temp2;
543   //zmins
544   gatherDispatcher.Invoke(iterator, bvh.AABB.zmins, temp1);
545 
546   temp2 = bvh.AABB.zmins;
547   bvh.AABB.zmins = temp1;
548   temp1 = temp2;
549   //xmaxs
550   gatherDispatcher.Invoke(iterator, bvh.AABB.xmaxs, temp1);
551 
552   temp2 = bvh.AABB.xmaxs;
553   bvh.AABB.xmaxs = temp1;
554   temp1 = temp2;
555   //ymaxs
556   gatherDispatcher.Invoke(iterator, bvh.AABB.ymaxs, temp1);
557 
558   temp2 = bvh.AABB.ymaxs;
559   bvh.AABB.ymaxs = temp1;
560   temp1 = temp2;
561   //zmaxs
562   gatherDispatcher.Invoke(iterator, bvh.AABB.zmaxs, temp1);
563 
564   temp2 = bvh.AABB.zmaxs;
565   bvh.AABB.zmaxs = temp1;
566   temp1 = temp2;
567 
568   // Create the leaf references
569   bvh.leafs.Allocate(arraySize * 2);
570   // we only actually have a single primitive, but the algorithm
571   // requires 2. Make sure they both point to the original
572   // primitive
573   if (singleAABB)
574   {
575     auto iterPortal = iterator.WritePortal();
576     for (int i = 0; i < 2; ++i)
577     {
578       iterPortal.Set(i, 0);
579     }
580   }
581 
582   vtkm::worklet::DispatcherMapField<CreateLeafs> leafDispatcher;
583   leafDispatcher.Invoke(iterator, bvh.leafs);
584 
585 } // method SortAABB
586 
Build(LinearBVH & linearBVH)587 VTKM_CONT void LinearBVHBuilder::Build(LinearBVH& linearBVH)
588 {
589 
590   //
591   //
592   // This algorithm needs at least 2 AABBs
593   //
594   bool singleAABB = false;
595   vtkm::Id numberOfAABBs = linearBVH.GetNumberOfAABBs();
596   if (numberOfAABBs == 1)
597   {
598     numberOfAABBs = 2;
599     singleAABB = true;
600     vtkm::Float32 xmin = linearBVH.AABB.xmins.WritePortal().Get(0);
601     vtkm::Float32 ymin = linearBVH.AABB.ymins.WritePortal().Get(0);
602     vtkm::Float32 zmin = linearBVH.AABB.zmins.WritePortal().Get(0);
603     vtkm::Float32 xmax = linearBVH.AABB.xmaxs.WritePortal().Get(0);
604     vtkm::Float32 ymax = linearBVH.AABB.ymaxs.WritePortal().Get(0);
605     vtkm::Float32 zmax = linearBVH.AABB.zmaxs.WritePortal().Get(0);
606 
607     linearBVH.AABB.xmins.Allocate(2);
608     linearBVH.AABB.ymins.Allocate(2);
609     linearBVH.AABB.zmins.Allocate(2);
610     linearBVH.AABB.xmaxs.Allocate(2);
611     linearBVH.AABB.ymaxs.Allocate(2);
612     linearBVH.AABB.zmaxs.Allocate(2);
613     for (int i = 0; i < 2; ++i)
614     {
615       linearBVH.AABB.xmins.WritePortal().Set(i, xmin);
616       linearBVH.AABB.ymins.WritePortal().Set(i, ymin);
617       linearBVH.AABB.zmins.WritePortal().Set(i, zmin);
618       linearBVH.AABB.xmaxs.WritePortal().Set(i, xmax);
619       linearBVH.AABB.ymaxs.WritePortal().Set(i, ymax);
620       linearBVH.AABB.zmaxs.WritePortal().Set(i, zmax);
621     }
622   }
623 
624 
625   const vtkm::Id numBBoxes = numberOfAABBs;
626   BVHData bvh(numBBoxes, linearBVH.GetAABBs());
627 
628 
629   // Find the extent of all bounding boxes to generate normalization for morton codes
630   vtkm::Vec3f_32 minExtent(vtkm::Infinity32(), vtkm::Infinity32(), vtkm::Infinity32());
631   vtkm::Vec3f_32 maxExtent(
632     vtkm::NegativeInfinity32(), vtkm::NegativeInfinity32(), vtkm::NegativeInfinity32());
633   maxExtent[0] = vtkm::cont::Algorithm::Reduce(bvh.AABB.xmaxs, maxExtent[0], MaxValue());
634   maxExtent[1] = vtkm::cont::Algorithm::Reduce(bvh.AABB.ymaxs, maxExtent[1], MaxValue());
635   maxExtent[2] = vtkm::cont::Algorithm::Reduce(bvh.AABB.zmaxs, maxExtent[2], MaxValue());
636   minExtent[0] = vtkm::cont::Algorithm::Reduce(bvh.AABB.xmins, minExtent[0], MinValue());
637   minExtent[1] = vtkm::cont::Algorithm::Reduce(bvh.AABB.ymins, minExtent[1], MinValue());
638   minExtent[2] = vtkm::cont::Algorithm::Reduce(bvh.AABB.zmins, minExtent[2], MinValue());
639 
640   linearBVH.TotalBounds.X.Min = minExtent[0];
641   linearBVH.TotalBounds.X.Max = maxExtent[0];
642   linearBVH.TotalBounds.Y.Min = minExtent[1];
643   linearBVH.TotalBounds.Y.Max = maxExtent[1];
644   linearBVH.TotalBounds.Z.Min = minExtent[2];
645   linearBVH.TotalBounds.Z.Max = maxExtent[2];
646 
647   vtkm::Vec3f_32 deltaExtent = maxExtent - minExtent;
648   vtkm::Vec3f_32 inverseExtent;
649   for (int i = 0; i < 3; ++i)
650   {
651     inverseExtent[i] = (deltaExtent[i] == 0.f) ? 0 : 1.f / deltaExtent[i];
652   }
653 
654   //Generate the morton codes
655   vtkm::worklet::DispatcherMapField<MortonCodeAABB> mortonDispatch(
656     MortonCodeAABB(inverseExtent, minExtent));
657   mortonDispatch.Invoke(bvh.AABB.xmins,
658                         bvh.AABB.ymins,
659                         bvh.AABB.zmins,
660                         bvh.AABB.xmaxs,
661                         bvh.AABB.ymaxs,
662                         bvh.AABB.zmaxs,
663                         bvh.mortonCodes);
664   linearBVH.Allocate(bvh.GetNumberOfPrimitives());
665 
666   SortAABBS(bvh, singleAABB);
667 
668   vtkm::worklet::DispatcherMapField<TreeBuilder> treeDispatch(
669     TreeBuilder(bvh.GetNumberOfPrimitives()));
670   treeDispatch.Invoke(bvh.leftChild, bvh.rightChild, bvh.mortonCodes, bvh.parent);
671 
672   const vtkm::Int32 primitiveCount = vtkm::Int32(bvh.GetNumberOfPrimitives());
673 
674   vtkm::cont::ArrayHandle<vtkm::Int32> counters;
675   counters.Allocate(bvh.GetNumberOfPrimitives() - 1);
676 
677   vtkm::cont::ArrayHandleConstant<vtkm::Int32> zero(0, bvh.GetNumberOfPrimitives() - 1);
678   vtkm::cont::Algorithm::Copy(zero, counters);
679 
680   vtkm::worklet::DispatcherMapField<PropagateAABBs> propDispatch(PropagateAABBs{ primitiveCount });
681 
682   propDispatch.Invoke(bvh.AABB.xmins,
683                       bvh.AABB.ymins,
684                       bvh.AABB.zmins,
685                       bvh.AABB.xmaxs,
686                       bvh.AABB.ymaxs,
687                       bvh.AABB.zmaxs,
688                       bvh.leafOffsets,
689                       bvh.parent,
690                       bvh.leftChild,
691                       bvh.rightChild,
692                       counters,
693                       linearBVH.FlatBVH);
694 
695   linearBVH.Leafs = bvh.leafs;
696 }
697 } //namespace detail
698 
LinearBVH()699 LinearBVH::LinearBVH()
700   : IsConstructed(false)
701   , CanConstruct(false){};
702 
703 VTKM_CONT
LinearBVH(AABBs & aabbs)704 LinearBVH::LinearBVH(AABBs& aabbs)
705   : AABB(aabbs)
706   , IsConstructed(false)
707   , CanConstruct(true)
708 {
709 }
710 
711 VTKM_CONT
LinearBVH(const LinearBVH & other)712 LinearBVH::LinearBVH(const LinearBVH& other)
713   : AABB(other.AABB)
714   , FlatBVH(other.FlatBVH)
715   , Leafs(other.Leafs)
716   , LeafCount(other.LeafCount)
717   , IsConstructed(other.IsConstructed)
718   , CanConstruct(other.CanConstruct)
719 {
720 }
721 
Allocate(const vtkm::Id & leafCount)722 VTKM_CONT void LinearBVH::Allocate(const vtkm::Id& leafCount)
723 {
724   LeafCount = leafCount;
725   FlatBVH.Allocate((leafCount - 1) * 4);
726 }
727 
Construct()728 void LinearBVH::Construct()
729 {
730   if (IsConstructed)
731     return;
732   if (!CanConstruct)
733     throw vtkm::cont::ErrorBadValue(
734       "Linear BVH: coordinates and triangles must be set before calling construct!");
735 
736   detail::LinearBVHBuilder builder;
737   builder.Build(*this);
738 }
739 
740 VTKM_CONT
SetData(AABBs & aabbs)741 void LinearBVH::SetData(AABBs& aabbs)
742 {
743   AABB = aabbs;
744   IsConstructed = false;
745   CanConstruct = true;
746 }
747 
748 // explicitly export
749 //template VTKM_RENDERING_EXPORT void LinearBVH::ConstructOnDevice<
750 //  vtkm::cont::DeviceAdapterTagSerial>(vtkm::cont::DeviceAdapterTagSerial);
751 //#ifdef VTKM_ENABLE_TBB
752 //template VTKM_RENDERING_EXPORT void LinearBVH::ConstructOnDevice<vtkm::cont::DeviceAdapterTagTBB>(
753 //  vtkm::cont::DeviceAdapterTagTBB);
754 //#endif
755 //#ifdef VTKM_ENABLE_OPENMP
756 //template VTKM_CONT_EXPORT void LinearBVH::ConstructOnDevice<vtkm::cont::DeviceAdapterTagOpenMP>(
757 //  vtkm::cont::DeviceAdapterTagOpenMP);
758 //#endif
759 //#ifdef VTKM_ENABLE_CUDA
760 //template VTKM_RENDERING_EXPORT void LinearBVH::ConstructOnDevice<vtkm::cont::DeviceAdapterTagCuda>(
761 //  vtkm::cont::DeviceAdapterTagCuda);
762 //#endif
763 //
764 VTKM_CONT
GetIsConstructed() const765 bool LinearBVH::GetIsConstructed() const
766 {
767   return IsConstructed;
768 }
769 
GetNumberOfAABBs() const770 vtkm::Id LinearBVH::GetNumberOfAABBs() const
771 {
772   return AABB.xmins.GetNumberOfValues();
773 }
774 
GetAABBs()775 AABBs& LinearBVH::GetAABBs()
776 {
777   return AABB;
778 }
779 }
780 }
781 } // namespace vtkm::rendering::raytracing
782