1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-06 18:26:22 +03:00

0026292: Visualization - Parallelize queue-based BVH builders (subclasses of BVH_QueueBuilder)

This commit is contained in:
dbp 2015-07-17 14:29:50 +03:00 committed by bugmaster
parent cf8096eccb
commit 65578e1c7c
17 changed files with 654 additions and 164 deletions

View File

@ -20,7 +20,7 @@
#include <algorithm> #include <algorithm>
//! Stores parameters of single node bin (slice of AABB). //! Stores parameters of single bin (slice of AABB).
template<class T, int N> template<class T, int N>
struct BVH_Bin struct BVH_Bin
{ {
@ -31,8 +31,12 @@ struct BVH_Bin
BVH_Box<T, N> Box; //!< AABB of primitives in the bin BVH_Box<T, N> Box; //!< AABB of primitives in the bin
}; };
//! Performs building of BVH tree using binned SAH algorithm. //! Performs construction of BVH tree using binned SAH algorithm. Number
//! Number of Bins controls tree's quality (greater - better) in cost of construction time. //! 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> template<class T, int N, int Bins = 32>
class BVH_BinnedBuilder : public BVH_QueueBuilder<T, N> class BVH_BinnedBuilder : public BVH_QueueBuilder<T, N>
{ {
@ -46,15 +50,16 @@ public:
//! Creates binned SAH BVH builder. //! Creates binned SAH BVH builder.
BVH_BinnedBuilder (const Standard_Integer theLeafNodeSize = 5, BVH_BinnedBuilder (const Standard_Integer theLeafNodeSize = 5,
const Standard_Integer theMaxTreeDepth = 32, 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. //! Releases resources of binned SAH BVH builder.
virtual ~BVH_BinnedBuilder(); virtual ~BVH_BinnedBuilder();
protected: protected:
//! Builds BVH node for specified task info. //! Performs splitting of the given BVH node.
virtual void BuildNode (BVH_Set<T, N>* theSet, typename BVH_QueueBuilder<T, N>::BVH_ChildNodes BuildNode (BVH_Set<T, N>* theSet,
BVH_Tree<T, N>* theBVH, BVH_Tree<T, N>* theBVH,
const Standard_Integer theNode); const Standard_Integer theNode);

View File

@ -20,10 +20,12 @@
template<class T, int N, int Bins> template<class T, int N, int Bins>
BVH_BinnedBuilder<T, N, Bins>::BVH_BinnedBuilder (const Standard_Integer theLeafNodeSize, BVH_BinnedBuilder<T, N, Bins>::BVH_BinnedBuilder (const Standard_Integer theLeafNodeSize,
const Standard_Integer theMaxTreeDepth, const Standard_Integer theMaxTreeDepth,
const Standard_Boolean theToUseMainAxis) const Standard_Boolean theDoMainSplits,
const Standard_Integer theNumOfThreads)
: BVH_QueueBuilder<T, N> (theLeafNodeSize, : BVH_QueueBuilder<T, N> (theLeafNodeSize,
theMaxTreeDepth), theMaxTreeDepth,
myUseMainAxis (theToUseMainAxis) theNumOfThreads),
myUseMainAxis (theDoMainSplits)
{ {
// //
} }
@ -176,7 +178,7 @@ namespace BVH
// purpose : // purpose :
// ======================================================================= // =======================================================================
template<class T, int N, int Bins> template<class T, int N, int Bins>
void BVH_BinnedBuilder<T, N, Bins>::BuildNode (BVH_Set<T, N>* theSet, typename BVH_QueueBuilder<T, N>::BVH_ChildNodes BVH_BinnedBuilder<T, N, Bins>::BuildNode (BVH_Set<T, N>* theSet,
BVH_Tree<T, N>* theBVH, BVH_Tree<T, N>* theBVH,
const Standard_Integer theNode) const Standard_Integer theNode)
{ {
@ -185,7 +187,7 @@ void BVH_BinnedBuilder<T, N, Bins>::BuildNode (BVH_Set<T, N>* theSet,
if (aNodeEndPrimitive - aNodeBegPrimitive < BVH_Builder<T, N>::myLeafNodeSize) 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), const BVH_Box<T, N> anAABB (theBVH->MinPoint (theNode),
@ -204,7 +206,7 @@ void BVH_BinnedBuilder<T, N, Bins>::BuildNode (BVH_Set<T, N>* theSet,
Standard_Real aMinSplitCost = std::numeric_limits<Standard_Real>::max(); 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 // Find best split
for (Standard_Integer anAxis = myUseMainAxis ? aMainAxis : 0; anAxis <= (myUseMainAxis ? aMainAxis : Min (N - 1, 2)); ++anAxis) for (Standard_Integer anAxis = myUseMainAxis ? aMainAxis : 0; anAxis <= (myUseMainAxis ? aMainAxis : Min (N - 1, 2)); ++anAxis)
@ -281,52 +283,19 @@ void BVH_BinnedBuilder<T, N, Bins>::BuildNode (BVH_Set<T, N>* theSet,
} }
else else
{ {
aMiddle = BVH::SplitPrimitives<T, N> (theSet, anAABB, aMiddle = BVH::SplitPrimitives<T, N> (theSet,
aNodeBegPrimitive, aNodeEndPrimitive, aMinSplitIndex - 1, aMinSplitAxis, Bins); anAABB,
aNodeBegPrimitive,
aNodeEndPrimitive,
aMinSplitIndex - 1,
aMinSplitAxis,
Bins);
} }
static const Standard_Integer aLftNode = 1; typedef typename BVH_QueueBuilder<T, N>::BVH_PrimitiveRange Range;
static const Standard_Integer aRghNode = 2;
// Setting up tasks for child nodes return typename BVH_QueueBuilder<T, N>::BVH_ChildNodes (aMinSplitBoxLft,
for (Standard_Integer aSide = aLftNode; aSide <= aRghNode; ++aSide) aMinSplitBoxRgh,
{ Range (aNodeBegPrimitive, aMiddle - 1),
typename BVH_Box<T, N>::BVH_VecNt aMinPoint = (aSide == aLftNode) Range (aMiddle, aNodeEndPrimitive));
? 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));
}
} }

View File

@ -0,0 +1,81 @@
// 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;
}

View File

@ -0,0 +1,75 @@
// 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

View File

@ -0,0 +1,64 @@
// 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;
}

View File

@ -0,0 +1,80 @@
// 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

View File

@ -13,8 +13,6 @@
// Alternatively, this file may be used under the terms of Open CASCADE // Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement. // commercial license or contractual agreement.
#include <Standard_Assert.hxx>
#include <BVH_Triangulation.hxx> #include <BVH_Triangulation.hxx>
#ifdef HAVE_TBB #ifdef HAVE_TBB

View File

@ -17,10 +17,19 @@
#define _BVH_QueueBuilder_Header #define _BVH_QueueBuilder_Header
#include <BVH_Builder.hxx> #include <BVH_Builder.hxx>
#include <BVH_BuildThread.hxx>
#include <NCollection_Vector.hxx> #include <NCollection_Vector.hxx>
//! Abstract BVH builder based on the concept of work queue. //! 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> template<class T, int N>
class BVH_QueueBuilder : public BVH_Builder<T, N> class BVH_QueueBuilder : public BVH_Builder<T, N>
{ {
@ -28,7 +37,8 @@ public:
//! Creates new BVH queue based builder. //! Creates new BVH queue based builder.
BVH_QueueBuilder (const Standard_Integer theLeafNodeSize, 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. //! Releases resources of BVH queue based builder.
virtual ~BVH_QueueBuilder() = 0; virtual ~BVH_QueueBuilder() = 0;
@ -42,14 +52,129 @@ public:
protected: protected:
//! Builds BVH node for the given task info. //! Stores range of primitives belonging to a BVH node.
virtual void BuildNode (BVH_Set<T, N>* theSet, 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_Tree<T, N>* theBVH,
const Standard_Integer theTask); 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: protected:
NCollection_Vector<Standard_Integer> myTasksQueue; //!< Queue to manage BVH node building tasks //! 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:
BVH_BuildQueue myBuildQueue; //!< Queue to manage BVH node building tasks
Standard_Integer myNumOfThreads; //!< Number of threads used to build BVH
}; };

View File

@ -13,15 +13,19 @@
// Alternatively, this file may be used under the terms of Open CASCADE // Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement. // commercial license or contractual agreement.
#include <NCollection_Vector.hxx>
// ======================================================================= // =======================================================================
// function : BVH_QueueBuilder // function : BVH_QueueBuilder
// purpose : Creates new BVH queue based builder // purpose : Creates new BVH queue based builder
// ======================================================================= // =======================================================================
template<class T, int N> template<class T, int N>
BVH_QueueBuilder<T, N>::BVH_QueueBuilder (const Standard_Integer theLeafNodeSize, 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, : BVH_Builder<T, N> (theLeafNodeSize,
theMaxTreeDepth) theMaxTreeDepth),
myNumOfThreads (theNumOfThreads)
{ {
// //
} }
@ -36,6 +40,56 @@ BVH_QueueBuilder<T, N>::~BVH_QueueBuilder()
// //
} }
// =======================================================================
// 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 // function : Build
// purpose : Builds BVH using specific algorithm // purpose : Builds BVH using specific algorithm
@ -45,10 +99,8 @@ void BVH_QueueBuilder<T, N>::Build (BVH_Set<T, N>* theSet,
BVH_Tree<T, N>* theBVH, BVH_Tree<T, N>* theBVH,
const BVH_Box<T, N>& theBox) const BVH_Box<T, N>& theBox)
{ {
if (theBVH == NULL) Standard_ASSERT_RETURN (theBVH != NULL,
{ "Error! BVH tree to construct is NULL", );
return;
}
theBVH->Clear(); theBVH->Clear();
if (theSet->Size() == 0) if (theSet->Size() == 0)
@ -62,23 +114,38 @@ void BVH_QueueBuilder<T, N>::Build (BVH_Set<T, N>* theSet,
return; return;
} }
myTasksQueue.Append (aRoot); myBuildQueue.Enqueue (aRoot);
for (Standard_Integer aTask = 0; aTask < myTasksQueue.Size(); ++aTask)
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);
NCollection_Vector<Handle(BVH_BuildThread)> aThreads;
// Run BVH build threads
for (Standard_Integer aThreadIndex = 0; aThreadIndex < myNumOfThreads; ++aThreadIndex)
{
aThreads.Append (new BVH_BuildThread (aBuildTool, myBuildQueue));
aThreads.Last()->Run();
} }
myTasksQueue.Clear(); // Wait until all threads finish their work
} for (Standard_Integer aThreadIndex = 0; aThreadIndex < myNumOfThreads; ++aThreadIndex)
{
aThreads.ChangeValue (aThreadIndex)->Wait();
}
// ======================================================================= // Free unused memory
// function : BuildNode theBVH->Reserve (theBVH->Length());
// purpose : Builds BVH node for the given task info }
// ======================================================================= else
template<class T, int N> {
void BVH_QueueBuilder<T, N>::BuildNode (BVH_Set<T, N>* /* theSet */, BVH_BuildThread aThread (aBuildTool, myBuildQueue);
BVH_Tree<T, N>* /* theBVH */,
const Standard_Integer /* theTask */) // Execute thread function inside current thread
{ aThread.execute();
// needed to disable compile warnings }
} }

View File

@ -26,15 +26,16 @@ public:
//! Creates sweep plane SAH BVH builder. //! Creates sweep plane SAH BVH builder.
BVH_SweepPlaneBuilder (const Standard_Integer theLeafNodeSize = 5, 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. //! Releases resources of sweep plane SAH BVH builder.
virtual ~BVH_SweepPlaneBuilder(); virtual ~BVH_SweepPlaneBuilder();
protected: protected:
//! Builds specified BVH node. //! Performs splitting of the given BVH node.
virtual void BuildNode (BVH_Set<T, N>* theSet, typename BVH_QueueBuilder<T, N>::BVH_ChildNodes BuildNode (BVH_Set<T, N>* theSet,
BVH_Tree<T, N>* theBVH, BVH_Tree<T, N>* theBVH,
const Standard_Integer theNode); const Standard_Integer theNode);

View File

@ -23,9 +23,11 @@
// ======================================================================= // =======================================================================
template<class T, int N> template<class T, int N>
BVH_SweepPlaneBuilder<T, N>::BVH_SweepPlaneBuilder (const Standard_Integer theLeafNodeSize, 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, : BVH_QueueBuilder<T, N> (theLeafNodeSize,
theMaxTreeDepth) theMaxTreeDepth,
theNumOfThreads)
{ {
// //
} }
@ -45,7 +47,7 @@ BVH_SweepPlaneBuilder<T, N>::~BVH_SweepPlaneBuilder()
// purpose : // purpose :
// ======================================================================= // =======================================================================
template<class T, int N> template<class T, int N>
void BVH_SweepPlaneBuilder<T, N>::BuildNode (BVH_Set<T, N>* theSet, typename BVH_QueueBuilder<T, N>::BVH_ChildNodes BVH_SweepPlaneBuilder<T, N>::BuildNode (BVH_Set<T, N>* theSet,
BVH_Tree<T, N>* theBVH, BVH_Tree<T, N>* theBVH,
const Standard_Integer theNode) const Standard_Integer theNode)
{ {
@ -55,7 +57,7 @@ void BVH_SweepPlaneBuilder<T, N>::BuildNode (BVH_Set<T, N>* theSet,
if (aNodeEndPrimitive - aNodeBegPrimitive < BVH_Builder<T, N>::myLeafNodeSize) 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 // Parameters for storing best split
@ -118,7 +120,7 @@ void BVH_SweepPlaneBuilder<T, N>::BuildNode (BVH_Set<T, N>* theSet,
if (aMinSplitAxis == -1) if (aMinSplitAxis == -1)
{ {
return; return typename BVH_QueueBuilder<T, N>::BVH_ChildNodes(); // failed to find split axis
} }
theBVH->SetInner (theNode); theBVH->SetInner (theNode);
@ -144,49 +146,10 @@ void BVH_SweepPlaneBuilder<T, N>::BuildNode (BVH_Set<T, N>* theSet,
const Standard_Integer aMiddle = aNodeBegPrimitive + aMinSplitIndex; const Standard_Integer aMiddle = aNodeBegPrimitive + aMinSplitIndex;
static const Standard_Integer aLftNode = 1; typedef typename BVH_QueueBuilder<T, N>::BVH_PrimitiveRange Range;
static const Standard_Integer aRghNode = 2;
// Setting up tasks for child nodes return typename BVH_QueueBuilder<T, N>::BVH_ChildNodes (aMinSplitBoxLft,
for (Standard_Integer aSide = aLftNode; aSide <= aRghNode; ++aSide) aMinSplitBoxRgh,
{ Range (aNodeBegPrimitive, aMiddle - 1),
typename BVH_Box<T, N>::BVH_VecNt aChildMinPoint = (aSide == aLftNode) Range (aMiddle, aNodeEndPrimitive));
? 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));
}
} }

View File

@ -47,6 +47,10 @@ public:
// //
} }
//! 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. //! Returns minimum point of the given node.
BVH_VecNt& MinPoint (const Standard_Integer theNodeIndex) BVH_VecNt& MinPoint (const Standard_Integer theNodeIndex)
{ {
@ -256,7 +260,7 @@ protected:
//! Array of node data records. //! Array of node data records.
BVH_Array4i myNodeInfoBuffer; BVH_Array4i myNodeInfoBuffer;
//! Depth of constructed tree. //! Current depth of BVH tree.
Standard_Integer myDepth; Standard_Integer myDepth;
}; };

View File

@ -99,7 +99,10 @@ Standard_Integer BVH_Tree<T, N>::AddLeafNode (const BVH_Box<T, N>& theAABB,
const Standard_Integer theBegElem, const Standard_Integer theBegElem,
const Standard_Integer theEndElem) const Standard_Integer theEndElem)
{ {
return AddLeafNode (theAABB.CornerMin(), theAABB.CornerMax(), theBegElem, theEndElem); return AddLeafNode (theAABB.CornerMin(),
theAABB.CornerMax(),
theBegElem,
theEndElem);
} }
// ======================================================================= // =======================================================================
@ -111,7 +114,10 @@ Standard_Integer BVH_Tree<T, N>::AddInnerNode (const BVH_Box<T, N>& theAABB,
const Standard_Integer theLftChild, const Standard_Integer theLftChild,
const Standard_Integer theRghChild) const Standard_Integer theRghChild)
{ {
return AddInnerNode (theAABB.CornerMin(), theAABB.CornerMax(), theLftChild, theRghChild); return AddInnerNode (theAABB.CornerMin(),
theAABB.CornerMax(),
theLftChild,
theRghChild);
} }
namespace BVH namespace BVH
@ -167,3 +173,15 @@ T BVH_Tree<T, N>::EstimateSAH() const
BVH::EstimateSAH (this, 0, static_cast<T> (1.0), aSAH); BVH::EstimateSAH (this, 0, static_cast<T> (1.0), aSAH);
return 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);
}

View File

