]> OCCT Git - occt-copy.git/commitdiff
0031757: Visualization - Prebuild BVH for Select3D_SensitiveEntity in separate threads
authorage <age@opencascade.com>
Tue, 8 Sep 2020 11:44:21 +0000 (14:44 +0300)
committernds <nds@opencascade.com>
Thu, 19 Nov 2020 08:45:44 +0000 (11:45 +0300)
(cherry picked from commit bb598fe0216163889af6aa054ec8081eb1cfd384)

src/SelectMgr/FILES
src/SelectMgr/SelectMgr_BVHThreadPool.cxx [new file with mode: 0644]
src/SelectMgr/SelectMgr_BVHThreadPool.hxx [new file with mode: 0644]
src/SelectMgr/SelectMgr_SelectionManager.cxx
src/SelectMgr/SelectMgr_ViewerSelector.cxx
src/SelectMgr/SelectMgr_ViewerSelector.hxx

index 3c05be68b88f2351cb1e1fe48be4bbc263bfdd05..85b038af82908e6a78d98496c0a86c28b638cc05 100755 (executable)
@@ -2,6 +2,8 @@ SelectMgr_AndFilter.cxx
 SelectMgr_AndFilter.hxx
 SelectMgr_BaseFrustum.cxx
 SelectMgr_BaseFrustum.hxx
+SelectMgr_BVHThreadPool.cxx
+SelectMgr_BVHThreadPool.hxx
 SelectMgr_CompositionFilter.cxx
 SelectMgr_CompositionFilter.hxx
 SelectMgr_CompositionFilter.lxx
