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)
committerbugmaster <bugmaster@opencascade.com>
Fri, 18 Sep 2020 14:46:57 +0000 (17:46 +0300)
- Added a new mode in SelectMgr_ViewerSelector for computing BVH for Select3D_SensitiveEntity in background which can be activated via method SelectMgr_ViewerSelector::SetToPrebuildBVH(). Default behavior has not been changed.
- New class SelectMgr_BVHThreadPool manages background processing of BVH building queue.
- Added Select3D_SensitiveEntity::ToBuildBVH() method that checks if BVH (if it used) is in invalidated state. Defined this method for all standard classes inherited from Select3D_SensitiveEntity.

22 files changed:
src/AIS/AIS_ColoredShape.cxx
src/MeshVS/MeshVS_DummySensitiveEntity.hxx
src/MeshVS/MeshVS_Mesh.cxx
src/Select3D/Select3D_SensitiveBox.hxx
src/Select3D/Select3D_SensitiveCircle.cxx
src/Select3D/Select3D_SensitiveCircle.hxx
src/Select3D/Select3D_SensitiveEntity.hxx
src/Select3D/Select3D_SensitiveFace.hxx
src/Select3D/Select3D_SensitivePoint.hxx
src/Select3D/Select3D_SensitiveSegment.hxx
src/Select3D/Select3D_SensitiveSet.hxx
src/Select3D/Select3D_SensitiveTriangle.hxx
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_SelectionManager.hxx
src/SelectMgr/SelectMgr_ViewerSelector.cxx
src/SelectMgr/SelectMgr_ViewerSelector.hxx
src/StdSelect/StdSelect_BRepSelectionTool.cxx
src/ViewerTest/ViewerTest_ViewerCommands.cxx
tests/v3d/mesh/C1 [new file with mode: 0644]

index 19a62d355f2143a864e69fa5f84a204d4f8117ca..01b5cd779f0df501638b88bf0fb550969e7afd06 100644 (file)
@@ -518,8 +518,6 @@ void AIS_ColoredShape::ComputeSelection (const Handle(SelectMgr_Selection)& theS
     const Handle(SelectMgr_EntityOwner)& anOwner = aSelEntIter.Value()->BaseSensitive()->OwnerId();
     anOwner->SetSelectable (aThis);
   }
-
-  StdSelect_BRepSelectionTool::PreBuildBVH (theSelection);
 }
 
 //=======================================================================
index 049e5f41bd0bf81ed77c88b79a5e2130e71cd3c7..414b3728b8caf842d228c15af951982a440d17d4 100644 (file)
@@ -42,6 +42,8 @@ public:
 
   Standard_EXPORT virtual void BVH() Standard_OVERRIDE;
 
+  virtual Standard_Boolean ToBuildBVH() const Standard_OVERRIDE { return Standard_False; }
+
   Standard_EXPORT virtual void Clear() Standard_OVERRIDE;
 
   Standard_EXPORT virtual Standard_Boolean HasInitLocation() const Standard_OVERRIDE;
index 51a50391583c85d545d05bffa786f894a51e9418..5fff7157101b69f6777330a22bd0a9ebf3fccd6d 100644 (file)
@@ -652,8 +652,6 @@ void MeshVS_Mesh::ComputeSelection (const Handle(SelectMgr_Selection)& theSelect
     }
   }
 
-  StdSelect_BRepSelectionTool::PreBuildBVH (theSelection);
-
   if (toShowComputeSelectionTime)
   {
     Standard_Real sec, cpu;
index ac5264f25f5640503e49fe50f117a7d2f0508a23..d10cd410c40bf73d326c1adfade2013e17bd0f4a 100644 (file)
@@ -70,6 +70,9 @@ public:
   //! transformation is set, it will be applied
   Standard_EXPORT virtual Select3D_BndBox3d BoundingBox() Standard_OVERRIDE;
 
+  //! Returns TRUE if BVH tree is in invalidated state
+  virtual Standard_Boolean ToBuildBVH() const Standard_OVERRIDE { return Standard_False; }
+
   //! Dumps the content of me into the stream
   Standard_EXPORT virtual void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const Standard_OVERRIDE;
 
index 82bf115bdecefa14d8dcfe1c7f33014b2dbaa162..0eea1fa5cc846a80ecc1058aa0fe6ef5f0fae406 100644 (file)
@@ -191,6 +191,20 @@ void Select3D_SensitiveCircle::BVH()
   }
 }
 
