diff --git a/src/AIS/AIS_ColoredShape.cxx b/src/AIS/AIS_ColoredShape.cxx index 19a62d355f..01b5cd779f 100644 --- a/src/AIS/AIS_ColoredShape.cxx +++ b/src/AIS/AIS_ColoredShape.cxx @@ -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); } //======================================================================= diff --git a/src/MeshVS/MeshVS_DummySensitiveEntity.hxx b/src/MeshVS/MeshVS_DummySensitiveEntity.hxx index 049e5f41bd..414b3728b8 100644 --- a/src/MeshVS/MeshVS_DummySensitiveEntity.hxx +++ b/src/MeshVS/MeshVS_DummySensitiveEntity.hxx @@ -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; diff --git a/src/MeshVS/MeshVS_Mesh.cxx b/src/MeshVS/MeshVS_Mesh.cxx index 51a5039158..5fff715710 100644 --- a/src/MeshVS/MeshVS_Mesh.cxx +++ b/src/MeshVS/MeshVS_Mesh.cxx @@ -652,8 +652,6 @@ void MeshVS_Mesh::ComputeSelection (const Handle(SelectMgr_Selection)& theSelect } } - StdSelect_BRepSelectionTool::PreBuildBVH (theSelection); - if (toShowComputeSelectionTime) { Standard_Real sec, cpu; diff --git a/src/Select3D/Select3D_SensitiveBox.hxx b/src/Select3D/Select3D_SensitiveBox.hxx index ac5264f25f..d10cd410c4 100644 --- a/src/Select3D/Select3D_SensitiveBox.hxx +++ b/src/Select3D/Select3D_SensitiveBox.hxx @@ -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; diff --git a/src/Select3D/Select3D_SensitiveCircle.cxx b/src/Select3D/Select3D_SensitiveCircle.cxx index 82bf115bde..0eea1fa5cc 100644 --- a/src/Select3D/Select3D_SensitiveCircle.cxx +++ b/src/Select3D/Select3D_SensitiveCircle.cxx @@ -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 diff --git a/src/Select3D/Select3D_SensitiveCircle.hxx b/src/Select3D/Select3D_SensitiveCircle.hxx index 57deeaf5fb..075c2658cf 100644 --- a/src/Select3D/Select3D_SensitiveCircle.hxx +++ b/src/Select3D/Select3D_SensitiveCircle.hxx @@ -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 diff --git a/src/Select3D/Select3D_SensitiveEntity.hxx b/src/Select3D/Select3D_SensitiveEntity.hxx index 19b039eafd..f99df8fcdb 100644 --- a/src/Select3D/Select3D_SensitiveEntity.hxx +++ b/src/Select3D/Select3D_SensitiveEntity.hxx @@ -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)()); } diff --git a/src/Select3D/Select3D_SensitiveFace.hxx b/src/Select3D/Select3D_SensitiveFace.hxx index b8d7ca5436..d8d7d95986 100644 --- a/src/Select3D/Select3D_SensitiveFace.hxx +++ b/src/Select3D/Select3D_SensitiveFace.hxx @@ -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; diff --git a/src/Select3D/Select3D_SensitivePoint.hxx b/src/Select3D/Select3D_SensitivePoint.hxx index f5332c8e04..983d8800b2 100644 --- a/src/Select3D/Select3D_SensitivePoint.hxx +++ b/src/Select3D/Select3D_SensitivePoint.hxx @@ -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; diff --git a/src/Select3D/Select3D_SensitiveSegment.hxx b/src/Select3D/Select3D_SensitiveSegment.hxx index abe00a3fa2..edf4890408 100644 --- a/src/Select3D/Select3D_SensitiveSegment.hxx +++ b/src/Select3D/Select3D_SensitiveSegment.hxx @@ -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; diff --git a/src/Select3D/Select3D_SensitiveSet.hxx b/src/Select3D/Select3D_SensitiveSet.hxx index be3ef600cf..60164f4396 100644 --- a/src/Select3D/Select3D_SensitiveSet.hxx +++ b/src/Select3D/Select3D_SensitiveSet.hxx @@ -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); } diff --git a/src/Select3D/Select3D_SensitiveTriangle.hxx b/src/Select3D/Select3D_SensitiveTriangle.hxx index 76c066d76b..8d605e1a62 100644 --- a/src/Select3D/Select3D_SensitiveTriangle.hxx +++ b/src/Select3D/Select3D_SensitiveTriangle.hxx @@ -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; } diff --git a/src/SelectMgr/FILES b/src/SelectMgr/FILES index 6166e38470..7e3351c4e1 100755 --- a/src/SelectMgr/FILES +++ b/src/SelectMgr/FILES @@ -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 index 0000000000..1be8be0826 --- /dev/null +++ b/src/SelectMgr/SelectMgr_BVHThreadPool.cxx @@ -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 +#include +#include +#include + +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(theTask); + aThread->performThread(); + return NULL; +} diff --git a/src/SelectMgr/SelectMgr_BVHThreadPool.hxx b/src/SelectMgr/SelectMgr_BVHThreadPool.hxx new file mode 100644 index 0000000000..84d8ab3765 --- /dev/null +++ b/src/SelectMgr/SelectMgr_BVHThreadPool.hxx @@ -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 +#include +#include +#include +#include +#include + +//! 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& 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 myBVHToBuildList; //!< list of queued sensitive entities + NCollection_Array1 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 diff --git a/src/SelectMgr/SelectMgr_SelectionManager.cxx b/src/SelectMgr/SelectMgr_SelectionManager.cxx index 195ed54c75..5de7197409 100644 --- a/src/SelectMgr/SelectMgr_SelectionManager.cxx +++ b/src/SelectMgr/SelectMgr_SelectionManager.cxx @@ -16,8 +16,10 @@ #include +#include #include #include +#include #include 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::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); + } } //======================================================================= diff --git a/src/SelectMgr/SelectMgr_SelectionManager.hxx b/src/SelectMgr/SelectMgr_SelectionManager.hxx index 8962efa05b..ecb1fc06f0 100644 --- a/src/SelectMgr/SelectMgr_SelectionManager.hxx +++ b/src/SelectMgr/SelectMgr_SelectionManager.hxx @@ -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; diff --git a/src/SelectMgr/SelectMgr_ViewerSelector.cxx b/src/SelectMgr/SelectMgr_ViewerSelector.cxx index da9b799587..9de41051fe 100644 --- a/src/SelectMgr/SelectMgr_ViewerSelector.cxx +++ b/src/SelectMgr/SelectMgr_ViewerSelector.cxx @@ -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(); + } +} diff --git a/src/SelectMgr/SelectMgr_ViewerSelector.hxx b/src/SelectMgr/SelectMgr_ViewerSelector.hxx index 7652f2cf34..405e2adb13 100644 --- a/src/SelectMgr/SelectMgr_ViewerSelector.hxx +++ b/src/SelectMgr/SelectMgr_ViewerSelector.hxx @@ -31,6 +31,7 @@ #include #include #include +#include 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; diff --git a/src/StdSelect/StdSelect_BRepSelectionTool.cxx b/src/StdSelect/StdSelect_BRepSelectionTool.cxx index accbbaee83..f945bda72f 100644 --- a/src/StdSelect/StdSelect_BRepSelectionTool.cxx +++ b/src/StdSelect/StdSelect_BRepSelectionTool.cxx @@ -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); } //================================================== diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index 7082f748dc..3b3692fbd3 100644 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -59,6 +59,7 @@ #include #include #include +#include #include #include #include @@ -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 index 0000000000..6e285accfb --- /dev/null +++ b/tests/v3d/mesh/C1 @@ -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