diff --git a/xs/Build.PL b/xs/Build.PL index 9cbd79f25..4846cb8bb 100644 --- a/xs/Build.PL +++ b/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"; diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index bab8a56eb..a47e76126 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1029,6 +1029,7 @@ GCode::needs_retraction(const Polyline &travel, ExtrusionRole role) if (role == erSupportMaterial) { const SupportLayer* support_layer = dynamic_cast(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; diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index 5a97d66fe..039911c71 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/xs/src/libslic3r/PrintObject.cpp @@ -7,6 +7,9 @@ #include #include +#include +#include + #include #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( - std::queue(std::deque(this->layers.begin(), this->layers.end())), // cast LayerPtrs to std::queue - 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(0, this->layers.size()), + [this](const tbb::blocked_range& 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( - std::queue(std::deque(this->layers.begin(), this->layers.end())), // cast LayerPtrs to std::queue - 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(0, this->layers.size()), + [this](const tbb::blocked_range& 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}; */ diff --git a/xs/src/libslic3r/TriangleMesh.cpp b/xs/src/libslic3r/TriangleMesh.cpp index aa9705035..f1fe74902 100644 --- a/xs/src/libslic3r/TriangleMesh.cpp +++ b/xs/src/libslic3r/TriangleMesh.cpp @@ -13,6 +13,8 @@ #include +#include + #if 0 #define DEBUG #define _DEBUG @@ -672,10 +674,12 @@ TriangleMeshSlicer::slice(const std::vector &z, std::vector* la std::vector lines(z.size()); { boost::mutex lines_mutex; - parallelize( - 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(0,this->mesh->stl.stats.number_of_facets), + [&lines, &lines_mutex, &z, this](const tbb::blocked_range& 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 &z, std::vector* la // build loops BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::_make_loops_do"; layers->resize(z.size()); - parallelize( - 0, - lines.size()-1, - boost::bind(&TriangleMeshSlicer::_make_loops_do, this, _1, &lines, layers) + tbb::parallel_for( + tbb::blocked_range(0, lines.size()), + [&lines, &layers, this](const tbb::blocked_range& 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* lines, std::vector* layers) const -{ - this->make_loops((*lines)[i], &(*layers)[i]); -} - void TriangleMeshSlicer::make_loops(std::vector &lines, Polygons* loops) const { // Remove tangent edges. diff --git a/xs/src/libslic3r/TriangleMesh.hpp b/xs/src/libslic3r/TriangleMesh.hpp index 262fe9d2e..907b1f7e9 100644 --- a/xs/src/libslic3r/TriangleMesh.hpp +++ b/xs/src/libslic3r/TriangleMesh.hpp @@ -132,7 +132,6 @@ private: std::vector v_scaled_shared; void _slice_do(size_t facet_idx, std::vector* lines, boost::mutex* lines_mutex, const std::vector &z) const; - void _make_loops_do(size_t i, std::vector* lines, std::vector* layers) const; void make_loops(std::vector &lines, Polygons* loops) const; void make_expolygons(const Polygons &loops, ExPolygons* slices) const; void make_expolygons_simple(std::vector &lines, ExPolygons* slices) const; diff --git a/xs/src/libslic3r/libslic3r.h b/xs/src/libslic3r/libslic3r.h index 0fe3ca53a..e2c99b00f 100644 --- a/xs/src/libslic3r/libslic3r.h +++ b/xs/src/libslic3r/libslic3r.h @@ -14,7 +14,7 @@ #include #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 &dst, const std::vector &src) dst.insert(dst.end(), src.begin(), src.end()); } -template void -_parallelize_do(std::queue* queue, boost::mutex* queue_mutex, boost::function func) -{ - //std::cout << "THREAD STARTED: " << boost::this_thread::get_id() << std::endl; - while (true) { - T i; - { - boost::lock_guard 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 void -parallelize(std::queue queue, boost::function 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, &queue, &queue_mutex, func)); - workers.join_all(); -#endif -} - -template void -parallelize(T start, T end, boost::function func, - int threads_count = boost::thread::hardware_concurrency()) -{ - std::queue queue; - for (T i = start; i <= end; ++i) queue.push(i); - parallelize(queue, func, threads_count); -} - template void append(std::vector& dest, const std::vector& src) {