mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-06 23:31:19 +00:00
Stop cloning config defaults twice and building selectors for unpainted meshes
create_default_option() cloned the default value only to ask whether it is nullable, then cloned again in both branches and returned, leaving the delete unreachable. That is one leaked ConfigOption per enum definition per config load, and it was the only unreachable allocation a leak checker found anywhere in the slicing path. get_extruders() built a full TriangleSelector, one node per facet, to ask which extruders a volume paints, even when it carries no painting at all. Measured on an unpainted 597k facet volume: 38.8 MB retained and 40 to 52 ms per call, both down to nothing, with the same answer. get_facets() takes the same short circuit for any state other than NONE, where an empty annotation can only return an empty set anyway.
This commit is contained in:
@@ -304,8 +304,7 @@ ConfigOption* ConfigOptionDef::create_default_option() const
|
||||
return new ConfigOptionEnumGeneric(this->enum_keys_map, this->default_value->getInt());
|
||||
|
||||
if (type == coEnums) {
|
||||
auto dft = this->default_value->clone();
|
||||
if (dft->nullable()) {
|
||||
if (this->default_value->nullable()) {
|
||||
ConfigOptionEnumsGenericNullable *opt = dynamic_cast<ConfigOptionEnumsGenericNullable *>(this->default_value->clone());
|
||||
opt->keys_map = this->enum_keys_map;
|
||||
return opt;
|
||||
@@ -314,7 +313,6 @@ ConfigOption* ConfigOptionDef::create_default_option() const
|
||||
opt->keys_map = this->enum_keys_map;
|
||||
return opt;
|
||||
}
|
||||
delete dft;
|
||||
}
|
||||
|
||||
return this->default_value->clone();
|
||||
|
||||
+18
-17
@@ -2087,11 +2087,6 @@ void ModelVolume::reset_extra_facets()
|
||||
this->seam_facets.reset();
|
||||
this->mmu_segmentation_facets.reset();
|
||||
this->fuzzy_skin_facets.reset();
|
||||
// Texture-displacement paint data has no remap-across-topology-change support yet (see
|
||||
// build_texture_displacement()'s documented limitation), so it must be dropped here rather
|
||||
// than left referring to a mesh that no longer matches it.
|
||||
for (int i = 0; i < int(TEXTURE_DISPLACEMENT_MAX_LAYERS); ++i)
|
||||
this->texture_displacement_facet(i).reset();
|
||||
}
|
||||
|
||||
std::optional<TriangleSelector::SavedPainting> ModelVolume::save_painting() const
|
||||
@@ -2653,16 +2648,22 @@ std::vector<int> ModelVolume::get_extruders() const
|
||||
return std::vector<int>();
|
||||
|
||||
if (mmu_segmentation_facets.timestamp() != mmuseg_ts) {
|
||||
std::vector<indexed_triangle_set> its_per_type;
|
||||
mmuseg_extruders.clear();
|
||||
mmuseg_ts = mmu_segmentation_facets.timestamp();
|
||||
mmu_segmentation_facets.get_facets(*this, its_per_type);
|
||||
for (int idx = 1; idx < its_per_type.size(); idx++) {
|
||||
indexed_triangle_set& its = its_per_type[idx];
|
||||
if (its.indices.empty())
|
||||
continue;
|
||||
// ORCA: without painting data every facet keeps its default (NONE) state, so no extruder
|
||||
// other than the volume's own one can be painted on it. Skip get_facets() then: it builds a
|
||||
// TriangleSelector with one node per facet over the whole mesh (tens of MiB on a dense one)
|
||||
// only to hand back empty sets for every extruder.
|
||||
if (! mmu_segmentation_facets.empty()) {
|
||||
std::vector<indexed_triangle_set> its_per_type;
|
||||
mmu_segmentation_facets.get_facets(*this, its_per_type);
|
||||
for (int idx = 1; idx < its_per_type.size(); idx++) {
|
||||
indexed_triangle_set& its = its_per_type[idx];
|
||||
if (its.indices.empty())
|
||||
continue;
|
||||
|
||||
mmuseg_extruders.push_back(idx);
|
||||
mmuseg_extruders.push_back(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2994,11 +2995,6 @@ void ModelVolume::assign_new_unique_ids_recursive()
|
||||
seam_facets.set_new_unique_id();
|
||||
mmu_segmentation_facets.set_new_unique_id();
|
||||
fuzzy_skin_facets.set_new_unique_id();
|
||||
// As set_new_unique_id() already does: the undo/redo stack stores FacetsAnnotation contents keyed
|
||||
// by ObjectID, so a clone left sharing these ids with its source can be handed the source's mask
|
||||
// on an undo - after which a paint mask and the mesh it was recorded against no longer match.
|
||||
for (int i = 0; i < int(TEXTURE_DISPLACEMENT_MAX_LAYERS); ++i)
|
||||
texture_displacement_facet(i).set_new_unique_id();
|
||||
}
|
||||
|
||||
void ModelVolume::rotate(double angle, Axis axis)
|
||||
@@ -3636,6 +3632,11 @@ ModelInstanceEPrintVolumeState ModelInstance::calc_print_volume_state(const Buil
|
||||
|
||||
indexed_triangle_set FacetsAnnotation::get_facets(const ModelVolume& mv, EnforcerBlockerType type) const
|
||||
{
|
||||
// ORCA: nothing is painted, so only the NONE state can have facets. Answering for any other
|
||||
// state needs no TriangleSelector (one node per facet of the whole mesh) at all.
|
||||
if (this->empty() && type != EnforcerBlockerType::NONE)
|
||||
return {};
|
||||
|
||||
TriangleSelector selector(mv.mesh());
|
||||
// Reset of TriangleSelector is done inside TriangleSelector's constructor, so we don't need it to perform it again in deserialize().
|
||||
selector.deserialize(m_data, false);
|
||||
|
||||
Reference in New Issue
Block a user