Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MultiThreading] Parallel BVH narrow phase #2053

Merged
merged 21 commits into from
May 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
cabbb77
[SofaUserInteraction] Minor cleaning of RayTraceDetection
alxbilger Apr 15, 2021
7b8edeb
[SofaBaseCollision] Introduce a brute force broad phase component
alxbilger Apr 15, 2021
c68f127
Merge branch 'ray_trace_clean'
alxbilger Apr 15, 2021
e31f391
[SofaUserInteraction] Use the component BruteForceBroadPhase in RayTr…
alxbilger Apr 15, 2021
198be24
[MultiThreading] Introduce ParallelBruteForceBroadPhase
alxbilger Apr 21, 2021
ce28996
Merge remote-tracking branch 'upstream/master' into parallel_brute_force
alxbilger Apr 21, 2021
af0e343
[MultiThreading] Fix compilation after merge
alxbilger Apr 21, 2021
04c2d00
[MultiThreading] Cleanup
alxbilger Apr 22, 2021
67b5592
[MultiThreading] Add a meaningful scene using ParallelBruteForceBroad…
alxbilger Apr 22, 2021
a789acc
Merge remote-tracking branch 'upstream/master' into parallel_brute_force
alxbilger Apr 22, 2021
0cdc12b
Merge remote-tracking branch 'upstream/master' into parallel_brute_force
alxbilger Apr 22, 2021
187c37d
[MultiThreading] Fix wrong export
alxbilger Apr 23, 2021
91b72d1
[MultiThreading] Add more security
alxbilger Apr 23, 2021
88769a2
[SofaBaseCollision] BruteForceDetection inherits from BruteForceBroad…
alxbilger Apr 23, 2021
2f1b299
[SofaBaseCollision] Extract the narrow phase code from BruteForceDete…
alxbilger Apr 23, 2021
9fe0db5
[SofaBaseCollision] Clean up
alxbilger Apr 23, 2021
4824248
Merge remote-tracking branch 'origin/bvh_narrow_phase' into parallel_…
alxbilger Apr 26, 2021
3de1a6b
Merge branch 'parallel_brute_force' into parallel_narrow_phase
alxbilger Apr 26, 2021
a9bde49
[MultiThreading] Introduce ParallelBVHNarrowPhase
alxbilger Apr 27, 2021
91ff284
Merge remote-tracking branch 'upstream/master' into parallel_narrow_p…
alxbilger Apr 29, 2021
252b3d3
Merge remote-tracking branch 'upstream/master' into parallel_narrow_p…
alxbilger May 5, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,6 @@ void BVHNarrowPhase::addCollisionPair(const std::pair<core::CollisionModel*, cor

const bool selfCollision = isSelfCollision(finestCollisionModel1, finestCollisionModel2);

const std::string timerName = "BVHNarrowPhase addCollisionPair: " + finestCollisionModel1->getName() + " - " + finestCollisionModel2->getName();
sofa::helper::ScopedAdvancedTimer bfTimer(timerName);

bool swapModels = false;
core::collision::ElementIntersector* finestIntersector = intersectionMethod->findIntersector(finestCollisionModel1, finestCollisionModel2, swapModels);//find the method for the finest CollisionModels
if (finestIntersector == nullptr)
Expand Down
2 changes: 2 additions & 0 deletions applications/plugins/MultiThreading/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ set(HEADER_FILES
src/MultiThreading/MeanComputation.h
src/MultiThreading/MeanComputation.inl
src/MultiThreading/ParallelBruteForceBroadPhase.h
src/MultiThreading/ParallelBVHNarrowPhase.h
)

set(SOURCE_FILES
Expand All @@ -23,6 +24,7 @@ set(SOURCE_FILES
src/MultiThreading/DataExchange.cpp
src/MultiThreading/MeanComputation.cpp
src/MultiThreading/ParallelBruteForceBroadPhase.cpp
src/MultiThreading/ParallelBVHNarrowPhase.cpp
)

find_package(SofaMiscMapping REQUIRED)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,13 @@ On a CPU with 6 cores, each core tests 3906 pairs of collision models.
<!-- Basic Components to perform the collision detection -->
<FreeMotionAnimationLoop name="FreeMotionAnimationLoop" parallel="true" />
<DefaultPipeline name="CollisionPipeline" />

<ParallelBruteForceBroadPhase/>
<BruteForceDetection name="BruteForceDetection" />
<ParallelBVHNarrowPhase/>

<!-- <BruteForceBroadPhase/>-->
<!-- <BVHNarrowPhase/>-->

<LocalMinDistance name="Proximity" alarmDistance="0.2" contactDistance="0.09" angleCone="0.0" />
<DefaultContactManager name="Response" response="FrictionContact" />
<LCPConstraintSolver maxIt="1000" tolerance="0.001"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/******************************************************************************
* SOFA, Simulation Open-Framework Architecture *
* (c) 2006 INRIA, USTL, UJF, CNRS, MGH *
* *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as published by *
* the Free Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
* for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*******************************************************************************
* Authors: The SOFA Team and external contributors (see Authors.txt) *
* *
* Contact information: contact@sofa-framework.org *
******************************************************************************/
#include <MultiThreading/ParallelBVHNarrowPhase.h>

#include <sofa/core/ObjectFactory.h>
#include <sofa/simulation/TaskScheduler.h>
#include <sofa/helper/ScopedAdvancedTimer.h>
#include <sofa/core/CollisionModel.h>
#include <sofa/core/collision/Intersection.h>
#include <SofaBaseTopology/MeshTopology.h>

namespace sofa::component::collision
{

using sofa::helper::ScopedAdvancedTimer;

int ParallelBVHNarrowPhaseClass = core::RegisterObject("Narrow phase collision detection based on boundary volume hierarchy")
.add< ParallelBVHNarrowPhase >()
;

ParallelBVHNarrowPhase::ParallelBVHNarrowPhase()
{}

void ParallelBVHNarrowPhase::init()
{
NarrowPhaseDetection::init();

// initialize the thread pool

auto* taskScheduler = sofa::simulation::TaskScheduler::getInstance();
assert(taskScheduler != nullptr);
if (taskScheduler->getThreadCount() < 1)
{
taskScheduler->init(0);
msg_info() << "Task scheduler initialized on " << taskScheduler->getThreadCount() << " threads";
}
else
{
msg_info() << "Task scheduler already initialized on " << taskScheduler->getThreadCount() << " threads";
}
}

void ParallelBVHNarrowPhase::addCollisionPairs(const sofa::helper::vector< std::pair<core::CollisionModel*, core::CollisionModel*> >& v)
{
ScopedAdvancedTimer createTasksTimer("addCollisionPairs");

if (v.empty())
{
return;
}

auto *taskScheduler = sofa::simulation::TaskScheduler::getInstance();
assert(taskScheduler != nullptr);

if (taskScheduler->getThreadCount() == 0)
{
msg_error() << "Task scheduler not correctly initialized";
return;
}

// initialize output
createOutput(v);

sofa::simulation::CpuTask::Status status;
const auto nbPairs = static_cast<unsigned int>(v.size());
m_tasks.reserve(nbPairs);

{
ScopedAdvancedTimer createTasksTimer("TasksCreation");
for (const auto &pair : v)
{
m_tasks.emplace_back(&status, this, pair);
taskScheduler->addTask(&m_tasks.back());
}
}

{
ScopedAdvancedTimer waitTimer("ParallelTasks");
taskScheduler->workUntilDone(&status);
}

m_tasks.clear();

// m_outputsMap should just be filled in addCollisionPair function
m_primitiveTestCount = m_outputsMap.size();
}

void ParallelBVHNarrowPhase::createOutput(
const helper::vector <std::pair<core::CollisionModel *, core::CollisionModel *>> &v)
{
ScopedAdvancedTimer createTasksTimer("OutputCreation");

for (const auto &pair : v)
{
core::CollisionModel *cm1 = pair.first;
core::CollisionModel *cm2 = pair.second;

core::CollisionModel *finestCollisionModel1 = cm1->getLast();//get the finest CollisionModel which is not a CubeModel
core::CollisionModel *finestCollisionModel2 = cm2->getLast();

initializeTopology(finestCollisionModel1->getCollisionTopology());
initializeTopology(finestCollisionModel2->getCollisionTopology());

bool swapModels = false;
core::collision::ElementIntersector *finestIntersector = intersectionMethod->findIntersector(
finestCollisionModel1, finestCollisionModel2,
swapModels);//find the method for the finest CollisionModels
if (finestIntersector == nullptr)
continue;
if (swapModels)
{
std::swap(cm1, cm2);
std::swap(finestCollisionModel1, finestCollisionModel2);
}

//force the creation of all Detection Output before the parallel computation
getDetectionOutputs(finestCollisionModel1, finestCollisionModel2);
};
}

void ParallelBVHNarrowPhase::initializeTopology(sofa::core::topology::BaseMeshTopology* topology)
{
auto insertionIt = m_initializedTopology.insert(topology);
if (insertionIt.second)
{
// The following calls force the creation of some topology arrays before the concurrent computing.
// Those arrays cannot be created on the fly, in a concurrent environment,
// due to possible race conditions.
// Depending on the scene graph, it is possible that those calls are not enough.
topology->getTrianglesAroundVertex(0);
topology->getEdgesInTriangle(0);
topology->getTrianglesAroundEdge(0);
}
}

ParallelBVHNarrowPhasePairTask::ParallelBVHNarrowPhasePairTask(
sofa::simulation::CpuTask::Status* status,
ParallelBVHNarrowPhase* bvhNarrowPhase,
std::pair<core::CollisionModel*, core::CollisionModel*> pair)
: sofa::simulation::CpuTask(status)
, m_bvhNarrowPhase(bvhNarrowPhase)
, m_pair(pair)
{}

sofa::simulation::Task::MemoryAlloc ParallelBVHNarrowPhasePairTask::run()
{
assert(m_bvhNarrowPhase != nullptr);

m_bvhNarrowPhase->addCollisionPair(m_pair);

return simulation::Task::Stack;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/******************************************************************************
* SOFA, Simulation Open-Framework Architecture *
* (c) 2006 INRIA, USTL, UJF, CNRS, MGH *
* *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as published by *
* the Free Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
* for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*******************************************************************************
* Authors: The SOFA Team and external contributors (see Authors.txt) *
* *
* Contact information: contact@sofa-framework.org *
******************************************************************************/
#pragma once

#include <MultiThreading/config.h>

#include <SofaBaseCollision/BVHNarrowPhase.h>
#include <sofa/simulation/CpuTask.h>
#include <unordered_set>

namespace sofa::component::collision
{

class ParallelBVHNarrowPhasePairTask;

class SOFA_MULTITHREADING_PLUGIN_API ParallelBVHNarrowPhase : public BVHNarrowPhase
{
public:
SOFA_CLASS(ParallelBVHNarrowPhase, BVHNarrowPhase);

protected:
ParallelBVHNarrowPhase();

std::vector<ParallelBVHNarrowPhasePairTask> m_tasks;

std::unordered_set< sofa::core::topology::BaseMeshTopology* > m_initializedTopology;
std::set< std::pair<core::CollisionModel*, core::CollisionModel*> > m_initializedPairs;

public:

void init() override;
void addCollisionPairs(const sofa::helper::vector< std::pair<core::CollisionModel*, core::CollisionModel*> >& v) override;

private:

/// Unlike the sequential algorithm which creates the output on the fly, the parallel implementation
/// requires to create the outputs before the computation, in order to avoid iterators invalidation
void createOutput(const helper::vector <std::pair<core::CollisionModel *, core::CollisionModel *>> &v);

/// This function makes sure some topology arrays are initialized. They cannot be initialized concurrently
void initializeTopology(sofa::core::topology::BaseMeshTopology*);
};

class SOFA_MULTITHREADING_PLUGIN_API ParallelBVHNarrowPhasePairTask : public sofa::simulation::CpuTask
{
public:
ParallelBVHNarrowPhasePairTask(
sofa::simulation::CpuTask::Status* status,
ParallelBVHNarrowPhase* bvhNarrowPhase,
std::pair<core::CollisionModel*, core::CollisionModel*> pair);
~ParallelBVHNarrowPhasePairTask() override = default;
sofa::simulation::Task::MemoryAlloc run() final;

private:

ParallelBVHNarrowPhase* m_bvhNarrowPhase { nullptr };
std::pair<core::CollisionModel*, core::CollisionModel*> m_pair;
};

} //namespace sofa::component::collision