0029177: Foundation Classes - Adapt BVH package for use of OSD_Parallel
authoroan <oan@opencascade.com>
Wed, 18 Apr 2018 08:21:00 +0000 (11:21 +0300)
committerapn <apn@opencascade.com>
Tue, 11 Dec 2018 16:14:27 +0000 (19:14 +0300)
Explicit calls to TBB in BVH_DistanceField, BVH_LinearBuilder and BVH_RadixSorter have been replaced.
Task functors have been separated on execution and state parts for the sake of usage by OSD_Parallel.

src/BVH/BVH_DistanceField.lxx
src/BVH/BVH_LinearBuilder.hxx
src/BVH/BVH_RadixSorter.hxx

index f4ddd36..a83a2a3 100644 (file)
 // commercial license or contractual agreement.
 
 #include <BVH_Triangulation.hxx>
-
-#ifdef HAVE_TBB
-  // On Windows, function TryEnterCriticalSection has appeared in Windows NT
-  // and is surrounded by #ifdef in MS VC++ 7.1 headers.
-  // Thus to use it we need to define appropriate macro saying that we will
-  // run on Windows NT 4.0 at least
-  #if defined(_WIN32) && !defined(_WIN32_WINNT)
-    #define _WIN32_WINNT 0x0501
-  #endif
-
-  #include <tbb/tbb.h>
-#endif
+#include <OSD_Parallel.hxx>
 
 // =======================================================================
 // function : BVH_DistanceField
@@ -407,8 +396,6 @@ namespace BVH
 
 #undef BVH_DOT3
 
-#ifdef HAVE_TBB
-
 //! Tool object for parallel construction of distance field (uses Intel TBB).
 template<class T, int N>
 class BVH_ParallelDistanceFieldBuilder
@@ -430,14 +417,12 @@ public:
     //
   }
 
-  void operator() (const tbb::blocked_range<Standard_Integer>& theRange) const
+  void operator() (const Standard_Integer theIndex) const
   {
-    myOutField->BuildSlices (*myGeometry, theRange.begin(), theRange.end());
+    myOutField->BuildSlices (*myGeometry, theIndex, theIndex + 1);
   }
 };
 
-#endif
-
 // =======================================================================
 // function : BuildSlices
 // purpose  : Performs building of distance field for the given Z slices
@@ -510,16 +495,7 @@ Standard_Boolean BVH_DistanceField<T, N>::Build (BVH_Geometry<T, N>& theGeometry
   myVoxelSize.y() = (myCornerMax.y() - myCornerMin.y()) / myDimensionY;
   myVoxelSize.z() = (myCornerMax.z() - myCornerMin.z()) / myDimensionZ;
 
-#ifdef HAVE_TBB
-  
-  tbb::parallel_for (tbb::blocked_range<Standard_Integer> (0, myDimensionZ),
-    BVH_ParallelDistanceFieldBuilder<T, N> (this, &theGeometry));
-
-#else
-
-  BuildSlices (theGeometry, 0, myDimensionZ);
-
-#endif
+  OSD_Parallel::For (0, myDimensionZ, BVH_ParallelDistanceFieldBuilder<T, N> (this, &theGeometry));
 
   return Standard_True;
 }
index 35e20d4..9f0a223 100644 (file)
@@ -211,92 +211,79 @@ namespace BVH
     return 0;
   }
 
-#ifdef HAVE_TBB
-
-  //! TBB task for parallel bounds updating.
   template<class T, int N>
-  class UpdateBoundTask: public tbb::task
+  struct BoundData
   {
-
-    BVH_Set<T, N>*    mySet;    //!< Set of geometric objects
+    BVH_Set <T, N>*   mySet;    //!< Set of geometric objects
     BVH_Tree<T, N>*   myBVH;    //!< BVH tree built over the set
     Standard_Integer  myNode;   //!< BVH node to update bounding box
     Standard_Integer  myLevel;  //!< Level of the processed BVH node
     Standard_Integer* myHeight; //!< Height of the processed BVH node
+  };
 
+  //! Task for parallel bounds updating.
+  template<class T, int N>
+  class UpdateBoundTask
+  {
   public:
 
-    //! Creates new TBB parallel bound update task.
-    UpdateBoundTask (BVH_Set<T, N>*    theSet,
-                     BVH_Tree<T, N>*   theBVH,
-                     Standard_Integer  theNode,
-                     Standard_Integer  theLevel,
-                     Standard_Integer* theHeight)
-    : mySet (theSet), myBVH (theBVH), myNode (theNode), myLevel (theLevel), myHeight (theHeight) {}
-
     //! Executes the task.
-    tbb::task* execute()
+    void operator()(const BoundData<T, N>& theData) const
     {
-      if (myBVH->IsOuter (myNode) || myLevel > 2)
+      if (theData.myBVH->IsOuter (theData.myNode) || theData.myLevel > 2)
       {
-        *myHeight = BVH::UpdateBounds (mySet, myBVH, myNode);
+        *theData.myHeight = BVH::UpdateBounds (theData.mySet, theData.myBVH, theData.myNode);
       }
       else
       {
         Standard_Integer aLftHeight = 0;
         Standard_Integer aRghHeight = 0;
 
-        const Standard_Integer aLftChild = myBVH->NodeInfoBuffer()[myNode].y();
-        const Standard_Integer aRghChild = myBVH->NodeInfoBuffer()[myNode].z();
+        const Standard_Integer aLftChild = theData.myBVH->NodeInfoBuffer()[theData.myNode].y();
+        const Standard_Integer aRghChild = theData.myBVH->NodeInfoBuffer()[theData.myNode].z();
 
-        Standard_Integer aCount = 1;
-        tbb::task_list aList;
-        if (!myBVH->IsOuter (aLftChild))
+        std::vector<BoundData<T, N> > aList;
+        aList.reserve (2);
+        if (!theData.myBVH->IsOuter (aLftChild))
         {
-          ++aCount;
-          aList.push_back (*new ( allocate_child() )
-            UpdateBoundTask (mySet, myBVH, aLftChild, myLevel + 1, &aLftHeight));
+          BoundData<T, N> aBoundData = {theData.mySet, theData.myBVH, aLftChild, theData.myLevel + 1, &aLftHeight};
+          aList.push_back (aBoundData);
         }
         else
         {
-          aLftHeight = BVH::UpdateBounds (mySet, myBVH, aLftChild);
+          aLftHeight = BVH::UpdateBounds (theData.mySet, theData.myBVH, aLftChild);
         }
 
-        if (!myBVH->IsOuter (aRghChild))
+        if (!theData.myBVH->IsOuter (aRghChild))
         {
-          ++aCount;
-          aList.push_back (*new( allocate_child() )
-            UpdateBoundTask (mySet, myBVH, aRghChild, myLevel + 1, &aRghHeight));
+          BoundData<T, N> aBoundData = {theData.mySet, theData.myBVH, aRghChild, theData.myLevel + 1, &aRghHeight};
+          aList.push_back (aBoundData);
         }
         else
         {
-          aRghHeight = BVH::UpdateBounds (mySet, myBVH, aRghChild);
+          aRghHeight = BVH::UpdateBounds (theData.mySet, theData.myBVH, aRghChild);
         }
 
-        if (aCount > 1)
+        if (!aList.empty())
         {
-          set_ref_count (aCount);
-          spawn_and_wait_for_all (aList);
+          OSD_Parallel::ForEach (aList.begin (), aList.end (), UpdateBoundTask<T, N> ());
         }
 
-        typename BVH_Box<T, N>::BVH_VecNt aLftMinPoint = myBVH->MinPointBuffer()[aLftChild];
-        typename BVH_Box<T, N>::BVH_VecNt aLftMaxPoint = myBVH->MaxPointBuffer()[aLftChild];
-        typename BVH_Box<T, N>::BVH_VecNt aRghMinPoint = myBVH->MinPointBuffer()[aRghChild];
-        typename BVH_Box<T, N>::BVH_VecNt aRghMaxPoint = myBVH->MaxPointBuffer()[aRghChild];
+        typename BVH_Box<T, N>::BVH_VecNt aLftMinPoint = theData.myBVH->MinPointBuffer()[aLftChild];
+        typename BVH_Box<T, N>::BVH_VecNt aLftMaxPoint = theData.myBVH->MaxPointBuffer()[aLftChild];
+        typename BVH_Box<T, N>::BVH_VecNt aRghMinPoint = theData.myBVH->MinPointBuffer()[aRghChild];
+        typename BVH_Box<T, N>::BVH_VecNt aRghMaxPoint = theData.myBVH->MaxPointBuffer()[aRghChild];
 
         BVH::BoxMinMax<T, N>::CwiseMin (aLftMinPoint, aRghMinPoint);
         BVH::BoxMinMax<T, N>::CwiseMax (aLftMaxPoint, aRghMaxPoint);
 
-        myBVH->MinPointBuffer()[myNode] = aLftMinPoint;
-        myBVH->MaxPointBuffer()[myNode] = aLftMaxPoint;
+        theData.myBVH->MinPointBuffer()[theData.myNode] = aLftMinPoint;
+        theData.myBVH->MaxPointBuffer()[theData.myNode] = aLftMaxPoint;
 
-        *myHeight = Max (aLftHeight, aRghHeight) + 1;
+        *theData.myHeight = Max (aLftHeight, aRghHeight) + 1;
       }
-      return NULL;
     }
   };