diff --git a/src/SelectMgr/SelectMgr_BVHThreadPool.cxx b/src/SelectMgr/SelectMgr_BVHThreadPool.cxx
new file mode 100644 (file)
index 0000000..9f4da57
--- /dev/null
@@ -0,0 +1,157 @@
+#include <SelectMgr_BVHThreadPool.hxx>
+#include <OSD_Parallel.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(SelectMgr_BVHThreadPool, Standard_Transient)
+
+//==================================================
+// Function: SelectMgr_BVHThreadPool
+// Purpose :
+//==================================================
+SelectMgr_BVHThreadPool::SelectMgr_BVHThreadPool (Standard_Integer theNbThreads)
+: myToStopBVHThread(Standard_False),
+  myWakeEvent(Standard_False),
+  myIdleEvent(Standard_True),
+  myIsStarted(Standard_False)
+{
+  Standard_Integer aBVHThreadsNum = theNbThreads > 0 ? theNbThreads : OSD_Parallel::NbLogicalProcessors() > 1 ? OSD_Parallel::NbLogicalProcessors() - 1 : 1;
+  myBVHThreads = NCollection_Array1<OSD_Thread>(1, aBVHThreadsNum);
+  myBVHBuildData = NCollection_Array1<BVHBuild_Data>(1, aBVHThreadsNum);
+
+  for (Standard_Integer i = myBVHThreads.Lower(); i <= myBVHThreads.Upper(); ++i)
+  {
+    myBVHThreads.ChangeValue(i).SetFunction (buildBVHThreadFunc);
+    myBVHThreads.ChangeValue(i).SetPriority (THREAD_PRIORITY_BELOW_NORMAL);
+    myBVHBuildData.ChangeValue(i).Pool = this;
+  }
+}
+
+//==================================================
+// Function: ~SelectMgr_BVHThreadPool
+// Purpose :
+//==================================================
+SelectMgr_BVHThreadPool::~SelectMgr_BVHThreadPool()
+{
+  StopThreads();
+}
+
+//==================================================
+// Function: StopThreads
+// Purpose :
+//==================================================
+void SelectMgr_BVHThreadPool::StopThreads()
+{
+  if (!myIsStarted)
+  {
+    return;
+  }
+  myToStopBVHThread = Standard_True;
+  myWakeEvent.Set();
+  for (Standard_Integer i = myBVHThreads.Lower(); i <= myBVHThreads.Upper(); ++i)
+  {
+    myBVHThreads.ChangeValue(i).Wait();
+  }
+  myToStopBVHThread = Standard_False;
+  myIsStarted = Standard_False;
+}
+
+//==================================================
+// Function: WaitThreads
+// Purpose :
+//==================================================
+void SelectMgr_BVHThreadPool::WaitThreads()
+{
+  myIdleEvent.Wait();
+
+  LockBVHBuildMutex();
+  UnlockBVHBuildMutex();
+}
+
+//=======================================================================
+//function : BuildBVH
+//purpose  : 
+//=======================================================================
+void SelectMgr_BVHThreadPool::BuildBVH (const Handle(Select3D_SensitiveEntity)& theEntity)
+{
+  myBVHListMutex.Lock();
+  myBVHToBuildList.Append (theEntity);
+  myWakeEvent.Set();
+  myIdleEvent.Reset();
+  myBVHListMutex.Unlock();
+
+  if (!myIsStarted)
+  {
+    myIsStarted = Standard_True;
+    for (Standard_Integer i = myBVHThreads.Lower(); i <= myBVHThreads.Upper(); ++i)
+    {
+      myBVHThreads.ChangeValue(i).Run((Standard_Address)(&myBVHBuildData.ChangeValue(i)));
+    }
+  }
+}
+
+//=======================================================================
+//function : buildBVHThreadFunc
+//purpose  : 
+//=======================================================================
+Standard_Address SelectMgr_BVHThreadPool::buildBVHThreadFunc (Standard_Address data)
+{
+  BVHBuild_Data* aData = reinterpret_cast<BVHBuild_Data*> (data);
+  SelectMgr_BVHThreadPool* aPool = aData->Pool;
+  Standard_Mutex& aBVHBuildMutex = aData->Mutex;
+
+  for (;;)
+  {
+    aPool->myWakeEvent.Wait();
+
+    if (aPool->myToStopBVHThread)
+    {
+      break;
+    }
+
+    aPool->myBVHListMutex.Lock();
+    if (aPool->myBVHToBuildList.IsEmpty())
+    {
+      aPool->myWakeEvent.Reset();
+      aPool->myIdleEvent.Set();
+      aPool->myBVHListMutex.Unlock();
+      continue;
+    }
+    Handle(Select3D_SensitiveEntity) anEntity = aPool->myBVHToBuildList.First();
+    aPool->myBVHToBuildList.RemoveFirst();
+    
+    aBVHBuildMutex.Lock();
+    aPool->myBVHListMutex.Unlock();
+
+    if (!anEntity.IsNull())
+    {
+      anEntity->BVH();
+    }
+    aBVHBuildMutex.Unlock();
+  }
+
+  return (Standard_Address)(0);
+}
+
+//=======================================================================
+//function : LockBVHBuildMutex
+//purpose  : 
+//=======================================================================
+void SelectMgr_BVHThreadPool::LockBVHBuildMutex()
+{
+  for (Standard_Integer i = myBVHBuildData.Lower(); i <= myBVHBuildData.Upper(); ++i)
+  {
+    myBVHBuildData.ChangeValue(i).Mutex.Lock();
+  }
+}
+
+//=======================================================================
+//function : UnlockBVHBuildMutex
+//purpose  : 
+//=======================================================================
+void SelectMgr_BVHThreadPool::UnlockBVHBuildMutex()
+{
+  for (Standard_Integer i = myBVHBuildData.Lower(); i <= myBVHBuildData.Upper(); ++i)
+  {
+    myBVHBuildData.ChangeValue(i).Mutex.Unlock();
+  }
+}
+
diff --git a/src/SelectMgr/SelectMgr_BVHThreadPool.hxx b/src/SelectMgr/SelectMgr_BVHThreadPool.hxx
new file mode 100644 (file)
index 0000000..c1d1ebd
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef _SelectMgr_BVHThreadPool_HeaderFile
+#define _SelectMgr_BVHThreadPool_HeaderFile
+
+#include <Standard_Transient.hxx>
+#include <OSD_Thread.hxx>
+#include <Standard_Mutex.hxx>
+#include <Select3D_SensitiveEntity.hxx>
+#include <Standard_Condition.hxx>
+
+//! Class defining a thread pool for building BVH for Select3D_SensitiveEntity in multi-threaded mode.
+class SelectMgr_BVHThreadPool : public Standard_Transient
+{
+  DEFINE_STANDARD_RTTIEXT(SelectMgr_BVHThreadPool, Standard_Transient)
+public:
+  //! Main constructor
+  Standard_EXPORT SelectMgr_BVHThreadPool (Standard_Integer theNbThreads);
+
+  //! Destructor
+  Standard_EXPORT virtual ~SelectMgr_BVHThreadPool();
+
+public:
+  //! Queue a sensitive entity to build its BVH
+  Standard_EXPORT void BuildBVH (const Handle(Select3D_SensitiveEntity)& theEntity);
+
+  //! Lock mutexes for building BVH
+  Standard_EXPORT void LockBVHBuildMutex();
+
+  //! Unlock mutexes for building BVH
+  Standard_EXPORT void UnlockBVHBuildMutex();
+
+  //! Stops threads
+  Standard_EXPORT void StopThreads();
+
+  //! Waits for all threads finish their jobs
+  Standard_EXPORT void WaitThreads();
+
+protected:
+
+  //! Thread function, accept address of BVHBuild_Data struct as parameter
+  static Standard_Address buildBVHThreadFunc (Standard_Address data);
+
+protected:
+
+  //! Structure that will be passed to a separate thread
+  struct BVHBuild_Data
+  {
+    SelectMgr_BVHThreadPool* Pool;
+    Standard_Mutex Mutex;
+  };
+  NCollection_List<Handle(Select3D_SensitiveEntity)> myBVHToBuildList; //!< list of queued sensitive entities
+  NCollection_Array1<OSD_Thread> myBVHThreads;                         //!< threads to build BVH
+  Standard_Boolean myToStopBVHThread;                                  //!< flag to stop BVH threads
+  Standard_Mutex myBVHListMutex;                                       //!< mutex for interaction with myBVHToBuildList
+  NCollection_Array1<BVHBuild_Data> myBVHBuildData;                    //!< list of mutexes for building BVH
+  Standard_Condition myWakeEvent;                                      //!< raises when any sensitive is added to the BVH list
+  Standard_Condition myIdleEvent;                                      //!< raises when BVH list become empty
+  Standard_Boolean myIsStarted;                                        //!< indicates that threads are running
+};
+
+#endif
index 195ed54c754b0a9cda1096a24d36adf518c1c813..99545fee2277e89ddcee6f9dcc5dcfab3b1ad842 100644 (file)
@@ -484,6 +484,16 @@ void SelectMgr_SelectionManager::loadMode (const Handle(SelectMgr_SelectableObje
         theObject->AddSelection (aNewSel, theMode);
         aNewSel->UpdateBVHStatus (SelectMgr_TBU_Remove);
         aNewSel->SetSelectionState (SelectMgr_SOS_Deactivated);
+
+        if (mySelector->ToPrebuildBVH())
+        {
+          NCollection_Vector<Handle(SelectMgr_SensitiveEntity)>::Iterator anIter(aNewSel->Entities());
+          for (; anIter.More(); anIter.Next())
+          {
+            const Handle(Select3D_SensitiveEntity)& anEntity = anIter.Value()->BaseSensitive();
+            mySelector->QueueBVHBuild(anEntity);
+          }
+        }
       }
     }
     return;
