From c0715866fff208b102b3f7c50fcc8de8e8c50558 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Tue, 22 Jun 2021 09:53:23 +0200 Subject: [PATCH 1/8] Win32 specific: SEH handler on background thread. Catches Windows structured exceptions (hard crashes, segmentation faults...), converts them to Slic3r::HardCrash exceptions and displays the exception using the usual PrusaSlicer way. The SEH handler is installed on the main background slicing thread as of now, therefore hard crashes in TBB worker threads are not handled. --- src/libslic3r/Exception.hpp | 1 + src/slic3r/GUI/BackgroundSlicingProcess.cpp | 145 +++++++++++++++++--- src/slic3r/GUI/BackgroundSlicingProcess.hpp | 25 +++- 3 files changed, 154 insertions(+), 17 deletions(-) diff --git a/src/libslic3r/Exception.hpp b/src/libslic3r/Exception.hpp index fababa47d5..1b8ad50a77 100644 --- a/src/libslic3r/Exception.hpp +++ b/src/libslic3r/Exception.hpp @@ -15,6 +15,7 @@ class Exception : public std::runtime_error { using std::runtime_error::runtime_ SLIC3R_DERIVE_EXCEPTION(CriticalException, Exception); SLIC3R_DERIVE_EXCEPTION(RuntimeError, CriticalException); SLIC3R_DERIVE_EXCEPTION(LogicError, CriticalException); +SLIC3R_DERIVE_EXCEPTION(HardCrash, CriticalException); SLIC3R_DERIVE_EXCEPTION(InvalidArgument, LogicError); SLIC3R_DERIVE_EXCEPTION(OutOfRange, LogicError); SLIC3R_DERIVE_EXCEPTION(IOError, CriticalException); diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 8b3b375131..482900c50f 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -74,11 +74,15 @@ std::pair SlicingProcessCompletedEvent::format_error_message( bool monospace = false; try { this->rethrow_exception(); - } catch (const std::bad_alloc& ex) { + } catch (const std::bad_alloc &ex) { wxString errmsg = GUI::from_u8((boost::format(_utf8(L("%s has encountered an error. It was likely caused by running out of memory. " "If you are sure you have enough RAM on your system, this may also be a bug and we would " "be glad if you reported it."))) % SLIC3R_APP_NAME).str()); error = std::string(errmsg.ToUTF8()) + "\n\n" + std::string(ex.what()); + } catch (const HardCrash &ex) { + error = GUI::format("PrusaSlicer has encountered a fatal error: \"%1%\"", ex.what()) + "\n\n" + + _u8L("Please save your project and restart PrusaSlicer. " + "We would be glad if you reported the issue."); } catch (PlaceholderParserError &ex) { error = ex.what(); monospace = true; @@ -277,19 +281,11 @@ void BackgroundSlicingProcess::thread_proc() m_state = STATE_RUNNING; lck.unlock(); std::exception_ptr exception; - try { - assert(m_print != nullptr); - switch(m_print->technology()) { - case ptFFF: this->process_fff(); break; - case ptSLA: this->process_sla(); break; - default: m_print->process(); break; - } - } catch (CanceledException & /* ex */) { - // Canceled, this is all right. - assert(m_print->canceled()); - } catch (...) { - exception = std::current_exception(); - } +#ifdef _WIN32 + this->call_process_seh_throw(exception); +#else + this->call_process(exception); +#endif m_print->finalize(); lck.lock(); m_state = m_print->canceled() ? STATE_CANCELED : STATE_FINISHED; @@ -312,7 +308,118 @@ void BackgroundSlicingProcess::thread_proc() // End of the background processing thread. The UI thread should join m_thread now. } -void BackgroundSlicingProcess::thread_proc_safe() +#ifdef _WIN32 +// Only these SEH exceptions will be catched and turned into Slic3r::HardCrash C++ exceptions. +static bool is_win32_seh_harware_exception(unsigned long ex) throw() { + return + ex == STATUS_ACCESS_VIOLATION || + ex == STATUS_DATATYPE_MISALIGNMENT || + ex == STATUS_FLOAT_DIVIDE_BY_ZERO || + ex == STATUS_FLOAT_OVERFLOW || + ex == STATUS_FLOAT_UNDERFLOW || +#ifdef STATUS_FLOATING_RESEVERED_OPERAND + ex == STATUS_FLOATING_RESEVERED_OPERAND || +#endif // STATUS_FLOATING_RESEVERED_OPERAND + ex == STATUS_ILLEGAL_INSTRUCTION || + ex == STATUS_PRIVILEGED_INSTRUCTION || + ex == STATUS_INTEGER_DIVIDE_BY_ZERO || + ex == STATUS_INTEGER_OVERFLOW || + ex == STATUS_STACK_OVERFLOW; +} + +// Rethrow some SEH exceptions as Slic3r::HardCrash C++ exceptions. +static void rethrow_seh_exception(unsigned long win32_seh_catched) +{ + if (win32_seh_catched) { + // Rethrow SEH exception as Slicer::HardCrash. + if (win32_seh_catched == STATUS_ACCESS_VIOLATION || win32_seh_catched == STATUS_DATATYPE_MISALIGNMENT) + throw Slic3r::HardCrash(_u8L("Access violation")); + if (win32_seh_catched == STATUS_ILLEGAL_INSTRUCTION || win32_seh_catched == STATUS_PRIVILEGED_INSTRUCTION) + throw Slic3r::HardCrash(_u8L("Illegal instruction")); + if (win32_seh_catched == STATUS_FLOAT_DIVIDE_BY_ZERO || win32_seh_catched == STATUS_INTEGER_DIVIDE_BY_ZERO) + throw Slic3r::HardCrash(_u8L("Divide by zero")); + if (win32_seh_catched == STATUS_FLOAT_OVERFLOW || win32_seh_catched == STATUS_INTEGER_OVERFLOW) + throw Slic3r::HardCrash(_u8L("Overflow")); + if (win32_seh_catched == STATUS_FLOAT_UNDERFLOW) + throw Slic3r::HardCrash(_u8L("Underflow")); +#ifdef STATUS_FLOATING_RESEVERED_OPERAND + if (win32_seh_catched == STATUS_FLOATING_RESEVERED_OPERAND) + throw Slic3r::HardCrash(_u8L("Floating reserved operand")); +#endif // STATUS_FLOATING_RESEVERED_OPERAND + if (win32_seh_catched == STATUS_STACK_OVERFLOW) + throw Slic3r::HardCrash(_u8L("Stack overflow")); + } +} + +// Wrapper for Win32 structured exceptions. Win32 structured exception blocks and C++ exception blocks cannot be mixed in the same function. +unsigned long BackgroundSlicingProcess::call_process_seh(std::exception_ptr &ex) throw() +{ + unsigned long win32_seh_catched = 0; + __try { + this->call_process(ex); + } __except (is_win32_seh_harware_exception(GetExceptionCode())) { + win32_seh_catched = GetExceptionCode(); + } + return win32_seh_catched; +} +void BackgroundSlicingProcess::call_process_seh_throw(std::exception_ptr &ex) throw() +{ + unsigned long win32_seh_catched = this->call_process_seh(ex); + if (win32_seh_catched) { + // Rethrow SEH exception as Slicer::HardCrash. + try { + rethrow_seh_exception(win32_seh_catched); + } catch (...) { + ex = std::current_exception(); + } + } +} +#endif // _WIN32 + +void BackgroundSlicingProcess::call_process(std::exception_ptr &ex) throw() +{ + try { + assert(m_print != nullptr); + switch (m_print->technology()) { + case ptFFF: this->process_fff(); break; + case ptSLA: this->process_sla(); break; + default: m_print->process(); break; + } + } catch (CanceledException& /* ex */) { + // Canceled, this is all right. + assert(m_print->canceled()); + ex = std::current_exception(); + } catch (...) { + ex = std::current_exception(); + } +} + +#ifdef _WIN32 +unsigned long BackgroundSlicingProcess::thread_proc_safe_seh() throw() +{ + unsigned long win32_seh_catched = 0; + __try { + this->thread_proc_safe(); + } __except (is_win32_seh_harware_exception(GetExceptionCode())) { + win32_seh_catched = GetExceptionCode(); + } + return win32_seh_catched; +} +void BackgroundSlicingProcess::thread_proc_safe_seh_throw() throw() +{ + unsigned long win32_seh_catched = this->thread_proc_safe_seh(); + if (win32_seh_catched) { + // Rethrow SEH exception as Slicer::HardCrash. + try { + rethrow_seh_exception(win32_seh_catched); + } catch (...) { + wxTheApp->OnUnhandledException(); + } + } +} +#endif // _WIN32 + +void BackgroundSlicingProcess::thread_proc_safe() throw() { try { this->thread_proc(); @@ -349,7 +456,13 @@ bool BackgroundSlicingProcess::start() if (m_state == STATE_INITIAL) { // The worker thread is not running yet. Start it. assert(! m_thread.joinable()); - m_thread = create_thread([this]{this->thread_proc_safe();}); + m_thread = create_thread([this]{ +#ifdef _WIN32 + this->thread_proc_safe_seh_throw(); +#else // _WIN32 + this->thread_proc_safe(); +#endif // _WIN32 + }); // Wait until the worker thread is ready to execute the background processing task. m_condition.wait(lck, [this](){ return m_state == STATE_IDLE; }); } diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index 12bf6fe021..6f5cd88521 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -174,7 +174,16 @@ public: private: void thread_proc(); - void thread_proc_safe(); + // Calls thread_proc(), catches all C++ exceptions and shows them using wxApp::OnUnhandledException(). + void thread_proc_safe() throw(); +#ifdef _WIN32 + // Wrapper for Win32 structured exceptions. Win32 structured exception blocks and C++ exception blocks cannot be mixed in the same function. + // Catch a SEH exception and return its ID or zero if no SEH exception has been catched. + unsigned long thread_proc_safe_seh() throw(); + // Calls thread_proc_safe_seh(), rethrows a Slic3r::HardCrash exception based on SEH exception + // returned by thread_proc_safe_seh() and lets wxApp::OnUnhandledException() display it. + void thread_proc_safe_seh_throw() throw(); +#endif // _WIN32 void join_background_thread(); // To be called by Print::apply() through the Print::m_cancel_callback to stop the background // processing before changing any data of running or finalized milestones. @@ -187,6 +196,20 @@ private: // Temporary: for mimicking the fff file export behavior with the raster output void process_sla(); + // Call Print::process() and catch all exceptions into ex, thus no exception could be thrown + // by this method. This exception behavior is required to combine C++ exceptions with Win32 SEH exceptions + // on the same thread. + void call_process(std::exception_ptr &ex) throw(); + +#ifdef _WIN32 + // Wrapper for Win32 structured exceptions. Win32 structured exception blocks and C++ exception blocks cannot be mixed in the same function. + // Catch a SEH exception and return its ID or zero if no SEH exception has been catched. + unsigned long call_process_seh(std::exception_ptr &ex) throw(); + // Calls call_process_seh(), rethrows a Slic3r::HardCrash exception based on SEH exception + // returned by call_process_seh(). + void call_process_seh_throw(std::exception_ptr &ex) throw(); +#endif // _WIN32 + // Currently active print. It is one of m_fff_print and m_sla_print. PrintBase *m_print = nullptr; // Non-owned pointers to Print instances. From d3233d66fb1ba84643dbcc415e4a29d79b164c6b Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Tue, 22 Jun 2021 10:05:03 +0200 Subject: [PATCH 2/8] Fixing previous commit --- src/slic3r/GUI/BackgroundSlicingProcess.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 482900c50f..816365d90b 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -2,6 +2,7 @@ #include "GUI_App.hpp" #include "GUI.hpp" #include "MainFrame.hpp" +#include "format.hpp" #include #include From 49c6ce76d0552112855067822f6a435d8a0b9797 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 22 Jun 2021 11:23:19 +0200 Subject: [PATCH 3/8] Search for suitable rotation when arranging items larger than the bed --- .../include/libnest2d/utils/rotcalipers.hpp | 242 +++++++++++++----- src/libslic3r/Arrange.cpp | 21 +- 2 files changed, 191 insertions(+), 72 deletions(-) diff --git a/src/libnest2d/include/libnest2d/utils/rotcalipers.hpp b/src/libnest2d/include/libnest2d/utils/rotcalipers.hpp index 76f91ba0cf..e703a38015 100644 --- a/src/libnest2d/include/libnest2d/utils/rotcalipers.hpp +++ b/src/libnest2d/include/libnest2d/utils/rotcalipers.hpp @@ -90,12 +90,29 @@ inline R rectarea(const Pt& w, const std::array& rect) return rectarea(w, *rect[0], *rect[1], *rect[2], *rect[3]); } +template, class R = TCompute> +inline R rectarea(const Pt& w, // the axis + const Unit& a, + const Unit& b) +{ + R m = R(a) / pl::magnsq(w); + m = m * b; + return m; +}; + +template +inline R rectarea(const RotatedBox &rb) +{ + return rectarea(rb.axis(), rb.bottom_extent(), rb.right_extent()); +}; + // This function is only applicable to counter-clockwise oriented convex // polygons where only two points can be collinear witch each other. -template , - class Ratio = TCompute> -RotatedBox, Unit> minAreaBoundingBox(const RawShape& sh) +template , + class Ratio = TCompute, + class VisitFn> +void rotcalipers(const RawShape& sh, VisitFn &&visitfn) { using Point = TPoint; using Iterator = typename TContour::const_iterator; @@ -104,21 +121,21 @@ RotatedBox, Unit> minAreaBoundingBox(const RawShape& sh) // Get the first and the last vertex iterator auto first = sl::cbegin(sh); auto last = std::prev(sl::cend(sh)); - + // Check conditions and return undefined box if input is not sane. - if(last == first) return {}; + if(last == first) return; if(getX(*first) == getX(*last) && getY(*first) == getY(*last)) --last; - if(last - first < 2) return {}; - + if(last - first < 2) return; + RawShape shcpy; // empty at this point - { + { Point p = *first, q = *std::next(first), r = *last; - + // Determine orientation from first 3 vertex (should be consistent) Unit d = (Unit(getY(q)) - getY(p)) * (Unit(getX(r)) - getX(p)) - (Unit(getX(q)) - getX(p)) * (Unit(getY(r)) - getY(p)); - - if(d > 0) { + + if(d > 0) { // The polygon is clockwise. A flip is needed (for now) sl::reserve(shcpy, last - first); auto it = last; while(it != first) sl::addVertex(shcpy, *it--); @@ -126,69 +143,69 @@ RotatedBox, Unit> minAreaBoundingBox(const RawShape& sh) first = sl::cbegin(shcpy); last = std::prev(sl::cend(shcpy)); } } - + // Cyclic iterator increment auto inc = [&first, &last](Iterator& it) { - if(it == last) it = first; else ++it; + if(it == last) it = first; else ++it; }; - + // Cyclic previous iterator - auto prev = [&first, &last](Iterator it) { - return it == first ? last : std::prev(it); + auto prev = [&first, &last](Iterator it) { + return it == first ? last : std::prev(it); }; - + // Cyclic next iterator auto next = [&first, &last](Iterator it) { - return it == last ? first : std::next(it); + return it == last ? first : std::next(it); }; - - // Establish initial (axis aligned) rectangle support verices by determining + + // Establish initial (axis aligned) rectangle support verices by determining // polygon extremes: - + auto it = first; Iterator minX = it, maxX = it, minY = it, maxY = it; - + do { // Linear walk through the vertices and save the extreme positions - + Point v = *it, d = v - *minX; if(getX(d) < 0 || (getX(d) == 0 && getY(d) < 0)) minX = it; - + d = v - *maxX; if(getX(d) > 0 || (getX(d) == 0 && getY(d) > 0)) maxX = it; - + d = v - *minY; if(getY(d) < 0 || (getY(d) == 0 && getX(d) > 0)) minY = it; - + d = v - *maxY; if(getY(d) > 0 || (getY(d) == 0 && getX(d) < 0)) maxY = it; - + } while(++it != std::next(last)); - + // Update the vertices defining the bounding rectangle. The rectangle with - // the smallest rotation is selected and the supporting vertices are + // the smallest rotation is selected and the supporting vertices are // returned in the 'rect' argument. auto update = [&next, &inc] - (const Point& w, std::array& rect) + (const Point& w, std::array& rect) { Iterator B = rect[0], Bn = next(B); Iterator R = rect[1], Rn = next(R); Iterator T = rect[2], Tn = next(T); Iterator L = rect[3], Ln = next(L); - + Point b = *Bn - *B, r = *Rn - *R, t = *Tn - *T, l = *Ln - *L; Point pw = perp(w); using Pt = Point; - + Unit dotwpb = dot( w, b), dotwpr = dot(-pw, r); Unit dotwpt = dot(-w, t), dotwpl = dot( pw, l); Unit dw = magnsq(w); - + std::array angles; angles[0] = (Ratio(dotwpb) / magnsq(b)) * dotwpb; angles[1] = (Ratio(dotwpr) / magnsq(r)) * dotwpr; angles[2] = (Ratio(dotwpt) / magnsq(t)) * dotwpt; angles[3] = (Ratio(dotwpl) / magnsq(l)) * dotwpl; - + using AngleIndex = std::pair; std::vector A; A.reserve(4); @@ -196,65 +213,84 @@ RotatedBox, Unit> minAreaBoundingBox(const RawShape& sh) if(rect[i] != rect[j] && angles[i] < dw) { auto iv = std::make_pair(angles[i], i); auto it = std::lower_bound(A.begin(), A.end(), iv, - [](const AngleIndex& ai, - const AngleIndex& aj) - { - return ai.first > aj.first; + [](const AngleIndex& ai, + const AngleIndex& aj) + { + return ai.first > aj.first; }); - + A.insert(it, iv); } } - + // The polygon is supposed to be a rectangle. if(A.empty()) return false; - + auto amin = A.front().first; auto imin = A.front().second; for(auto& a : A) if(a.first == amin) inc(rect[a.second]); - + std::rotate(rect.begin(), rect.begin() + imin, rect.end()); - + return true; }; - + Point w(1, 0); - Point w_min = w; - Ratio minarea((Unit(getX(*maxX)) - getX(*minX)) * - (Unit(getY(*maxY)) - getY(*minY))); - std::array rect = {minY, maxX, maxY, minX}; - std::array minrect = rect; - + + { + Unit a = dot(w, *rect[1] - *rect[3]); + Unit b = dot(-perp(w), *rect[2] - *rect[0]); + if (!visitfn(RotatedBox{w, a, b})) + return; + } + // An edge might be examined twice in which case the algorithm terminates. size_t c = 0, count = last - first + 1; std::vector edgemask(count, false); - - while(c++ < count) - { + + while(c++ < count) + { // Update the support vertices, if cannot be updated, break the cycle. if(! update(w, rect)) break; - + size_t eidx = size_t(rect[0] - first); - + if(edgemask[eidx]) break; edgemask[eidx] = true; - + // get the unnormalized direction vector w = *rect[0] - *prev(rect[0]); - - // get the area of the rotated rectangle - Ratio rarea = rectarea(w, rect); - - // Update min area and the direction of the min bounding box; - if(rarea <= minarea) { w_min = w; minarea = rarea; minrect = rect; } + + Unit a = dot(w, *rect[1] - *rect[3]); + Unit b = dot(-perp(w), *rect[2] - *rect[0]); + if (!visitfn(RotatedBox{w, a, b})) + break; } - - Unit a = dot(w_min, *minrect[1] - *minrect[3]); - Unit b = dot(-perp(w_min), *minrect[2] - *minrect[0]); - RotatedBox bb(w_min, a, b); - - return bb; +} + +// This function is only applicable to counter-clockwise oriented convex +// polygons where only two points can be collinear witch each other. +template , + class Ratio = TCompute> +RotatedBox, Unit> minAreaBoundingBox(const S& sh) +{ + RotatedBox, Unit> minbox; + Ratio minarea = std::numeric_limits::max(); + auto minfn = [&minarea, &minbox](const RotatedBox, Unit> &rbox){ + Ratio area = rectarea(rbox); + if (area <= minarea) { + minarea = area; + minbox = rbox; + } + + return true; // continue search + }; + + rotcalipers(sh, minfn); + + return minbox; } template Radians minAreaBoundingBoxRotation(const RawShape& sh) @@ -262,7 +298,75 @@ template Radians minAreaBoundingBoxRotation(const RawShape& sh) return minAreaBoundingBox(sh).angleToX(); } +// Function to find a rotation for a shape that makes it fit into a box. +// +// The method is based on finding a pair of rotations from the rotating calipers +// algorithm such that the aspect ratio is changing from being smaller than +// that of the target to being bigger or vice versa. So that the correct +// AR is somewhere between the obtained pair of angles. Then bisecting that +// interval is sufficient to find the correct angle. +// +// The argument eps is the absolute error limit for the searched angle interval. +template, class Ratio = TCompute> +Radians fitIntoBoxRotation(const S &shape, const _Box> &box, Radians eps = 1e-4) +{ + constexpr auto get_aspect_r = [](const auto &b) -> double { + return double(b.width()) / b.height(); + }; + auto aspect_r = get_aspect_r(box); + + RotatedBox, Unit> prev_rbox; + Radians a_from = 0., a_to = 0.; + auto visitfn = [&](const RotatedBox, Unit> &rbox) { + bool lower_prev = get_aspect_r(prev_rbox) < aspect_r; + bool lower_current = get_aspect_r(rbox) < aspect_r; + + if (lower_prev != lower_current) { + a_from = prev_rbox.angleToX(); + a_to = rbox.angleToX(); + return false; + } + + return true; + }; + + rotcalipers(shape, visitfn); + + auto rot_shape_bb = [&shape](Radians r) { + auto s = shape; + sl::rotate(s, r); + return sl::boundingBox(s); + }; + + auto rot_aspect_r = [&rot_shape_bb, &get_aspect_r](Radians r) { + return get_aspect_r(rot_shape_bb(r)); + }; + + // Lets bisect the retrieved interval where the correct aspect ratio is. + double ar_from = rot_aspect_r(a_from); + auto would_fit = [&box](const _Box> &b) { + return b.width() < box.width() && b.height() < box.height(); + }; + + Radians middle = (a_from + a_to) / 2.; + _Box> box_middle = rot_shape_bb(middle); + while (!would_fit(box_middle) && std::abs(a_to - a_from) > eps) + { + double ar_middle = get_aspect_r(box_middle); + if ((ar_from < aspect_r) != (ar_middle < aspect_r)) + a_to = middle; + else + a_from = middle; + + ar_from = rot_aspect_r(a_from); + middle = (a_from + a_to) / 2.; + box_middle = rot_shape_bb(middle); + } + + return middle; } +} // namespace libnest2d + #endif // ROTCALIPERS_HPP diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp index 9602ebdbd1..bf2a219d0d 100644 --- a/src/libslic3r/Arrange.cpp +++ b/src/libslic3r/Arrange.cpp @@ -379,7 +379,7 @@ public: }); if (stopcond) m_pck.stopCondition(stopcond); - + m_pck.configure(m_pconf); } @@ -472,6 +472,12 @@ template Radians min_area_boundingbox_rotation(const S &sh) .angleToX(); } +template +Radians fit_into_box_rotation(const S &sh, const _Box> &box) +{ + return fitIntoBoxRotation, boost::rational>(sh, box); +} + template // Arrange for arbitrary bin type void _arrange( std::vector & shapes, @@ -509,10 +515,19 @@ void _arrange( // Use the minimum bounding box rotation as a starting point. // TODO: This only works for convex hull. If we ever switch to concave // polygon nesting, a convex hull needs to be calculated. - if (params.allow_rotations) - for (auto &itm : shapes) + if (params.allow_rotations) { + for (auto &itm : shapes) { itm.rotation(min_area_boundingbox_rotation(itm.rawShape())); + // If the item is too big, try to find a rotation that makes it fit + if constexpr (std::is_same_v) { + auto bb = itm.boundingBox(); + if (bb.width() >= bin.width() || bb.height() >= bin.height()) + itm.rotate(fit_into_box_rotation(itm.transformedShape(), bin)); + } + } + } + arranger(inp.begin(), inp.end()); for (Item &itm : inp) itm.inflate(-infl); } From 77c4aebebeba1c4790f283339bc6037b9b7253c0 Mon Sep 17 00:00:00 2001 From: rtyr <36745189+rtyr@users.noreply.github.com> Date: Tue, 22 Jun 2021 11:23:39 +0200 Subject: [PATCH 4/8] 1.4.0-alpha1 Added new SL1S resin profiles. --- resources/profiles/PrusaResearch.idx | 1 + resources/profiles/PrusaResearch.ini | 65 ++++++++++++++++++---------- 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/resources/profiles/PrusaResearch.idx b/resources/profiles/PrusaResearch.idx index 0ce99a416b..c6b22d1eab 100644 --- a/resources/profiles/PrusaResearch.idx +++ b/resources/profiles/PrusaResearch.idx @@ -1,4 +1,5 @@ min_slic3r_version = 2.4.0-alpha0 +1.4.0-alpha1 Added new SL1S resin profiles. 1.4.0-alpha0 Bumped up config version. 1.3.0-alpha2 Added SL1S SPEED profiles. 1.3.0-alpha1 Added Prusament PCCF. Increased travel acceleration for Prusa MINI. Updated start g-code for Prusa MINI. Added multiple add:north and Extrudr filament profiles. Updated Z travel speed values. diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini index 3bc4a039bb..c19cc4a0da 100644 --- a/resources/profiles/PrusaResearch.ini +++ b/resources/profiles/PrusaResearch.ini @@ -5,7 +5,7 @@ name = Prusa Research # Configuration version of this file. Config file will only be installed, if the config_version differs. # This means, the server may force the PrusaSlicer configuration to be downgraded. -config_version = 1.4.0-alpha0 +config_version = 1.4.0-alpha1 # Where to get the updates from? config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaResearch/ changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1% @@ -5426,13 +5426,6 @@ initial_exposure_time = 25 material_type = Tough material_vendor = Made for Prusa -[sla_material:Prusa Polymers Orange @0.025 SL1S] -inherits = *0.025_sl1s* -exposure_time = 1.8 -initial_exposure_time = 25 -material_type = Tough -material_vendor = Prusa Polymers - [sla_material:3DM-ABS Orange @0.025 SL1S] inherits = *0.025_sl1s* exposure_time = 1.8 @@ -5461,6 +5454,20 @@ initial_exposure_time = 25 material_type = Tough material_vendor = Peopoly +[sla_material:Peopoly Deft White @0.025 SL1S] +inherits = *0.025_sl1s* +exposure_time = 1.8 +initial_exposure_time = 25 +material_type = Tough +material_vendor = Peopoly + +[sla_material:Peopoly Neo Clear @0.025 SL1S] +inherits = *0.025_sl1s* +exposure_time = 1.8 +initial_exposure_time = 25 +material_type = Tough +material_vendor = Peopoly + ## 0.05 SL1S [sla_material:Prusa Orange Tough @0.05 SL1S] @@ -5547,13 +5554,6 @@ initial_exposure_time = 25 material_type = Tough material_vendor = Made for Prusa -[sla_material:Prusa Polymers Orange @0.05 SL1S] -inherits = *0.05_sl1s* -exposure_time = 2 -initial_exposure_time = 25 -material_type = Tough -material_vendor = Prusa Polymers - [sla_material:3DM-ABS Orange @0.05 SL1S] inherits = *0.05_sl1s* exposure_time = 2.6 @@ -5582,6 +5582,20 @@ initial_exposure_time = 25 material_type = Tough material_vendor = Peopoly +[sla_material:Peopoly Deft White @0.05 SL1S] +inherits = *0.05_sl1s* +exposure_time = 2 +initial_exposure_time = 25 +material_type = Tough +material_vendor = Peopoly + +[sla_material:Peopoly Neo Clear @0.05 SL1S] +inherits = *0.05_sl1s* +exposure_time = 2 +initial_exposure_time = 25 +material_type = Tough +material_vendor = Peopoly + ## 0.1 SL1S [sla_material:Prusa Orange Tough @0.1 SL1S] @@ -5668,13 +5682,6 @@ initial_exposure_time = 25 material_type = Tough material_vendor = Made for Prusa -[sla_material:Prusa Polymers Orange @0.1 SL1S] -inherits = *0.1_sl1s* -exposure_time = 2.6 -initial_exposure_time = 25 -material_type = Tough -material_vendor = Prusa Polymers - [sla_material:3DM-ABS Orange @0.1 SL1S] inherits = *0.1_sl1s* exposure_time = 3 @@ -5703,6 +5710,20 @@ initial_exposure_time = 25 material_type = Tough material_vendor = Peopoly +[sla_material:Peopoly Deft White @0.1 SL1S] +inherits = *0.1_sl1s* +exposure_time = 2.6 +initial_exposure_time = 25 +material_type = Tough +material_vendor = Peopoly + +[sla_material:Peopoly Neo Clear @0.1 SL1S] +inherits = *0.1_sl1s* +exposure_time = 2.6 +initial_exposure_time = 25 +material_type = Tough +material_vendor = Peopoly + [printer:*common*] printer_technology = FFF bed_shape = 0x0,250x0,250x210,0x210 From 48cd3b21b64ede649a0e5e4e9d0fdf150e48d470 Mon Sep 17 00:00:00 2001 From: rtyr <36745189+rtyr@users.noreply.github.com> Date: Tue, 22 Jun 2021 12:19:21 +0200 Subject: [PATCH 5/8] Updated Prusa MINI machine limits. --- resources/profiles/PrusaResearch.idx | 1 + resources/profiles/PrusaResearch.ini | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/resources/profiles/PrusaResearch.idx b/resources/profiles/PrusaResearch.idx index c6b22d1eab..bf92297530 100644 --- a/resources/profiles/PrusaResearch.idx +++ b/resources/profiles/PrusaResearch.idx @@ -1,4 +1,5 @@ min_slic3r_version = 2.4.0-alpha0 +1.4.0-alpha2 Updated Prusa MINI machine limits. 1.4.0-alpha1 Added new SL1S resin profiles. 1.4.0-alpha0 Bumped up config version. 1.3.0-alpha2 Added SL1S SPEED profiles. diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini index c19cc4a0da..3dd9100570 100644 --- a/resources/profiles/PrusaResearch.ini +++ b/resources/profiles/PrusaResearch.ini @@ -5,7 +5,7 @@ name = Prusa Research # Configuration version of this file. Config file will only be installed, if the config_version differs. # This means, the server may force the PrusaSlicer configuration to be downgraded. -config_version = 1.4.0-alpha1 +config_version = 1.4.0-alpha2 # Where to get the updates from? config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaResearch/ changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1% @@ -6351,8 +6351,8 @@ machine_max_acceleration_e = 5000 machine_max_acceleration_extruding = 1250 machine_max_acceleration_retracting = 1250 machine_max_acceleration_travel = 2500 -machine_max_acceleration_x = 1250 -machine_max_acceleration_y = 1250 +machine_max_acceleration_x = 2500 +machine_max_acceleration_y = 2500 machine_max_acceleration_z = 400 machine_max_feedrate_e = 80 machine_max_feedrate_x = 180 From 2096a6dbbff83a22eb5c386bad7f85f7c10a93fb Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 22 Jun 2021 18:13:35 +0200 Subject: [PATCH 6/8] Fix error reporting when cgal mesh boolean crashes. Change error report when catching SEH on cgal mesh boolean. --- src/libslic3r/MeshBoolean.cpp | 6 +++++- src/libslic3r/SLAPrintSteps.cpp | 3 +-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/MeshBoolean.cpp b/src/libslic3r/MeshBoolean.cpp index f58ae0bfe0..599ac47845 100644 --- a/src/libslic3r/MeshBoolean.cpp +++ b/src/libslic3r/MeshBoolean.cpp @@ -208,16 +208,20 @@ static bool _cgal_intersection(CGALMesh &A, CGALMesh &B, CGALMesh &R) template void _cgal_do(Op &&op, CGALMesh &A, CGALMesh &B) { bool success = false; + bool hw_fail = false; try { CGALMesh result; try_catch_signal({SIGSEGV, SIGFPE}, [&success, &A, &B, &result, &op] { success = op(A, B, result); - }, [&] { success = false; }); + }, [&] { hw_fail = true; }); A = std::move(result); // In-place operation does not work } catch (...) { success = false; } + if (hw_fail) + throw Slic3r::HardCrash("CGAL mesh boolean operation crashed."); + if (! success) throw Slic3r::RuntimeError("CGAL mesh boolean operation failed."); } diff --git a/src/libslic3r/SLAPrintSteps.cpp b/src/libslic3r/SLAPrintSteps.cpp index b267116e98..4a8d0d4bef 100644 --- a/src/libslic3r/SLAPrintSteps.cpp +++ b/src/libslic3r/SLAPrintSteps.cpp @@ -453,8 +453,7 @@ void SLAPrint::Steps::drill_holes(SLAPrintObject &po) sla::remove_inside_triangles(mesh_view, interior, exclude_mask); } - - } catch (const std::runtime_error &) { + } catch (const Slic3r::RuntimeError &) { throw Slic3r::SlicingError(L( "Drilling holes into the mesh failed. " "This is usually caused by broken model. Try to fix it first.")); From 7a7108b2aded9630e2587a20ad9355e9abf041b1 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 23 Jun 2021 10:30:15 +0200 Subject: [PATCH 7/8] Fixed warning --- src/slic3r/GUI/MainFrame.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 3b902879c2..9c7533acd1 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -658,7 +658,7 @@ void MainFrame::init_tabpanel() #endif #if ENABLE_VALIDATE_CUSTOM_GCODE if (int old_selection = e.GetOldSelection(); - old_selection != wxNOT_FOUND && old_selection < m_tabpanel->GetPageCount()) { + old_selection != wxNOT_FOUND && old_selection < static_cast(m_tabpanel->GetPageCount())) { Tab* old_tab = dynamic_cast(m_tabpanel->GetPage(old_selection)); if (old_tab) old_tab->validate_custom_gcodes(); From e13535f822b5efe0e3b471bc366e8d3ea96059d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Ber=C3=A1nek?= Date: Wed, 23 Jun 2021 11:48:48 +0200 Subject: [PATCH 8/8] drop deprecated TBB components (#6590) Quite some time ago, many of the TBB components were deprecated in favor of their near-equivalents in the STL or, in the case of task_scheduler_init, were broken up and reconstituted under a less ad-hoc logic. Every time a header file marked deprecated gets included, a rather loud warning is emitted, which leads to a complete TBB's domination over the stderr stream during build time, making it harder to notice _legitimate_ warnings. Instead of merely muting the output with TBB_SUPPRESS_DEPRECATED_MESSAGES, perform a genuine migration away from the deprecated components with the added benefit of achieving a source compatibility with oneTBB, the successor to TBB which has dropped the deprecated API for good. What got replaced for what? | Deprecated | Replacement | | ------------------------------------- | --------------------------------------------- | | `tbb::atomic` | `std::atomic` | | `tbb::mutex` | `std::mutex` | | `tbb::mutex::scoped_lock` | `std::scoped_lock` | | `tbb::mutex::scoped_lock` (empty) | `std::unique_lock` (deferred) | | `tbb::task_scheduler_init` | `tbb::global_control` | | `tbb::this_thread` | `std::this_thread` | Signed-off-by: Roman Beranek --- src/libslic3r/Execution/ExecutionTBB.hpp | 5 +-- src/libslic3r/Print.cpp | 4 +-- src/libslic3r/PrintApply.cpp | 2 +- src/libslic3r/PrintBase.cpp | 2 +- src/libslic3r/PrintBase.hpp | 40 ++++++++++----------- src/libslic3r/PrintObject.cpp | 1 - src/libslic3r/SLA/SupportTree.cpp | 3 -- src/libslic3r/SLAPrint.cpp | 10 +++--- src/libslic3r/SupportMaterial.cpp | 1 - src/libslic3r/Thread.cpp | 12 +++---- src/libslic3r/pchheader.hpp | 3 -- src/libslic3r/utils.cpp | 6 ++-- src/slic3r/GUI/BackgroundSlicingProcess.cpp | 6 ++-- src/slic3r/GUI/InstanceCheck.hpp | 2 +- src/slic3r/GUI/Mouse3DController.cpp | 38 ++++++++++---------- src/slic3r/GUI/Mouse3DController.hpp | 10 +++--- src/slic3r/GUI/RemovableDriveManager.cpp | 24 ++++++------- src/slic3r/GUI/RemovableDriveManager.hpp | 6 ++-- 18 files changed, 80 insertions(+), 95 deletions(-) diff --git a/src/libslic3r/Execution/ExecutionTBB.hpp b/src/libslic3r/Execution/ExecutionTBB.hpp index cf6373c466..2250b8e322 100644 --- a/src/libslic3r/Execution/ExecutionTBB.hpp +++ b/src/libslic3r/Execution/ExecutionTBB.hpp @@ -1,8 +1,9 @@ #ifndef EXECUTIONTBB_HPP #define EXECUTIONTBB_HPP +#include + #include -#include #include #include #include @@ -34,7 +35,7 @@ private: public: using SpinningMutex = tbb::spin_mutex; - using BlockingMutex = tbb::mutex; + using BlockingMutex = std::mutex; template static void for_each(const ExecutionTBB &, diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 4561de247d..dca11a9209 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -36,7 +36,7 @@ PrintRegion::PrintRegion(PrintRegionConfig &&config) : PrintRegion(std::move(con void Print::clear() { - tbb::mutex::scoped_lock lock(this->state_mutex()); + std::scoped_lock lock(this->state_mutex()); // The following call should stop background processing if it is running. this->invalidate_all_steps(); for (PrintObject *object : m_objects) @@ -252,7 +252,7 @@ bool Print::is_step_done(PrintObjectStep step) const { if (m_objects.empty()) return false; - tbb::mutex::scoped_lock lock(this->state_mutex()); + std::scoped_lock lock(this->state_mutex()); for (const PrintObject *object : m_objects) if (! object->is_step_done_unguarded(step)) return false; diff --git a/src/libslic3r/PrintApply.cpp b/src/libslic3r/PrintApply.cpp index 698edbf3b6..a3b96bfe14 100644 --- a/src/libslic3r/PrintApply.cpp +++ b/src/libslic3r/PrintApply.cpp @@ -915,7 +915,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ update_apply_status(false); // Grab the lock for the Print / PrintObject milestones. - tbb::mutex::scoped_lock lock(this->state_mutex()); + std::scoped_lock lock(this->state_mutex()); // The following call may stop the background processing. if (! print_diff.empty()) diff --git a/src/libslic3r/PrintBase.cpp b/src/libslic3r/PrintBase.cpp index d129aaad2b..c4b6b7ccea 100644 --- a/src/libslic3r/PrintBase.cpp +++ b/src/libslic3r/PrintBase.cpp @@ -104,7 +104,7 @@ void PrintBase::status_update_warnings(int step, PrintStateBase::WarningLevel /* printf("%s warning: %s\n", print_object ? "print_object" : "print", message.c_str()); } -tbb::mutex& PrintObjectBase::state_mutex(PrintBase *print) +std::mutex& PrintObjectBase::state_mutex(PrintBase *print) { return print->state_mutex(); } diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp index e0aa56ba5a..8cb997c771 100644 --- a/src/libslic3r/PrintBase.hpp +++ b/src/libslic3r/PrintBase.hpp @@ -6,12 +6,8 @@ #include #include #include - -// tbb/mutex.h includes Windows, which in turn defines min/max macros. Convince Windows.h to not define these min/max macros. -#ifndef NOMINMAX - #define NOMINMAX -#endif -#include "tbb/mutex.h" +#include +#include #include "ObjectID.hpp" #include "Model.hpp" @@ -84,23 +80,23 @@ class PrintState : public PrintStateBase public: PrintState() {} - StateWithTimeStamp state_with_timestamp(StepType step, tbb::mutex &mtx) const { - tbb::mutex::scoped_lock lock(mtx); + StateWithTimeStamp state_with_timestamp(StepType step, std::mutex &mtx) const { + std::scoped_lock lock(mtx); StateWithTimeStamp state = m_state[step]; return state; } - StateWithWarnings state_with_warnings(StepType step, tbb::mutex &mtx) const { - tbb::mutex::scoped_lock lock(mtx); + StateWithWarnings state_with_warnings(StepType step, std::mutex &mtx) const { + std::scoped_lock lock(mtx); StateWithWarnings state = m_state[step]; return state; } - bool is_started(StepType step, tbb::mutex &mtx) const { + bool is_started(StepType step, std::mutex &mtx) const { return this->state_with_timestamp(step, mtx).state == STARTED; } - bool is_done(StepType step, tbb::mutex &mtx) const { + bool is_done(StepType step, std::mutex &mtx) const { return this->state_with_timestamp(step, mtx).state == DONE; } @@ -121,8 +117,8 @@ public: // This is necessary to block until the Print::apply() updates its state, which may // influence the processing step being entered. template - bool set_started(StepType step, tbb::mutex &mtx, ThrowIfCanceled throw_if_canceled) { - tbb::mutex::scoped_lock lock(mtx); + bool set_started(StepType step, std::mutex &mtx, ThrowIfCanceled throw_if_canceled) { + std::scoped_lock lock(mtx); // If canceled, throw before changing the step state. throw_if_canceled(); #ifndef NDEBUG @@ -154,8 +150,8 @@ public: // Timestamp when this stepentered the DONE state. // bool indicates whether the UI has to update the slicing warnings of this step or not. template - std::pair set_done(StepType step, tbb::mutex &mtx, ThrowIfCanceled throw_if_canceled) { - tbb::mutex::scoped_lock lock(mtx); + std::pair set_done(StepType step, std::mutex &mtx, ThrowIfCanceled throw_if_canceled) { + std::scoped_lock lock(mtx); // If canceled, throw before changing the step state. throw_if_canceled(); assert(m_state[step].state == STARTED); @@ -266,9 +262,9 @@ public: // Return value: // Current milestone (StepType). // bool indicates whether the UI has to be updated or not. - std::pair active_step_add_warning(PrintStateBase::WarningLevel warning_level, const std::string &message, int message_id, tbb::mutex &mtx) + std::pair active_step_add_warning(PrintStateBase::WarningLevel warning_level, const std::string &message, int message_id, std::mutex &mtx) { - tbb::mutex::scoped_lock lock(mtx); + std::scoped_lock lock(mtx); assert(m_step_active != -1); StateWithWarnings &state = m_state[m_step_active]; assert(state.state == STARTED); @@ -314,7 +310,7 @@ protected: PrintObjectBase(ModelObject *model_object) : m_model_object(model_object) {} virtual ~PrintObjectBase() {} // Declared here to allow access from PrintBase through friendship. - static tbb::mutex& state_mutex(PrintBase *print); + static std::mutex& state_mutex(PrintBase *print); static std::function cancel_callback(PrintBase *print); // Notify UI about a new warning of a milestone "step" on this PrintObjectBase. // The UI will be notified by calling a status callback registered on print. @@ -475,7 +471,7 @@ protected: friend class PrintObjectBase; friend class BackgroundSlicingProcess; - tbb::mutex& state_mutex() const { return m_state_mutex; } + std::mutex& state_mutex() const { return m_state_mutex; } std::function cancel_callback() { return m_cancel_callback; } void call_cancel_callback() { m_cancel_callback(); } // Notify UI about a new warning of a milestone "step" on this PrintBase. @@ -502,7 +498,7 @@ protected: status_callback_type m_status_callback; private: - tbb::atomic m_cancel_status; + std::atomic m_cancel_status; // Callback to be evoked to stop the background processing before a state is updated. cancel_callback_type m_cancel_callback = [](){}; @@ -510,7 +506,7 @@ private: // Mutex used for synchronization of the worker thread with the UI thread: // The mutex will be used to guard the worker thread against entering a stage // while the data influencing the stage is modified. - mutable tbb::mutex m_state_mutex; + mutable std::mutex m_state_mutex; friend PrintTryCancel; }; diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index eb46537ec7..ec3f4f92a2 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -22,7 +22,6 @@ #include #include -#include #include diff --git a/src/libslic3r/SLA/SupportTree.cpp b/src/libslic3r/SLA/SupportTree.cpp index d9f8958a21..a0f88ed608 100644 --- a/src/libslic3r/SLA/SupportTree.cpp +++ b/src/libslic3r/SLA/SupportTree.cpp @@ -17,9 +17,6 @@ #include #include #include -#include -#include -#include #include //! macro used to mark string used at localization, diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 27423793ee..0b9dde1228 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -19,8 +19,6 @@ #include #endif -//#include //#include "tbb/mutex.h" - #include "I18N.hpp" //! macro used to mark string used at localization, @@ -118,7 +116,7 @@ bool validate_pad(const indexed_triangle_set &pad, const sla::PadConfig &pcfg) void SLAPrint::clear() { - tbb::mutex::scoped_lock lock(this->state_mutex()); + std::scoped_lock lock(this->state_mutex()); // The following call should stop background processing if it is running. this->invalidate_all_steps(); for (SLAPrintObject *object : m_objects) @@ -212,7 +210,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con update_apply_status(false); // Grab the lock for the Print / PrintObject milestones. - tbb::mutex::scoped_lock lock(this->state_mutex()); + std::scoped_lock lock(this->state_mutex()); // The following call may stop the background processing. bool invalidate_all_model_objects = false; @@ -514,7 +512,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con void SLAPrint::set_task(const TaskParams ¶ms) { // Grab the lock for the Print / PrintObject milestones. - tbb::mutex::scoped_lock lock(this->state_mutex()); + std::scoped_lock lock(this->state_mutex()); int n_object_steps = int(params.to_object_step) + 1; if (n_object_steps == 0) @@ -884,7 +882,7 @@ bool SLAPrint::is_step_done(SLAPrintObjectStep step) const { if (m_objects.empty()) return false; - tbb::mutex::scoped_lock lock(this->state_mutex()); + std::scoped_lock lock(this->state_mutex()); for (const SLAPrintObject *object : m_objects) if (! object->is_step_done_unguarded(step)) return false; diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index 5eb9c9433a..8fb8756eb7 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -14,7 +14,6 @@ #include #include -#include #include #include diff --git a/src/libslic3r/Thread.cpp b/src/libslic3r/Thread.cpp index d203acb90e..51dec618e4 100644 --- a/src/libslic3r/Thread.cpp +++ b/src/libslic3r/Thread.cpp @@ -9,10 +9,10 @@ #include #include #include +#include +#include #include -#include #include -#include #include "Thread.hpp" @@ -206,13 +206,13 @@ void name_tbb_thread_pool_threads() nthreads = 1; #endif - if (nthreads != nthreads_hw) - new tbb::task_scheduler_init(int(nthreads)); + if (nthreads != nthreads_hw) + tbb::global_control(tbb::global_control::max_allowed_parallelism, nthreads); std::atomic nthreads_running(0); std::condition_variable cv; std::mutex cv_m; - auto master_thread_id = tbb::this_tbb_thread::get_id(); + auto master_thread_id = std::this_thread::get_id(); tbb::parallel_for( tbb::blocked_range(0, nthreads, 1), [&nthreads_running, nthreads, &master_thread_id, &cv, &cv_m](const tbb::blocked_range &range) { @@ -226,7 +226,7 @@ void name_tbb_thread_pool_threads() std::unique_lock lk(cv_m); cv.wait(lk, [&nthreads_running, nthreads]{return nthreads_running == nthreads;}); } - auto thread_id = tbb::this_tbb_thread::get_id(); + auto thread_id = std::this_thread::get_id(); if (thread_id == master_thread_id) { // The calling thread runs the 0'th task. assert(range.begin() == 0); diff --git a/src/libslic3r/pchheader.hpp b/src/libslic3r/pchheader.hpp index b55755b892..ad22b855a7 100644 --- a/src/libslic3r/pchheader.hpp +++ b/src/libslic3r/pchheader.hpp @@ -100,12 +100,9 @@ #include #include -#include #include #include -#include #include -#include #include #include diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index c6e409edc9..763be8af74 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -43,7 +43,7 @@ #include #include -#include +#include #if defined(__linux__) || defined(__GNUC__ ) #include @@ -118,9 +118,7 @@ void trace(unsigned int level, const char *message) void disable_multi_threading() { // Disable parallelization so the Shiny profiler works - static tbb::task_scheduler_init *tbb_init = nullptr; - if (tbb_init == nullptr) - tbb_init = new tbb::task_scheduler_init(1); + tbb::global_control(tbb::global_control::max_allowed_parallelism, 1); } static std::string g_var_dir; diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 816365d90b..5503eefbfa 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -645,7 +645,7 @@ void BackgroundSlicingProcess::schedule_export(const std::string &path, bool exp return; // Guard against entering the export step before changing the export path. - tbb::mutex::scoped_lock lock(m_print->state_mutex()); + std::scoped_lock lock(m_print->state_mutex()); this->invalidate_step(bspsGCodeFinalize); m_export_path = path; m_export_path_on_removable_media = export_path_on_removable_media; @@ -658,7 +658,7 @@ void BackgroundSlicingProcess::schedule_upload(Slic3r::PrintHostJob upload_job) return; // Guard against entering the export step before changing the export path. - tbb::mutex::scoped_lock lock(m_print->state_mutex()); + std::scoped_lock lock(m_print->state_mutex()); this->invalidate_step(bspsGCodeFinalize); m_export_path.clear(); m_upload_job = std::move(upload_job); @@ -671,7 +671,7 @@ void BackgroundSlicingProcess::reset_export() m_export_path.clear(); m_export_path_on_removable_media = false; // invalidate_step expects the mutex to be locked. - tbb::mutex::scoped_lock lock(m_print->state_mutex()); + std::scoped_lock lock(m_print->state_mutex()); this->invalidate_step(bspsGCodeFinalize); } } diff --git a/src/slic3r/GUI/InstanceCheck.hpp b/src/slic3r/GUI/InstanceCheck.hpp index 907b831929..10ccf7b925 100644 --- a/src/slic3r/GUI/InstanceCheck.hpp +++ b/src/slic3r/GUI/InstanceCheck.hpp @@ -13,7 +13,7 @@ #if __linux__ #include -#include +#include #include #endif // __linux__ diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp index 57b82fc782..b89bb454b4 100644 --- a/src/slic3r/GUI/Mouse3DController.cpp +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -66,7 +66,7 @@ void update_maximum(std::atomic& maximum_value, T const& value) noexcept void Mouse3DController::State::append_translation(const Vec3d& translation, size_t input_queue_max_size) { - tbb::mutex::scoped_lock lock(m_input_queue_mutex); + std::scoped_lock lock(m_input_queue_mutex); while (m_input_queue.size() >= input_queue_max_size) m_input_queue.pop_front(); m_input_queue.emplace_back(QueueItem::translation(translation)); @@ -77,7 +77,7 @@ void Mouse3DController::State::append_translation(const Vec3d& translation, size void Mouse3DController::State::append_rotation(const Vec3f& rotation, size_t input_queue_max_size) { - tbb::mutex::scoped_lock lock(m_input_queue_mutex); + std::scoped_lock lock(m_input_queue_mutex); while (m_input_queue.size() >= input_queue_max_size) m_input_queue.pop_front(); m_input_queue.emplace_back(QueueItem::rotation(rotation.cast())); @@ -92,7 +92,7 @@ void Mouse3DController::State::append_rotation(const Vec3f& rotation, size_t inp void Mouse3DController::State::append_button(unsigned int id, size_t /* input_queue_max_size */) { - tbb::mutex::scoped_lock lock(m_input_queue_mutex); + std::scoped_lock lock(m_input_queue_mutex); m_input_queue.emplace_back(QueueItem::buttons(id)); #if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT update_maximum(input_queue_max_size_achieved, m_input_queue.size()); @@ -274,7 +274,7 @@ void Mouse3DController::device_attached(const std::string &device) m_stop_condition.notify_all(); m_device_str = format_device_string(vid, pid); if (auto it_params = m_params_by_device.find(m_device_str); it_params != m_params_by_device.end()) { - tbb::mutex::scoped_lock lock(m_params_ui_mutex); + std::scoped_lock lock(m_params_ui_mutex); m_params = m_params_ui = it_params->second; } else @@ -290,7 +290,7 @@ void Mouse3DController::device_detached(const std::string& device) int pid = 0; if (sscanf(device.c_str(), "\\\\?\\HID#VID_%x&PID_%x&", &vid, &pid) == 2) { if (std::find(_3DCONNEXION_VENDORS.begin(), _3DCONNEXION_VENDORS.end(), vid) != _3DCONNEXION_VENDORS.end()) { - tbb::mutex::scoped_lock lock(m_params_ui_mutex); + std::scoped_lock lock(m_params_ui_mutex); m_params_by_device[format_device_string(vid, pid)] = m_params_ui; } } @@ -301,12 +301,12 @@ void Mouse3DController::device_detached(const std::string& device) // Filter out mouse scroll events produced by the 3DConnexion driver. bool Mouse3DController::State::process_mouse_wheel() { - tbb::mutex::scoped_lock lock(m_input_queue_mutex); - if (m_mouse_wheel_counter == 0) - // No 3DConnexion rotation has been captured since the last mouse scroll event. + std::scoped_lock lock(m_input_queue_mutex); + if (m_mouse_wheel_counter == 0) + // No 3DConnexion rotation has been captured since the last mouse scroll event. return false; if (std::find_if(m_input_queue.begin(), m_input_queue.end(), [](const QueueItem &item){ return item.is_rotation(); }) != m_input_queue.end()) { - // There is a rotation stored in the queue. Suppress one mouse scroll event. + // There is a rotation stored in the queue. Suppress one mouse scroll event. -- m_mouse_wheel_counter; return true; } @@ -323,7 +323,7 @@ bool Mouse3DController::State::apply(const Mouse3DController::Params ¶ms, Ca std::deque input_queue; { // Atomically move m_input_queue to input_queue. - tbb::mutex::scoped_lock lock(m_input_queue_mutex); + std::scoped_lock lock(m_input_queue_mutex); input_queue = std::move(m_input_queue); m_input_queue.clear(); } @@ -411,7 +411,7 @@ bool Mouse3DController::apply(Camera& camera) #ifdef _WIN32 { - tbb::mutex::scoped_lock lock(m_params_ui_mutex); + std::scoped_lock lock(m_params_ui_mutex); if (m_params_ui_changed) { m_params = m_params_ui; m_params_ui_changed = false; @@ -439,7 +439,7 @@ void Mouse3DController::render_settings_dialog(GLCanvas3D& canvas) const Params params_copy; bool params_changed = false; { - tbb::mutex::scoped_lock lock(m_params_ui_mutex); + std::scoped_lock lock(m_params_ui_mutex); params_copy = m_params_ui; } @@ -557,7 +557,7 @@ void Mouse3DController::render_settings_dialog(GLCanvas3D& canvas) const if (params_changed) { // Synchronize front end parameters to back end. - tbb::mutex::scoped_lock lock(m_params_ui_mutex); + std::scoped_lock lock(m_params_ui_mutex); auto pthis = const_cast(this); #if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT if (params_copy.input_queue_max_size != params_copy.input_queue_max_size) @@ -578,7 +578,7 @@ void Mouse3DController::connected(std::string device_name) m_device_str = device_name; // Copy the parameters for m_device_str into the current parameters. if (auto it_params = m_params_by_device.find(m_device_str); it_params != m_params_by_device.end()) { - tbb::mutex::scoped_lock lock(m_params_ui_mutex); + std::scoped_lock lock(m_params_ui_mutex); m_params = m_params_ui = it_params->second; } m_connected = true; @@ -589,7 +589,7 @@ void Mouse3DController::disconnected() // Copy the current parameters for m_device_str into the parameter database. assert(m_connected == ! m_device_str.empty()); if (m_connected) { - tbb::mutex::scoped_lock lock(m_params_ui_mutex); + std::scoped_lock lock(m_params_ui_mutex); m_params_by_device[m_device_str] = m_params_ui; m_device_str.clear(); m_connected = false; @@ -613,7 +613,7 @@ bool Mouse3DController::handle_input(const DataPacketAxis& packet) { // Synchronize parameters between the UI thread and the background thread. //FIXME is this necessary on OSX? Are these notifications triggered from the main thread or from a worker thread? - tbb::mutex::scoped_lock lock(m_params_ui_mutex); + std::scoped_lock lock(m_params_ui_mutex); if (m_params_ui_changed) { m_params = m_params_ui; m_params_ui_changed = false; @@ -721,7 +721,7 @@ void Mouse3DController::run() for (;;) { { - tbb::mutex::scoped_lock lock(m_params_ui_mutex); + std::scoped_lock lock(m_params_ui_mutex); if (m_stop) break; if (m_params_ui_changed) { @@ -986,7 +986,7 @@ bool Mouse3DController::connect_device() #endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT // Copy the parameters for m_device_str into the current parameters. if (auto it_params = m_params_by_device.find(m_device_str); it_params != m_params_by_device.end()) { - tbb::mutex::scoped_lock lock(m_params_ui_mutex); + std::scoped_lock lock(m_params_ui_mutex); m_params = m_params_ui = it_params->second; } } @@ -1011,7 +1011,7 @@ void Mouse3DController::disconnect_device() BOOST_LOG_TRIVIAL(info) << "Disconnected device: " << m_device_str; // Copy the current parameters for m_device_str into the parameter database. { - tbb::mutex::scoped_lock lock(m_params_ui_mutex); + std::scoped_lock lock(m_params_ui_mutex); m_params_by_device[m_device_str] = m_params_ui; } m_device_str.clear(); diff --git a/src/slic3r/GUI/Mouse3DController.hpp b/src/slic3r/GUI/Mouse3DController.hpp index 3376ef8140..12e9b7dc9e 100644 --- a/src/slic3r/GUI/Mouse3DController.hpp +++ b/src/slic3r/GUI/Mouse3DController.hpp @@ -10,12 +10,12 @@ #include #include +#include #include #include #include #include -#include namespace Slic3r { @@ -85,7 +85,7 @@ class Mouse3DController // m_input_queue is accessed by the background thread and by the UI thread. Access to m_input_queue // is guarded with m_input_queue_mutex. std::deque m_input_queue; - mutable tbb::mutex m_input_queue_mutex; + mutable std::mutex m_input_queue_mutex; #ifdef WIN32 // When the 3Dconnexion driver is running the system gets, by default, mouse wheel events when rotations around the X axis are detected. @@ -112,12 +112,12 @@ class Mouse3DController #if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT Vec3d get_first_vector_of_type(unsigned int type) const { - tbb::mutex::scoped_lock lock(m_input_queue_mutex); + std::scoped_lock lock(m_input_queue_mutex); auto it = std::find_if(m_input_queue.begin(), m_input_queue.end(), [type](const QueueItem& item) { return item.type_or_buttons == type; }); return (it == m_input_queue.end()) ? Vec3d::Zero() : it->vector; } size_t input_queue_size_current() const { - tbb::mutex::scoped_lock lock(m_input_queue_mutex); + std::scoped_lock lock(m_input_queue_mutex); return m_input_queue.size(); } std::atomic input_queue_max_size_achieved; @@ -133,7 +133,7 @@ class Mouse3DController // UI thread will read / write this copy. Params m_params_ui; bool m_params_ui_changed { false }; - mutable tbb::mutex m_params_ui_mutex; + mutable std::mutex m_params_ui_mutex; // This is a database of parametes of all 3DConnexion devices ever connected. // This database is loaded from AppConfig on application start and it is stored to AppConfig on application exit. diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 83f7077b4d..593d8241d4 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -84,7 +84,7 @@ void RemovableDriveManager::eject_drive() this->update(); #endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS BOOST_LOG_TRIVIAL(info) << "Ejecting started"; - tbb::mutex::scoped_lock lock(m_drives_mutex); + std::scoped_lock lock(m_drives_mutex); auto it_drive_data = this->find_last_save_path_drive_data(); if (it_drive_data != m_current_drives.end()) { // get handle to device @@ -130,7 +130,7 @@ std::string RemovableDriveManager::get_removable_drive_path(const std::string &p this->update(); #endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS - tbb::mutex::scoped_lock lock(m_drives_mutex); + std::scoped_lock lock(m_drives_mutex); if (m_current_drives.empty()) return std::string(); std::size_t found = path.find_last_of("\\"); @@ -146,7 +146,7 @@ std::string RemovableDriveManager::get_removable_drive_path(const std::string &p std::string RemovableDriveManager::get_removable_drive_from_path(const std::string& path) { - tbb::mutex::scoped_lock lock(m_drives_mutex); + std::scoped_lock lock(m_drives_mutex); std::size_t found = path.find_last_of("\\"); std::string new_path = path.substr(0, found); int letter = PathGetDriveNumberW(boost::nowide::widen(new_path).c_str()); @@ -287,7 +287,7 @@ void RemovableDriveManager::eject_drive() DriveData drive_data; { - tbb::mutex::scoped_lock lock(m_drives_mutex); + std::scoped_lock lock(m_drives_mutex); auto it_drive_data = this->find_last_save_path_drive_data(); if (it_drive_data == m_current_drives.end()) return; @@ -343,7 +343,7 @@ void RemovableDriveManager::eject_drive() if (success) { // Remove the drive_data from m_current drives, searching by value, not by pointer, as m_current_drives may get modified during // asynchronous execution on m_eject_thread. - tbb::mutex::scoped_lock lock(m_drives_mutex); + std::scoped_lock lock(m_drives_mutex); auto it = std::find(m_current_drives.begin(), m_current_drives.end(), drive_data); if (it != m_current_drives.end()) m_current_drives.erase(it); @@ -363,7 +363,7 @@ std::string RemovableDriveManager::get_removable_drive_path(const std::string &p std::size_t found = path.find_last_of("/"); std::string new_path = found == path.size() - 1 ? path.substr(0, found) : path; - tbb::mutex::scoped_lock lock(m_drives_mutex); + std::scoped_lock lock(m_drives_mutex); for (const DriveData &data : m_current_drives) if (search_for_drives_internal::compare_filesystem_id(new_path, data.path)) return path; @@ -379,7 +379,7 @@ std::string RemovableDriveManager::get_removable_drive_from_path(const std::stri new_path = new_path.substr(0, found); // check if same filesystem - tbb::mutex::scoped_lock lock(m_drives_mutex); + std::scoped_lock lock(m_drives_mutex); for (const DriveData &drive_data : m_current_drives) if (search_for_drives_internal::compare_filesystem_id(new_path, drive_data.path)) return drive_data.path; @@ -454,7 +454,7 @@ RemovableDriveManager::RemovableDrivesStatus RemovableDriveManager::status() RemovableDriveManager::RemovableDrivesStatus out; { - tbb::mutex::scoped_lock lock(m_drives_mutex); + std::scoped_lock lock(m_drives_mutex); out.has_eject = // Cannot control eject on Chromium. platform_flavor() != PlatformFlavor::LinuxOnChromium && @@ -470,17 +470,17 @@ RemovableDriveManager::RemovableDrivesStatus RemovableDriveManager::status() // Update is called from thread_proc() and from most of the public methods on demand. void RemovableDriveManager::update() { - tbb::mutex::scoped_lock inside_update_lock; + std::unique_lock inside_update_lock(m_inside_update_mutex, std::defer_lock); #ifdef _WIN32 // All wake up calls up to now are now consumed when the drive enumeration starts. m_wakeup = false; #endif // _WIN32 - if (inside_update_lock.try_acquire(m_inside_update_mutex)) { + if (inside_update_lock.try_lock()) { // Got the lock without waiting. That means, the update was not running. // Run the update. std::vector current_drives = this->search_for_removable_drives(); // Post update events. - tbb::mutex::scoped_lock lock(m_drives_mutex); + std::scoped_lock lock(m_drives_mutex); std::sort(current_drives.begin(), current_drives.end()); if (current_drives != m_current_drives) { assert(m_callback_evt_handler); @@ -491,7 +491,7 @@ void RemovableDriveManager::update() } else { // Acquiring the m_iniside_update lock failed, therefore another update is running. // Just block until the other instance of update() finishes. - inside_update_lock.acquire(m_inside_update_mutex); + inside_update_lock.lock(); } } diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index f707b40c32..29363647c8 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include // Custom wxWidget events @@ -111,9 +111,9 @@ private: // m_current_drives is guarded by m_drives_mutex // sorted ascending by path std::vector m_current_drives; - mutable tbb::mutex m_drives_mutex; + mutable std::mutex m_drives_mutex; // Locking the update() function to avoid that the function is executed multiple times. - mutable tbb::mutex m_inside_update_mutex; + mutable std::mutex m_inside_update_mutex; // Returns drive path (same as path in DriveData) if exists otherwise empty string. std::string get_removable_drive_from_path(const std::string& path);