+//=======================================================================
+// function : ToBuildBVH
+// purpose  : 
+//=======================================================================
+Standard_Boolean Select3D_SensitiveCircle::ToBuildBVH() const
+{
+  if (mySensType != Select3D_TOS_BOUNDARY)
+  {
+    return Standard_False;
+  }
+
+  return Select3D_SensitivePoly::ToBuildBVH();
+}
+
 //=======================================================================
 // function : Matches
 // purpose  : Checks whether the circle overlaps current selecting volume
index 57deeaf5fb3b0011761a904747012aaed1b9627b..075c2658cff9c8693288b83d89eeb6856a27a655 100644 (file)
@@ -81,6 +81,9 @@ public:
   //! Builds BVH tree for a circle's edge segments if needed
   Standard_EXPORT virtual void BVH() Standard_OVERRIDE;
 
+  //! Returns TRUE if BVH tree is in invalidated state
+  Standard_EXPORT virtual Standard_Boolean ToBuildBVH() const Standard_OVERRIDE;
+
 protected:
 
   //! Calculates distance from the 3d projection of used-picked screen point
index 19b039eafd908b22b7198fd94de69acd8e33999f..f99df8fcdb5db9d08063d0df08d6e7ff39fb6d07 100644 (file)
@@ -81,6 +81,9 @@ public:
   //! Builds BVH tree for a sensitive if needed
   virtual void BVH() {}
 
+  //! Returns TRUE if BVH tree is in invalidated state
+  virtual Standard_Boolean ToBuildBVH() const { return Standard_True; }
+
   //! Clears up all resources and memory
   virtual void Clear() { Set (Handle(SelectMgr_EntityOwner)()); }
 
index b8d7ca5436368434a49f684222be6e44bcac7cf8..d8d7d95986cef31514b2883c3c4ad4386c995e07 100644 (file)
@@ -70,6 +70,9 @@ public:
   //! Builds BVH tree for the face
   Standard_EXPORT virtual void BVH() Standard_OVERRIDE;
 
+  //! Returns TRUE if BVH tree is in invalidated state
+  virtual Standard_Boolean ToBuildBVH() const Standard_OVERRIDE { return myFacePoints->ToBuildBVH(); }
+
   //! Returns the amount of sub-entities (points or planar convex polygons)
   Standard_EXPORT virtual Standard_Integer NbSubElements() const Standard_OVERRIDE;
 
index f5332c8e04cbd17ae2e7398ec7a2dbc9623c1e31..983d8800b2aedb0ba8e405b7c3ed9322316d4cfd 100644 (file)
@@ -50,6 +50,9 @@ public:
   //! transformation is set, it will be applied
   Standard_EXPORT virtual Select3D_BndBox3d BoundingBox() Standard_OVERRIDE;
 
+  //! Returns TRUE if BVH tree is in invalidated state
+  virtual Standard_Boolean ToBuildBVH() const Standard_OVERRIDE { return Standard_False; }
+
   //! Dumps the content of me into the stream
   Standard_EXPORT virtual void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const Standard_OVERRIDE;
 
index abe00a3fa2b799f61de79c793de29b589a870e54..edf4890408d3a682911d9d1ae19698d0281f33f8 100644 (file)
@@ -62,6 +62,9 @@ public:
   //! transformation is set, it will be applied
   Standard_EXPORT virtual Select3D_BndBox3d BoundingBox() Standard_OVERRIDE;
 
+  //! Returns TRUE if BVH tree is in invalidated state
+  virtual Standard_Boolean ToBuildBVH() const Standard_OVERRIDE { return Standard_False; }
+
 public:
 
   //! changes the start Point of the Segment;
index be3ef600cfc15126af616e69406fe8dccb8cd6ec..60164f43963c9ad4bca92c7fccfb3da51eb15e93 100644 (file)
@@ -75,6 +75,9 @@ public:
   //! but element by element
   Standard_EXPORT virtual void BVH() Standard_OVERRIDE;
 
