diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index 3b0020b08..132e7d0df 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -2,7 +2,6 @@ #define slic3r_Print_hpp_ #include "libslic3r.h" -#include #include #include #include @@ -156,8 +155,6 @@ private: // parameter PrintObject(Print* print, ModelObject* model_object, const BoundingBoxf3 &modobj_bbox); ~PrintObject(); - void _make_perimeters_do(std::queue* queue, boost::mutex* queue_mutex); - void _infill_do(std::queue* queue, boost::mutex* queue_mutex); }; typedef std::vector PrintObjectPtrs; diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 5e1732a0f..6aace7732 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -1292,7 +1292,7 @@ PrintConfigDef::PrintConfigDef() def->readonly = true; def->min = 1; def->max = 16; - def->default_value = new ConfigOptionInt(boost::thread::hardware_concurrency()); + def->default_value = new ConfigOptionInt((boost::thread::hardware_concurrency() == 0) ? 2 : boost::thread::hardware_concurrency()); def = this->add("toolchange_gcode", coString); def->label = "Tool change G-code"; diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index 3f41179dc..b276744c4 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/xs/src/libslic3r/PrintObject.cpp @@ -1009,18 +1009,11 @@ PrintObject::_make_perimeters() } } - { - // queue all the layer numbers - std::queue queue; - boost::mutex queue_mutex; - for (size_t i = 0; i < this->layer_count(); ++i) - queue.push(i); - - boost::thread_group workers; - for (int i = 0; i < this->_print->config.threads; i++) - workers.add_thread(new boost::thread(&Slic3r::PrintObject::_make_perimeters_do, this, &queue, &queue_mutex)); - workers.join_all(); - } + 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 + ); /* simplify slices (both layer and region slices), @@ -1032,43 +1025,17 @@ PrintObject::_make_perimeters() this->state.set_done(posPerimeters); } -void -PrintObject::_make_perimeters_do(std::queue* queue, boost::mutex* queue_mutex) -{ - //std::cout << "THREAD STARTED: " << boost::this_thread::get_id() << std::endl; - - while (true) { - size_t layer_id; - { - boost::lock_guard l(*queue_mutex); - if (queue->empty()) return; - layer_id = queue->front(); - queue->pop(); - } - //std::cout << " Layer " << layer_id << " (" << boost::this_thread::get_id() << ")" << std::endl; - this->get_layer(layer_id)->make_perimeters(); - boost::this_thread::interruption_point(); - } -} - void PrintObject::_infill() { if (this->state.is_done(posInfill)) return; this->state.set_started(posInfill); - { - // queue all the layer numbers - std::queue queue; - boost::mutex queue_mutex; - for (size_t i = 0; i < this->layer_count(); ++i) - queue.push(i); - - boost::thread_group workers; - for (int i = 0; i < this->_print->config.threads; i++) - workers.add_thread(new boost::thread(&Slic3r::PrintObject::_infill_do, this, &queue, &queue_mutex)); - workers.join_all(); - } + 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 + ); /* we could free memory now, but this would make this step not idempotent ### $_->fill_surfaces->clear for map @{$_->regions}, @{$object->layers}; @@ -1077,23 +1044,4 @@ PrintObject::_infill() this->state.set_done(posInfill); } -void -PrintObject::_infill_do(std::queue* queue, boost::mutex* queue_mutex) -{ - //std::cout << "THREAD STARTED: " << boost::this_thread::get_id() << std::endl; - - while (true) { - size_t layer_id; - { - boost::lock_guard l(*queue_mutex); - if (queue->empty()) return; - layer_id = queue->front(); - queue->pop(); - } - //std::cout << " Layer " << layer_id << " (" << boost::this_thread::get_id() << ")" << std::endl; - this->get_layer(layer_id)->make_fills(); - boost::this_thread::interruption_point(); - } -} - } diff --git a/xs/src/libslic3r/TriangleMesh.cpp b/xs/src/libslic3r/TriangleMesh.cpp index 9ed0dfcd4..ee09ac532 100644 --- a/xs/src/libslic3r/TriangleMesh.cpp +++ b/xs/src/libslic3r/TriangleMesh.cpp @@ -3,6 +3,7 @@ #include "Geometry.hpp" #include #include +#include #include #include #include @@ -432,83 +433,55 @@ TriangleMeshSlicer::slice(const std::vector &z, std::vector* la */ std::vector lines(z.size()); - { - // queue all the facet indices - std::queue queue; - boost::mutex queue_mutex, lines_mutex; - for (size_t i = 0; i < this->mesh->stl.stats.number_of_facets; ++i) queue.push(i); - - boost::thread_group workers; - for (int i = 0; i < boost::thread::hardware_concurrency(); i++) - workers.add_thread(new boost::thread(&TriangleMeshSlicer::_slice_do, this, - &queue, &queue_mutex, &lines, &lines_mutex, z)); - workers.join_all(); + 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) + ); } // v_scaled_shared could be freed here // build loops layers->resize(z.size()); - { - // queue all the layer numbers - std::queue queue; - boost::mutex queue_mutex; - for (size_t i = 0; i < lines.size(); ++i) queue.push(i); - - // We don't use a mutex for lines because workers are only writing the skip property - // and no workers work on the same layer (i.e. item of 'lines'). - boost::thread_group workers; - for (int i = 0; i < boost::thread::hardware_concurrency(); i++) - workers.add_thread(new boost::thread(&TriangleMeshSlicer::_make_loops_do, this, - &queue, &queue_mutex, &lines, layers)); - workers.join_all(); - } + parallelize( + 0, + lines.size()-1, + boost::bind(&TriangleMeshSlicer::_make_loops_do, this, _1, &lines, layers) + ); } void -TriangleMeshSlicer::_slice_do(std::queue* queue, boost::mutex* queue_mutex, - std::vector* lines, boost::mutex* lines_mutex, const std::vector &z) const +TriangleMeshSlicer::_slice_do(size_t facet_idx, std::vector* lines, boost::mutex* lines_mutex, + const std::vector &z) const { - //std::cout << "THREAD STARTED: " << boost::this_thread::get_id() << std::endl; + const stl_facet &facet = this->mesh->stl.facet_start[facet_idx]; - while (true) { - int facet_idx; - { - boost::lock_guard l(*queue_mutex); - if (queue->empty()) return; - facet_idx = queue->front(); - queue->pop(); - } - //std::cout << " Facet " << facet_idx << " (" << boost::this_thread::get_id() << ")" << std::endl; - - const stl_facet &facet = this->mesh->stl.facet_start[facet_idx]; - - // find facet extents - const float min_z = fminf(facet.vertex[0].z, fminf(facet.vertex[1].z, facet.vertex[2].z)); - const float max_z = fmaxf(facet.vertex[0].z, fmaxf(facet.vertex[1].z, facet.vertex[2].z)); - - #ifdef SLIC3R_TRIANGLEMESH_DEBUG - printf("\n==> FACET %d (%f,%f,%f - %f,%f,%f - %f,%f,%f):\n", facet_idx, - facet.vertex[0].x, facet.vertex[0].y, facet.vertex[0].z, - facet.vertex[1].x, facet.vertex[1].y, facet.vertex[1].z, - facet.vertex[2].x, facet.vertex[2].y, facet.vertex[2].z); - printf("z: min = %.2f, max = %.2f\n", min_z, max_z); - #endif - - // find layer extents - std::vector::const_iterator min_layer, max_layer; - min_layer = std::lower_bound(z.begin(), z.end(), min_z); // first layer whose slice_z is >= min_z - max_layer = std::upper_bound(z.begin() + (min_layer - z.begin()), z.end(), max_z) - 1; // last layer whose slice_z is <= max_z - #ifdef SLIC3R_TRIANGLEMESH_DEBUG - printf("layers: min = %d, max = %d\n", (int)(min_layer - z.begin()), (int)(max_layer - z.begin())); - #endif - - for (std::vector::const_iterator it = min_layer; it != max_layer + 1; ++it) { - std::vector::size_type layer_idx = it - z.begin(); - this->slice_facet(*it / SCALING_FACTOR, facet, facet_idx, min_z, max_z, &(*lines)[layer_idx], lines_mutex); - } - boost::this_thread::interruption_point(); + // find facet extents + const float min_z = fminf(facet.vertex[0].z, fminf(facet.vertex[1].z, facet.vertex[2].z)); + const float max_z = fmaxf(facet.vertex[0].z, fmaxf(facet.vertex[1].z, facet.vertex[2].z)); + + #ifdef SLIC3R_DEBUG + printf("\n==> FACET %d (%f,%f,%f - %f,%f,%f - %f,%f,%f):\n", facet_idx, + facet.vertex[0].x, facet.vertex[0].y, facet.vertex[0].z, + facet.vertex[1].x, facet.vertex[1].y, facet.vertex[1].z, + facet.vertex[2].x, facet.vertex[2].y, facet.vertex[2].z); + printf("z: min = %.2f, max = %.2f\n", min_z, max_z); + #endif + + // find layer extents + std::vector::const_iterator min_layer, max_layer; + min_layer = std::lower_bound(z.begin(), z.end(), min_z); // first layer whose slice_z is >= min_z + max_layer = std::upper_bound(z.begin() + (min_layer - z.begin()), z.end(), max_z) - 1; // last layer whose slice_z is <= max_z + #ifdef SLIC3R_DEBUG + printf("layers: min = %d, max = %d\n", (int)(min_layer - z.begin()), (int)(max_layer - z.begin())); + #endif + + for (std::vector::const_iterator it = min_layer; it != max_layer + 1; ++it) { + std::vector::size_type layer_idx = it - z.begin(); + this->slice_facet(*it / SCALING_FACTOR, facet, facet_idx, min_z, max_z, &(*lines)[layer_idx], lines_mutex); } } @@ -653,23 +626,9 @@ TriangleMeshSlicer::slice_facet(float slice_z, const stl_facet &facet, const int } void -TriangleMeshSlicer::_make_loops_do(std::queue* queue, boost::mutex* queue_mutex, - std::vector* lines, std::vector* layers) const +TriangleMeshSlicer::_make_loops_do(size_t i, std::vector* lines, std::vector* layers) const { - //std::cout << "THREAD STARTED: " << boost::this_thread::get_id() << std::endl; - - while (true) { - size_t layer_id; - { - boost::lock_guard l(*queue_mutex); - if (queue->empty()) return; - layer_id = queue->front(); - queue->pop(); - } - //std::cout << " Layer " << layer_id << " (" << boost::this_thread::get_id() << ")" << std::endl; - this->make_loops((*lines)[layer_id], &(*layers)[layer_id]); - boost::this_thread::interruption_point(); - } + this->make_loops((*lines)[i], &(*layers)[i]); } void diff --git a/xs/src/libslic3r/TriangleMesh.hpp b/xs/src/libslic3r/TriangleMesh.hpp index ec08f0d7c..ff332ed66 100644 --- a/xs/src/libslic3r/TriangleMesh.hpp +++ b/xs/src/libslic3r/TriangleMesh.hpp @@ -3,7 +3,6 @@ #include "libslic3r.h" #include -#include #include #include #include "BoundingBox.hpp" @@ -101,10 +100,8 @@ class TriangleMeshSlicer typedef std::vector< std::vector > t_facets_edges; t_facets_edges facets_edges; stl_vertex* v_scaled_shared; - void _slice_do(std::queue* queue, boost::mutex* queue_mutex, - std::vector* lines, boost::mutex* lines_mutex, const std::vector &z) const; - void _make_loops_do(std::queue* queue, boost::mutex* queue_mutex, - std::vector* lines, std::vector* layers) const; + 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 5aa7866b8..77d30489d 100644 --- a/xs/src/libslic3r/libslic3r.h +++ b/xs/src/libslic3r/libslic3r.h @@ -4,10 +4,13 @@ // this needs to be included early for MSVC (listing it in Build.PL is not enough) #include #include +#include #include #include #include #include +#include +#include #define SLIC3R_FORK_NAME "Slic3r Prusa Edition" #define SLIC3R_VERSION "1.31.6" @@ -40,13 +43,6 @@ typedef long coord_t; typedef double coordf_t; -namespace Slic3r { - -enum Axis { X=0, Y, Z }; - -} -using namespace Slic3r; - /* Implementation of CONFESS("foo"): */ #ifdef _MSC_VER #define CONFESS(...) confess_at(__FILE__, __LINE__, __FUNCTION__, __VA_ARGS__) @@ -91,4 +87,54 @@ inline std::string debug_out_path(const char *name, ...) // Write slices as SVG images into out directory during the 2D processing of the slices. // #define SLIC3R_DEBUG_SLICE_PROCESSING +namespace Slic3r { + +enum Axis { X=0, Y, Z }; + +template +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()) +{ + boost::mutex queue_mutex; + boost::thread_group workers; + for (int i = 0; i < threads_count; i++) + workers.add_thread(new boost::thread(&_parallelize_do, &queue, &queue_mutex, func)); + workers.join_all(); +} + +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); +} + +} // namespace Slic3r + #endif