@@ -496,6 +506,16 @@ void SelectMgr_SelectionManager::loadMode (const Handle(SelectMgr_SelectableObje
     mySelector->AddSelectionToObject (theObject, aNewSel);
     aNewSel->UpdateBVHStatus (SelectMgr_TBU_None);
   }
+
+  if (mySelector->ToPrebuildBVH())
+  {
+    NCollection_Vector<Handle(SelectMgr_SensitiveEntity)>::Iterator anIter(aNewSel->Entities());
+    for (; anIter.More(); anIter.Next())
+    {
+      const Handle(Select3D_SensitiveEntity)& anEntity = anIter.Value()->BaseSensitive();
+      mySelector->QueueBVHBuild(anEntity);
+    }
+  }
 }
 
 //=======================================================================
index 9e467d2df607f4800dc1e1167ec6d8e753b7fc28..1ce25db8a98b01c5cebba68c9a7fe3507a2f8f2d 100644 (file)
@@ -125,7 +125,8 @@ myToUpdateTolerance (Standard_True),
 myCameraScale (1.0),
 myCurRank (0),
 myIsLeftChildQueuedFirst (Standard_False),
-myEntityIdx (0)
+myEntityIdx (0),
+myToPrebuildBVH (Standard_False)
 {
   myEntitySetBuilder = new BVH_BinnedBuilder<Standard_Real, 3, 4> (BVH_Constants_LeafNodeSizeSingle, BVH_Constants_MaxTreeDepth, Standard_True);
 }