+  //! Returns TRUE if BVH tree is in invalidated state
+  virtual Standard_Boolean ToBuildBVH() const Standard_OVERRIDE { return myContent.IsDirty(); }
+
   //! Sets the method (builder) used to construct BVH.
   void SetBuilder (const Handle(Select3D_BVHBuilder3d)& theBuilder) { myContent.SetBuilder (theBuilder); }
 
index 76c066d76b14af4a7f067bd405a91571f9ea41f8..8d605e1a62f9c597d232df5f5f09b1fe4a478450 100644 (file)
@@ -62,6 +62,9 @@ public:
   //! will be applied
   Standard_EXPORT virtual Select3D_BndBox3d BoundingBox() Standard_OVERRIDE;
 
+  //! Returns TRUE if BVH tree is in invalidated state
+  virtual Standard_Boolean ToBuildBVH() const Standard_OVERRIDE { return Standard_False; }
+
   //! Returns the amount of points
   virtual Standard_Integer NbSubElements() const Standard_OVERRIDE { return 3; }
 
index 6166e3847055fcb2ce41e23f72b79734eb50e7b0..7e3351c4e19ef924202bb7c26d4f1e48ef13ce96 100755 (executable)
@@ -6,6 +6,8 @@ SelectMgr_AndOrFilter.cxx
 SelectMgr_AndOrFilter.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..1be8be0
