mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-08-04 13:13:25 +03:00
0031757: Visualization - Prebuild BVH for Select3D_SensitiveEntity in separate threads
- 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.
This commit is contained in:
@@ -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
|
||||
|
180
src/SelectMgr/SelectMgr_BVHThreadPool.cxx
Normal file
180
src/SelectMgr/SelectMgr_BVHThreadPool.cxx
Normal file
@@ -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;
|
||||
}
|
165
src/SelectMgr/SelectMgr_BVHThreadPool.hxx
Normal file
165
src/SelectMgr/SelectMgr_BVHThreadPool.hxx
Normal file
@@ -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
|
@@ -16,8 +16,10 @@
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
|
@@ -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;
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user