mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	Added dependencies on the Intel Thread Building Blocks.
Changed the C++ parallelization code to Intel Thread Building Blocks.
This commit is contained in:
		
							parent
							
								
									8a42c0ad9f
								
							
						
					
					
						commit
						cb1a6eae1e
					
				
					 6 changed files with 158 additions and 96 deletions
				
			
		
							
								
								
									
										140
									
								
								xs/Build.PL
									
										
									
									
									
								
							
							
						
						
									
										140
									
								
								xs/Build.PL
									
										
									
									
									
								
							|  | @ -8,8 +8,18 @@ use ExtUtils::CppGuess; | |||
| use Module::Build::WithXSpp; | ||||
| 
 | ||||
| my $cpp_guess = ExtUtils::CppGuess->new; | ||||
| my $lib_ext = ${$cpp_guess}{config}{lib_ext}; | ||||
| my $mswin = $^O eq 'MSWin32'; | ||||
| 
 | ||||
| # Library paths to search for boost, thread building blocks and such. | ||||
| # On Windows, there is really no standard. On Unices, this is a bit better. | ||||
| my @library_path_prefixes = (); | ||||
| if ($mswin) { | ||||
|     @library_path_prefixes = ("C:\\", "C:\\dev\\", "C:\\local\\", "D:\\", "D:\\dev\\", "D:\\local\\"); | ||||
| } else { | ||||
|     @library_path_prefixes = qw(/opt/local/ /usr/local/ /opt/ /usr/); | ||||
| } | ||||
| 
 | ||||