--- /dev/null
@@ -0,0 +1,180 @@
+// Copyright (c) 2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <SelectMgr_BVHThreadPool.hxx>
+#include <Message.hxx>
+#include <OSD.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 = Max (1, theNbThreads);
+  myBVHThreads.Resize (1, aBVHThreadsNum, Standard_False);
+
+  Standard_Boolean toCatchFpe = OSD::ToCatchFloatingSignals();
+
+  for (Standard_Integer i = myBVHThreads.Lower(); i <= myBVHThreads.Upper(); ++i)
+  {
+    BVHThread& aThread = myBVHThreads.ChangeValue(i);
+    aThread.SetFunction (&BVHThread::runThread);
+    aThread.myPool = this;
+    aThread.myToCatchFpe = toCatchFpe;
+  }
+}
+
+//==================================================
+// 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();
+
+  Sentry aSentry (this);
+}
+
+//=======================================================================
+//function : AddEntity
+//purpose  : 
+//=======================================================================
+void SelectMgr_BVHThreadPool::AddEntity (const Handle(Select3D_SensitiveEntity)& theEntity)
+{
+  if (!theEntity->ToBuildBVH())
+  {
+    return;
+  }
+
+  {
+    Standard_Mutex::Sentry aSentry (myBVHListMutex);
+    myBVHToBuildList.Append (theEntity);
+    myWakeEvent.Set();
+    myIdleEvent.Reset();
+  }
+
+  if (!myIsStarted)
+  {
+    myIsStarted = Standard_True;
+    for (Standard_Integer i = myBVHThreads.Lower(); i <= myBVHThreads.Upper(); ++i)
+    {
+      myBVHThreads.ChangeValue(i).Run ((Standard_Address) (&myBVHThreads.ChangeValue(i)));
+    }
+  }
+}
+
+//=======================================================================
+//function : performThread
+//purpose  : 
+//=======================================================================
+void SelectMgr_BVHThreadPool::BVHThread::performThread()
+{
+  OSD::SetThreadLocalSignal (OSD::SignalMode(), myToCatchFpe);
+
+  for (;;)
+  {
+    myPool->myWakeEvent.Wait();
+
+    if (myPool->myToStopBVHThread)
+    {
+      return;
+    }
+
+    myPool->myBVHListMutex.Lock();
+    if (myPool->myBVHToBuildList.IsEmpty())
+    {
+      myPool->myWakeEvent.Reset();
+      myPool->myIdleEvent.Set();
+      myPool->myBVHListMutex.Unlock();
+      continue;
+    }
+    Handle(Select3D_SensitiveEntity) anEntity = myPool->myBVHToBuildList.First();
+    myPool->myBVHToBuildList.RemoveFirst();
+    
+    Standard_Mutex::Sentry anEntry (myMutex);
+    myPool->myBVHListMutex.Unlock();
+
+    if (!anEntity.IsNull())
+    {
+      try
+      {
+        OCC_CATCH_SIGNALS
+          anEntity->BVH();
+      }
+      catch (Standard_Failure const& aFailure)
+      {
+        TCollection_AsciiString aMsg = TCollection_AsciiString (aFailure.DynamicType()->Name())
+          + ": " + aFailure.GetMessageString();
+        Message::DefaultMessenger()->SendFail (aMsg);
+      }
+      catch (std::exception& anStdException)
+      {
+        TCollection_AsciiString aMsg = TCollection_AsciiString (typeid(anStdException).name())
+          + ": " + anStdException.what();
+        Message::DefaultMessenger()->SendFail (aMsg);
+      }
+      catch (...)
+      {
+        Message::DefaultMessenger()->SendFail ("Error: Unknown exception");
+      }
+    }
+  }
+}
+
+// =======================================================================
+// function : runThread
+// purpose  :
+// =======================================================================
+Standard_Address SelectMgr_BVHThreadPool::BVHThread::runThread (Standard_Address theTask)
+{
+  BVHThread* aThread = static_cast<BVHThread*>(theTask);
+  aThread->performThread();
+  return NULL;
+}
diff --git a/src/SelectMgr/SelectMgr_BVHThreadPool.hxx b/src/SelectMgr/SelectMgr_BVHThreadPool.hxx
new file mode 100644 (file)
index 0000000..84d8ab3
--- /dev/null
@@ -0,0 +1,165 @@
+// Copyright (c) 2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#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>
+#include <Message_Messenger.hxx>
+
+//! Class defining a thread pool for building BVH for the list of Select3D_SensitiveEntity within background thread(s).
+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:
+
+  //! Thread with back reference to thread pool and thread mutex in it.
+  class BVHThread : public OSD_Thread
+  {
+    friend class SelectMgr_BVHThreadPool;
+  public:
+
+    BVHThread()
+      : OSD_Thread(),
+      myToCatchFpe (Standard_False)
+    {
+
+    }
+
+    //! Returns mutex used for BVH building
+    Standard_Mutex& BVHMutex()
+    {
+      return myMutex;
+    }
+
+    //! Assignment operator.
+    BVHThread& operator= (const BVHThread& theCopy)
+    {
+      Assign (theCopy);
+      return *this;
+    }
+
+    //! Assignment operator.
+    void Assign (const BVHThread& theCopy)
+    {
+      OSD_Thread::Assign (theCopy);
+      myPool = theCopy.myPool;
+      myToCatchFpe = theCopy.myToCatchFpe;
+    }
+
+  private:
+    //! Method is executed in the context of thread.
+    void performThread();
+
+    //! Method is executed in the context of thread.
+    static Standard_Address runThread (Standard_Address theTask);
+
+  private:
+
+    SelectMgr_BVHThreadPool* myPool;
+    Standard_Mutex myMutex;
+    bool myToCatchFpe;
+  };
+
+public:
+  //! Queue a sensitive entity to build its BVH
+  Standard_EXPORT void AddEntity (const Handle(Select3D_SensitiveEntity)& theEntity);
+
+  //! Stops threads
+  Standard_EXPORT void StopThreads();
+
+  //! Waits for all threads finish their jobs
+  Standard_EXPORT void WaitThreads();
+
+  //! Returns array of threads
+  NCollection_Array1<BVHThread>& Threads()
+  {
+    return myBVHThreads;
+  }
+
+public:
+
+  //! Class providing a simple interface to mutexes for list of BVHThread
+  class Sentry 
+  {
+  public:
+
+    //! Constructor - initializes the sentry object and locks list of mutexes immediately
+    Sentry (const Handle(SelectMgr_BVHThreadPool)& thePool)
+    : myPool (thePool)
+    {
+      Lock();
+    }
+    
+    //! Destructor - unlocks list of mutexes if already locked.
+    ~Sentry()
+    {
+        Unlock();
+    }
+
+    //! Lock list of mutexes
+    void Lock()
+    {
+      if (!myPool.IsNull())
+      {
+        for (Standard_Integer i = myPool->Threads().Lower(); i <= myPool->Threads().Upper(); ++i)
+        {
+          myPool->Threads().ChangeValue(i).BVHMutex().Lock();
+        }
+      }
+    }
+
+    //! Unlock list of mutexes
+    void Unlock()
+    {
+      if (!myPool.IsNull())
+      {
+        for (Standard_Integer i = myPool->Threads().Lower(); i <= myPool->Threads().Upper(); ++i)
+        {
+          myPool->Threads().ChangeValue(i).BVHMutex().Unlock();
+        }
+      }
+    }
+
+    //! This method should not be called (prohibited).
+    Sentry (const Sentry &);
+    //! This method should not be called (prohibited).
+    Sentry& operator = (const Sentry &);
+
+  private:
+    Handle(SelectMgr_BVHThreadPool) myPool;
+  };
+
+protected:
+
+  NCollection_List<Handle(Select3D_SensitiveEntity)> myBVHToBuildList; //!< list of queued sensitive entities
+  NCollection_Array1<BVHThread> myBVHThreads;                          //!< threads to build BVH
+  Standard_Boolean myToStopBVHThread;                                  //!< flag to stop BVH threads
+  Standard_Mutex myBVHListMutex;                                       //!< mutex for interaction with myBVHToBuildList
+  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..5de719740968e353d6d6cf49b052d9f6af3fb820 100644 (file)
 
 #include <SelectMgr_SelectionManager.hxx>
 
