#include <algorithm>
-//! Stores parameters of single node bin (slice of AABB).
+//! Stores parameters of single bin (slice of AABB).
template<class T, int N>
struct BVH_Bin
{
BVH_Box<T, N> Box; //!< AABB of primitives in the bin
};
-//! Performs building of BVH tree using binned SAH algorithm.
-//! Number of Bins controls tree's quality (greater - better) in cost of construction time.
+//! Performs construction of BVH tree using binned SAH algorithm. Number
+//! of bins controls BVH quality in cost of construction time (greater -
+//! better). For optimal results, use 32 - 48 bins. However, reasonable
+//! performance is provided even for 4 - 8 bins (it is only 10-20% lower
+//! in comparison with optimal settings). Note that multiple threads can
+//! be used only with thread safe BVH primitive sets.
template<class T, int N, int Bins = 32>
class BVH_BinnedBuilder : public BVH_QueueBuilder<T, N>
{
//! Creates binned SAH BVH builder.
BVH_BinnedBuilder (const Standard_Integer theLeafNodeSize = 5,
const Standard_Integer theMaxTreeDepth = 32,
- const Standard_Boolean theToUseMainAxis = Standard_False);
+ const Standard_Boolean theDoMainSplits = 0,
+ const Standard_Integer theNumOfThreads = 1);
//! Releases resources of binned SAH BVH builder.
virtual ~BVH_BinnedBuilder();
protected:
- //! Builds BVH node for specified task info.
- virtual void BuildNode (BVH_Set<T, N>* theSet,
- BVH_Tree<T, N>* theBVH,
- const Standard_Integer theNode);
+ //! Performs splitting of the given BVH node.
+ typename BVH_QueueBuilder<T, N>::BVH_ChildNodes BuildNode (BVH_Set<T, N>* theSet,
+ BVH_Tree<T, N>* theBVH,
+ const Standard_Integer theNode);
//! Arranges node primitives into bins.
virtual void GetSubVolumes (BVH_Set<T, N>* theSet,
template<class T, int N, int Bins>
BVH_BinnedBuilder<T, N, Bins>::BVH_BinnedBuilder (const Standard_Integer theLeafNodeSize,
const Standard_Integer theMaxTreeDepth,
- const Standard_Boolean theToUseMainAxis)
+ const Standard_Boolean theDoMainSplits,
+ const Standard_Integer theNumOfThreads)
: BVH_QueueBuilder<T, N> (theLeafNodeSize,
- theMaxTreeDepth),
- myUseMainAxis (theToUseMainAxis)
+ theMaxTreeDepth,
+ theNumOfThreads),
+ myUseMainAxis (theDoMainSplits)
{
//
}
// purpose :
// =======================================================================
template<class T, int N, int Bins>
-void BVH_BinnedBuilder<T, N, Bins>::BuildNode (BVH_Set<T, N>* theSet,
- BVH_Tree<T, N>* theBVH,
- const Standard_Integer theNode)
+typename BVH_QueueBuilder<T, N>::BVH_ChildNodes BVH_BinnedBuilder<T, N, Bins>::BuildNode (BVH_Set<T, N>* theSet,
+ BVH_Tree<T, N>* theBVH,
+ const Standard_Integer theNode)
{
const Standard_Integer aNodeBegPrimitive = theBVH->BegPrimitive (theNode);
const Standard_Integer aNodeEndPrimitive = theBVH->EndPrimitive (theNode);
if (aNodeEndPrimitive - aNodeBegPrimitive < BVH_Builder<T, N>::myLeafNodeSize)
{
- return; // node does not require partitioning
+ return typename BVH_QueueBuilder<T, N>::BVH_ChildNodes(); // node does not require partitioning
}
const BVH_Box<T, N> anAABB (theBVH->MinPoint (theNode),
Standard_Real aMinSplitCost = std::numeric_limits<Standard_Real>::max();
- Standard_Integer aMainAxis = BVH::BVH_AxisSelector<T, N>::MainAxis (aSize);
+ const Standard_Integer aMainAxis = BVH::BVH_AxisSelector<T, N>::MainAxis (aSize);
// Find best split
for (Standard_Integer anAxis = myUseMainAxis ? aMainAxis : 0; anAxis <= (myUseMainAxis ? aMainAxis : Min (N - 1, 2)); ++anAxis)
}
else
{
- aMiddle = BVH::SplitPrimitives<T, N> (theSet, anAABB,
- aNodeBegPrimitive, aNodeEndPrimitive, aMinSplitIndex - 1, aMinSplitAxis, Bins);
+ aMiddle = BVH::SplitPrimitives<T, N> (theSet,
+ anAABB,
+ aNodeBegPrimitive,
+ aNodeEndPrimitive,
+ aMinSplitIndex - 1,
+ aMinSplitAxis,
+ Bins);
}
- static const Standard_Integer aLftNode = 1;
- static const Standard_Integer aRghNode = 2;
+ typedef typename BVH_QueueBuilder<T, N>::BVH_PrimitiveRange Range;
- // Setting up tasks for child nodes
- for (Standard_Integer aSide = aLftNode; aSide <= aRghNode; ++aSide)
- {
- typename BVH_Box<T, N>::BVH_VecNt aMinPoint = (aSide == aLftNode)
- ? aMinSplitBoxLft.CornerMin()
- : aMinSplitBoxRgh.CornerMin();
- typename BVH_Box<T, N>::BVH_VecNt aMaxPoint = (aSide == aLftNode)
- ? aMinSplitBoxLft.CornerMax()
- : aMinSplitBoxRgh.CornerMax();
-
- Standard_Integer aBegPrimitive = (aSide == aLftNode)
- ? aNodeBegPrimitive
- : aMiddle;
- Standard_Integer aEndPrimitive = (aSide == aLftNode)
- ? aMiddle - 1
- : aNodeEndPrimitive;
-
- Standard_Integer aChildIndex = theBVH->AddLeafNode (aMinPoint, aMaxPoint, aBegPrimitive, aEndPrimitive);
-
- theBVH->Level (aChildIndex) = theBVH->Level (theNode) + 1;
-
- // Check to see if child node must be split
- const Standard_Integer aNbPimitives = (aSide == aLftNode)
- ? aMinSplitNumLft
- : aMinSplitNumRgh;
-
- if (aSide == aLftNode)
- theBVH->LeftChild (theNode) = aChildIndex;
- else
- theBVH->RightChild (theNode) = aChildIndex;
-
- const Standard_Boolean isLeaf = aNbPimitives <= BVH_Builder<T, N>::myLeafNodeSize
- || theBVH->Level (aChildIndex) >= BVH_Builder<T, N>::myMaxTreeDepth;
-
- if (!isLeaf)
- {
- BVH_QueueBuilder<T, N>::myTasksQueue.Append (aChildIndex);
- }
-
- BVH_Builder<T, N>::UpdateDepth (theBVH, theBVH->Level (aChildIndex));
- }
+ return typename BVH_QueueBuilder<T, N>::BVH_ChildNodes (aMinSplitBoxLft,
+ aMinSplitBoxRgh,
+ Range (aNodeBegPrimitive, aMiddle - 1),
+ Range (aMiddle, aNodeEndPrimitive));
}
--- /dev/null
+// Created on: 2015-05-27
+// Created by: Denis BOGOLEPOV
+// Copyright (c) 2015 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 <BVH_BuildQueue.hxx>
+
+// =======================================================================
+// function : Size
+// purpose : Returns current size of BVH build queue
+// =======================================================================
+Standard_Integer BVH_BuildQueue::Size()
+{
+ Standard_Integer aSize;
+
+ myMutex.Lock();
+ {
+ aSize = myQueue.Size();
+ }
+ myMutex.Unlock();
+
+ return aSize;
+}
+
+// =======================================================================
+// function : Enqueue
+// purpose : Enqueues new work-item onto BVH build queue
+// =======================================================================
+void BVH_BuildQueue::Enqueue (const Standard_Integer& theWorkItem)
+{
+ myMutex.Lock();
+ {
+ myQueue.Append (theWorkItem);
+ }
+ myMutex.Unlock();
+}
+
+// =======================================================================
+// function : Fetch
+// purpose : Fetches first work-item from BVH build queue
+// =======================================================================
+Standard_Integer BVH_BuildQueue::Fetch (Standard_Boolean& wasBusy)
+{
+ Standard_Integer aQuery = -1;
+ {
+ Standard_Mutex::Sentry aSentry (myMutex);
+
+ if (!myQueue.IsEmpty())
+ {
+ aQuery = myQueue.First();
+
+ myQueue.Remove (1); // remove item from queue
+ }
+
+ if (aQuery != -1)
+ {
+ if (!wasBusy)
+ {
+ ++myNbThreads;
+ }
+ }
+ else if (wasBusy)
+ {
+ --myNbThreads;
+ }
+
+ wasBusy = aQuery != -1;
+ }
+
+ return aQuery;
+}
--- /dev/null
+// Created on: 2015-05-28
+// Created by: Denis BOGOLEPOV
+// Copyright (c) 2015 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 _BVH_BuildQueue_Header
+#define _BVH_BuildQueue_Header
+
+#include <BVH_Builder.hxx>
+
+#include <Standard_Mutex.hxx>
+#include <NCollection_Sequence.hxx>
+
+//! Command-queue for parallel building of BVH nodes.
+class BVH_BuildQueue
+{
+ template <class T, int N> friend class BVH_QueueBuilder;
+
+public:
+
+ //! Creates new BVH build queue.
+ BVH_BuildQueue()
+ : myNbThreads (0)
+ {
+ //
+ }
+
+ //! Releases resources of BVH build queue.
+ ~BVH_BuildQueue()
+ {
+ //
+ }
+
+public:
+
+ //! Returns current size of BVH build queue.
+ Standard_EXPORT Standard_Integer Size();
+
+ //! Enqueues new work-item onto BVH build queue.
+ Standard_EXPORT void Enqueue (const Standard_Integer& theNode);
+
+ //! Fetches first work-item from BVH build queue.
+ Standard_EXPORT Standard_Integer Fetch (Standard_Boolean& wasBusy);
+
+ //! Checks if there are active build threads.
+ Standard_Boolean HasBusyThreads()
+ {
+ return myNbThreads != 0;
+ }
+
+protected:
+
+ //! Queue of BVH nodes to build.
+ NCollection_Sequence<Standard_Integer> myQueue;
+
+protected:
+
+ //! Manages access serialization of working threads.
+ Standard_Mutex myMutex;
+
+ //! Number of active build threads.
+ Standard_Integer myNbThreads;
+};
+
+#endif // _BVH_BuildQueue_Header
--- /dev/null
+// Created on: 2015-05-29
+// Created by: Denis BOGOLEPOV
+// Copyright (c) 2013-2014 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 <BVH_BuildThread.hxx>
+
+// =======================================================================
+// function : BVH_BuildThread
+// purpose : Creates new BVH build thread
+// =======================================================================
+BVH_BuildThread::BVH_BuildThread (BVH_BuildTool& theBuildTool,
+ BVH_BuildQueue& theBuildQueue)
+: myBuildTool (theBuildTool),
+ myBuildQueue (theBuildQueue),
+ myWorkThread (threadFunction)
+{
+ //
+}
+
+// =======================================================================
+// function : execute
+// purpose : Executes BVH build thread
+// =======================================================================
+void BVH_BuildThread::execute()
+{
+ for (Standard_Boolean wasBusy = Standard_False; /**/; /**/)
+ {
+ const Standard_Integer aNode = myBuildQueue.Fetch (wasBusy);
+
+ if (aNode == -1) // queue is empty
+ {
+ if (!myBuildQueue.HasBusyThreads())
+ {
+ break; // no active threads
+ }
+ }
+ else
+ {
+ myBuildTool.Perform (aNode);
+ }
+ }
+}
+
+// =======================================================================
+// function : threadFunction
+// purpose : Thread function for BVH build thread
+// =======================================================================
+Standard_Address BVH_BuildThread::threadFunction (Standard_Address theData)
+{
+ static_cast<BVH_BuildThread*> (theData)->execute();
+
+ return NULL;
+}
--- /dev/null
+// Created on: 2015-05-29
+// Created by: Denis BOGOLEPOV
+// Copyright (c) 2013-2014 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 _BVH_BuildThread_Header
+#define _BVH_BuildThread_Header
+
+#include <OSD_Thread.hxx>
+#include <BVH_BuildQueue.hxx>
+
+//! Tool object to call BVH builder subroutines.
+struct BVH_BuildTool
+{
+ //! Performs splitting of the given BVH node.
+ virtual void Perform (const Standard_Integer theNode) = 0;
+};
+
+//! Wrapper for BVH build thread.
+class BVH_BuildThread : public Standard_Transient
+{
+ template <class T, int N> friend class BVH_QueueBuilder;
+
+public:
+
+ //! Creates new BVH build thread.
+ Standard_EXPORT BVH_BuildThread (BVH_BuildTool& theBuildTool, BVH_BuildQueue& theBuildQueue);
+
+ //! Starts execution of BVH build thread.
+ void Run()
+ {
+ myWorkThread.Run (this);
+ }
+
+ //! Waits till the thread finishes execution.
+ void Wait()
+ {
+ myWorkThread.Wait();
+ }
+
+protected:
+
+ //! Executes BVH build thread.
+ Standard_EXPORT void execute();
+
+ //! Thread function for BVH build thread.
+ static Standard_Address threadFunction (Standard_Address theData);
+
+ //! Assignment operator (to remove VC compile warning).
+ BVH_BuildThread& operator= (const BVH_BuildThread&);
+
+protected:
+
+ //! Data needed to build the BVH.
+ BVH_BuildTool& myBuildTool;
+
+ //! Reference to BVH build queue.
+ BVH_BuildQueue& myBuildQueue;
+
+ //! Thread to execute work items.
+ OSD_Thread myWorkThread;
+
+public:
+
+ DEFINE_STANDARD_RTTI(BVH_BuildThread, Standard_Transient)
+};
+
+DEFINE_STANDARD_HANDLE (BVH_BuildThread, Standard_Transient)
+
+#endif // _BVH_BuildThread_Header
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
-#include <Standard_Assert.hxx>
-
#include <BVH_Triangulation.hxx>
#ifdef HAVE_TBB
#define _BVH_QueueBuilder_Header
#include <BVH_Builder.hxx>
-
+#include <BVH_BuildThread.hxx>
#include <NCollection_Vector.hxx>
//! Abstract BVH builder based on the concept of work queue.
+//! Queue based BVH builders support parallelization with a
+//! fixed number of threads (maximum efficiency is achieved
+//! by setting the number of threads equal to the number of
+//! CPU cores plus one). Note that to support parallel mode,
+//! a corresponding BVH primitive set should provide thread
+//! safe implementations of interface functions (e.g., Swap,
+//! Box, Center). Otherwise, the results will be undefined.
+//! \tparam T Numeric data type
+//! \tparam N Vector dimension
template<class T, int N>
class BVH_QueueBuilder : public BVH_Builder<T, N>
{
//! Creates new BVH queue based builder.
BVH_QueueBuilder (const Standard_Integer theLeafNodeSize,
- const Standard_Integer theMaxTreeDepth);
+ const Standard_Integer theMaxTreeDepth,
+ const Standard_Integer theNumOfThreads = 1);
//! Releases resources of BVH queue based builder.
virtual ~BVH_QueueBuilder() = 0;
protected:
- //! Builds BVH node for the given task info.
- virtual void BuildNode (BVH_Set<T, N>* theSet,
- BVH_Tree<T, N>* theBVH,
- const Standard_Integer theTask);
+ //! Stores range of primitives belonging to a BVH node.
+ struct BVH_PrimitiveRange
+ {
+ Standard_Integer Start;
+ Standard_Integer Final;
+
+ //! Creates new primitive range.
+ BVH_PrimitiveRange (Standard_Integer theStart = -1,
+ Standard_Integer theFinal = -1)
+ : Start (theStart),
+ Final (theFinal)
+ {
+ //
+ }
+
+ //! Returns total number of primitives.
+ Standard_Integer Size() const
+ {
+ return Final - Start + 1;
+ }
+
+ //! Checks if the range is initialized.
+ Standard_Boolean IsValid() const
+ {
+ return Start != -1;
+ }
+ };
+
+ //! Stores parameters of constructed child nodes.
+ struct BVH_ChildNodes
+ {
+ //! Bounding boxes of child nodes.
+ BVH_Box<T, N> Boxes[2];
+
+ //! Primitive ranges of child nodes.
+ BVH_PrimitiveRange Ranges[2];
+
+ //! Creates new parameters of BVH child nodes.
+ BVH_ChildNodes()
+ {
+ //
+ }
+
+ //! Creates new parameters of BVH child nodes.
+ BVH_ChildNodes (const BVH_Box<T, N>& theLftBox,
+ const BVH_Box<T, N>& theRghBox,
+ const BVH_PrimitiveRange& theLftRange,
+ const BVH_PrimitiveRange& theRghRange)
+ {
+ Boxes[0] = theLftBox;
+ Boxes[1] = theRghBox;
+ Ranges[0] = theLftRange;
+ Ranges[1] = theRghRange;
+ }
+
+ //! Returns number of primitives in the given child.
+ Standard_Integer NbPrims (const Standard_Integer theChild) const
+ {
+ return Ranges[theChild].Size();
+ }
+
+ //! Checks if the parameters is initialized.
+ Standard_Boolean IsValid() const
+ {
+ return Ranges[0].IsValid() && Ranges[1].IsValid();
+ }
+ };
+
+ //! Wrapper for BVH build data.
+ class BVH_TypedBuildTool : public BVH_BuildTool
+ {
+ public:
+
+ //! Creates new BVH build thread.
+ BVH_TypedBuildTool (BVH_Set<T, N>* theSet,
+ BVH_Tree<T, N>* theBVH,
+ BVH_Builder<T, N>* theAlgo)
+ : mySet (theSet),
+ myBVH (theBVH)
+ {
+ myAlgo = dynamic_cast<BVH_QueueBuilder<T, N>* > (theAlgo);
+
+ Standard_ASSERT_RAISE (myAlgo != NULL,
+ "Error! BVH builder should be queue based");
+ }
+
+ //! Performs splitting of the given BVH node.
+ virtual void Perform (const Standard_Integer theNode)
+ {
+ const typename BVH_QueueBuilder<T, N>::BVH_ChildNodes aChildren = myAlgo->BuildNode (mySet, myBVH, theNode);
+
+ myAlgo->AddChildren (myBVH, theNode, aChildren);
+ }
+
+ protected:
+
+ //! Primitive set to build BVH.
+ BVH_Set<T, N>* mySet;
+
+ //! Output BVH tree for the set.
+ BVH_Tree<T, N>* myBVH;
+
+ //! Queue based BVH builder to use.
+ BVH_QueueBuilder<T, N>* myAlgo;
+ };
+
+protected:
+
+ //! Performs splitting of the given BVH node.
+ virtual typename BVH_QueueBuilder<T, N>::BVH_ChildNodes BuildNode (BVH_Set<T, N>* theSet,
+ BVH_Tree<T, N>* theBVH,
+ const Standard_Integer theNode) = 0;
+
+ //! Processes child nodes of the splitted BVH node.
+ virtual void AddChildren (BVH_Tree<T, N>* theBVH,
+ const Standard_Integer theNode,
+ const BVH_ChildNodes& theSubNodes);
protected:
- NCollection_Vector<Standard_Integer> myTasksQueue; //!< Queue to manage BVH node building tasks
+ BVH_BuildQueue myBuildQueue; //!< Queue to manage BVH node building tasks
+
+ Standard_Integer myNumOfThreads; //!< Number of threads used to build BVH
};
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
+#include <NCollection_Vector.hxx>
+
// =======================================================================
// function : BVH_QueueBuilder
// purpose : Creates new BVH queue based builder
// =======================================================================
template<class T, int N>
BVH_QueueBuilder<T, N>::BVH_QueueBuilder (const Standard_Integer theLeafNodeSize,
- const Standard_Integer theMaxTreeDepth)
+ const Standard_Integer theMaxTreeDepth,
+ const Standard_Integer theNumOfThreads)
: BVH_Builder<T, N> (theLeafNodeSize,
- theMaxTreeDepth)
+ theMaxTreeDepth),
+ myNumOfThreads (theNumOfThreads)
{
//
}
//
}
+// =======================================================================
+// function : AddChildren
+// purpose :
+// =======================================================================
+template<class T, int N>
+void BVH_QueueBuilder<T, N>::AddChildren (BVH_Tree<T, N>* theBVH,
+ const Standard_Integer theNode,
+ const typename BVH_QueueBuilder<T, N>::BVH_ChildNodes& theSubNodes)
+{
+ Standard_Integer aChildren[] = { -1, -1 };
+
+ if (!theSubNodes.IsValid())
+ {
+ return;
+ }
+
+ // Add child nodes
+ {
+ Standard_Mutex::Sentry aSentry (myBuildQueue.myMutex);
+
+ for (Standard_Integer anIdx = 0; anIdx < 2; ++anIdx)
+ {
+ aChildren[anIdx] = theBVH->AddLeafNode (theSubNodes.Boxes[anIdx],
+ theSubNodes.Ranges[anIdx].Start,
+ theSubNodes.Ranges[anIdx].Final);
+ }
+
+ BVH_Builder<T, N>::UpdateDepth (theBVH, theBVH->Level (theNode) + 1);
+ }
+
+ // Set parameters of child nodes and generate new tasks
+ for (Standard_Integer anIdx = 0; anIdx < 2; ++anIdx)
+ {
+ const Standard_Integer aChildIndex = aChildren[anIdx];
+
+ theBVH->Level (aChildIndex) = theBVH->Level (theNode) + 1;
+
+ (anIdx == 0 ? theBVH->LeftChild (theNode) : theBVH->RightChild (theNode)) = aChildIndex;
+
+ // Check to see if the child node must be split
+ const Standard_Boolean isLeaf = theSubNodes.NbPrims (anIdx) <= BVH_Builder<T, N>::myLeafNodeSize
+ || theBVH->Level (aChildIndex) >= BVH_Builder<T, N>::myMaxTreeDepth;
+
+ if (!isLeaf)
+ {
+ myBuildQueue.Enqueue (aChildIndex);
+ }
+ }
+}
+
// =======================================================================
// function : Build
// purpose : Builds BVH using specific algorithm
BVH_Tree<T, N>* theBVH,
const BVH_Box<T, N>& theBox)
{
- if (theBVH == NULL)
- {
- return;
- }
+ Standard_ASSERT_RETURN (theBVH != NULL,
+ "Error! BVH tree to construct is NULL", );
theBVH->Clear();
if (theSet->Size() == 0)
return;
}
- myTasksQueue.Append (aRoot);
- for (Standard_Integer aTask = 0; aTask < myTasksQueue.Size(); ++aTask)
+ myBuildQueue.Enqueue (aRoot);
+
+ BVH_TypedBuildTool aBuildTool (theSet, theBVH, this);
+
+ if (myNumOfThreads > 1)
{
- BuildNode (theSet, theBVH, myTasksQueue.Value (aTask));
- }
+ // Reserve the maximum possible number of nodes in the BVH
+ theBVH->Reserve (2 * theSet->Size() - 1);
- myTasksQueue.Clear();
-}
+ NCollection_Vector<Handle(BVH_BuildThread)> aThreads;
-// =======================================================================
-// function : BuildNode
-// purpose : Builds BVH node for the given task info
-// =======================================================================
-template<class T, int N>
-void BVH_QueueBuilder<T, N>::BuildNode (BVH_Set<T, N>* /* theSet */,
- BVH_Tree<T, N>* /* theBVH */,
- const Standard_Integer /* theTask */)
-{
- // needed to disable compile warnings
+ // Run BVH build threads
+ for (Standard_Integer aThreadIndex = 0; aThreadIndex < myNumOfThreads; ++aThreadIndex)
+ {
+ aThreads.Append (new BVH_BuildThread (aBuildTool, myBuildQueue));
+ aThreads.Last()->Run();
+ }
+
+ // Wait until all threads finish their work
+ for (Standard_Integer aThreadIndex = 0; aThreadIndex < myNumOfThreads; ++aThreadIndex)
+ {
+ aThreads.ChangeValue (aThreadIndex)->Wait();
+ }
+
+ // Free unused memory
+ theBVH->Reserve (theBVH->Length());
+ }
+ else
+ {
+ BVH_BuildThread aThread (aBuildTool, myBuildQueue);
+
+ // Execute thread function inside current thread
+ aThread.execute();
+ }
}
//! Creates sweep plane SAH BVH builder.
BVH_SweepPlaneBuilder (const Standard_Integer theLeafNodeSize = 5,
- const Standard_Integer theMaxTreeDepth = 32);
+ const Standard_Integer theMaxTreeDepth = 32,
+ const Standard_Integer theNumOfThreads = 1);
//! Releases resources of sweep plane SAH BVH builder.
virtual ~BVH_SweepPlaneBuilder();
protected:
- //! Builds specified BVH node.
- virtual void BuildNode (BVH_Set<T, N>* theSet,
- BVH_Tree<T, N>* theBVH,
- const Standard_Integer theNode);
+ //! Performs splitting of the given BVH node.
+ typename BVH_QueueBuilder<T, N>::BVH_ChildNodes BuildNode (BVH_Set<T, N>* theSet,
+ BVH_Tree<T, N>* theBVH,
+ const Standard_Integer theNode);
};
// =======================================================================
template<class T, int N>
BVH_SweepPlaneBuilder<T, N>::BVH_SweepPlaneBuilder (const Standard_Integer theLeafNodeSize,
- const Standard_Integer theMaxTreeDepth)
+ const Standard_Integer theMaxTreeDepth,
+ const Standard_Integer theNumOfThreads)
: BVH_QueueBuilder<T, N> (theLeafNodeSize,
- theMaxTreeDepth)
+ theMaxTreeDepth,
+ theNumOfThreads)
{
//
}
// purpose :
// =======================================================================
template<class T, int N>
-void BVH_SweepPlaneBuilder<T, N>::BuildNode (BVH_Set<T, N>* theSet,
- BVH_Tree<T, N>* theBVH,
- const Standard_Integer theNode)
+typename BVH_QueueBuilder<T, N>::BVH_ChildNodes BVH_SweepPlaneBuilder<T, N>::BuildNode (BVH_Set<T, N>* theSet,
+ BVH_Tree<T, N>* theBVH,
+ const Standard_Integer theNode)
{
const Standard_Integer aNodeBegPrimitive = theBVH->BegPrimitive (theNode);
const Standard_Integer aNodeEndPrimitive = theBVH->EndPrimitive (theNode);
if (aNodeEndPrimitive - aNodeBegPrimitive < BVH_Builder<T, N>::myLeafNodeSize)
{
- return; // node does not require partitioning
+ return typename BVH_QueueBuilder<T, N>::BVH_ChildNodes(); // node does not require partitioning
}
// Parameters for storing best split
if (aMinSplitAxis == -1)
{
- return;
+ return typename BVH_QueueBuilder<T, N>::BVH_ChildNodes(); // failed to find split axis
}
theBVH->SetInner (theNode);
const Standard_Integer aMiddle = aNodeBegPrimitive + aMinSplitIndex;
- static const Standard_Integer aLftNode = 1;
- static const Standard_Integer aRghNode = 2;
+ typedef typename BVH_QueueBuilder<T, N>::BVH_PrimitiveRange Range;
- // Setting up tasks for child nodes
- for (Standard_Integer aSide = aLftNode; aSide <= aRghNode; ++aSide)
- {
- typename BVH_Box<T, N>::BVH_VecNt aChildMinPoint = (aSide == aLftNode)
- ? aMinSplitBoxLft.CornerMin()
- : aMinSplitBoxRgh.CornerMin();
- typename BVH_Box<T, N>::BVH_VecNt aChildMaxPoint = (aSide == aLftNode)
- ? aMinSplitBoxLft.CornerMax()
- : aMinSplitBoxRgh.CornerMax();
-
- Standard_Integer aChildBegPrimitive = (aSide == aLftNode)
- ? aNodeBegPrimitive
- : aMiddle;
- Standard_Integer aChildEndPrimitive = (aSide == aLftNode)
- ? aMiddle - 1
- : aNodeEndPrimitive;
-
- Standard_Integer aChildIndex = theBVH->AddLeafNode (aChildMinPoint, aChildMaxPoint,
- aChildBegPrimitive, aChildEndPrimitive);
-
- theBVH->Level (aChildIndex) = theBVH->Level (theNode) + 1;
-
- // Check to see if child node must be split
- const Standard_Integer aChildNbPimitives = (aSide == aLftNode)
- ? aMiddle - aNodeBegPrimitive
- : aNodeEndPrimitive - aMiddle + 1;
-
- if (aSide == aLftNode)
- theBVH->LeftChild (theNode) = aChildIndex;
- else
- theBVH->RightChild (theNode) = aChildIndex;
-
- const Standard_Boolean isLeaf = aChildNbPimitives <= BVH_Builder<T, N>::myLeafNodeSize
- || theBVH->Level (aChildIndex) >= BVH_Builder<T, N>::myMaxTreeDepth;
-
- if (!isLeaf)
- {
- BVH_QueueBuilder<T, N>::myTasksQueue.Append (aChildIndex);
- }
-
- BVH_Builder<T, N>::UpdateDepth (theBVH, theBVH->Level (aChildIndex));
- }
+ return typename BVH_QueueBuilder<T, N>::BVH_ChildNodes (aMinSplitBoxLft,
+ aMinSplitBoxRgh,
+ Range (aNodeBegPrimitive, aMiddle - 1),
+ Range (aMiddle, aNodeEndPrimitive));
}
//
}
+ //! Reserves internal BVH storage, so that it
+ //! can contain specified number of tree nodes.
+ void Reserve (const Standard_Integer theNbNodes);
+
//! Returns minimum point of the given node.
BVH_VecNt& MinPoint (const Standard_Integer theNodeIndex)
{
//! Array of node data records.
BVH_Array4i myNodeInfoBuffer;
- //! Depth of constructed tree.
+ //! Current depth of BVH tree.
Standard_Integer myDepth;
};
const Standard_Integer theBegElem,
const Standard_Integer theEndElem)
{
- return AddLeafNode (theAABB.CornerMin(), theAABB.CornerMax(), theBegElem, theEndElem);
+ return AddLeafNode (theAABB.CornerMin(),
+ theAABB.CornerMax(),
+ theBegElem,
+ theEndElem);
}
// =======================================================================
const Standard_Integer theLftChild,
const Standard_Integer theRghChild)
{
- return AddInnerNode (theAABB.CornerMin(), theAABB.CornerMax(), theLftChild, theRghChild);
+ return AddInnerNode (theAABB.CornerMin(),
+ theAABB.CornerMax(),
+ theLftChild,
+ theRghChild);
}
namespace BVH
BVH::EstimateSAH (this, 0, static_cast<T> (1.0), aSAH);
return aSAH;
}
+
+// =======================================================================
+// function : Reserve
+// purpose :
+// =======================================================================
+template<class T, int N>
+void BVH_Tree<T, N>::Reserve (const Standard_Integer theNbNodes)
+{
+ BVH::Array<T, N>::Reserve (myMinPointBuffer, theNbNodes);
+ BVH::Array<T, N>::Reserve (myMaxPointBuffer, theNbNodes);
+ BVH::Array<Standard_Integer, 4>::Reserve (myNodeInfoBuffer, theNbNodes);
+}
#include <NCollection_Vec3.hxx>
#include <NCollection_Vector.hxx>
+// GCC supports shrink function only in C++11 mode
+#if defined(_BVH_USE_STD_VECTOR_) && defined(_MSC_VER) && !defined(__INTEL_COMPILER)
+ #define _STD_VECTOR_SHRINK
+#endif
+
namespace BVH
{
//! Tool class for selecting appropriate vector type (Eigen or NCollection).
{
typedef typename BVH::ArrayType<T, N>::Type BVH_ArrayNt;
+ //! Returns a const reference to the element with the given index.
static inline const typename BVH::VectorType<T, N>::Type& Value (
const BVH_ArrayNt& theArray, const Standard_Integer theIndex)
{
#endif
}
+ //! Returns a reference to the element with the given index.
static inline typename BVH::VectorType<T, N>::Type& ChangeValue (
BVH_ArrayNt& theArray, const Standard_Integer theIndex)
{
#endif
}
+ //! Adds the new element at the end of the array.
static inline void Append (BVH_ArrayNt& theArray,
const typename BVH::VectorType<T, N>::Type& theElement)
{
#endif
}
+ //! Returns the number of elements in the given array.
static inline Standard_Integer Size (const BVH_ArrayNt& theArray)
{
#ifdef _BVH_USE_STD_VECTOR_
#endif
}
+ //! Removes all elements from the given array.
static inline void Clear (BVH_ArrayNt& theArray)
{
#ifdef _BVH_USE_STD_VECTOR_
theArray.clear();
#else
theArray.Clear();
+#endif
+ }
+
+ //! Requests that the array capacity be at least enough to
+ //! contain given number of elements. This function has no
+ //! effect in case of NCollection based array.
+ static inline void Reserve (BVH_ArrayNt& theArray, const Standard_Integer theCount)
+ {
+#ifdef _BVH_USE_STD_VECTOR_
+ if (Size (theArray) == theCount)
+ {
+#ifdef _STD_VECTOR_SHRINK
+ theArray.shrink_to_fit();
+#endif
+ }
+ else
+ {
+ theArray.reserve (theCount);
+ }
+#else
+ // do nothing
#endif
}
};
BVH_Box.lxx
BVH_Builder.hxx
BVH_Builder.lxx
+BVH_BuildQueue.hxx
+BVH_BuildQueue.cxx
+BVH_BuildThread.hxx
+BVH_BuildThread.cxx
BVH_DistanceField.hxx
BVH_DistanceField.lxx
BVH_Geometry.hxx
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
-#include <Standard_Assert.hxx>
+#include <OSD_Timer.hxx>
#include <OSD_Parallel.hxx>
-
-#include <OpenGl_SceneGeometry.hxx>
-
+#include <Standard_Assert.hxx>
#include <OpenGl_ArbTexBindless.hxx>
#include <OpenGl_PrimitiveArray.hxx>
+#include <OpenGl_SceneGeometry.hxx>
#include <OpenGl_Structure.hxx>
-#include <OSD_Timer.hxx>
-#include <Standard_Assert.hxx>
#include <Graphic3d_GraphicDriver.hxx>
//! Use this macro to output BVH profiling info
return aBox;
}
+// =======================================================================
+// function : OpenGl_TriangleSet
+// purpose : Creates new OpenGL element triangulation
+// =======================================================================
+OpenGl_TriangleSet::OpenGl_TriangleSet (const Standard_Size theArrayID)
+: BVH_Triangulation<Standard_ShortReal, 3>(),
+ myArrayID (theArrayID)
+{
+ myBuilder = new BVH_BinnedBuilder<Standard_ShortReal, 3 /* dim */, 48 /* bins */>
+ (5 /* leaf size */, 32 /* max height */, Standard_False, OSD_Parallel::NbLogicalProcessors() + 1 /* threads */);
+}
+
// =======================================================================
// function : Clear
// purpose : Clears ray-tracing geometry
BVH_ObjectSet<Standard_ShortReal, 3>* Set;
OpenGL_BVHParallelBuilder (BVH_ObjectSet<Standard_ShortReal, 3>* theSet)
- : Set (theSet)
+ : Set (theSet)
{
//
}
#include <BVH_Geometry.hxx>
#include <BVH_Triangulation.hxx>
+#include <BVH_BinnedBuilder.hxx>
#include <NCollection_StdAllocator.hxx>
#include <OpenGl_TextureBufferArb.hxx>
#include <OpenGl_Texture.hxx>
public:
//! Creates new OpenGL element triangulation.
- OpenGl_TriangleSet (const Standard_Size theArrayID)
- : BVH_Triangulation<Standard_ShortReal, 3>(),
- myArrayID (theArrayID)
- {
- //
- }
+ OpenGl_TriangleSet (const Standard_Size theArrayID);
//! Releases resources of OpenGL element triangulation.
~OpenGl_TriangleSet()