Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-16 09:16:47

0001 // Created on: 2014-09-15
0002 // Created by: Denis BOGOLEPOV
0003 // Copyright (c) 2013-2014 OPEN CASCADE SAS
0004 //
0005 // This file is part of Open CASCADE Technology software library.
0006 //
0007 // This library is free software; you can redistribute it and/or modify it under
0008 // the terms of the GNU Lesser General Public License version 2.1 as published
0009 // by the Free Software Foundation, with special exception defined in the file
0010 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0011 // distribution for complete text of the license and disclaimer of any warranty.
0012 //
0013 // Alternatively, this file may be used under the terms of Open CASCADE
0014 // commercial license or contractual agreement.
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 //! Abstract BVH builder based on the concept of work queue.
0026 //! Queue based BVH builders support parallelization with a
0027 //! fixed number of threads (maximum efficiency is achieved
0028 //! by setting the number of threads equal to the number of
0029 //! CPU cores plus one). Note that to support parallel mode,
0030 //! a corresponding BVH primitive set should provide thread
0031 //! safe implementations of interface functions (e.g., Swap,
0032 //! Box, Center). Otherwise, the results will be undefined.
0033 //! \tparam T Numeric data type
0034 //! \tparam N Vector dimension
0035 template <class T, int N>
0036 class BVH_QueueBuilder : public BVH_Builder<T, N>
0037 {
0038 public:
0039   //! Creates new BVH queue based builder.
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   //! Releases resources of BVH queue based builder.
0049   ~BVH_QueueBuilder() override = default;
0050 
0051 public:
0052   //! Builds BVH using specific algorithm.
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   //! Stores range of primitives belonging to a BVH node.
0059   struct BVH_PrimitiveRange
0060   {
0061     int Start;
0062     int Final;
0063 
0064     //! Creates new primitive range.
0065     BVH_PrimitiveRange(int theStart = -1, int theFinal = -1)
0066         : Start(theStart),
0067           Final(theFinal)
0068     {
0069       //
0070     }
0071 
0072     //! Returns total number of primitives.
0073     int Size() const { return Final - Start + 1; }
0074 
0075     //! Checks if the range is initialized.
0076     bool IsValid() const { return Start != -1; }
0077   };
0078 
0079   //! Stores parameters of constructed child nodes.
0080   struct BVH_ChildNodes
0081   {
0082     //! Bounding boxes of child nodes.
0083     BVH_Box<T, N> Boxes[2];
0084 
0085     //! Primitive ranges of child nodes.
0086     BVH_PrimitiveRange Ranges[2];
0087 
0088     //! Creates new parameters of BVH child nodes.
0089     BVH_ChildNodes() = default;
0090 
0091     //! Creates new parameters of BVH child nodes.
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     //! Returns number of primitives in the given child.
0104     int NbPrims(const int theChild) const { return Ranges[theChild].Size(); }
0105 
0106     //! Checks if the parameters is initialized.
0107     bool IsValid() const { return Ranges[0].IsValid() && Ranges[1].IsValid(); }
0108   };
0109 
0110   //! Wrapper for BVH build data.
0111   class BVH_TypedBuildTool : public BVH_BuildTool
0112   {
0113   public:
0114     //! Creates new BVH build thread.
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     //! Performs splitting of the given BVH node.
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; //!< Primitive set to build BVH
0137     BVH_Tree<T, N>*               myBVH; //!< Output BVH tree for the set
0138     BVH_BuildQueue*               myBuildQueue;
0139     const BVH_QueueBuilder<T, N>* myAlgo; //!< Queue based BVH builder to use
0140   };
0141 
0142 protected:
0143   //! Performs splitting of the given BVH node.
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   //! Processes child nodes of the split BVH node.
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; //!< Number of threads used to build BVH
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   // Add child nodes
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   // Set parameters of child nodes and generate new tasks
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     // Check to see if the child node must be split
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 // function : Build
0210 // purpose  : Builds BVH using specific algorithm
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     // Reserve the maximum possible number of nodes in the BVH
0241     theBVH->Reserve(2 * aSetSize - 1);
0242 
0243     NCollection_DynamicArray<occ::handle<BVH_BuildThread>> aThreads;
0244 
0245     // Run BVH build threads
0246     for (int aThreadIndex = 0; aThreadIndex < myNumOfThreads; ++aThreadIndex)
0247     {
0248       aThreads.Append(new BVH_BuildThread(aBuildTool, aBuildQueue));
0249       aThreads.Last()->Run();
0250     }
0251 
0252     // Wait until all threads finish their work
0253     for (int aThreadIndex = 0; aThreadIndex < myNumOfThreads; ++aThreadIndex)
0254     {
0255       aThreads.ChangeValue(aThreadIndex)->Wait();
0256     }
0257 
0258     // Free unused memory
0259     theBVH->Reserve(theBVH->Length());
0260   }
0261   else
0262   {
0263     BVH_BuildThread aThread(aBuildTool, aBuildQueue);
0264 
0265     // Execute thread function inside current thread
0266     aThread.execute();
0267   }
0268 }
0269 
0270 #endif // _BVH_QueueBuilder_Header