+#include <Select3D_SensitiveGroup.hxx>
 #include <SelectMgr_SelectableObject.hxx>
 #include <SelectMgr_Selection.hxx>
+#include <StdSelect_BRepSelectionTool.hxx>
 #include <TCollection_AsciiString.hxx>
 
 IMPLEMENT_STANDARD_RTTIEXT(SelectMgr_SelectionManager,Standard_Transient)
@@ -484,6 +486,8 @@ void SelectMgr_SelectionManager::loadMode (const Handle(SelectMgr_SelectableObje
         theObject->AddSelection (aNewSel, theMode);
         aNewSel->UpdateBVHStatus (SelectMgr_TBU_Remove);
         aNewSel->SetSelectionState (SelectMgr_SOS_Deactivated);
+
+        buildBVH (aNewSel);
       }
     }
     return;
@@ -496,6 +500,37 @@ void SelectMgr_SelectionManager::loadMode (const Handle(SelectMgr_SelectableObje
     mySelector->AddSelectionToObject (theObject, aNewSel);
     aNewSel->UpdateBVHStatus (SelectMgr_TBU_None);
   }
+
+  buildBVH (aNewSel);
+}
+
+//==================================================
+// Function: buildBVH
+// Purpose : Private Method
+//==================================================
+void SelectMgr_SelectionManager::buildBVH (const Handle(SelectMgr_Selection)& theSelection)
+{
+  if (mySelector->ToPrebuildBVH())
+  {
+    for (NCollection_Vector<Handle(SelectMgr_SensitiveEntity)>::Iterator anIter (theSelection->Entities()); anIter.More(); anIter.Next())
+    {
+      const Handle(Select3D_SensitiveEntity)& anEntity = anIter.Value()->BaseSensitive();
+      mySelector->QueueBVHBuild (anEntity);
+
+      if (Handle(Select3D_SensitiveGroup) aGroup = Handle(Select3D_SensitiveGroup)::DownCast (anEntity))
+      {
+        for (Select3D_IndexedMapOfEntity::Iterator aSubEntitiesIter (aGroup->Entities()); aSubEntitiesIter.More(); aSubEntitiesIter.Next())
+        {
+          const Handle(Select3D_SensitiveEntity)& aSubEntity = aSubEntitiesIter.Value();
+          mySelector->QueueBVHBuild (aSubEntity);
+        }
+      }
+    }
+  }
+  else
+  {
+    StdSelect_BRepSelectionTool::PreBuildBVH (theSelection);
+  }
 }
 
 //=======================================================================
index 8962efa05bb57564fbaae0273552308c29aa1c7b..ecb1fc06f04d7cbd57c62d759ec7f0b069ecff30 100644 (file)
@@ -117,6 +117,10 @@ private:
   Standard_EXPORT void loadMode (const Handle(SelectMgr_SelectableObject)& theObject,
                                  const Standard_Integer theMode);
 