-
-#endif
 }
 
 // =======================================================================
@@ -331,21 +318,9 @@ void BVH_LinearBuilder<T, N>::Build (BVH_Set<T, N>*       theSet,
   theBVH->MaxPointBuffer().resize (theBVH->NodeInfoBuffer().size());
 
   Standard_Integer aHeight = 0;
-
-#ifdef HAVE_TBB
-
-  // Note: Although TBB tasks are allocated using placement
-  // new, we do not need to delete them explicitly
-  BVH::UpdateBoundTask<T, N>& aRootTask = *new ( tbb::task::allocate_root() )
-    BVH::UpdateBoundTask<T, N> (theSet, theBVH, 0, 0, &aHeight);
-
-  tbb::task::spawn_root_and_wait (aRootTask);
-
-#else
-
-  aHeight = BVH::UpdateBounds (theSet, theBVH, 0);
-
-#endif
+  BVH::BoundData<T, N> aBoundData = { theSet, theBVH, 0, 0, &aHeight };
+  BVH::UpdateBoundTask<T, N> aBoundTask;
+  aBoundTask (aBoundData);
 
   BVH_Builder<T, N>::updateDepth (theBVH, aHeight);
 }
index 4425a74..b0a8b06 100644 (file)
 #include <BVH_Builder.hxx>
 #include <NCollection_Array1.hxx>
 #include <NCollection_Shared.hxx>
+#include <OSD_Parallel.hxx>
 
 #include <algorithm>
 
-#ifdef HAVE_TBB
-  // On Windows, function TryEnterCriticalSection has appeared in Windows NT
-  // and is surrounded by #ifdef in MS VC++ 7.1 headers.
-  // Thus to use it we need to define appropriate macro saying that we will
-  // run on Windows NT 4.0 at least
-  #if defined(_WIN32) && !defined(_WIN32_WINNT)
-    #define _WIN32_WINNT 0x0501
-  #endif
-
-  #include <tbb/parallel_invoke.h>
-#endif
-
 //! Pair of Morton code and primitive ID.
 typedef std::pair<Standard_Integer, Standard_Integer> BVH_EncodedLink;
 
@@ -113,21 +102,21 @@ namespace BVH
 
   private:
 
-    //! TBB functor class to run sorting.
-    struct Functor
+    //! Structure defining sorting range.
+    struct SortRange
     {
       LinkIterator     myStart; //!< Start element of exclusive sorting range
       LinkIterator     myFinal; //!< Final element of exclusive sorting range
       Standard_Integer myDigit; //!< Bit number used for partition operation
+    };
 
-      //! Creates new sorting functor.
-      Functor (LinkIterator theStart, LinkIterator theFinal, Standard_Integer theDigit)
-      : myStart (theStart), myFinal (theFinal), myDigit (theDigit) {}
-
+    //! Functor class to run sorting in parallel.
+    struct Functor
+    {
       //! Runs sorting function for the given range.
-      void operator() () const
+      void operator()(const SortRange& theRange) const
       {
-        RadixSorter::Sort (myStart, myFinal, myDigit);
+        RadixSorter::Sort (theRange.myStart, theRange.myFinal, theRange.myDigit);
       }
     };
 
@@ -135,7 +124,6 @@ namespace BVH
 
     static void Sort (LinkIterator theStart, LinkIterator theFinal, Standard_Integer theDigit)
     {
-    #ifdef HAVE_TBB
       if (theDigit < 24)
       {
         BVH::RadixSorter::perform (theStart, theFinal, theDigit);
@@ -143,12 +131,13 @@ namespace BVH
       else
       {
         LinkIterator anOffset = std::partition (theStart, theFinal, BitPredicate (theDigit));
-        tbb::parallel_invoke (Functor (theStart, anOffset, theDigit - 1),
-                              Functor (anOffset, theFinal, theDigit - 1));
+        SortRange aSplits[2] = {
+          {theStart, anOffset, theDigit - 1},
+          {anOffset, theFinal, theDigit - 1}
+        };
+
+        OSD_Parallel::ForEach (std::begin (aSplits), std::end (aSplits), Functor ());
       }
-    #else
-      BVH::RadixSorter::perform (theStart, theFinal, theDigit);
-    #endif
     }
 
   protected: