Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:03:19

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_Vector.hxx>
0022 
0023 //! Abstract BVH builder based on the concept of work queue.
0024 //! Queue based BVH builders support parallelization with a
0025 //! fixed number of threads (maximum efficiency is achieved
0026 //! by setting the number of threads equal to the number of
0027 //! CPU cores plus one). Note that to support parallel mode,
0028 //! a corresponding BVH primitive set should provide thread
0029 //! safe implementations of interface functions (e.g., Swap,
0030 //! Box, Center). Otherwise, the results will be undefined.
0031 //! \tparam T Numeric data type
0032 //! \tparam N Vector dimension
0033 template<class T, int N>
0034 class BVH_QueueBuilder : public BVH_Builder<T, N>
0035 {
0036 public:
0037 
0038   //! Creates new BVH queue based builder.
0039   BVH_QueueBuilder (const Standard_Integer theLeafNodeSize,
0040                     const Standard_Integer theMaxTreeDepth,
0041                     const Standard_Integer theNumOfThreads = 1)
0042   : BVH_Builder<T, N> (theLeafNodeSize,
0043                        theMaxTreeDepth),
0044     myNumOfThreads (theNumOfThreads) {}
0045 
0046   //! Releases resources of BVH queue based builder.
0047   virtual ~BVH_QueueBuilder() {}
0048 
0049 public:
0050 
0051   //! Builds BVH using specific algorithm.
0052   virtual void Build (BVH_Set<T, N>*       theSet,
0053                       BVH_Tree<T, N>*      theBVH,
0054                       const BVH_Box<T, N>& theBox) const Standard_OVERRIDE;
0055 
0056 protected:
0057 
0058   //! Stores range of primitives belonging to a BVH node.
0059   struct BVH_PrimitiveRange
0060   {
0061     Standard_Integer Start;
0062     Standard_Integer Final;
0063 
0064     //! Creates new primitive range.
0065     BVH_PrimitiveRange (Standard_Integer theStart = -1,
0066                         Standard_Integer theFinal = -1)
0067     : Start (theStart),
0068       Final (theFinal)
0069     {
0070       //
0071     }
0072 
0073     //! Returns total number of primitives.
0074     Standard_Integer Size() const
0075     {
0076       return Final - Start + 1;
0077     }
0078 
0079     //! Checks if the range is initialized.
0080     Standard_Boolean IsValid() const
0081     {
0082       return Start != -1;
0083     }
0084   };
0085 
0086   //! Stores parameters of constructed child nodes.
0087   struct BVH_ChildNodes
0088   {
0089     //! Bounding boxes of child nodes.
0090     BVH_Box<T, N> Boxes[2];
0091 
0092     //! Primitive ranges of child nodes.
0093     BVH_PrimitiveRange Ranges[2];
0094 
0095     //! Creates new parameters of BVH child nodes.
0096     BVH_ChildNodes()
0097     {
0098       //
0099     }
0100 
0101     //! Creates new parameters of BVH child nodes.
0102     BVH_ChildNodes (const BVH_Box<T, N>&      theLftBox,
0103                     const BVH_Box<T, N>&      theRghBox,
0104                     const BVH_PrimitiveRange& theLftRange,
0105                     const BVH_PrimitiveRange& theRghRange)
0106     {
0107       Boxes[0]  = theLftBox;
0108       Boxes[1]  = theRghBox;
0109       Ranges[0] = theLftRange;
0110       Ranges[1] = theRghRange;
0111     }
0112 
0113     //! Returns number of primitives in the given child.
0114     Standard_Integer NbPrims (const Standard_Integer theChild) const
0115     {
0116       return Ranges[theChild].Size();
0117     }
0118 
0119     //! Checks if the parameters is initialized.
0120     Standard_Boolean IsValid() const
0121     {
0122       return Ranges[0].IsValid() && Ranges[1].IsValid();
0123     }
0124   };
0125 
0126   //! Wrapper for BVH build data.
0127   class BVH_TypedBuildTool : public BVH_BuildTool
0128   {
0129   public:
0130 
0131     //! Creates new BVH build thread.
0132     BVH_TypedBuildTool (BVH_Set<T, N>*  theSet,
0133                         BVH_Tree<T, N>* theBVH,
0134                         BVH_BuildQueue& theBuildQueue,
0135                         const BVH_QueueBuilder<T, N>* theAlgo)
0136     : mySet  (theSet),
0137       myBVH  (theBVH),
0138       myBuildQueue (&theBuildQueue),
0139       myAlgo (theAlgo)
0140     {
0141       Standard_ASSERT_RAISE (myAlgo != NULL, "Error! BVH builder should be queue based");
0142     }
0143 
0144     //! Performs splitting of the given BVH node.
0145     virtual void Perform (const Standard_Integer theNode) Standard_OVERRIDE
0146     {
0147       const typename BVH_QueueBuilder<T, N>::BVH_ChildNodes aChildren = myAlgo->buildNode (mySet, myBVH, theNode);
0148       myAlgo->addChildren (myBVH, *myBuildQueue, theNode, aChildren);
0149     }
0150 
0151   protected:
0152 
0153     BVH_Set<T, N>*                mySet;        //!< Primitive set to build BVH
0154     BVH_Tree<T, N>*               myBVH;        //!< Output BVH tree for the set
0155     BVH_BuildQueue*               myBuildQueue;
0156     const BVH_QueueBuilder<T, N>* myAlgo;       //!< Queue based BVH builder to use
0157 
0158   };
0159 
0160 protected:
0161 
0162   //! Performs splitting of the given BVH node.
0163   virtual typename BVH_QueueBuilder<T, N>::BVH_ChildNodes buildNode (BVH_Set<T, N>*         theSet,
0164                                                                      BVH_Tree<T, N>*        theBVH,
0165                                                                      const Standard_Integer theNode) const = 0;
0166 
0167   //! Processes child nodes of the split BVH node.
0168   virtual void addChildren (BVH_Tree<T, N>*        theBVH,
0169                             BVH_BuildQueue&        theBuildQueue,
0170                             const Standard_Integer theNode,
0171                             const BVH_ChildNodes&  theSubNodes) const;
0172 
0173 protected:
0174 
0175   Standard_Integer myNumOfThreads; //!< Number of threads used to build BVH
0176 
0177 };
0178 
0179 // =======================================================================
0180 // function : addChildren
0181 // purpose  :
0182 // =======================================================================
0183 template<class T, int N>
0184 void BVH_QueueBuilder<T, N>::addChildren (BVH_Tree<T, N>* theBVH,
0185                                           BVH_BuildQueue& theBuildQueue,
0186                                           const Standard_Integer theNode,
0187                                           const typename BVH_QueueBuilder<T, N>::BVH_ChildNodes& theSubNodes) const
0188 {
0189   Standard_Integer aChildren[] = { -1, -1 };
0190   if (!theSubNodes.IsValid())
0191   {
0192     return;
0193   }
0194 
0195   // Add child nodes
0196   {
0197     Standard_Mutex::Sentry aSentry (theBuildQueue.myMutex);
0198 
0199     for (Standard_Integer anIdx = 0; anIdx < 2; ++anIdx)
0200     {
0201       aChildren[anIdx] = theBVH->AddLeafNode (theSubNodes.Boxes[anIdx],
0202                                               theSubNodes.Ranges[anIdx].Start,
0203                                               theSubNodes.Ranges[anIdx].Final);
0204     }
0205 
0206     BVH_Builder<T, N>::updateDepth (theBVH, theBVH->Level (theNode) + 1);
0207   }
0208 
0209   // Set parameters of child nodes and generate new tasks
0210   for (Standard_Integer anIdx = 0; anIdx < 2; ++anIdx)
0211   {
0212     const Standard_Integer aChildIndex = aChildren[anIdx];
0213 
0214     theBVH->Level (aChildIndex) = theBVH->Level (theNode) + 1;
0215 
0216     (anIdx == 0 ? theBVH->template Child<0> (theNode)
0217                 : theBVH->template Child<1> (theNode)) = aChildIndex;
0218 
0219     // Check to see if the child node must be split
0220     const Standard_Boolean isLeaf = theSubNodes.NbPrims (anIdx) <= BVH_Builder<T, N>::myLeafNodeSize
0221                                  || theBVH->Level (aChildIndex) >= BVH_Builder<T, N>::myMaxTreeDepth;
0222 
0223     if (!isLeaf)
0224     {
0225       theBuildQueue.Enqueue (aChildIndex);
0226     }
0227   }
0228 }
0229 
0230 // =======================================================================
0231 // function : Build
0232 // purpose  : Builds BVH using specific algorithm
0233 // =======================================================================
0234 template<class T, int N>
0235 void BVH_QueueBuilder<T, N>::Build (BVH_Set<T, N>*       theSet,
0236                                     BVH_Tree<T, N>*      theBVH,
0237                                     const BVH_Box<T, N>& theBox) const
0238 {
0239   Standard_ASSERT_RETURN (theBVH != NULL,
0240     "Error! BVH tree to construct is NULL", );
0241 
0242   theBVH->Clear();
0243   const Standard_Integer aSetSize = theSet->Size();
0244   if (aSetSize == 0)
0245   {
0246     return;
0247   }
0248 
0249   const Standard_Integer aRoot = theBVH->AddLeafNode (theBox, 0, aSetSize - 1);
0250   if (theSet->Size() == 1)
0251   {
0252     return;
0253   }
0254 
0255   BVH_BuildQueue aBuildQueue;
0256   aBuildQueue.Enqueue (aRoot);
0257 
0258   BVH_TypedBuildTool aBuildTool (theSet, theBVH, aBuildQueue, this);
0259   if (myNumOfThreads > 1)
0260   {
0261     // Reserve the maximum possible number of nodes in the BVH
0262     theBVH->Reserve (2 * aSetSize - 1);
0263 
0264     NCollection_Vector<Handle(BVH_BuildThread)> aThreads;
0265 
0266     // Run BVH build threads
0267     for (Standard_Integer aThreadIndex = 0; aThreadIndex < myNumOfThreads; ++aThreadIndex)
0268     {
0269       aThreads.Append (new BVH_BuildThread (aBuildTool, aBuildQueue));
0270       aThreads.Last()->Run();
0271     }
0272 
0273     // Wait until all threads finish their work
0274     for (Standard_Integer aThreadIndex = 0; aThreadIndex < myNumOfThreads; ++aThreadIndex)
0275     {
0276       aThreads.ChangeValue (aThreadIndex)->Wait();
0277     }
0278 
0279     // Free unused memory
0280     theBVH->Reserve (theBVH->Length());
0281   }
0282   else
0283   {
0284     BVH_BuildThread aThread (aBuildTool, aBuildQueue);
0285 
0286     // Execute thread function inside current thread
0287     aThread.execute();
0288   }
0289 }
0290 
0291 #endif // _BVH_QueueBuilder_Header