From b846569888e9b6f6653f22e34d5fbef1d8032a73 Mon Sep 17 00:00:00 2001 From: Egor Olefirenko Date: Fri, 2 Feb 2024 00:45:39 +0300 Subject: [PATCH] xrGame/space_restriction_shape.h: parallelize iterate_vertices in fill_shape --- src/xrAICore/Navigation/level_graph.h | 1 + src/xrAICore/Navigation/level_graph_inline.h | 11 ++++-- src/xrGame/Level.cpp | 3 +- src/xrGame/space_restriction_shape.cpp | 38 ++++++++++++++++++-- src/xrGame/space_restrictor.cpp | 9 ++++- 5 files changed, 55 insertions(+), 7 deletions(-) diff --git a/src/xrAICore/Navigation/level_graph.h b/src/xrAICore/Navigation/level_graph.h index b9793c5aca0..0e062528a98 100644 --- a/src/xrAICore/Navigation/level_graph.h +++ b/src/xrAICore/Navigation/level_graph.h @@ -232,6 +232,7 @@ class XRAICORE_API CLevelGraph IC void assign_y_values(xr_vector& path); template IC void iterate_vertices(const Fvector& min_position, const Fvector& max_position, const P& predicate) const; + IC std::pair get_range(const Fvector& min_position, const Fvector& max_position) const; IC bool check_vertex_in_direction(u32 start_vertex_id, const Fvector2& start_position, u32 finish_vertex_id) const; IC u32 check_position_in_direction( u32 start_vertex_id, const Fvector2& start_position, const Fvector2& finish_position) const; diff --git a/src/xrAICore/Navigation/level_graph_inline.h b/src/xrAICore/Navigation/level_graph_inline.h index 2a79520eb3f..c3a9b49a3f6 100644 --- a/src/xrAICore/Navigation/level_graph_inline.h +++ b/src/xrAICore/Navigation/level_graph_inline.h @@ -571,6 +571,14 @@ IC void CLevelGraph::clear_mask_no_check(u32 vertex_id) { m_access_mask[vertex_i template IC void CLevelGraph::iterate_vertices( const Fvector& min_position, const Fvector& max_position, const P& predicate) const +{ + auto [I, E] = get_range(min_position, max_position); + + for (; I != E; ++I) + predicate(*I); +} + +IC std::pair CLevelGraph::get_range(const Fvector& min_position, const Fvector& max_position) const { const auto begin = m_nodes->begin(), end = m_nodes->end(); @@ -591,8 +599,7 @@ IC void CLevelGraph::iterate_vertices( else E = end; - for (; I != E; ++I) - predicate(*I); + return {I, E}; } IC u32 CLevelGraph::max_x() const { return (m_max_x); } diff --git a/src/xrGame/Level.cpp b/src/xrGame/Level.cpp index 2f34fdfa841..8fd66abe36b 100644 --- a/src/xrGame/Level.cpp +++ b/src/xrGame/Level.cpp @@ -443,8 +443,7 @@ void CLevel::OnFrame() if (g_mt_config.test(mtMap)) { R_ASSERT(m_map_manager); - Device.seqParallel.push_back( - fastdelegate::FastDelegate0<>(m_map_manager, &CMapManager::Update)); + Device.seqParallel.emplace_back(m_map_manager, &CMapManager::Update); } else MapManager().Update(); diff --git a/src/xrGame/space_restriction_shape.cpp b/src/xrGame/space_restriction_shape.cpp index 59b3dcb3cb0..aeaace289b0 100644 --- a/src/xrGame/space_restriction_shape.cpp +++ b/src/xrGame/space_restriction_shape.cpp @@ -12,6 +12,7 @@ #include "xrAICore/Navigation/level_graph.h" #include "space_restrictor.h" #include "xrAICore/Navigation/graph_engine.h" +#include "xrCore/Threading/ParallelFor.hpp" struct CBorderMergePredicate { @@ -79,10 +80,43 @@ void CSpaceRestrictionShape::fill_shape(const CCF_Shape::shape_def& shape) } default: NODEFAULT; } - ai().level_graph().iterate_vertices(start, dest, CBorderMergePredicate(this)); + + CLevelGraph& graph = ai().level_graph(); + + std::mutex mergeMutex; + + auto [begin, end] = graph.get_range(start, dest); + xr_parallel_for(TaskRange{begin, end}, [this, &mergeMutex, &graph] (auto &range) { + xr_vector m_border_chunk; + m_border_chunk.reserve(range.size()); + for (auto &vertex : range) + { + if (inside(graph.vertex_id(&vertex), true) && + !inside(graph.vertex_id(&vertex), false)) + m_border_chunk.push_back(graph.vertex_id(&vertex)); + } + std::lock_guard lock(mergeMutex); + if (m_border.capacity() < m_border.size() + m_border_chunk.size()) + m_border.reserve(m_border.size() + m_border_chunk.size()); + for (auto x : m_border_chunk) + m_border.push_back(x); + }); #ifdef DEBUG - ai().level_graph().iterate_vertices(start, dest, CShapeTestPredicate(this)); + xr_parallel_for(TaskRange{begin, end}, [this, &mergeMutex, &graph] (const auto &range) { + xr_vector m_test_storage_chunk; + m_test_storage_chunk.reserve(range.size()); + for (auto &vertex : range) + { + if (inside(graph.vertex_id(&vertex), false)) + m_test_storage_chunk.push_back(graph.vertex_id(&vertex)); + } + std::lock_guard lock(mergeMutex); + if (m_test_storage.capacity() < m_test_storage.size() + m_test_storage_chunk.size()) + m_test_storage.reserve(m_test_storage.size() + m_test_storage_chunk.size()); + for (auto x : m_test_storage_chunk) + m_test_storage.push_back(x); + }); #endif } diff --git a/src/xrGame/space_restrictor.cpp b/src/xrGame/space_restrictor.cpp index c2287aeb4ce..4f04e87c26b 100644 --- a/src/xrGame/space_restrictor.cpp +++ b/src/xrGame/space_restrictor.cpp @@ -100,7 +100,14 @@ void CSpaceRestrictor::net_Destroy() bool CSpaceRestrictor::inside(const Fsphere& sphere) const { if (!actual()) - prepare(); + { + static std::mutex prepareMutex; + std::lock_guard lock(prepareMutex); + + // Double-checked locking + if (!actual()) + prepare(); + } if (!m_selfbounds.intersect(sphere)) return (false);