From 8474ec0b521d947b78193e81b0c4473189c59d9e Mon Sep 17 00:00:00 2001 From: Romain Janvier Date: Thu, 20 Nov 2025 16:11:40 +0100 Subject: [PATCH 1/4] Initial fix for CloudCompare/CloudCompare#2247 --- CMakeLists.txt | 36 +++++++++++--------------------- include/ParallelSort.h | 6 +++--- src/DgmOctree.cpp | 16 +++++++------- src/DistanceComputationTools.cpp | 23 ++++++++++---------- 4 files changed, 35 insertions(+), 46 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a18965..e671b87 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -158,20 +158,15 @@ endif() # TBB (optional) # Must come before CGAL so it can use TBB properly if ( CCCORELIB_USE_TBB ) - find_package( TBB COMPONENTS tbb CONFIG ) + find_package( TBB COMPONENTS tbb 2022.0.0 CONFIG ) + set( CCCORELIB_USE_QT_CONCURRENT OFF ) if ( TBB_FOUND ) - if ( ${TBB_VERSION} VERSION_GREATER 2021.0.0 ) - target_link_libraries( CCCoreLib - PUBLIC - TBB::tbb - ) - else() - target_link_libraries( CCCoreLib - PUBLIC - ${TBB_IMPORTED_TARGETS} - ) - endif() + target_link_libraries( CCCoreLib + PUBLIC + TBB::tbb + ) + target_compile_definitions( CCCoreLib PUBLIC CC_CORE_LIB_USES_TBB @@ -192,14 +187,7 @@ if ( CCCORELIB_USE_CGAL ) if ( CCCORELIB_USE_TBB ) if ( TBB_FOUND ) - # Once Linux libcgal-dev >= 5.0, target_compile_definitions replaced by: - # CGAL_target_use_TBB( CCCoreLib ) - - target_compile_definitions( CCCoreLib - PRIVATE - CGAL_LINKED_WITH_TBB - NOMINMAX - ) + CGAL_target_use_TBB( CCCoreLib ) else() message( WARNING "CGAL cannot compile with TBB (TBB not found)" ) endif() @@ -232,7 +220,7 @@ if ( CCCORELIB_USE_QT_CONCURRENT ) target_link_libraries( CCCoreLib PUBLIC - Qt6::Concurrent + Qt6::Concurrent ) target_compile_definitions( CCCoreLib @@ -268,9 +256,9 @@ install( include( CMakePackageConfigHelpers ) configure_package_config_file(${CMAKE_CURRENT_LIST_DIR}/cmake/${PROJECT_NAME}Config.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake - INSTALL_DESTINATION lib/cmake/${PROJECT_NAME} - NO_CHECK_REQUIRED_COMPONENTS_MACRO + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake + INSTALL_DESTINATION lib/cmake/${PROJECT_NAME} + NO_CHECK_REQUIRED_COMPONENTS_MACRO ) write_basic_package_version_file( CCCoreLibConfigVersion.cmake diff --git a/include/ParallelSort.h b/include/ParallelSort.h index 07fec9b..6792709 100644 --- a/include/ParallelSort.h +++ b/include/ParallelSort.h @@ -20,14 +20,14 @@ #ifndef Q_MOC_RUN #if defined(emit) #undef emit - #include + #include #define emit // restore the macro definition of "emit", as it was defined in gtmetamacros.h #else - #include + #include #endif // defined(emit) #endif // Q_MOC_RUN - #define ParallelSort tbb::parallel_sort + #define ParallelSort oneapi::tbb::parallel_sort #else diff --git a/src/DgmOctree.cpp b/src/DgmOctree.cpp index 60ef26a..3d7858e 100644 --- a/src/DgmOctree.cpp +++ b/src/DgmOctree.cpp @@ -35,10 +35,10 @@ #ifndef Q_MOC_RUN #if defined(emit) #undef emit - #include + #include #define emit // restore the macro definition of "emit", as it was defined in gtmetamacros.h #else - #include + #include #endif // defined(emit) #endif // Q_MOC_RUN #endif @@ -3266,9 +3266,9 @@ unsigned DgmOctree::executeFunctionForAllCellsAtLevel( unsigned char level, QThreadPool::globalInstance()->setMaxThreadCount(maxThreadCount); QtConcurrent::blockingMap(cells, [this](const octreeCellDesc& desc) { m_MT_wrapper.launchOctreeCellFunc(desc); }); #elif defined(CC_CORE_LIB_USES_TBB) - tbb::task_scheduler_init init(maxThreadCount != 0 ? maxThreadCount : tbb::task_scheduler_init::automatic); - tbb::parallel_for(tbb::blocked_range(0, cells.size()), - [&](tbb::blocked_range r) + //tbb::task_scheduler_init init(maxThreadCount != 0 ? maxThreadCount : tbb::task_scheduler_init::automatic); + oneapi::tbb::parallel_for(oneapi::tbb::blocked_range(0, cells.size()), + [&](oneapi::tbb::blocked_range r) { for (auto i = r.begin(); i < r.end(); ++i) { @@ -3873,9 +3873,9 @@ unsigned DgmOctree::executeFunctionForAllCellsStartingAtLevel(unsigned char star QtConcurrent::blockingMap(cells, [this](const octreeCellDesc& desc) { m_MT_wrapper.launchOctreeCellFunc(desc); } ); #elif defined(CC_CORE_LIB_USES_TBB) // Otherwise we use TBB if we can - tbb::task_scheduler_init init(maxThreadCount != 0 ? maxThreadCount : tbb::task_scheduler_init::automatic); - tbb::parallel_for(tbb::blocked_range(0, cells.size()), - [&](tbb::blocked_range r) + //tbb::task_scheduler_init init(maxThreadCount != 0 ? maxThreadCount : tbb::task_scheduler_init::automatic); + oneapi::tbb::parallel_for(oneapi::tbb::blocked_range(0, cells.size()), + [&](tbb::blocked_range r) { for (auto i = r.begin(); i < r.end(); ++i) { diff --git a/src/DistanceComputationTools.cpp b/src/DistanceComputationTools.cpp index 679d040..a62ae17 100644 --- a/src/DistanceComputationTools.cpp +++ b/src/DistanceComputationTools.cpp @@ -30,14 +30,14 @@ #elif defined(CC_CORE_LIB_USES_TBB) //enables multi-threading handling with TBB #define ENABLE_CLOUD2MESH_DIST_MT -#include +#include #ifndef Q_MOC_RUN #if defined(emit) #undef emit - #include + #include #define emit // restore the macro definition of "emit", as it was defined in gtmetamacros.h #else - #include + #include #endif // defined(emit) #endif // Q_MOC_RUN #else @@ -934,7 +934,7 @@ namespace CCCoreLib #if defined(CC_CORE_LIB_USES_QT_CONCURRENT) QMutex currentBitMaskMutex; #elif defined(CC_CORE_LIB_USES_TBB) - std::mutex currentBitMaskMutex; + oneapi::tbb::mutex currentBitMaskMutex; #endif }; } @@ -956,8 +956,9 @@ static void CloudMeshDistCellFunc_MT(const DgmOctree::IndexAndCode& desc) if (s_multiThreadingWrapper.normProgressCb) { +#if defined(CC_CORE_LIB_USES_QT_CONCURRENT) QCoreApplication::processEvents(QEventLoop::EventLoopExec); // to allow the GUI to refresh itself - +#endif if (!s_multiThreadingWrapper.normProgressCb->oneStep()) { s_multiThreadingWrapper.cellFunc_success = false; @@ -1565,7 +1566,7 @@ int DistanceComputationTools::computePoint2MeshDistancesWithOctree( const CCVect return DISTANCE_COMPUTATION_RESULTS::SUCCESS; } -int DistanceComputationTools::computeCloud2MeshDistancesWithOctree( const DgmOctree* octree, +int DistanceComputationTools::computeCloud2MeshDistancesWithOctree( const DgmOctree* octree, const GridAndMeshIntersection& intersection, Cloud2MeshDistancesComputationParams& params, GenericProgressCallback* progressCb/*=nullptr*/) @@ -1819,10 +1820,10 @@ int DistanceComputationTools::computeCloud2MeshDistancesWithOctree( const DgmOct QThreadPool::globalInstance()->setMaxThreadCount(params.maxThreadCount); QtConcurrent::blockingMap(cellsDescs, CloudMeshDistCellFunc_MT); #elif defined(CC_CORE_LIB_USES_TBB) - tbb::parallel_for(tbb::blocked_range(0, cellsDescs.size()), - [&](tbb::blocked_range r) + oneapi::tbb::parallel_for(oneapi::tbb::blocked_range(0, cellsDescs.size()), + [&](oneapi::tbb::blocked_range r) { - for (auto i = r.begin(); r.end(); ++i) + for (auto i = r.begin(); i < r.end(); ++i) { CloudMeshDistCellFunc_MT(cellsDescs[i]); } @@ -1859,7 +1860,7 @@ int DistanceComputationTools::computeCloud2MeshDistances( GenericIndexedCloudPer DgmOctree* cloudOctree/*=nullptr*/) { //check the input - if (!pointCloud) + if (!pointCloud) { assert(false); return DISTANCE_COMPUTATION_RESULTS::ERROR_NULL_COMPAREDCLOUD; @@ -1921,7 +1922,7 @@ int DistanceComputationTools::computeCloud2MeshDistances( GenericIndexedCloudPer maxBB.u[k] = std::max(meshMaxBB.u[k], cloudMaxBB.u[k]); } - //max cubical bounding-box + //max cubical bounding-box cubicalMinBB = minBB; cubicalMaxBB = maxBB; From bbab1bc1a6836bb8d1609018f9ebe9af407ccca7 Mon Sep 17 00:00:00 2001 From: Romain Janvier Date: Thu, 20 Nov 2025 17:07:42 +0100 Subject: [PATCH 2/4] Fix indentation in ParallelSort.h --- include/ParallelSort.h | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/include/ParallelSort.h b/include/ParallelSort.h index 6792709..a1f63f5 100644 --- a/include/ParallelSort.h +++ b/include/ParallelSort.h @@ -10,29 +10,28 @@ #if defined(_MSC_VER) && (_MSC_VER >= 1800) - //Parallel Patterns Library (for parallel sort) - #include + //Parallel Patterns Library (for parallel sort) + #include - #define ParallelSort Concurrency::parallel_sort + #define ParallelSort Concurrency::parallel_sort #elif CC_CORE_LIB_USES_TBB - #ifndef Q_MOC_RUN - #if defined(emit) - #undef emit - #include - #define emit // restore the macro definition of "emit", as it was defined in gtmetamacros.h - #else - #include - #endif // defined(emit) - #endif // Q_MOC_RUN + #ifndef Q_MOC_RUN + #if defined(emit) + #undef emit + #include + #define emit // restore the macro definition of "emit", as it was defined in gtmetamacros.h + #else + #include + #endif // defined(emit) + #endif // Q_MOC_RUN - #define ParallelSort oneapi::tbb::parallel_sort + #define ParallelSort oneapi::tbb::parallel_sort #else - #include - - #define ParallelSort std::sort + #include + #define ParallelSort std::sort #endif From 438ebe45d7b174fd24c88a58f7db2bd3264daf1b Mon Sep 17 00:00:00 2001 From: Romain Janvier Date: Thu, 20 Nov 2025 17:27:10 +0100 Subject: [PATCH 3/4] TBB, new way to limit concurrency (task_scheduler_init is no longer part of the API) --- src/DgmOctree.cpp | 28 ++++++++++++++++++---------- src/DistanceComputationTools.cpp | 19 +++++++++++++------ 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/DgmOctree.cpp b/src/DgmOctree.cpp index 3d7858e..60a99d4 100644 --- a/src/DgmOctree.cpp +++ b/src/DgmOctree.cpp @@ -36,11 +36,14 @@ #if defined(emit) #undef emit #include + #include #define emit // restore the macro definition of "emit", as it was defined in gtmetamacros.h #else #include + #include #endif // defined(emit) #endif // Q_MOC_RUN +using namespace oneapi; #endif //#endif // #ifndef CC_DEBUG @@ -3111,7 +3114,7 @@ unsigned DgmOctree::executeFunctionForAllCellsAtLevel( unsigned char level, progressCb->update(0); progressCb->start(); } - + NormalizedProgress nprogress(progressCb, m_theAssociatedCloud->size()); #ifdef COMPUTE_NN_SEARCH_STATISTICS @@ -3266,15 +3269,17 @@ unsigned DgmOctree::executeFunctionForAllCellsAtLevel( unsigned char level, QThreadPool::globalInstance()->setMaxThreadCount(maxThreadCount); QtConcurrent::blockingMap(cells, [this](const octreeCellDesc& desc) { m_MT_wrapper.launchOctreeCellFunc(desc); }); #elif defined(CC_CORE_LIB_USES_TBB) - //tbb::task_scheduler_init init(maxThreadCount != 0 ? maxThreadCount : tbb::task_scheduler_init::automatic); - oneapi::tbb::parallel_for(oneapi::tbb::blocked_range(0, cells.size()), - [&](oneapi::tbb::blocked_range r) + tbb::task_arena local_arena(maxThreadCount != 0 ? maxThreadCount : tbb::info::default_concurrency()); + local_arena.execute([&] { + tbb::parallel_for(tbb::blocked_range(0, cells.size()), + [&](tbb::blocked_range r) { - for (auto i = r.begin(); i < r.end(); ++i) - { - m_MT_wrapper.launchOctreeCellFunc(cells[i]); - } + for (auto i = r.begin(); i < r.end(); ++i) + { + m_MT_wrapper.launchOctreeCellFunc(cells[i]); + } }); + }); #endif #ifdef COMPUTE_NN_SEARCH_STATISTICS FILE* fp = fopen("octree_log.txt", "at"); @@ -3873,8 +3878,10 @@ unsigned DgmOctree::executeFunctionForAllCellsStartingAtLevel(unsigned char star QtConcurrent::blockingMap(cells, [this](const octreeCellDesc& desc) { m_MT_wrapper.launchOctreeCellFunc(desc); } ); #elif defined(CC_CORE_LIB_USES_TBB) // Otherwise we use TBB if we can - //tbb::task_scheduler_init init(maxThreadCount != 0 ? maxThreadCount : tbb::task_scheduler_init::automatic); - oneapi::tbb::parallel_for(oneapi::tbb::blocked_range(0, cells.size()), + tbb::task_arena local_arena(maxThreadCount != 0 ? maxThreadCount : tbb::info::default_concurrency()); + local_arena.execute([&] + { + tbb::parallel_for(tbb::blocked_range(0, cells.size()), [&](tbb::blocked_range r) { for (auto i = r.begin(); i < r.end(); ++i) @@ -3882,6 +3889,7 @@ unsigned DgmOctree::executeFunctionForAllCellsStartingAtLevel(unsigned char star m_MT_wrapper.launchOctreeCellFunc(cells[i]); } }); + }); #endif #ifdef COMPUTE_NN_SEARCH_STATISTICS diff --git a/src/DistanceComputationTools.cpp b/src/DistanceComputationTools.cpp index a62ae17..a0b1500 100644 --- a/src/DistanceComputationTools.cpp +++ b/src/DistanceComputationTools.cpp @@ -30,16 +30,20 @@ #elif defined(CC_CORE_LIB_USES_TBB) //enables multi-threading handling with TBB #define ENABLE_CLOUD2MESH_DIST_MT -#include #ifndef Q_MOC_RUN #if defined(emit) #undef emit #include + #include + #include #define emit // restore the macro definition of "emit", as it was defined in gtmetamacros.h #else #include + #include + #include #endif // defined(emit) #endif // Q_MOC_RUN +using namespace oneapi; #else //Note that there is the case CC_DEBUG=OFF and neither TBB nor Qt #undef ENABLE_CLOUD2MESH_DIST_MT @@ -934,7 +938,7 @@ namespace CCCoreLib #if defined(CC_CORE_LIB_USES_QT_CONCURRENT) QMutex currentBitMaskMutex; #elif defined(CC_CORE_LIB_USES_TBB) - oneapi::tbb::mutex currentBitMaskMutex; + tbb::mutex currentBitMaskMutex; #endif }; } @@ -1820,15 +1824,18 @@ int DistanceComputationTools::computeCloud2MeshDistancesWithOctree( const DgmOct QThreadPool::globalInstance()->setMaxThreadCount(params.maxThreadCount); QtConcurrent::blockingMap(cellsDescs, CloudMeshDistCellFunc_MT); #elif defined(CC_CORE_LIB_USES_TBB) - oneapi::tbb::parallel_for(oneapi::tbb::blocked_range(0, cellsDescs.size()), - [&](oneapi::tbb::blocked_range r) + tbb::task_arena local_arena(params.maxThreadCount != 0 ? params.maxThreadCount : tbb::info::default_concurrency()); + local_arena.execute([&] + { + tbb::parallel_for(tbb::blocked_range(0, cellsDescs.size()), + [&](tbb::blocked_range r) { for (auto i = r.begin(); i < r.end(); ++i) { CloudMeshDistCellFunc_MT(cellsDescs[i]); } - } - ); + }); + }); #endif s_multiThreadingWrapper.octree = nullptr; From e2b5b7ba7b08e8697749b71421126ecafd1ba281 Mon Sep 17 00:00:00 2001 From: Romain Janvier Date: Thu, 20 Nov 2025 19:52:57 +0100 Subject: [PATCH 4/4] Fix build without QTConcurrent on non apple OSes --- src/DgmOctree.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/DgmOctree.cpp b/src/DgmOctree.cpp index 60a99d4..3e490f1 100644 --- a/src/DgmOctree.cpp +++ b/src/DgmOctree.cpp @@ -3253,8 +3253,10 @@ unsigned DgmOctree::executeFunctionForAllCellsAtLevel( unsigned char level, progressCb->update(0); m_MT_wrapper.normProgressCb = new NormalizedProgress(progressCb, m_theAssociatedCloud->size()); progressCb->start(); +#if defined(CC_CORE_LIB_USES_QT_CONCURRENT) #ifndef __APPLE__ QCoreApplication::processEvents(QEventLoop::EventLoopExec); // to allow the GUI to refresh itself +#endif #endif }