Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/slic3r/GUI/BackgroundSlicingProcess.cpp')
-rw-r--r--src/slic3r/GUI/BackgroundSlicingProcess.cpp167
1 files changed, 167 insertions, 0 deletions
diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp
new file mode 100644
index 000000000..99997e390
--- /dev/null
+++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp
@@ -0,0 +1,167 @@
+#include "BackgroundSlicingProcess.hpp"
+#include "GUI.hpp"
+
+#include <wx/event.h>
+#include <wx/panel.h>
+#include <wx/stdpaths.h>
+
+// Print now includes tbb, and tbb includes Windows. This breaks compilation of wxWidgets if included before wx.
+#include "../../libslic3r/Print.hpp"
+#include "../../libslic3r/Utils.hpp"
+#include "../../libslic3r/GCode/PostProcessor.hpp"
+
+//#undef NDEBUG
+#include <cassert>
+#include <stdexcept>
+
+#include <boost/format.hpp>
+#include <boost/nowide/cstdio.hpp>
+
+namespace Slic3r {
+
+namespace GUI {
+ extern wxPanel *g_wxPlater;
+};
+
+BackgroundSlicingProcess::BackgroundSlicingProcess()
+{
+ m_temp_output_path = wxStandardPaths::Get().GetTempDir().utf8_str().data();
+ m_temp_output_path += (boost::format(".%1%.gcode") % get_current_pid()).str();
+}
+
+BackgroundSlicingProcess::~BackgroundSlicingProcess()
+{
+ this->stop();
+ this->join_background_thread();
+ boost::nowide::remove(m_temp_output_path.c_str());
+}
+
+void BackgroundSlicingProcess::thread_proc()
+{
+ std::unique_lock<std::mutex> lck(m_mutex);
+ // Let the caller know we are ready to run the background processing task.
+ m_state = STATE_IDLE;
+ lck.unlock();
+ m_condition.notify_one();
+ for (;;) {
+ assert(m_state == STATE_IDLE || m_state == STATE_CANCELED || m_state == STATE_FINISHED);
+ // Wait until a new task is ready to be executed, or this thread should be finished.
+ lck.lock();
+ m_condition.wait(lck, [this](){ return m_state == STATE_STARTED || m_state == STATE_EXIT; });
+ if (m_state == STATE_EXIT)
+ // Exiting this thread.
+ break;
+ // Process the background slicing task.
+ m_state = STATE_RUNNING;
+ lck.unlock();
+ std::string error;
+ try {
+ assert(m_print != nullptr);
+ m_print->process();
+ if (! m_print->canceled()) {
+ wxQueueEvent(GUI::g_wxPlater, new wxCommandEvent(m_event_sliced_id));
+ m_print->export_gcode(m_temp_output_path, m_gcode_preview_data);
+ if (! m_print->canceled() && ! m_output_path.empty()) {
+ if (copy_file(m_temp_output_path, m_output_path) != 0)
+ throw std::runtime_error("Copying of the temporary G-code to the output G-code failed");
+ m_print->set_status(95, "Running post-processing scripts");
+ run_post_process_scripts(m_output_path, m_print->config());
+ }
+ }
+ } catch (CanceledException &ex) {
+ // Canceled, this is all right.
+ assert(m_print->canceled());
+ } catch (std::exception &ex) {
+ error = ex.what();
+ } catch (...) {
+ error = "Unknown C++ exception.";
+ }
+ lck.lock();
+ m_state = m_print->canceled() ? STATE_CANCELED : STATE_FINISHED;
+ wxCommandEvent evt(m_event_finished_id);
+ evt.SetString(error);
+ evt.SetInt(m_print->canceled() ? -1 : (error.empty() ? 1 : 0));
+ wxQueueEvent(GUI::g_wxPlater, evt.Clone());
+ m_print->restart();
+ lck.unlock();
+ // Let the UI thread wake up if it is waiting for the background task to finish.
+ m_condition.notify_one();
+ // Let the UI thread see the result.
+ }
+ m_state = STATE_EXITED;
+ lck.unlock();
+ // End of the background processing thread. The UI thread should join m_thread now.
+}
+
+void BackgroundSlicingProcess::join_background_thread()
+{
+ std::unique_lock<std::mutex> lck(m_mutex);
+ if (m_state == STATE_INITIAL) {
+ // Worker thread has not been started yet.
+ assert(! m_thread.joinable());
+ } else {
+ assert(m_state == STATE_IDLE);
+ assert(m_thread.joinable());
+ // Notify the worker thread to exit.
+ m_state = STATE_EXIT;
+ lck.unlock();
+ m_condition.notify_one();
+ // Wait until the worker thread exits.
+ m_thread.join();
+ }
+}
+
+bool BackgroundSlicingProcess::start()
+{
+ std::unique_lock<std::mutex> lck(m_mutex);
+ if (m_state == STATE_INITIAL) {
+ // The worker thread is not running yet. Start it.
+ assert(! m_thread.joinable());
+ m_thread = std::thread([this]{this->thread_proc();});
+ // Wait until the worker thread is ready to execute the background processing task.
+ m_condition.wait(lck, [this](){ return m_state == STATE_IDLE; });
+ }
+ assert(m_state == STATE_IDLE || this->running());
+ if (this->running())
+ // The background processing thread is already running.
+ return false;
+ if (! this->idle())
+ throw std::runtime_error("Cannot start a background task, the worker thread is not idle.");
+ m_state = STATE_STARTED;
+ lck.unlock();
+ m_condition.notify_one();
+ return true;
+}
+
+bool BackgroundSlicingProcess::stop()
+{
+ std::unique_lock<std::mutex> lck(m_mutex);
+ if (m_state == STATE_INITIAL) {
+ this->m_output_path.clear();
+ return false;
+ }
+ assert(this->running());
+ if (m_state == STATE_STARTED || m_state == STATE_RUNNING) {
+ m_print->cancel();
+ // Wait until the background processing stops by being canceled.
+ m_condition.wait(lck, [this](){ return m_state == STATE_CANCELED; });
+ // In the "Canceled" state. Reset the state to "Idle".
+ m_state = STATE_IDLE;
+ } else if (m_state == STATE_FINISHED || m_state == STATE_CANCELED) {
+ // In the "Finished" or "Canceled" state. Reset the state to "Idle".
+ m_state = STATE_IDLE;
+ }
+ this->m_output_path.clear();
+ return true;
+}
+
+// Apply config over the print. Returns false, if the new config values caused any of the already
+// processed steps to be invalidated, therefore the task will need to be restarted.
+bool BackgroundSlicingProcess::apply_config(const DynamicPrintConfig &config)
+{
+ this->stop();
+ bool invalidated = m_print->apply_config(config);
+ return invalidated;
+}
+
+}; // namespace Slic3r