Initial commit.
This commit is contained in:
		
						commit
						d3bb49b3f5
					
				
					 1073 changed files with 484757 additions and 0 deletions
				
			
		
							
								
								
									
										411
									
								
								Framework/external/embree/kernels/builders/bvh_builder_hair.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										411
									
								
								Framework/external/embree/kernels/builders/bvh_builder_hair.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,411 @@ | |||
| // Copyright 2009-2021 Intel Corporation
 | ||||
| // SPDX-License-Identifier: Apache-2.0
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "../bvh/bvh.h" | ||||
| #include "../geometry/primitive.h" | ||||
| #include "../builders/bvh_builder_sah.h" | ||||
| #include "../builders/heuristic_binning_array_aligned.h" | ||||
| #include "../builders/heuristic_binning_array_unaligned.h" | ||||
| #include "../builders/heuristic_strand_array.h" | ||||
| 
 | ||||
| #define NUM_HAIR_OBJECT_BINS 32 | ||||
| 
 | ||||
| namespace embree | ||||
| { | ||||
|   namespace isa | ||||
|   { | ||||
|     struct BVHBuilderHair | ||||
|     { | ||||
|       /*! settings for builder */ | ||||
|       struct Settings | ||||
|       { | ||||
|         /*! default settings */ | ||||
|         Settings () | ||||
|         : branchingFactor(2), maxDepth(32), logBlockSize(0), minLeafSize(1), maxLeafSize(7), finished_range_threshold(inf) {} | ||||
| 
 | ||||
|       public: | ||||
|         size_t branchingFactor;  //!< branching factor of BVH to build
 | ||||
|         size_t maxDepth;         //!< maximum depth of BVH to build
 | ||||
|         size_t logBlockSize;     //!< log2 of blocksize for SAH heuristic
 | ||||
|         size_t minLeafSize;      //!< minimum size of a leaf
 | ||||
|         size_t maxLeafSize;      //!< maximum size of a leaf
 | ||||
|         size_t finished_range_threshold;  //!< finished range threshold
 | ||||
|       }; | ||||
| 
 | ||||
|       template<typename NodeRef, | ||||
|         typename CreateAllocFunc, | ||||
|         typename CreateAABBNodeFunc, | ||||
|         typename SetAABBNodeFunc, | ||||
|         typename CreateOBBNodeFunc, | ||||
|         typename SetOBBNodeFunc, | ||||
|         typename CreateLeafFunc, | ||||
|         typename ProgressMonitor, | ||||
|         typename ReportFinishedRangeFunc> | ||||
| 
 | ||||
|         class BuilderT | ||||
|         { | ||||
|           ALIGNED_CLASS_(16); | ||||
|           friend struct BVHBuilderHair; | ||||
| 
 | ||||
|           typedef FastAllocator::CachedAllocator Allocator; | ||||
|           typedef HeuristicArrayBinningSAH<PrimRef,NUM_HAIR_OBJECT_BINS> HeuristicBinningSAH; | ||||
|           typedef UnalignedHeuristicArrayBinningSAH<PrimRef,NUM_HAIR_OBJECT_BINS> UnalignedHeuristicBinningSAH; | ||||
|           typedef HeuristicStrandSplit HeuristicStrandSplitSAH; | ||||
| 
 | ||||
|           static const size_t MAX_BRANCHING_FACTOR =  8;         //!< maximum supported BVH branching factor
 | ||||
|           static const size_t MIN_LARGE_LEAF_LEVELS = 8;         //!< create balanced tree if we are that many levels before the maximum tree depth
 | ||||
|           static const size_t SINGLE_THREADED_THRESHOLD = 4096;  //!< threshold to switch to single threaded build
 | ||||
| 
 | ||||
|           static const size_t travCostAligned = 1; | ||||
|           static const size_t travCostUnaligned = 5; | ||||
|           static const size_t intCost = 6; | ||||
| 
 | ||||
|           BuilderT (Scene* scene, | ||||
|                     PrimRef* prims, | ||||
|                     const CreateAllocFunc& createAlloc, | ||||
|                     const CreateAABBNodeFunc& createAABBNode, | ||||
|                     const SetAABBNodeFunc& setAABBNode, | ||||
|                     const CreateOBBNodeFunc& createOBBNode, | ||||
|                     const SetOBBNodeFunc& setOBBNode, | ||||
|                     const CreateLeafFunc& createLeaf, | ||||
|                     const ProgressMonitor& progressMonitor, | ||||
|                     const ReportFinishedRangeFunc& reportFinishedRange, | ||||
|                     const Settings settings) | ||||
| 
 | ||||
|             : cfg(settings), | ||||
|             prims(prims), | ||||
|             createAlloc(createAlloc), | ||||
|             createAABBNode(createAABBNode), | ||||
|             setAABBNode(setAABBNode), | ||||
|             createOBBNode(createOBBNode), | ||||
|             setOBBNode(setOBBNode), | ||||
|             createLeaf(createLeaf), | ||||
|             progressMonitor(progressMonitor), | ||||
|             reportFinishedRange(reportFinishedRange), | ||||
|             alignedHeuristic(prims), unalignedHeuristic(scene,prims), strandHeuristic(scene,prims) {} | ||||
| 
 | ||||
|           /*! checks if all primitives are from the same geometry */ | ||||
|           __forceinline bool sameGeometry(const PrimInfoRange& range) | ||||
|           { | ||||
|             if (range.size() == 0) return true; | ||||
|             unsigned int firstGeomID = prims[range.begin()].geomID(); | ||||
|             for (size_t i=range.begin()+1; i<range.end(); i++) { | ||||
|               if (prims[i].geomID() != firstGeomID){ | ||||
|                 return false; | ||||
|               } | ||||
|             } | ||||
|             return true; | ||||
|           } | ||||
| 
 | ||||
|           /*! creates a large leaf that could be larger than supported by the BVH */ | ||||
|           NodeRef createLargeLeaf(size_t depth, const PrimInfoRange& pinfo, Allocator alloc) | ||||
|           { | ||||
|             /* this should never occur but is a fatal error */ | ||||
|             if (depth > cfg.maxDepth) | ||||
|               throw_RTCError(RTC_ERROR_UNKNOWN,"depth limit reached"); | ||||
| 
 | ||||
|             /* create leaf for few primitives */ | ||||
|             if (pinfo.size() <= cfg.maxLeafSize && sameGeometry(pinfo)) | ||||
|               return createLeaf(prims,pinfo,alloc); | ||||
| 
 | ||||
|             /* fill all children by always splitting the largest one */ | ||||
|             PrimInfoRange children[MAX_BRANCHING_FACTOR]; | ||||
|             unsigned numChildren = 1; | ||||
|             children[0] = pinfo; | ||||
| 
 | ||||
|             do { | ||||
| 
 | ||||
|               /* find best child with largest bounding box area */ | ||||
|               int bestChild = -1; | ||||
|               size_t bestSize = 0; | ||||
|               for (unsigned i=0; i<numChildren; i++) | ||||
|               { | ||||
|                 /* ignore leaves as they cannot get split */ | ||||
|                 if (children[i].size() <= cfg.maxLeafSize && sameGeometry(children[i])) | ||||
|                   continue; | ||||
| 
 | ||||
|                 /* remember child with largest size */ | ||||
|                 if (children[i].size() > bestSize) { | ||||
|                   bestSize = children[i].size(); | ||||
|                   bestChild = i; | ||||
|                 } | ||||
|               } | ||||
|               if (bestChild == -1) break; | ||||
| 
 | ||||
|               /*! split best child into left and right child */ | ||||
|               __aligned(64) PrimInfoRange left, right; | ||||
|               if (!sameGeometry(children[bestChild])) { | ||||
|                 alignedHeuristic.splitByGeometry(children[bestChild],left,right); | ||||
|               } else { | ||||
|                 alignedHeuristic.splitFallback(children[bestChild],left,right); | ||||
|               } | ||||
| 
 | ||||
|               /* add new children left and right */ | ||||
|               children[bestChild] = children[numChildren-1]; | ||||
|               children[numChildren-1] = left; | ||||
|               children[numChildren+0] = right; | ||||
|               numChildren++; | ||||
| 
 | ||||
|             } while (numChildren < cfg.branchingFactor); | ||||
| 
 | ||||
|             /* create node */ | ||||
|             auto node = createAABBNode(alloc); | ||||
| 
 | ||||
|             for (size_t i=0; i<numChildren; i++) { | ||||
|               const NodeRef child = createLargeLeaf(depth+1,children[i],alloc); | ||||
|               setAABBNode(node,i,child,children[i].geomBounds); | ||||
|             } | ||||
| 
 | ||||
|             return node; | ||||
|           } | ||||
| 
 | ||||
|           /*! performs split */ | ||||
|           __noinline void split(const PrimInfoRange& pinfo, PrimInfoRange& linfo, PrimInfoRange& rinfo, bool& aligned) // FIXME: not inlined as ICC otherwise uses much stack
 | ||||
|           { | ||||
|             /* variable to track the SAH of the best splitting approach */ | ||||
|             float bestSAH = inf; | ||||
|             const size_t blocks = (pinfo.size()+(1ull<<cfg.logBlockSize)-1ull) >> cfg.logBlockSize; | ||||
|             const float leafSAH = intCost*float(blocks)*halfArea(pinfo.geomBounds); | ||||
| 
 | ||||
|             /* try standard binning in aligned space */ | ||||
|             float alignedObjectSAH = inf; | ||||
|             HeuristicBinningSAH::Split alignedObjectSplit; | ||||
|             if (aligned) { | ||||
|               alignedObjectSplit = alignedHeuristic.find(pinfo,cfg.logBlockSize); | ||||
|               alignedObjectSAH = travCostAligned*halfArea(pinfo.geomBounds) + intCost*alignedObjectSplit.splitSAH(); | ||||
|               bestSAH = min(alignedObjectSAH,bestSAH); | ||||
|             } | ||||
| 
 | ||||
|             /* try standard binning in unaligned space */ | ||||
|             UnalignedHeuristicBinningSAH::Split unalignedObjectSplit; | ||||
|             LinearSpace3fa uspace; | ||||
|             float unalignedObjectSAH = inf; | ||||
|             if (bestSAH > 0.7f*leafSAH) { | ||||
|               uspace = unalignedHeuristic.computeAlignedSpace(pinfo); | ||||
|               const PrimInfoRange sinfo = unalignedHeuristic.computePrimInfo(pinfo,uspace); | ||||
|               unalignedObjectSplit = unalignedHeuristic.find(sinfo,cfg.logBlockSize,uspace); | ||||
|               unalignedObjectSAH = travCostUnaligned*halfArea(pinfo.geomBounds) + intCost*unalignedObjectSplit.splitSAH(); | ||||
|               bestSAH = min(unalignedObjectSAH,bestSAH); | ||||
|             } | ||||
| 
 | ||||
|             /* try splitting into two strands */ | ||||
|             HeuristicStrandSplitSAH::Split strandSplit; | ||||
|             float strandSAH = inf; | ||||
|             if (bestSAH > 0.7f*leafSAH && pinfo.size() <= 256) { | ||||
|               strandSplit = strandHeuristic.find(pinfo,cfg.logBlockSize); | ||||
|               strandSAH = travCostUnaligned*halfArea(pinfo.geomBounds) + intCost*strandSplit.splitSAH(); | ||||
|               bestSAH = min(strandSAH,bestSAH); | ||||
|             } | ||||
| 
 | ||||
|             /* fallback if SAH heuristics failed */ | ||||
|             if (unlikely(!std::isfinite(bestSAH))) | ||||
|             { | ||||
|               alignedHeuristic.deterministic_order(pinfo); | ||||
|               alignedHeuristic.splitFallback(pinfo,linfo,rinfo); | ||||
|             } | ||||
| 
 | ||||
|             /* perform aligned split if this is best */ | ||||
|             else if (bestSAH == alignedObjectSAH) { | ||||
|               alignedHeuristic.split(alignedObjectSplit,pinfo,linfo,rinfo); | ||||
|             } | ||||
| 
 | ||||
|             /* perform unaligned split if this is best */ | ||||
|             else if (bestSAH == unalignedObjectSAH) { | ||||
|               unalignedHeuristic.split(unalignedObjectSplit,uspace,pinfo,linfo,rinfo); | ||||
|               aligned = false; | ||||
|             } | ||||
| 
 | ||||
|             /* perform strand split if this is best */ | ||||
|             else if (bestSAH == strandSAH) { | ||||
|               strandHeuristic.split(strandSplit,pinfo,linfo,rinfo); | ||||
|               aligned = false; | ||||
|             } | ||||
| 
 | ||||
|             /* can never happen */ | ||||
|             else | ||||
|               assert(false); | ||||
|           } | ||||
| 
 | ||||
|           /*! recursive build */ | ||||
|           NodeRef recurse(size_t depth, const PrimInfoRange& pinfo, Allocator alloc, bool toplevel, bool alloc_barrier) | ||||
|           { | ||||
|             /* get thread local allocator */ | ||||
|             if (!alloc) | ||||
|               alloc = createAlloc(); | ||||
| 
 | ||||
|             /* call memory monitor function to signal progress */ | ||||
|             if (toplevel && pinfo.size() <= SINGLE_THREADED_THRESHOLD) | ||||
|               progressMonitor(pinfo.size()); | ||||
| 
 | ||||
|             PrimInfoRange children[MAX_BRANCHING_FACTOR]; | ||||
| 
 | ||||
|             /* create leaf node */ | ||||
|             if (depth+MIN_LARGE_LEAF_LEVELS >= cfg.maxDepth || pinfo.size() <= cfg.minLeafSize) { | ||||
|               alignedHeuristic.deterministic_order(pinfo); | ||||
|               return createLargeLeaf(depth,pinfo,alloc); | ||||
|             } | ||||
| 
 | ||||
|             /* fill all children by always splitting the one with the largest surface area */ | ||||
|             size_t numChildren = 1; | ||||
|             children[0] = pinfo; | ||||
|             bool aligned = true; | ||||
| 
 | ||||
|             do { | ||||
| 
 | ||||
|               /* find best child with largest bounding box area */ | ||||
|               ssize_t bestChild = -1; | ||||
|               float bestArea = neg_inf; | ||||
|               for (size_t i=0; i<numChildren; i++) | ||||
|               { | ||||
|                 /* ignore leaves as they cannot get split */ | ||||
|                 if (children[i].size() <= cfg.minLeafSize) | ||||
|                   continue; | ||||
| 
 | ||||
|                 /* remember child with largest area */ | ||||
|                 if (area(children[i].geomBounds) > bestArea) { | ||||
|                   bestArea = area(children[i].geomBounds); | ||||
|                   bestChild = i; | ||||
|                 } | ||||
|               } | ||||
|               if (bestChild == -1) break; | ||||
| 
 | ||||
|               /*! split best child into left and right child */ | ||||
|               PrimInfoRange left, right; | ||||
|               split(children[bestChild],left,right,aligned); | ||||
| 
 | ||||
|               /* add new children left and right */ | ||||
|               children[bestChild] = children[numChildren-1]; | ||||
|               children[numChildren-1] = left; | ||||
|               children[numChildren+0] = right; | ||||
|               numChildren++; | ||||
| 
 | ||||
|             } while (numChildren < cfg.branchingFactor); | ||||
| 
 | ||||
|             NodeRef node; | ||||
| 
 | ||||
|             /* create aligned node */ | ||||
|             if (aligned) | ||||
|             { | ||||
|               node = createAABBNode(alloc); | ||||
| 
 | ||||
|               /* spawn tasks or ... */ | ||||
|               if (pinfo.size() > SINGLE_THREADED_THRESHOLD) | ||||
|               { | ||||
|                 parallel_for(size_t(0), numChildren, [&] (const range<size_t>& r) { | ||||
|                     for (size_t i=r.begin(); i<r.end(); i++) { | ||||
|                       const bool child_alloc_barrier = pinfo.size() > cfg.finished_range_threshold && children[i].size() <= cfg.finished_range_threshold; | ||||
|                       setAABBNode(node,i,recurse(depth+1,children[i],nullptr,true,child_alloc_barrier),children[i].geomBounds); | ||||
|                       _mm_mfence(); // to allow non-temporal stores during build
 | ||||
|                     } | ||||
|                   }); | ||||
|               } | ||||
|               /* ... continue sequentially */ | ||||
|               else { | ||||
|                 for (size_t i=0; i<numChildren; i++) { | ||||
|                   const bool child_alloc_barrier = pinfo.size() > cfg.finished_range_threshold && children[i].size() <= cfg.finished_range_threshold; | ||||
|                   setAABBNode(node,i,recurse(depth+1,children[i],alloc,false,child_alloc_barrier),children[i].geomBounds); | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
| 
 | ||||
|             /* create unaligned node */ | ||||
|             else | ||||
|             { | ||||
|               node = createOBBNode(alloc); | ||||
| 
 | ||||
|               /* spawn tasks or ... */ | ||||
|               if (pinfo.size() > SINGLE_THREADED_THRESHOLD) | ||||
|               { | ||||
|                 parallel_for(size_t(0), numChildren, [&] (const range<size_t>& r) { | ||||
|                     for (size_t i=r.begin(); i<r.end(); i++) { | ||||
|                       const LinearSpace3fa space = unalignedHeuristic.computeAlignedSpace(children[i]); | ||||
|                       const PrimInfoRange sinfo = unalignedHeuristic.computePrimInfo(children[i],space); | ||||
|                       const OBBox3fa obounds(space,sinfo.geomBounds); | ||||
|                       const bool child_alloc_barrier = pinfo.size() > cfg.finished_range_threshold && children[i].size() <= cfg.finished_range_threshold; | ||||
|                       setOBBNode(node,i,recurse(depth+1,children[i],nullptr,true,child_alloc_barrier),obounds); | ||||
|                       _mm_mfence(); // to allow non-temporal stores during build
 | ||||
|                     } | ||||
|                   }); | ||||
|               } | ||||
|               /* ... continue sequentially */ | ||||
|               else | ||||
|               { | ||||
|                 for (size_t i=0; i<numChildren; i++) { | ||||
|                   const LinearSpace3fa space = unalignedHeuristic.computeAlignedSpace(children[i]); | ||||
|                   const PrimInfoRange sinfo = unalignedHeuristic.computePrimInfo(children[i],space); | ||||
|                   const OBBox3fa obounds(space,sinfo.geomBounds); | ||||
|                   const bool child_alloc_barrier = pinfo.size() > cfg.finished_range_threshold && children[i].size() <= cfg.finished_range_threshold; | ||||
|                   setOBBNode(node,i,recurse(depth+1,children[i],alloc,false,child_alloc_barrier),obounds); | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
| 
 | ||||
|             /* reports a finished range of primrefs */ | ||||
|             if (unlikely(alloc_barrier)) | ||||
|               reportFinishedRange(pinfo); | ||||
| 
 | ||||
|             return node; | ||||
|           } | ||||
| 
 | ||||
|         private: | ||||
|           Settings cfg; | ||||
|           PrimRef* prims; | ||||
|           const CreateAllocFunc& createAlloc; | ||||
|           const CreateAABBNodeFunc& createAABBNode; | ||||
|           const SetAABBNodeFunc& setAABBNode; | ||||
|           const CreateOBBNodeFunc& createOBBNode; | ||||
|           const SetOBBNodeFunc& setOBBNode; | ||||
|           const CreateLeafFunc& createLeaf; | ||||
|           const ProgressMonitor& progressMonitor; | ||||
|           const ReportFinishedRangeFunc& reportFinishedRange; | ||||
| 
 | ||||
|         private: | ||||
|           HeuristicBinningSAH alignedHeuristic; | ||||
|           UnalignedHeuristicBinningSAH unalignedHeuristic; | ||||
|           HeuristicStrandSplitSAH strandHeuristic; | ||||
|         }; | ||||
| 
 | ||||
|       template<typename NodeRef, | ||||
|         typename CreateAllocFunc, | ||||
|         typename CreateAABBNodeFunc, | ||||
|         typename SetAABBNodeFunc, | ||||
|         typename CreateOBBNodeFunc, | ||||
|         typename SetOBBNodeFunc, | ||||
|         typename CreateLeafFunc, | ||||
|         typename ProgressMonitor, | ||||
|         typename ReportFinishedRangeFunc> | ||||
| 
 | ||||
|         static NodeRef build (const CreateAllocFunc& createAlloc, | ||||
|                               const CreateAABBNodeFunc& createAABBNode, | ||||
|                               const SetAABBNodeFunc& setAABBNode, | ||||
|                               const CreateOBBNodeFunc& createOBBNode, | ||||
|                               const SetOBBNodeFunc& setOBBNode, | ||||
|                               const CreateLeafFunc& createLeaf, | ||||
|                               const ProgressMonitor& progressMonitor, | ||||
|                               const ReportFinishedRangeFunc& reportFinishedRange, | ||||
|                               Scene* scene, | ||||
|                               PrimRef* prims, | ||||
|                               const PrimInfo& pinfo, | ||||
|                               const Settings settings) | ||||
|         { | ||||
|           typedef BuilderT<NodeRef, | ||||
|             CreateAllocFunc, | ||||
|             CreateAABBNodeFunc,SetAABBNodeFunc, | ||||
|             CreateOBBNodeFunc,SetOBBNodeFunc, | ||||
|             CreateLeafFunc,ProgressMonitor, | ||||
|             ReportFinishedRangeFunc> Builder; | ||||
| 
 | ||||
|           Builder builder(scene,prims,createAlloc, | ||||
|                           createAABBNode,setAABBNode, | ||||
|                           createOBBNode,setOBBNode, | ||||
|                           createLeaf,progressMonitor,reportFinishedRange,settings); | ||||
| 
 | ||||
|           NodeRef root = builder.recurse(1,pinfo,nullptr,true,false); | ||||
|           _mm_mfence(); // to allow non-temporal stores during build
 | ||||
|           return root; | ||||
|         } | ||||
|     }; | ||||
|   } | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue