// Copyright 2009-2021 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #pragma once /* include all node types */ #include "bvh_node_aabb.h" #include "bvh_node_aabb_mb.h" #include "bvh_node_aabb_mb4d.h" #include "bvh_node_obb.h" #include "bvh_node_obb_mb.h" #include "bvh_node_qaabb.h" namespace embree { /*! flags used to enable specific node types in intersectors */ enum BVHNodeFlags { BVH_FLAG_ALIGNED_NODE = 0x00001, BVH_FLAG_ALIGNED_NODE_MB = 0x00010, BVH_FLAG_UNALIGNED_NODE = 0x00100, BVH_FLAG_UNALIGNED_NODE_MB = 0x01000, BVH_FLAG_QUANTIZED_NODE = 0x100000, BVH_FLAG_ALIGNED_NODE_MB4D = 0x1000000, /* short versions */ BVH_AN1 = BVH_FLAG_ALIGNED_NODE, BVH_AN2 = BVH_FLAG_ALIGNED_NODE_MB, BVH_AN2_AN4D = BVH_FLAG_ALIGNED_NODE_MB | BVH_FLAG_ALIGNED_NODE_MB4D, BVH_UN1 = BVH_FLAG_UNALIGNED_NODE, BVH_UN2 = BVH_FLAG_UNALIGNED_NODE_MB, BVH_MB = BVH_FLAG_ALIGNED_NODE_MB | BVH_FLAG_UNALIGNED_NODE_MB | BVH_FLAG_ALIGNED_NODE_MB4D, BVH_AN1_UN1 = BVH_FLAG_ALIGNED_NODE | BVH_FLAG_UNALIGNED_NODE, BVH_AN2_UN2 = BVH_FLAG_ALIGNED_NODE_MB | BVH_FLAG_UNALIGNED_NODE_MB, BVH_AN2_AN4D_UN2 = BVH_FLAG_ALIGNED_NODE_MB | BVH_FLAG_ALIGNED_NODE_MB4D | BVH_FLAG_UNALIGNED_NODE_MB, BVH_QN1 = BVH_FLAG_QUANTIZED_NODE }; /*! Multi BVH with N children. Each node stores the bounding box of * it's N children as well as N child references. */ template<int N> class BVHN : public AccelData { ALIGNED_CLASS_(16); public: /*! forward declaration of node ref type */ typedef NodeRefPtr<N> NodeRef; typedef BaseNode_t<NodeRef,N> BaseNode; typedef AABBNode_t<NodeRef,N> AABBNode; typedef AABBNodeMB_t<NodeRef,N> AABBNodeMB; typedef AABBNodeMB4D_t<NodeRef,N> AABBNodeMB4D; typedef OBBNode_t<NodeRef,N> OBBNode; typedef OBBNodeMB_t<NodeRef,N> OBBNodeMB; typedef QuantizedBaseNode_t<N> QuantizedBaseNode; typedef QuantizedBaseNodeMB_t<N> QuantizedBaseNodeMB; typedef QuantizedNode_t<NodeRef,N> QuantizedNode; /*! Number of bytes the nodes and primitives are minimally aligned to.*/ static const size_t byteAlignment = 16; static const size_t byteNodeAlignment = 4*N; /*! Empty node */ static const size_t emptyNode = NodeRef::emptyNode; /*! Invalid node, used as marker in traversal */ static const size_t invalidNode = NodeRef::invalidNode; static const size_t popRay = NodeRef::popRay; /*! Maximum depth of the BVH. */ static const size_t maxBuildDepth = 32; static const size_t maxBuildDepthLeaf = maxBuildDepth+8; static const size_t maxDepth = 2*maxBuildDepthLeaf; // 2x because of two level builder /*! Maximum number of primitive blocks in a leaf. */ static const size_t maxLeafBlocks = NodeRef::maxLeafBlocks; public: /*! Builder interface to create allocator */ struct CreateAlloc : public FastAllocator::Create { __forceinline CreateAlloc (BVHN* bvh) : FastAllocator::Create(&bvh->alloc) {} }; typedef BVHNodeRecord<NodeRef> NodeRecord; typedef BVHNodeRecordMB<NodeRef> NodeRecordMB; typedef BVHNodeRecordMB4D<NodeRef> NodeRecordMB4D; public: /*! BVHN default constructor. */ BVHN (const PrimitiveType& primTy, Scene* scene); /*! BVHN destruction */ ~BVHN (); /*! clears the acceleration structure */ void clear(); /*! sets BVH members after build */ void set (NodeRef root, const LBBox3fa& bounds, size_t numPrimitives); /*! Clears the barrier bits of a subtree. */ void clearBarrier(NodeRef& node); /*! lays out num large nodes of the BVH */ void layoutLargeNodes(size_t num); NodeRef layoutLargeNodesRecursion(NodeRef& node, const FastAllocator::CachedAllocator& allocator); /*! called by all builders before build starts */ double preBuild(const std::string& builderName); /*! called by all builders after build ended */ void postBuild(double t0); /*! allocator class */ struct Allocator { BVHN* bvh; Allocator (BVHN* bvh) : bvh(bvh) {} __forceinline void* operator() (size_t bytes) const { return bvh->alloc._threadLocal()->malloc(&bvh->alloc,bytes); } }; /*! post build cleanup */ void cleanup() { alloc.cleanup(); } public: /*! Encodes a node */ static __forceinline NodeRef encodeNode(AABBNode* node) { return NodeRef::encodeNode(node); } static __forceinline NodeRef encodeNode(AABBNodeMB* node) { return NodeRef::encodeNode(node); } static __forceinline NodeRef encodeNode(AABBNodeMB4D* node) { return NodeRef::encodeNode(node); } static __forceinline NodeRef encodeNode(OBBNode* node) { return NodeRef::encodeNode(node); } static __forceinline NodeRef encodeNode(OBBNodeMB* node) { return NodeRef::encodeNode(node); } static __forceinline NodeRef encodeLeaf(void* tri, size_t num) { return NodeRef::encodeLeaf(tri,num); } static __forceinline NodeRef encodeTypedLeaf(void* ptr, size_t ty) { return NodeRef::encodeTypedLeaf(ptr,ty); } public: /*! Prefetches the node this reference points to */ __forceinline static void prefetch(const NodeRef ref, int types=0) { #if defined(__AVX512PF__) // MIC if (types != BVH_FLAG_QUANTIZED_NODE) { prefetchL2(((char*)ref.ptr)+0*64); prefetchL2(((char*)ref.ptr)+1*64); if ((N >= 8) || (types > BVH_FLAG_ALIGNED_NODE)) { prefetchL2(((char*)ref.ptr)+2*64); prefetchL2(((char*)ref.ptr)+3*64); } if ((N >= 8) && (types > BVH_FLAG_ALIGNED_NODE)) { /* KNL still needs L2 prefetches for large nodes */ prefetchL2(((char*)ref.ptr)+4*64); prefetchL2(((char*)ref.ptr)+5*64); prefetchL2(((char*)ref.ptr)+6*64); prefetchL2(((char*)ref.ptr)+7*64); } } else { /* todo: reduce if 32bit offsets are enabled */ prefetchL2(((char*)ref.ptr)+0*64); prefetchL2(((char*)ref.ptr)+1*64); prefetchL2(((char*)ref.ptr)+2*64); } #else if (types != BVH_FLAG_QUANTIZED_NODE) { prefetchL1(((char*)ref.ptr)+0*64); prefetchL1(((char*)ref.ptr)+1*64); if ((N >= 8) || (types > BVH_FLAG_ALIGNED_NODE)) { prefetchL1(((char*)ref.ptr)+2*64); prefetchL1(((char*)ref.ptr)+3*64); } if ((N >= 8) && (types > BVH_FLAG_ALIGNED_NODE)) { /* deactivate for large nodes on Xeon, as it introduces regressions */ //prefetchL1(((char*)ref.ptr)+4*64); //prefetchL1(((char*)ref.ptr)+5*64); //prefetchL1(((char*)ref.ptr)+6*64); //prefetchL1(((char*)ref.ptr)+7*64); } } else { /* todo: reduce if 32bit offsets are enabled */ prefetchL1(((char*)ref.ptr)+0*64); prefetchL1(((char*)ref.ptr)+1*64); prefetchL1(((char*)ref.ptr)+2*64); } #endif } __forceinline static void prefetchW(const NodeRef ref, int types=0) { embree::prefetchEX(((char*)ref.ptr)+0*64); embree::prefetchEX(((char*)ref.ptr)+1*64); if ((N >= 8) || (types > BVH_FLAG_ALIGNED_NODE)) { embree::prefetchEX(((char*)ref.ptr)+2*64); embree::prefetchEX(((char*)ref.ptr)+3*64); } if ((N >= 8) && (types > BVH_FLAG_ALIGNED_NODE)) { embree::prefetchEX(((char*)ref.ptr)+4*64); embree::prefetchEX(((char*)ref.ptr)+5*64); embree::prefetchEX(((char*)ref.ptr)+6*64); embree::prefetchEX(((char*)ref.ptr)+7*64); } } /*! bvh type information */ public: const PrimitiveType* primTy; //!< primitive type stored in the BVH /*! bvh data */ public: Device* device; //!< device pointer Scene* scene; //!< scene pointer NodeRef root; //!< root node FastAllocator alloc; //!< allocator used to allocate nodes /*! statistics data */ public: size_t numPrimitives; //!< number of primitives the BVH is build over size_t numVertices; //!< number of vertices the BVH references /*! data arrays for special builders */ public: std::vector<BVHN*> objects; vector_t<char,aligned_allocator<char,32>> subdiv_patches; }; typedef BVHN<4> BVH4; typedef BVHN<8> BVH8; }