File indexing completed on 2026-09-16 09:16:47
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #ifndef _BVH_QueueBuilder_Header
0017 #define _BVH_QueueBuilder_Header
0018
0019 #include <BVH_Builder.hxx>
0020 #include <BVH_BuildThread.hxx>
0021 #include <NCollection_DynamicArray.hxx>
0022
0023 #include <mutex>
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 template <class T, int N>
0036 class BVH_QueueBuilder : public BVH_Builder<T, N>
0037 {
0038 public:
0039
0040 BVH_QueueBuilder(const int theLeafNodeSize,
0041 const int theMaxTreeDepth,
0042 const int theNumOfThreads = 1)
0043 : BVH_Builder<T, N>(theLeafNodeSize, theMaxTreeDepth),
0044 myNumOfThreads(theNumOfThreads)
0045 {
0046 }
0047
0048
0049 ~BVH_QueueBuilder() override = default;
0050
0051 public:
0052
0053 void Build(BVH_Set<T, N>* theSet,
0054 BVH_Tree<T, N>* theBVH,
0055 const BVH_Box<T, N>& theBox) const override;
0056
0057 protected:
0058
0059 struct BVH_PrimitiveRange
0060 {
0061 int Start;
0062 int Final;
0063
0064
0065 BVH_PrimitiveRange(int theStart = -1, int theFinal = -1)
0066 : Start(theStart),
0067 Final(theFinal)
0068 {
0069
0070 }
0071
0072
0073 int Size() const { return Final - Start + 1; }
0074
0075
0076 bool IsValid() const { return Start != -1; }
0077 };
0078
0079
0080 struct BVH_ChildNodes
0081 {
0082
0083 BVH_Box<T, N> Boxes[2];
0084
0085
0086 BVH_PrimitiveRange Ranges[2];
0087
0088
0089 BVH_ChildNodes() = default;
0090
0091
0092 BVH_ChildNodes(const BVH_Box<T, N>& theLftBox,
0093 const BVH_Box<T, N>& theRghBox,
0094 const BVH_PrimitiveRange& theLftRange,
0095 const BVH_PrimitiveRange& theRghRange)
0096 {
0097 Boxes[0] = theLftBox;
0098 Boxes[1] = theRghBox;
0099 Ranges[0] = theLftRange;
0100 Ranges[1] = theRghRange;
0101 }
0102
0103
0104 int NbPrims(const int theChild) const { return Ranges[theChild].Size(); }
0105
0106
0107 bool IsValid() const { return Ranges[0].IsValid() && Ranges[1].IsValid(); }
0108 };
0109
0110
0111 class BVH_TypedBuildTool : public BVH_BuildTool
0112 {
0113 public:
0114
0115 BVH_TypedBuildTool(BVH_Set<T, N>* theSet,
0116 BVH_Tree<T, N>* theBVH,
0117 BVH_BuildQueue& theBuildQueue,
0118 const BVH_QueueBuilder<T, N>* theAlgo)
0119 : mySet(theSet),
0120 myBVH(theBVH),
0121 myBuildQueue(&theBuildQueue),
0122 myAlgo(theAlgo)
0123 {
0124 Standard_ASSERT_RAISE(myAlgo != nullptr, "Error! BVH builder should be queue based");
0125 }
0126
0127
0128 void Perform(const int theNode) override
0129 {
0130 const typename BVH_QueueBuilder<T, N>::BVH_ChildNodes aChildren =
0131 myAlgo->buildNode(mySet, myBVH, theNode);
0132 myAlgo->addChildren(myBVH, *myBuildQueue, theNode, aChildren);
0133 }
0134
0135 protected:
0136 BVH_Set<T, N>* mySet;
0137 BVH_Tree<T, N>* myBVH;
0138 BVH_BuildQueue* myBuildQueue;
0139 const BVH_QueueBuilder<T, N>* myAlgo;
0140 };
0141
0142 protected:
0143
0144 virtual typename BVH_QueueBuilder<T, N>::BVH_ChildNodes buildNode(BVH_Set<T, N>* theSet,
0145 BVH_Tree<T, N>* theBVH,
0146 const int theNode) const = 0;
0147
0148
0149 virtual void addChildren(BVH_Tree<T, N>* theBVH,
0150 BVH_BuildQueue& theBuildQueue,
0151 const int theNode,
0152 const BVH_ChildNodes& theSubNodes) const;
0153
0154 protected:
0155 int myNumOfThreads;
0156 };
0157
0158
0159
0160 template <class T, int N>
0161 void BVH_QueueBuilder<T, N>::addChildren(
0162 BVH_Tree<T, N>* theBVH,
0163 BVH_BuildQueue& theBuildQueue,
0164 const int theNode,
0165 const typename BVH_QueueBuilder<T, N>::BVH_ChildNodes& theSubNodes) const
0166 {
0167 int aChildren[] = {-1, -1};
0168 if (!theSubNodes.IsValid())
0169 {
0170 return;
0171 }
0172
0173
0174 {
0175 std::lock_guard<std::mutex> aLock(theBuildQueue.myMutex);
0176
0177 for (int anIdx = 0; anIdx < 2; ++anIdx)
0178 {
0179 aChildren[anIdx] = theBVH->AddLeafNode(theSubNodes.Boxes[anIdx],
0180 theSubNodes.Ranges[anIdx].Start,
0181 theSubNodes.Ranges[anIdx].Final);
0182 }
0183
0184 BVH_Builder<T, N>::updateDepth(theBVH, theBVH->Level(theNode) + 1);
0185 }
0186
0187
0188 for (int anIdx = 0; anIdx < 2; ++anIdx)
0189 {
0190 const int aChildIndex = aChildren[anIdx];
0191
0192 theBVH->Level(aChildIndex) = theBVH->Level(theNode) + 1;
0193
0194 (anIdx == 0 ? theBVH->template Child<0>(theNode) : theBVH->template Child<1>(theNode)) =
0195 aChildIndex;
0196
0197
0198 const bool isLeaf = theSubNodes.NbPrims(anIdx) <= BVH_Builder<T, N>::myLeafNodeSize
0199 || theBVH->Level(aChildIndex) >= BVH_Builder<T, N>::myMaxTreeDepth;
0200
0201 if (!isLeaf)
0202 {
0203 theBuildQueue.Enqueue(aChildIndex);
0204 }
0205 }
0206 }
0207
0208
0209
0210
0211
0212 template <class T, int N>
0213 void BVH_QueueBuilder<T, N>::Build(BVH_Set<T, N>* theSet,
0214 BVH_Tree<T, N>* theBVH,
0215 const BVH_Box<T, N>& theBox) const
0216 {
0217 Standard_ASSERT_RETURN(theBVH != nullptr,
0218 "Error! BVH tree to construct is NULL",
0219 Standard_VOID_RETURN);
0220
0221 theBVH->Clear();
0222 const int aSetSize = theSet->Size();
0223 if (aSetSize == 0)
0224 {
0225 return;
0226 }
0227
0228 const int aRoot = theBVH->AddLeafNode(theBox, 0, aSetSize - 1);
0229 if (theSet->Size() == 1)
0230 {
0231 return;
0232 }
0233
0234 BVH_BuildQueue aBuildQueue;
0235 aBuildQueue.Enqueue(aRoot);
0236
0237 BVH_TypedBuildTool aBuildTool(theSet, theBVH, aBuildQueue, this);
0238 if (myNumOfThreads > 1)
0239 {
0240
0241 theBVH->Reserve(2 * aSetSize - 1);
0242
0243 NCollection_DynamicArray<occ::handle<BVH_BuildThread>> aThreads;
0244
0245
0246 for (int aThreadIndex = 0; aThreadIndex < myNumOfThreads; ++aThreadIndex)
0247 {
0248 aThreads.Append(new BVH_BuildThread(aBuildTool, aBuildQueue));
0249 aThreads.Last()->Run();
0250 }
0251
0252
0253 for (int aThreadIndex = 0; aThreadIndex < myNumOfThreads; ++aThreadIndex)
0254 {
0255 aThreads.ChangeValue(aThreadIndex)->Wait();
0256 }
0257
0258
0259 theBVH->Reserve(theBVH->Length());
0260 }
0261 else
0262 {
0263 BVH_BuildThread aThread(aBuildTool, aBuildQueue);
0264
0265
0266 aThread.execute();
0267 }
0268 }
0269
0270 #endif