@ -26,6 +26,11 @@
#include <NCollection_Vec3.hxx> #include <NCollection_Vec3.hxx>
#include <NCollection_Vector.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 namespace BVH
{ {
//! Tool class for selecting appropriate vector type (Eigen or NCollection). //! Tool class for selecting appropriate vector type (Eigen or NCollection).
@ -179,6 +184,7 @@ namespace BVH
{ {
typedef typename BVH::ArrayType<T, N>::Type BVH_ArrayNt; 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 ( static inline const typename BVH::VectorType<T, N>::Type& Value (
const BVH_ArrayNt& theArray, const Standard_Integer theIndex) const BVH_ArrayNt& theArray, const Standard_Integer theIndex)
{ {
@ -189,6 +195,7 @@ namespace BVH
#endif #endif
} }
//! Returns a reference to the element with the given index.
static inline typename BVH::VectorType<T, N>::Type& ChangeValue ( static inline typename BVH::VectorType<T, N>::Type& ChangeValue (
BVH_ArrayNt& theArray, const Standard_Integer theIndex) BVH_ArrayNt& theArray, const Standard_Integer theIndex)
{ {
@ -199,6 +206,7 @@ namespace BVH
#endif #endif
} }
//! Adds the new element at the end of the array.
static inline void Append (BVH_ArrayNt& theArray, static inline void Append (BVH_ArrayNt& theArray,
const typename BVH::VectorType<T, N>::Type& theElement) const typename BVH::VectorType<T, N>::Type& theElement)
{ {
@ -209,6 +217,7 @@ namespace BVH
#endif #endif
} }
//! Returns the number of elements in the given array.
static inline Standard_Integer Size (const BVH_ArrayNt& theArray) static inline Standard_Integer Size (const BVH_ArrayNt& theArray)
{ {
#ifdef _BVH_USE_STD_VECTOR_ #ifdef _BVH_USE_STD_VECTOR_
@ -218,12 +227,34 @@ namespace BVH
#endif #endif
} }
//! Removes all elements from the given array.
static inline void Clear (BVH_ArrayNt& theArray) static inline void Clear (BVH_ArrayNt& theArray)
{ {
#ifdef _BVH_USE_STD_VECTOR_ #ifdef _BVH_USE_STD_VECTOR_
theArray.clear(); theArray.clear();
#else #else
theArray.Clear(); 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 #endif
} }
}; };

View File

@ -5,6 +5,10 @@ BVH_Box.hxx
BVH_Box.lxx BVH_Box.lxx
BVH_Builder.hxx BVH_Builder.hxx
BVH_Builder.lxx BVH_Builder.lxx
BVH_BuildQueue.hxx
BVH_BuildQueue.cxx
BVH_BuildThread.hxx
BVH_BuildThread.cxx
BVH_DistanceField.hxx BVH_DistanceField.hxx
BVH_DistanceField.lxx BVH_DistanceField.lxx
BVH_Geometry.hxx BVH_Geometry.hxx

View File

@ -13,16 +13,13 @@
// Alternatively, this file may be used under the terms of Open CASCADE // Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement. // commercial license or contractual agreement.
#include <Standard_Assert.hxx> #include <OSD_Timer.hxx>
#include <OSD_Parallel.hxx> #include <OSD_Parallel.hxx>
#include <Standard_Assert.hxx>
#include <OpenGl_SceneGeometry.hxx>
#include <OpenGl_ArbTexBindless.hxx> #include <OpenGl_ArbTexBindless.hxx>
#include <OpenGl_PrimitiveArray.hxx> #include <OpenGl_PrimitiveArray.hxx>
#include <OpenGl_SceneGeometry.hxx>
#include <OpenGl_Structure.hxx> #include <OpenGl_Structure.hxx>
#include <OSD_Timer.hxx>
#include <Standard_Assert.hxx>
#include <Graphic3d_GraphicDriver.hxx> #include <Graphic3d_GraphicDriver.hxx>
//! Use this macro to output BVH profiling info //! Use this macro to output BVH profiling info
@ -181,6 +178,18 @@ OpenGl_TriangleSet::BVH_BoxNt OpenGl_TriangleSet::Box() const
return aBox; 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 // function : Clear
// purpose : Clears ray-tracing geometry // purpose : Clears ray-tracing geometry

View File

@ -18,6 +18,7 @@
#include <BVH_Geometry.hxx> #include <BVH_Geometry.hxx>
#include <BVH_Triangulation.hxx> #include <BVH_Triangulation.hxx>
#include <BVH_BinnedBuilder.hxx>
#include <NCollection_StdAllocator.hxx> #include <NCollection_StdAllocator.hxx>
#include <OpenGl_TextureBufferArb.hxx> #include <OpenGl_TextureBufferArb.hxx>
#include <OpenGl_Texture.hxx> #include <OpenGl_Texture.hxx>
@ -166,12 +167,7 @@ public:
public: public:
//! Creates new OpenGL element triangulation. //! Creates new OpenGL element triangulation.
OpenGl_TriangleSet (const Standard_Size theArrayID) OpenGl_TriangleSet (const Standard_Size theArrayID);
: BVH_Triangulation<Standard_ShortReal, 3>(),
myArrayID (theArrayID)
{
//
}
//! Releases resources of OpenGL element triangulation. //! Releases resources of OpenGL element triangulation.
~OpenGl_TriangleSet() ~OpenGl_TriangleSet()