Fix a bunch of race conditions between arrange and bg processing, fix #1770
This commit is contained in:
parent
0c1e223414
commit
b57452d090
2 changed files with 43 additions and 27 deletions
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
#include "../Utils/PresetUpdater.hpp"
|
#include "../Utils/PresetUpdater.hpp"
|
||||||
#include "../Utils/PrintHost.hpp"
|
#include "../Utils/PrintHost.hpp"
|
||||||
#include "ConfigWizard_private.hpp"
|
#include "ConfigWizard.hpp"
|
||||||
#include "slic3r/Config/Snapshot.hpp"
|
#include "slic3r/Config/Snapshot.hpp"
|
||||||
#include "ConfigSnapshotDialog.hpp"
|
#include "ConfigSnapshotDialog.hpp"
|
||||||
#include "FirmwareDialog.hpp"
|
#include "FirmwareDialog.hpp"
|
||||||
|
@ -230,7 +230,7 @@ bool GUI_App::on_init_inner()
|
||||||
// and after MainFrame is created & shown.
|
// and after MainFrame is created & shown.
|
||||||
// The extra CallAfter() is needed because of Mac, where this is the only way
|
// The extra CallAfter() is needed because of Mac, where this is the only way
|
||||||
// to popup a modal dialog on start without screwing combo boxes.
|
// to popup a modal dialog on start without screwing combo boxes.
|
||||||
// This is ugly but I honestly found not better way to do it.
|
// This is ugly but I honestly found no better way to do it.
|
||||||
// Neither wxShowEvent nor wxWindowCreateEvent work reliably.
|
// Neither wxShowEvent nor wxWindowCreateEvent work reliably.
|
||||||
static bool once = true;
|
static bool once = true;
|
||||||
if (once) {
|
if (once) {
|
||||||
|
|
|
@ -1169,8 +1169,8 @@ struct Plater::priv
|
||||||
wxString project_filename;
|
wxString project_filename;
|
||||||
|
|
||||||
BackgroundSlicingProcess background_process;
|
BackgroundSlicingProcess background_process;
|
||||||
std::atomic<bool> arranging;
|
bool arranging;
|
||||||
std::atomic<bool> rotoptimizing;
|
bool rotoptimizing;
|
||||||
bool delayed_scene_refresh;
|
bool delayed_scene_refresh;
|
||||||
std::string delayed_error_message;
|
std::string delayed_error_message;
|
||||||
|
|
||||||
|
@ -1333,8 +1333,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
||||||
, view_toolbar(GLToolbar::Radio)
|
, view_toolbar(GLToolbar::Radio)
|
||||||
#endif // ENABLE_SVG_ICONS
|
#endif // ENABLE_SVG_ICONS
|
||||||
{
|
{
|
||||||
arranging.store(false);
|
arranging = false;
|
||||||
rotoptimizing.store(false);
|
rotoptimizing = false;
|
||||||
background_process.set_fff_print(&fff_print);
|
background_process.set_fff_print(&fff_print);
|
||||||
background_process.set_sla_print(&sla_print);
|
background_process.set_sla_print(&sla_print);
|
||||||
background_process.set_gcode_preview_data(&gcode_preview_data);
|
background_process.set_gcode_preview_data(&gcode_preview_data);
|
||||||
|
@ -2025,15 +2025,14 @@ void Plater::priv::mirror(Axis axis)
|
||||||
|
|
||||||
void Plater::priv::arrange()
|
void Plater::priv::arrange()
|
||||||
{
|
{
|
||||||
// don't do anything if currently arranging. Then this is a re-entrance
|
if (arranging) { return; }
|
||||||
if(arranging.load()) return;
|
arranging = true;
|
||||||
|
Slic3r::ScopeGuard arranging_guard([this]() { arranging = false; });
|
||||||
// Guard the arrange process
|
|
||||||
arranging.store(true);
|
|
||||||
|
|
||||||
wxBusyCursor wait;
|
wxBusyCursor wait;
|
||||||
|
|
||||||
this->background_process.stop();
|
this->background_process.stop();
|
||||||
|
|
||||||
unsigned count = 0;
|
unsigned count = 0;
|
||||||
for(auto obj : model.objects) count += obj->instances.size();
|
for(auto obj : model.objects) count += obj->instances.size();
|
||||||
|
|
||||||
|
@ -2049,14 +2048,14 @@ void Plater::priv::arrange()
|
||||||
statusbar()->set_progress(count - st);
|
statusbar()->set_progress(count - st);
|
||||||
statusbar()->set_status_text(msg);
|
statusbar()->set_status_text(msg);
|
||||||
|
|
||||||
// ok, this is dangerous, but we are protected by the atomic flag
|
// ok, this is dangerous, but we are protected by the flag
|
||||||
// 'arranging' and the arrange button is also disabled.
|
// 'arranging' and the arrange button is also disabled.
|
||||||
// This call is needed for the cancel button to work.
|
// This call is needed for the cancel button to work.
|
||||||
wxYieldIfNeeded();
|
wxYieldIfNeeded();
|
||||||
};
|
};
|
||||||
|
|
||||||
statusbar()->set_cancel_callback([this, statusfn](){
|
statusbar()->set_cancel_callback([this, statusfn](){
|
||||||
arranging.store(false);
|
arranging = false;
|
||||||
statusfn(0, L("Arranging canceled"));
|
statusfn(0, L("Arranging canceled"));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2092,7 +2091,7 @@ void Plater::priv::arrange()
|
||||||
hint,
|
hint,
|
||||||
false, // create many piles not just one pile
|
false, // create many piles not just one pile
|
||||||
[statusfn](unsigned st) { statusfn(st, arrangestr); },
|
[statusfn](unsigned st) { statusfn(st, arrangestr); },
|
||||||
[this] () { return !arranging.load(); });
|
[this] () { return !arranging; });
|
||||||
} catch(std::exception& /*e*/) {
|
} catch(std::exception& /*e*/) {
|
||||||
GUI::show_error(this->q, L("Could not arrange model objects! "
|
GUI::show_error(this->q, L("Could not arrange model objects! "
|
||||||
"Some geometries may be invalid."));
|
"Some geometries may be invalid."));
|
||||||
|
@ -2101,7 +2100,6 @@ void Plater::priv::arrange()
|
||||||
statusfn(0, L("Arranging done."));
|
statusfn(0, L("Arranging done."));
|
||||||
statusbar()->set_range(prev_range);
|
statusbar()->set_range(prev_range);
|
||||||
statusbar()->set_cancel_callback(); // remove cancel button
|
statusbar()->set_cancel_callback(); // remove cancel button
|
||||||
arranging.store(false);
|
|
||||||
|
|
||||||
// Do a full refresh of scene tree, including regenerating all the GLVolumes.
|
// Do a full refresh of scene tree, including regenerating all the GLVolumes.
|
||||||
//FIXME The update function shall just reload the modified matrices.
|
//FIXME The update function shall just reload the modified matrices.
|
||||||
|
@ -2116,11 +2114,12 @@ void Plater::priv::sla_optimize_rotation() {
|
||||||
// running we should probably disable explicit slicing and background
|
// running we should probably disable explicit slicing and background
|
||||||
// processing
|
// processing
|
||||||
|
|
||||||
if(rotoptimizing.load()) return;
|
if (rotoptimizing) { return; }
|
||||||
rotoptimizing.store(true);
|
rotoptimizing = true;
|
||||||
|
Slic3r::ScopeGuard rotoptimizing_guard([this]() { rotoptimizing = false; });
|
||||||
|
|
||||||
int obj_idx = get_selected_object_idx();
|
int obj_idx = get_selected_object_idx();
|
||||||
if(obj_idx < 0) { rotoptimizing.store(false); return; }
|
if (obj_idx < 0) { return; }
|
||||||
|
|
||||||
ModelObject * o = model.objects[size_t(obj_idx)];
|
ModelObject * o = model.objects[size_t(obj_idx)];
|
||||||
|
|
||||||
|
@ -2138,14 +2137,14 @@ void Plater::priv::sla_optimize_rotation() {
|
||||||
};
|
};
|
||||||
|
|
||||||
statusbar()->set_cancel_callback([this, stfn](){
|
statusbar()->set_cancel_callback([this, stfn](){
|
||||||
rotoptimizing.store(false);
|
rotoptimizing = false;
|
||||||
stfn(0, L("Orientation search canceled"));
|
stfn(0, L("Orientation search canceled"));
|
||||||
});
|
});
|
||||||
|
|
||||||
auto r = sla::find_best_rotation(
|
auto r = sla::find_best_rotation(
|
||||||
*o, .005f,
|
*o, .005f,
|
||||||
[stfn](unsigned s) { stfn(s, L("Searching for optimal orientation")); },
|
[stfn](unsigned s) { stfn(s, L("Searching for optimal orientation")); },
|
||||||
[this](){ return !rotoptimizing.load(); }
|
[this](){ return !rotoptimizing; }
|
||||||
);
|
);
|
||||||
|
|
||||||
const auto *bed_shape_opt = config->opt<ConfigOptionPoints>("bed_shape");
|
const auto *bed_shape_opt = config->opt<ConfigOptionPoints>("bed_shape");
|
||||||
|
@ -2158,7 +2157,7 @@ void Plater::priv::sla_optimize_rotation() {
|
||||||
double mindist = 6.0; // FIXME
|
double mindist = 6.0; // FIXME
|
||||||
double offs = mindist / 2.0 - EPSILON;
|
double offs = mindist / 2.0 - EPSILON;
|
||||||
|
|
||||||
if(rotoptimizing.load()) // wasn't canceled
|
if(rotoptimizing) // wasn't canceled
|
||||||
for(ModelInstance * oi : o->instances) {
|
for(ModelInstance * oi : o->instances) {
|
||||||
oi->set_rotation({r[X], r[Y], r[Z]});
|
oi->set_rotation({r[X], r[Y], r[Z]});
|
||||||
|
|
||||||
|
@ -2208,7 +2207,6 @@ void Plater::priv::sla_optimize_rotation() {
|
||||||
stfn(0, L("Orientation found."));
|
stfn(0, L("Orientation found."));
|
||||||
statusbar()->set_range(prev_range);
|
statusbar()->set_range(prev_range);
|
||||||
statusbar()->set_cancel_callback();
|
statusbar()->set_cancel_callback();
|
||||||
rotoptimizing.store(false);
|
|
||||||
|
|
||||||
update(true);
|
update(true);
|
||||||
}
|
}
|
||||||
|
@ -2386,6 +2384,11 @@ unsigned int Plater::priv::update_background_process(bool force_validation)
|
||||||
// Restart background processing thread based on a bitmask of UpdateBackgroundProcessReturnState.
|
// Restart background processing thread based on a bitmask of UpdateBackgroundProcessReturnState.
|
||||||
bool Plater::priv::restart_background_process(unsigned int state)
|
bool Plater::priv::restart_background_process(unsigned int state)
|
||||||
{
|
{
|
||||||
|
if (arranging || rotoptimizing) {
|
||||||
|
// Avoid a race condition
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if ( ! this->background_process.empty() &&
|
if ( ! this->background_process.empty() &&
|
||||||
(state & priv::UPDATE_BACKGROUND_PROCESS_INVALID) == 0 &&
|
(state & priv::UPDATE_BACKGROUND_PROCESS_INVALID) == 0 &&
|
||||||
( ((state & UPDATE_BACKGROUND_PROCESS_FORCE_RESTART) != 0 && ! this->background_process.finished()) ||
|
( ((state & UPDATE_BACKGROUND_PROCESS_FORCE_RESTART) != 0 && ! this->background_process.finished()) ||
|
||||||
|
@ -2612,6 +2615,11 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt)
|
||||||
void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
|
void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
|
||||||
{
|
{
|
||||||
if (evt.status.percent >= -1) {
|
if (evt.status.percent >= -1) {
|
||||||
|
if (arranging || rotoptimizing) {
|
||||||
|
// Avoid a race condition
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this->statusbar()->set_progress(evt.status.percent);
|
this->statusbar()->set_progress(evt.status.percent);
|
||||||
this->statusbar()->set_status_text(_(L(evt.status.text)) + wxString::FromUTF8("…"));
|
this->statusbar()->set_status_text(_(L(evt.status.text)) + wxString::FromUTF8("…"));
|
||||||
}
|
}
|
||||||
|
@ -3069,12 +3077,20 @@ bool Plater::priv::can_delete_all() const
|
||||||
|
|
||||||
bool Plater::priv::can_increase_instances() const
|
bool Plater::priv::can_increase_instances() const
|
||||||
{
|
{
|
||||||
|
if (arranging || rotoptimizing) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int obj_idx = get_selected_object_idx();
|
int obj_idx = get_selected_object_idx();
|
||||||
return (0 <= obj_idx) && (obj_idx < (int)model.objects.size());
|
return (0 <= obj_idx) && (obj_idx < (int)model.objects.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Plater::priv::can_decrease_instances() const
|
bool Plater::priv::can_decrease_instances() const
|
||||||
{
|
{
|
||||||
|
if (arranging || rotoptimizing) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int obj_idx = get_selected_object_idx();
|
int obj_idx = get_selected_object_idx();
|
||||||
return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()) && (model.objects[obj_idx]->instances.size() > 1);
|
return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()) && (model.objects[obj_idx]->instances.size() > 1);
|
||||||
}
|
}
|
||||||
|
@ -3091,7 +3107,7 @@ bool Plater::priv::can_split_to_volumes() const
|
||||||
|
|
||||||
bool Plater::priv::can_arrange() const
|
bool Plater::priv::can_arrange() const
|
||||||
{
|
{
|
||||||
return !model.objects.empty() && !arranging.load();
|
return !model.objects.empty() && !arranging;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Plater::priv::can_layers_editing() const
|
bool Plater::priv::can_layers_editing() const
|
||||||
|
@ -3232,9 +3248,9 @@ void Plater::remove_selected()
|
||||||
|
|
||||||
void Plater::increase_instances(size_t num)
|
void Plater::increase_instances(size_t num)
|
||||||
{
|
{
|
||||||
|
if (! can_increase_instances()) { return; }
|
||||||
|
|
||||||
int obj_idx = p->get_selected_object_idx();
|
int obj_idx = p->get_selected_object_idx();
|
||||||
if (obj_idx == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ModelObject* model_object = p->model.objects[obj_idx];
|
ModelObject* model_object = p->model.objects[obj_idx];
|
||||||
ModelInstance* model_instance = model_object->instances.back();
|
ModelInstance* model_instance = model_object->instances.back();
|
||||||
|
@ -3266,9 +3282,9 @@ void Plater::increase_instances(size_t num)
|
||||||
|
|
||||||
void Plater::decrease_instances(size_t num)
|
void Plater::decrease_instances(size_t num)
|
||||||
{
|
{
|
||||||
|
if (! can_decrease_instances()) { return; }
|
||||||
|
|
||||||
int obj_idx = p->get_selected_object_idx();
|
int obj_idx = p->get_selected_object_idx();
|
||||||
if (obj_idx == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ModelObject* model_object = p->model.objects[obj_idx];
|
ModelObject* model_object = p->model.objects[obj_idx];
|
||||||
if (model_object->instances.size() > num) {
|
if (model_object->instances.size() > num) {
|
||||||
|
|
Loading…
Reference in a new issue