+  //! In multi-thread mode queues sensitive entities to build its BVH in separate threads.
+  //! Otherwise, builds BVH for heavyweight entities immediately.
+  Standard_EXPORT void buildBVH (const Handle(SelectMgr_Selection)& theSelection);
+
 private:
 
   Handle(SelectMgr_ViewerSelector)                    mySelector;
index da9b799587218f7087e223b8632c5f77e69512a3..9de41051feb64fd8f9b378c87de1765adf616701 100644 (file)
@@ -137,6 +137,7 @@ SelectMgr_ViewerSelector::SelectMgr_ViewerSelector():
 preferclosest(Standard_True),
 myToUpdateTolerance (Standard_True),
 myCameraScale (1.0),
+myToPrebuildBVH (Standard_False),
 myCurRank (0),
 myIsLeftChildQueuedFirst (Standard_False),
 myEntityIdx (0)
@@ -579,6 +580,8 @@ void SelectMgr_ViewerSelector::traverseObject (const Handle(SelectMgr_Selectable
 //=======================================================================
 void SelectMgr_ViewerSelector::TraverseSensitives()
 {
+  SelectMgr_BVHThreadPool::Sentry aSentry (myBVHThreadPool);
+
   mystored.Clear();
 
   Standard_Integer aWidth;
@@ -1122,3 +1125,44 @@ void SelectMgr_ViewerSelector::DumpJson (Standard_OStream& theOStream, Standard_
   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myEntityIdx)
   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMapOfObjectSensitives.Extent())
 }
+
+//=======================================================================
+//function : SetToPrebuildBVH
+//purpose  : 
+//=======================================================================
+void SelectMgr_ViewerSelector::SetToPrebuildBVH (Standard_Boolean theToPrebuild, Standard_Integer theThreadsNum)
+{
+  if (!theToPrebuild && !myBVHThreadPool.IsNull())
+  {
+    myBVHThreadPool.Nullify();
+  }
+  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->AddEntity (theEntity);
+  }
+}
+
+//=======================================================================
+//function : WaitForBVHBuild
+//purpose  : 
+//=======================================================================
+void SelectMgr_ViewerSelector::WaitForBVHBuild()
+{
+  if (myToPrebuildBVH)
+  {
+    myBVHThreadPool->WaitThreads();
+  }
+}
index 7652f2cf3411a39b450b77e1f08ba8d3343ad2ca..405e2adb13a3e856d0bda7c30e23569b59b24474 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;
@@ -260,6 +261,23 @@ 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);
+
+  //! Queues a sensitive entity to build its BVH
+  Standard_EXPORT void QueueBVHBuild(const Handle(Select3D_SensitiveEntity)& theEntity);
+
+  //! Waits BVH threads finished building
+  Standard_EXPORT void WaitForBVHBuild();
+
+  //! Returns TRUE if building BVH for sensitives in separate threads is enabled
+  Standard_Boolean ToPrebuildBVH() const
+  {
+    return myToPrebuildBVH;
+  }
+
 protected:
 
   Standard_EXPORT SelectMgr_ViewerSelector();
@@ -351,6 +369,9 @@ protected:
   gp_Dir                                        myCameraDir;
   Standard_Real                                 myCameraScale;
 
+  Standard_Boolean                              myToPrebuildBVH;
+  Handle(SelectMgr_BVHThreadPool)               myBVHThreadPool;
+
 private:
 
   Handle(TColStd_HArray1OfInteger)             myIndexes;
index accbbaee83ca5fcb028deaecbf2d09c15a328162..f945bda72f5a1aa78085bdbd87973de2f8210e65 100644 (file)
@@ -192,8 +192,6 @@ void StdSelect_BRepSelectionTool::Load (const Handle(SelectMgr_Selection)& theSe
     const Handle(SelectMgr_EntityOwner)& anOwner = aSelEntIter.Value()->BaseSensitive()->OwnerId();
     anOwner->SetSelectable (theSelectableObj);
   }
-
-  PreBuildBVH (theSelection);
 }
 
 //==================================================
index 7082f748dcc30a9f07d1aa4f319b4c283a0ea2f8..3b3692fbd3d4841b137dbca48f4599945d7f08cb 100644 (file)
@@ -59,6 +59,7 @@
 #include <NCollection_LocalArray.hxx>
 #include <NCollection_Vector.hxx>
 #include <OSD.hxx>
+#include <OSD_Parallel.hxx>
 #include <OSD_Timer.hxx>
 #include <OpenGl_GraphicDriver.hxx>
 #include <Prs3d_ShadingAspect.hxx>
@@ -13982,6 +13983,83 @@ static int VColorDiff (Draw_Interpretor& theDI, Standard_Integer  theNbArgs, con
   return 0;
 }
  
+//===============================================================================================
+//function : VBVHPrebuid
+//purpose  :
+//===============================================================================================
+static int VSelBvhBuild (Draw_Interpretor& /*theDI*/, Standard_Integer theNbArgs, const char** theArgVec)
+{
+  const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
+  if (aCtx.IsNull())
+  {
+    Message::SendFail ("Error: no active viewer");
+    return 1;
+  }
+
+  if (theNbArgs < 2)
+  {
+    Message::SendFail ("Error: command syntax is incorrect, see help");
+    return 1;
+  }
+
+  Standard_Integer toEnable = -1;
+  Standard_Integer aThreadsNb = -1;
+  Standard_Boolean toWait = Standard_False;
+
+  for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
+  {
+    TCollection_AsciiString anArg (theArgVec[anArgIter]);
+    anArg.LowerCase();
+
+    if (anArg == "-nbthreads"
+        && anArgIter + 1 < theNbArgs)
+    {
+      aThreadsNb = Draw::Atoi (theArgVec[++anArgIter]);
+      if (aThreadsNb < 1)
+      {
+        aThreadsNb = Max (1, OSD_Parallel::NbLogicalProcessors() - 1);
+      }
+    }
+    else if (anArg == "-wait")
+    {
+      toWait = Standard_True;
+    }
+    else if (toEnable == -1)
+    {
+      Standard_Boolean toEnableValue = Standard_True;
+      if (Draw::ParseOnOff (anArg.ToCString(), toEnableValue))
+      {
+        toEnable = toEnableValue ? 1 : 0;
+      }
+      else
+      {
+        Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
+        return 1;
+      }
+    }
+    else
+    {
+      Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
+      return 1;
+    }
+  }
+
+  if (aThreadsNb == -1)
+  {
+    aThreadsNb = 1;
+  }
+  if (toEnable != -1)
+  {
+    aCtx->MainSelector()->SetToPrebuildBVH (toEnable == 1, aThreadsNb);
+  }
+  if (toWait)
+  {
+    aCtx->MainSelector()->WaitForBVHBuild();
+  }
+
+  return 0;
+}
+
 //=======================================================================
 //function : ViewerCommands
 //purpose  :
@@ -14887,4 +14965,10 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
   theCommands.Add("vcolordiff" ,
                   "vcolordiff R1 G1 B1 R2 G2 B2: returns CIEDE2000 color difference between two RGB colors",
                   __FILE__,VColorDiff,group);
+  theCommands.Add("vselbvhbuild",
+                  "vselbvhbuild [{0|1}] [-nbThreads value] [-wait]"
+                  "\n\t\t: Turns on/off prebuilding of BVH within background thread(s)"
+                  "\n\t\t:   -nbThreads   number of threads, 1 by default; if < 1 then used (NbLogicalProcessors - 1)"
+                  "\n\t\t:   -wait        waits for building all of BVH",
+                  __FILE__,VSelBvhBuild,group);
 }
diff --git a/tests/v3d/mesh/C1 b/tests/v3d/mesh/C1
new file mode 100644 (file)
index 0000000..6e285ac
--- /dev/null
@@ -0,0 +1,14 @@
+puts "========"
+puts "OCC31757: Visualization - Prebuild BVH for Select3D_SensitiveEntity in separate threads"
+puts "========"
+
+vclear
+set aShape [locate_data_file occ/Motor-c.brep]
+restore $aShape s
+vdisplay s
+vfit
+vselbvhbuild 1 -nbThreads 1
+vselmode s FACE 1
+vselbvhbuild -wait
+vselect 0 0 512 512
+vdump $imagedir/${test_image}.png
\ No newline at end of file