@@ -543,6 +544,11 @@ void SelectMgr_ViewerSelector::traverseObject (const Handle(SelectMgr_Selectable
 //=======================================================================
 void SelectMgr_ViewerSelector::TraverseSensitives()
 {
+  if (myToPrebuildBVH)
+  {
+    myBVHThreadPool->LockBVHBuildMutex();
+  }
+
   mystored.Clear();
 
   Standard_Integer aWidth;
@@ -679,6 +685,11 @@ void SelectMgr_ViewerSelector::TraverseSensitives()
   }
 
   SortResult();
+
+  if (myToPrebuildBVH)
+  {
+    myBVHThreadPool->UnlockBVHBuildMutex();
+  }
 }
 
 //==================================================
@@ -1046,3 +1057,32 @@ void SelectMgr_ViewerSelector::AllowOverlapDetection (const Standard_Boolean the
 {
   mySelectingVolumeMgr.AllowOverlapDetection (theIsToAllow);
 }
+
+//=======================================================================
+//function : SetToPrebuildBVH
+//purpose  : 
+//=======================================================================
+void SelectMgr_ViewerSelector::SetToPrebuildBVH (Standard_Boolean theToPrebuild, Standard_Integer theThreadsNum)
+{
+  if (!theToPrebuild && !myBVHThreadPool.IsNull())
+  {
+    myBVHThreadPool->StopThreads();
+  }
+  else if (theToPrebuild)
+  {
+    myBVHThreadPool = new SelectMgr_BVHThreadPool (theThreadsNum);
+  }
+  myToPrebuildBVH = theToPrebuild;
+}
+
+//=======================================================================
+//function : QueueBVHBuild
+//purpose  : 
+//=======================================================================
+void SelectMgr_ViewerSelector::QueueBVHBuild (const Handle(Select3D_SensitiveEntity)& theEntity)
+{
+  if (myToPrebuildBVH)
+  {
+    myBVHThreadPool->BuildBVH (theEntity);
+  }
+}
\ No newline at end of file
index 70b032cd1c3b077ff5198975c946d5b72b1f26f9..9929ef79f24607acb5f6578fbf84404a1fd4baf1 100644 (file)
@@ -31,6 +31,7 @@
 #include <SelectMgr_StateOfSelection.hxx>
 #include <SelectMgr_ToleranceMap.hxx>
 #include <Standard_OStream.hxx>
+#include <SelectMgr_BVHThreadPool.hxx>
 
 class SelectMgr_SelectionManager;
 class SelectMgr_SensitiveEntitySet;
@@ -245,6 +246,20 @@ public:
   Standard_DEPRECATED("Deprecated method DetectedEntity() should be replaced by DetectedEntity(int)")
   Standard_EXPORT const Handle(Select3D_SensitiveEntity)& DetectedEntity() const;
 
+public:
+
+  //! Enables/disables building BVH for sensitives in separate threads
+  Standard_EXPORT void SetToPrebuildBVH(Standard_Boolean theToPrebuild, Standard_Integer theThreadsNum = -1);
+
+  //! Queue a sensitive entity to build its BVH
+  Standard_EXPORT void QueueBVHBuild(const Handle(Select3D_SensitiveEntity)& theEntity);
+
+  //! Returns TRUE if building BVH for sensitives in separate threads is enabled
+  Standard_Boolean ToPrebuildBVH()
+  {
+    return myToPrebuildBVH;
+  }
+
 protected:
 
   Standard_EXPORT SelectMgr_ViewerSelector();
@@ -336,6 +351,9 @@ protected:
   gp_Dir                                        myCameraDir;
   Standard_Real                                 myCameraScale;
 
+  Standard_Boolean                              myToPrebuildBVH;
+  Handle(SelectMgr_BVHThreadPool)               myBVHThreadPool;
+
 private:
 
   Handle(TColStd_HArray1OfInteger)             myIndexes;