| # _GLIBCXX_USE_C99 : to get the long long type for g++ | ||||
| # HAS_BOOL         : stops Perl/lib/CORE/handy.h from doing "#  define bool char" for MSVC | ||||
| # NOGDI            : prevents inclusion of wingdi.h which defines functions Polygon() and Polyline() in global namespace | ||||
|  | @ -76,24 +86,23 @@ if (defined $ENV{BOOST_INCLUDEDIR}) { | |||
|     # Boost library was not defined by the environment. | ||||
|     # Try to guess at some default paths. | ||||
|     if ($mswin) { | ||||
|         for my $path (glob('C:\dev\boost*\include'), glob ('C:\boost*\include')) { | ||||
|         for my $path (map glob($_ . 'boost*\include'), @library_path_prefixes) { | ||||
|             push @boost_include, $path; | ||||
|         } | ||||
|         if (! @boost_include) { | ||||
|             # No boost\include. Try to include the boost root. | ||||
|             for my $path (glob('C:\dev\boost*'), glob ('C:\boost*')) { | ||||
|             for my $path (map glob($_ . 'boost*'), @library_path_prefixes) { | ||||
|                 push @boost_include, $path; | ||||
|             } | ||||
|         } | ||||
|     } else { | ||||
|         push @boost_include, grep { -d $_ } | ||||
|             qw(/opt/local/include /usr/local/include /opt/include /usr/include); | ||||
|         @boost_include = grep { -d $_ . '/boost' } map { $_ . 'include' } @library_path_prefixes; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| my @boost_libs = (); | ||||
| if (defined $ENV{BOOST_LIBRARYDIR}) { | ||||
|     push @boost_libs, $ENV{BOOST_LIBRARYDIR} | ||||
|     push @boost_libs, $ENV{BOOST_LIBRARYDIR}; | ||||
| } elsif (defined $ENV{BOOST_DIR}) { | ||||
|     my $subdir = $ENV{BOOST_DIR} . ($mswin ? '\stage\lib' : '/stage/lib'); | ||||
|     if (-d $subdir) { | ||||
|  | @ -105,14 +114,11 @@ if (defined $ENV{BOOST_LIBRARYDIR}) { | |||
|     # Boost library was not defined by the environment. | ||||
|     # Try to guess at some default paths. | ||||
|     if ($mswin) { | ||||
|         for my $path ( | ||||
|             glob('C:\dev\boost*\lib'),       glob ('C:\boost*\lib'),  | ||||
|             glob('C:\dev\boost*\stage\lib'), glob ('C:\boost*\stage\lib')) { | ||||
|         for my $path (map (glob($_ . 'boost*\lib'), glob($_ . 'boost*\stage\lib')), @library_path_prefixes) { | ||||
|             push @boost_libs, $path; | ||||
|         } | ||||
|     } else { | ||||
|         push @boost_libs, grep { -d $_ } | ||||
|             qw(/opt/local/lib /usr/local/lib /opt/lib /usr/lib /lib); | ||||
|         push @boost_libs, grep { -d $_ } map $_ . 'lib', @library_path_prefixes; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -138,7 +144,6 @@ if ($have_boost) { | |||
| } else { | ||||
|     # Either static linking, or check_lib could not be used to find the boost libraries. | ||||
|     my $lib_prefix = 'libboost_'; | ||||
|     my $lib_ext = ${$cpp_guess}{config}{lib_ext}; | ||||
|     PATH: foreach my $path (@boost_libs) { | ||||
|         # Try to find the boost system library. | ||||
|         my @files = glob "$path/${lib_prefix}system*$lib_ext"; | ||||
|  | @ -185,6 +190,110 @@ is handy, if you have built Boost libraries with mutliple settings. | |||
| 
 | ||||
| EOF | ||||
| 
 | ||||
| # Search for the Intel Thread Building Blocks. | ||||
| my @tbb_include = (); | ||||
| if (defined $ENV{TBB_INCLUDEDIR}) { | ||||
|     push @tbb_include, $ENV{TBB_INCLUDEDIR} | ||||
| } elsif (defined $ENV{TBB_DIR}) { | ||||
|     my $subdir = $ENV{TBB_DIR} . (($mswin == 1) ? '\include' : '/include'); | ||||
|     push @tbb_include, $subdir if (-d $subdir); | ||||
| } else { | ||||
|     # Thread Building Blocks library was not defined by the environment. | ||||
|     # Try to guess at some default paths. | ||||
|     if ($mswin) { | ||||
|         for my $path (map glob($_ . 'tbb*\include'), @library_path_prefixes) { | ||||
|             push @tbb_include, $path; | ||||
|         } | ||||
|     } else { | ||||
|         @tbb_include = grep { -d $_ . '/tbb' } map { $_ . 'include' } @library_path_prefixes; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| my @tbb_libs = (); | ||||
| if (defined $ENV{TBB_LIBRARYDIR}) { | ||||
|     push @tbb_libs, $ENV{TBB_LIBRARYDIR} | ||||
| } elsif (defined $ENV{TBB_DIR}) { | ||||
|     my $subdir = $ENV{TBB_DIR} . ($mswin ? '\lib' : '/lib'); | ||||
|     push @tbb_libs, $subdir if (-d $subdir); | ||||
| } else { | ||||
|     # Thread Building Blocks library was not defined by the environment. | ||||
|     # Try to guess at some default paths. | ||||
|     if ($mswin) { | ||||
|         for my $path (map { glob($_ . 'tbb*\lib') } @library_path_prefixes) { | ||||
|             push @tbb_libs, $path; | ||||
|         } | ||||
|     } else { | ||||
|         @tbb_libs = grep { -d $_ } map { $_ . 'lib' } @library_path_prefixes; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| # In order to generate the -l switches we need to know how Thread Building Blocks libraries are named | ||||
| my $have_tbb = 0; | ||||
| #my @tbb_libraries = qw(tbb tbbmalloc tbbmalloc_proxy); # we need these | ||||
| my @tbb_libraries = qw(tbb); # we need these | ||||
| 
 | ||||
| if (!$ENV{SLIC3R_STATIC}) { | ||||
|     # Dynamic linking of Thread Building Blocks libraries. | ||||
|     if (! $mswin) { | ||||
|         # Check without explicit lib path (works on Linux and OSX). | ||||
|         $have_tbb = 1 | ||||
|             if check_lib( | ||||
|                 lib     => [ @tbb_libraries ], | ||||
|             ); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| if ($have_tbb) { | ||||
|     # The Thread Building Blocks library was detected by check_lib on Linux. | ||||
|     push @LIBS, map "-l${_}", @tbb_libraries; | ||||
| } else { | ||||
|     # Either static linking, or check_lib could not be used to find the Thread Building Blocks libraries. | ||||
|     my $lib_prefix = $cpp_guess->is_msvc ? '' : 'lib'; | ||||
|     PATH: foreach my $path (@tbb_libs) { | ||||
|         # Try to find the Thread Building Blocks system library. | ||||
|         my @files = glob "$path/${lib_prefix}tbb*$lib_ext"; | ||||
|         next if !@files; | ||||
|         if ($files[0] =~ /\Q${lib_prefix}tbb\E([^.]*)\Q$lib_ext\E$/) { | ||||
|             # Suffix contains the version number, the build type etc. | ||||
|             my $suffix = $1; | ||||
|             # Verify existence of all required TBB libraries at $path. | ||||
|             for my $lib (map "${lib_prefix}${_}${suffix}${lib_ext}", @tbb_libraries) { | ||||
|                 # If the library file does not exist, try next library path. | ||||
|                 -f "$path/$lib" or next PATH; | ||||
|             } | ||||
|             if (! $cpp_guess->is_msvc) { | ||||
|                 # Test the correctness of TBB libraries by linking them to a minimal C program. | ||||
|                 check_lib( | ||||
|                     lib     => [ map "${_}${suffix}", @tbb_libraries ], | ||||
|                     INC     => join(' ', map "-I$_", @INC,  @tbb_include), | ||||
|                     LIBS    => "-L$path", | ||||
|                 ) or next; | ||||
|             } | ||||
|             push @INC, (map " -I$_", @tbb_include);  # TODO: only use the one related to the chosen lib path | ||||
|             if ($ENV{SLIC3R_STATIC} || $cpp_guess->is_msvc) { | ||||
|                 push @LIBS, map "${path}/${_}_static.lib", @tbb_libraries; | ||||
|             } else { | ||||
|                 push @LIBS, " -L$path", (map " -l$_$suffix", @tbb_libraries); | ||||
|             } | ||||
|             $have_tbb = 1; | ||||
|             last; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| die <<'EOF' if !$have_tbb; | ||||
| Slic3r requires the Intel Thread Building Blocks libraries. Please make sure the library is installed. | ||||
| 
 | ||||
| If the Intel Thread Building Blocks library is installed, this script should be able to locate them in several | ||||
| standard locations. If this is not the case, you might want to supply a path to the library  | ||||
| through the TBB_DIR environment variable: | ||||
| 
 | ||||
|     TBB_DIR=/path/to/TBB perl Build.PL | ||||
| 
 | ||||
| Or you may specify TBB_INCLUDEPATH and TBB_LIBRARYPATH separatly, which | ||||
| is handy, if you have built the Thread Building Blocks libraries with mutliple settings. | ||||
| 
 | ||||
| EOF | ||||
| 
 | ||||
| # Add the OpenGL and GLU libraries. | ||||
| if ($ENV{SLIC3R_GUI}) { | ||||
|     if ($mswin) { | ||||
|  | @ -206,15 +315,6 @@ if ($ENV{SLIC3R_DEBUG}) { | |||
|     # Disable asserts in the release builds. | ||||
|     push @cflags, '-DNDEBUG'; | ||||
| } | ||||
| if ($cpp_guess->is_gcc) { | ||||
|     # check whether we're dealing with a buggy GCC version | ||||
|     # see https://github.com/alexrj/Slic3r/issues/1965 | ||||
|     if (`cc --version` =~ m/ 4\.7\.[012]/) { | ||||
|         # Workaround suggested by Boost devs: | ||||
|         # https://svn.boost.org/trac/boost/ticket/8695 | ||||
|         push @cflags, qw(-fno-inline-small-functions); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| print "\n"; | ||||
| print 'With @cflags: ', join(', ', map "\"$_\"", @cflags), "\n"; | ||||
|  |  | |||
|  | @ -1029,6 +1029,7 @@ GCode::needs_retraction(const Polyline &travel, ExtrusionRole role) | |||
|      | ||||
|     if (role == erSupportMaterial) { | ||||
|         const SupportLayer* support_layer = dynamic_cast<const SupportLayer*>(this->layer); | ||||
|         //FIXME support_layer->support_islands.contains should use some search structure!
 | ||||
|         if (support_layer != NULL && support_layer->support_islands.contains(travel)) { | ||||
|             // skip retraction if this is a travel move inside a support material island
 | ||||
|             return false; | ||||
|  |  | |||
|  | @ -7,6 +7,9 @@ | |||
| #include <utility> | ||||
| #include <boost/log/trivial.hpp> | ||||
| 
 | ||||
| #include <tbb/parallel_for.h> | ||||
| #include <tbb/atomic.h> | ||||
| 
 | ||||
| #include <Shiny/Shiny.h> | ||||
| 
 | ||||
| #ifdef SLIC3R_DEBUG_SLICE_PROCESSING | ||||
|  | @ -632,7 +635,7 @@ PrintObject::discover_vertical_shells() | |||
|                         LayerRegion &neighbor_region = *neighbor_layer.get_region(int(idx_region)); | ||||
|                         Polygons newholes; | ||||
|                         for (size_t idx_region = 0; idx_region < this->_print->regions.size(); ++ idx_region) | ||||
|                             polygons_append(newholes, to_polygons(neighbor_layer.get_region(idx_region)->fill_expolygons)); | ||||
|                             polygons_append(newholes, to_polygons(neighbor_layer.regions[idx_region]->fill_expolygons)); | ||||
|                         if (hole_first) { | ||||
|                             hole_first = false; | ||||
|                             polygons_append(holes, STDMOVE(newholes)); | ||||
|  | @ -1267,13 +1270,16 @@ PrintObject::_make_perimeters() | |||
|         } | ||||
|     } | ||||
|      | ||||
|     BOOST_LOG_TRIVIAL(debug) << "Generating perimeters in parallel"; | ||||
|     parallelize<Layer*>( | ||||
|         std::queue<Layer*>(std::deque<Layer*>(this->layers.begin(), this->layers.end())),  // cast LayerPtrs to std::queue<Layer*>
 | ||||
|         boost::bind(&Slic3r::Layer::make_perimeters, _1), | ||||
|         this->_print->config.threads.value | ||||
|     BOOST_LOG_TRIVIAL(debug) << "Generating perimeters in parallel - start"; | ||||
|     tbb::parallel_for( | ||||
|         tbb::blocked_range<size_t>(0, this->layers.size()), | ||||
|         [this](const tbb::blocked_range<size_t>& range) { | ||||
|             for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) | ||||
|                 this->layers[layer_idx]->make_perimeters(); | ||||
|         } | ||||
|     ); | ||||
|      | ||||
|     BOOST_LOG_TRIVIAL(debug) << "Generating perimeters in parallel - end"; | ||||
| 
 | ||||
|     /*
 | ||||
|         simplify slices (both layer and region slices), | ||||
|         we only need the max resolution for perimeters | ||||
|  | @ -1290,13 +1296,16 @@ PrintObject::_infill() | |||
|     if (this->state.is_done(posInfill)) return; | ||||
|     this->state.set_started(posInfill); | ||||
|      | ||||
|     BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel"; | ||||
|     parallelize<Layer*>( | ||||
|         std::queue<Layer*>(std::deque<Layer*>(this->layers.begin(), this->layers.end())),  // cast LayerPtrs to std::queue<Layer*>
 | ||||
|         boost::bind(&Slic3r::Layer::make_fills, _1), | ||||
|         this->_print->config.threads.value | ||||
|     BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel - start"; | ||||
|     tbb::parallel_for( | ||||
|         tbb::blocked_range<size_t>(0, this->layers.size()), | ||||
|         [this](const tbb::blocked_range<size_t>& range) { | ||||
|             for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) | ||||
|                 this->layers[layer_idx]->make_fills(); | ||||
|         } | ||||
|     ); | ||||
|      | ||||
|     BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel - end"; | ||||
| 
 | ||||
|     /*  we could free memory now, but this would make this step not idempotent
 | ||||
|     ### $_->fill_surfaces->clear for map @{$_->regions}, @{$object->layers}; | ||||
|     */ | ||||
|  |  | |||
|  | @ -13,6 +13,8 @@ | |||
| 
 | ||||
| #include <boost/log/trivial.hpp> | ||||
| 
 | ||||
| #include <tbb/parallel_for.h> | ||||
| 
 | ||||
| #if 0 | ||||
|     #define DEBUG | ||||
|     #define _DEBUG | ||||
|  | @ -672,10 +674,12 @@ TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* la | |||
|     std::vector<IntersectionLines> lines(z.size()); | ||||
|     { | ||||
|         boost::mutex lines_mutex; | ||||
|         parallelize<int>( | ||||
|             0, | ||||
|             this->mesh->stl.stats.number_of_facets-1, | ||||
|             boost::bind(&TriangleMeshSlicer::_slice_do, this, _1, &lines, &lines_mutex, z) | ||||
|         tbb::parallel_for( | ||||
|             tbb::blocked_range<int>(0,this->mesh->stl.stats.number_of_facets), | ||||
|             [&lines, &lines_mutex, &z, this](const tbb::blocked_range<int>& range) { | ||||
|                 for (int facet_idx = range.begin(); facet_idx < range.end(); ++ facet_idx) | ||||
|                     this->_slice_do(facet_idx, &lines, &lines_mutex, z); | ||||
|             } | ||||
|         ); | ||||
|     } | ||||
|      | ||||
|  | @ -684,10 +688,12 @@ TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* la | |||
|     // build loops
 | ||||
|     BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::_make_loops_do"; | ||||
|     layers->resize(z.size()); | ||||
|     parallelize<size_t>( | ||||
|         0, | ||||
|         lines.size()-1, | ||||
|         boost::bind(&TriangleMeshSlicer::_make_loops_do, this, _1, &lines, layers) | ||||
|     tbb::parallel_for( | ||||
|         tbb::blocked_range<size_t>(0, lines.size()), | ||||
|         [&lines, &layers, this](const tbb::blocked_range<size_t>& range) { | ||||
|             for (size_t line_idx = range.begin(); line_idx < range.end(); ++ line_idx) | ||||
|                 this->make_loops(lines[line_idx], &(*layers)[line_idx]); | ||||
|         } | ||||
|     ); | ||||
|     BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::slice finished"; | ||||
| } | ||||
|  | @ -873,12 +879,6 @@ bool TriangleMeshSlicer::slice_facet( | |||
|     return false; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| TriangleMeshSlicer::_make_loops_do(size_t i, std::vector<IntersectionLines>* lines, std::vector<Polygons>* layers) const | ||||
| { | ||||
|     this->make_loops((*lines)[i], &(*layers)[i]); | ||||
| } | ||||
| 
 | ||||
| void TriangleMeshSlicer::make_loops(std::vector<IntersectionLine> &lines, Polygons* loops) const | ||||
| { | ||||
|     // Remove tangent edges.
 | ||||
|  |  | |||
|  | @ -132,7 +132,6 @@ private: | |||
|     std::vector<stl_vertex>  v_scaled_shared; | ||||
| 
 | ||||
|     void _slice_do(size_t facet_idx, std::vector<IntersectionLines>* lines, boost::mutex* lines_mutex, const std::vector<float> &z) const; | ||||
|     void _make_loops_do(size_t i, std::vector<IntersectionLines>* lines, std::vector<Polygons>* layers) const; | ||||
|     void make_loops(std::vector<IntersectionLine> &lines, Polygons* loops) const; | ||||
|     void make_expolygons(const Polygons &loops, ExPolygons* slices) const; | ||||
|     void make_expolygons_simple(std::vector<IntersectionLine> &lines, ExPolygons* slices) const; | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ | |||
| #include <boost/thread.hpp> | ||||
| 
 | ||||
| #define SLIC3R_FORK_NAME "Slic3r Prusa Edition" | ||||
| #define SLIC3R_VERSION "1.31.6" | ||||
| #define SLIC3R_VERSION "1.33.8.devel" | ||||
| #define SLIC3R_BUILD "UNKNOWN" | ||||
| 
 | ||||
| //FIXME This epsilon value is used for many non-related purposes:
 | ||||
|  | @ -99,53 +99,6 @@ inline void append_to(std::vector<T> &dst, const std::vector<T> &src) | |||
|     dst.insert(dst.end(), src.begin(), src.end()); | ||||
| } | ||||
| 
 | ||||
| template <class T> void | ||||
| _parallelize_do(std::queue<T>* queue, boost::mutex* queue_mutex, boost::function<void(T)> func) | ||||
| { | ||||
|     //std::cout << "THREAD STARTED: " << boost::this_thread::get_id() << std::endl;
 | ||||
|     while (true) { | ||||
|         T i; | ||||
|         { | ||||
|             boost::lock_guard<boost::mutex> l(*queue_mutex); | ||||
|             if (queue->empty()) return; | ||||
|             i = queue->front(); | ||||
|             queue->pop(); | ||||
|         } | ||||
|         //std::cout << "  Thread " << boost::this_thread::get_id() << " processing item " << i << std::endl;
 | ||||
|         func(i); | ||||
|         boost::this_thread::interruption_point(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| template <class T> void | ||||
| parallelize(std::queue<T> queue, boost::function<void(T)> func, | ||||
|     int threads_count = boost::thread::hardware_concurrency()) | ||||
| { | ||||
| #ifdef SLIC3R_PROFILE | ||||
|     while (! queue.empty()) { | ||||
|         func(queue.front()); | ||||
|         queue.pop(); | ||||
|     } | ||||
| #else | ||||
|     if (threads_count == 0) | ||||
|         threads_count = 2; | ||||
|     boost::mutex queue_mutex; | ||||
|     boost::thread_group workers; | ||||
|     for (int i = 0; i < std::min(threads_count, int(queue.size())); ++ i) | ||||
|         workers.add_thread(new boost::thread(&_parallelize_do<T>, &queue, &queue_mutex, func)); | ||||
|     workers.join_all(); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| template <class T> void | ||||
| parallelize(T start, T end, boost::function<void(T)> func, | ||||
|     int threads_count = boost::thread::hardware_concurrency()) | ||||
| { | ||||
|     std::queue<T> queue; | ||||
|     for (T i = start; i <= end; ++i) queue.push(i); | ||||
|     parallelize(queue, func, threads_count); | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| void append(std::vector<T>& dest, const std::vector<T>& src) | ||||
| { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv