Skip to content

Commit

Permalink
Fix slowdown issue due to copy of large data.
Browse files Browse the repository at this point in the history
Since `make_shared` is a constructor, the mesh data was copied over each time we started a new layer. Properly fix this by using smart-pointers from the beginning, so we only have the creation overhead, which is nearly nothing. In fact, this solution may be _faster_ than the original, perhaps due to some constness that is now also enforced.

fixes internal ticket CURA-11019
  • Loading branch information
rburema committed Sep 15, 2023
1 parent 4aa7391 commit 9b5da0e
Show file tree
Hide file tree
Showing 14 changed files with 90 additions and 76 deletions.
5 changes: 2 additions & 3 deletions include/FffGcodeWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -328,13 +328,12 @@ class FffGcodeWriter : public NoCopy
* This adds all features (e.g. walls, skin etc.) of this \p mesh to the gcode which are printed using \p extruder_nr
*
* \param[in] storage where the slice data is stored.
* \param mesh The mesh to add to the layer plan \p gcode_layer.
* \param mesh_ptr The mesh to add to the layer plan \p gcode_layer.
* \param extruder_nr The extruder for which to print all features of the mesh which should be printed with this extruder
* \param mesh_config the line config with which to print a print feature
* \param gcode_layer The initial planning of the gcode of the layer.
*/
void addMeshLayerToGCode(const SliceDataStorage& storage, const SliceMeshStorage& mesh, const size_t extruder_nr, const MeshPathConfigs& mesh_config, LayerPlan& gcode_layer)
const;
void addMeshLayerToGCode(const SliceDataStorage& storage, const std::shared_ptr<SliceMeshStorage>& mesh_ptr, const size_t extruder_nr, const MeshPathConfigs& mesh_config, LayerPlan& gcode_layer) const;

/*!
* Add all features of the given extruder from a single part from a given layer of a mesh-volume to the layer plan \p gcode_layer.
Expand Down
4 changes: 2 additions & 2 deletions include/LayerPlan.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class LayerPlan : public NoCopy
std::vector<bool> has_prime_tower_planned_per_extruder; //!< For each extruder, whether the prime tower is planned yet or not.
std::optional<Point> last_planned_position; //!< The last planned XY position of the print head (if known)

std::shared_ptr<SliceMeshStorage> current_mesh; //!< The mesh of the last planned move.
std::shared_ptr<const SliceMeshStorage> current_mesh; //!< The mesh of the last planned move.

/*!
* Whether the skirt or brim polygons have been processed into planned paths
Expand Down Expand Up @@ -238,7 +238,7 @@ class LayerPlan : public NoCopy
* Track the currently printing mesh.
* \param mesh_id A unique ID indicating the current mesh.
*/
void setMesh(const std::shared_ptr<SliceMeshStorage>& mesh);
void setMesh(const std::shared_ptr<const SliceMeshStorage>& mesh);

/*!
* Set bridge_wall_mask.
Expand Down
2 changes: 1 addition & 1 deletion include/pathPlanning/GCodePath.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ namespace cura
struct GCodePath
{
GCodePathConfig config{}; //!< The configuration settings of the path.
std::shared_ptr<SliceMeshStorage> mesh; //!< Which mesh this path belongs to, if any. If it's not part of any mesh, the mesh should be nullptr;
std::shared_ptr<const SliceMeshStorage> mesh; //!< Which mesh this path belongs to, if any. If it's not part of any mesh, the mesh should be nullptr;
SpaceFillType space_fill_type{}; //!< The type of space filling of which this path is a part
Ratio flow{}; //!< A type-independent flow configuration
Ratio width_factor{}; //!< Adjustment to the line width. Similar to flow, but causes the speed_back_pressure_factor to be adjusted.
Expand Down
2 changes: 1 addition & 1 deletion include/sliceDataStorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ class SliceDataStorage : public NoCopy

Point3 model_size, model_min, model_max;
AABB3D machine_size; //!< The bounding box with the width, height and depth of the printer.
std::vector<SliceMeshStorage> meshes;
std::vector<std::shared_ptr<SliceMeshStorage>> meshes;

std::vector<RetractionAndWipeConfig> retraction_wipe_config_per_extruder; //!< Config for retractions, extruder switch retractions, and wipes, per extruder.

Expand Down
39 changes: 22 additions & 17 deletions src/FffGcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,9 @@ void FffGcodeWriter::writeGCode(SliceDataStorage& storage, TimeKeeper& time_keep
}

size_t total_layers = 0;
for (SliceMeshStorage& mesh : storage.meshes)
for (auto& mesh_ptr : storage.meshes)
{
auto& mesh = *mesh_ptr;
size_t mesh_layer_num = mesh.layers.size();

// calculation of _actual_ number of layers in loop.
Expand Down Expand Up @@ -269,7 +270,7 @@ void FffGcodeWriter::findLayerSeamsForSpiralize(SliceDataStorage& storage, size_
const std::vector<size_t>& mesh_order = mesh_order_per_extruder[extruder_nr];
for (unsigned int mesh_idx : mesh_order)
{
SliceMeshStorage& mesh = storage.meshes[mesh_idx];
auto& mesh = *storage.meshes[mesh_idx];
// if this mesh has layer data for this layer process it
if (! done_this_layer && mesh.layers.size() > layer_nr)
{
Expand Down Expand Up @@ -371,9 +372,9 @@ void FffGcodeWriter::setConfigRetractionAndWipe(SliceDataStorage& storage)
ExtruderTrain& train = scene.extruders[extruder_index];
retractionAndWipeConfigFromSettings(train.settings, &storage.retraction_wipe_config_per_extruder[extruder_index]);
}
for (SliceMeshStorage& mesh : storage.meshes)
for (auto& mesh : storage.meshes)
{
retractionAndWipeConfigFromSettings(mesh.settings, &mesh.retraction_wipe_config);
retractionAndWipeConfigFromSettings(mesh->settings, &mesh->retraction_wipe_config);
}
}

Expand Down Expand Up @@ -505,9 +506,9 @@ void FffGcodeWriter::setSupportAngles(SliceDataStorage& storage)
}
else
{
for (const SliceMeshStorage& mesh : storage.meshes)
for (const auto& mesh : storage.meshes)
{
if (mesh.settings.get<coord_t>(interface_height_setting)
if (mesh->settings.get<coord_t>(interface_height_setting)
>= 2 * Application::getInstance().current_slice->scene.current_mesh_group->settings.get<coord_t>("layer_height"))
{
// Some roofs are quite thick.
Expand Down Expand Up @@ -913,10 +914,11 @@ LayerPlan& FffGcodeWriter::processLayer(const SliceDataStorage& storage, LayerIn
}
else
{
z = storage.meshes[0].layers[layer_nr].printZ; // stub default
z = storage.meshes[0]->layers[layer_nr].printZ; // stub default
// find printZ of first actual printed mesh
for (const SliceMeshStorage& mesh : storage.meshes)
for (const auto& mesh_ptr : storage.meshes)
{
const auto& mesh = *mesh_ptr;
if (layer_nr >= static_cast<int>(mesh.layers.size()) || mesh.settings.get<bool>("support_mesh") || mesh.settings.get<bool>("anti_overhang_mesh")
|| mesh.settings.get<bool>("cutting_mesh") || mesh.settings.get<bool>("infill_mesh"))
{
Expand Down Expand Up @@ -951,8 +953,9 @@ LayerPlan& FffGcodeWriter::processLayer(const SliceDataStorage& storage, LayerIn
}

coord_t max_inner_wall_width = 0;
for (const SliceMeshStorage& mesh : storage.meshes)
for (const auto& mesh_ptr : storage.meshes)
{
const auto& mesh = *mesh_ptr;
coord_t mesh_inner_wall_width = mesh.settings.get<coord_t>((mesh.settings.get<size_t>("wall_line_count") > 1) ? "wall_line_width_x" : "wall_line_width_0");
if (layer_nr == 0)
{
Expand Down Expand Up @@ -1022,14 +1025,14 @@ LayerPlan& FffGcodeWriter::processLayer(const SliceDataStorage& storage, LayerIn
const std::vector<size_t>& mesh_order = mesh_order_per_extruder[extruder_nr];
for (size_t mesh_idx : mesh_order)
{
const SliceMeshStorage& mesh = storage.meshes[mesh_idx];
const auto& mesh = storage.meshes[mesh_idx];
const MeshPathConfigs& mesh_config = gcode_layer.configs_storage.mesh_configs[mesh_idx];
if (mesh.settings.get<ESurfaceMode>("magic_mesh_surface_mode") == ESurfaceMode::SURFACE
if (mesh->settings.get<ESurfaceMode>("magic_mesh_surface_mode") == ESurfaceMode::SURFACE
&& extruder_nr
== mesh.settings.get<ExtruderTrain&>("wall_0_extruder_nr").extruder_nr // mesh surface mode should always only be printed with the outer wall extruder!
== mesh->settings.get<ExtruderTrain&>("wall_0_extruder_nr").extruder_nr // mesh surface mode should always only be printed with the outer wall extruder!
)
{
addMeshLayerToGCode_meshSurfaceMode(storage, mesh, mesh_config, gcode_layer);
addMeshLayerToGCode_meshSurfaceMode(storage, *mesh, mesh_config, gcode_layer);
}
else
{
Expand Down Expand Up @@ -1382,7 +1385,7 @@ std::vector<size_t> FffGcodeWriter::calculateMeshOrder(const SliceDataStorage& s
std::vector<MeshGroup>::iterator mesh_group = Application::getInstance().current_slice->scene.current_mesh_group;
for (unsigned int mesh_idx = 0; mesh_idx < storage.meshes.size(); mesh_idx++)
{
const SliceMeshStorage& mesh = storage.meshes[mesh_idx];
const auto& mesh = *storage.meshes[mesh_idx];
if (mesh.getExtruderIsUsed(extruder_nr))
{
const Mesh& mesh_data = mesh_group->meshes[mesh_idx];
Expand Down Expand Up @@ -1449,11 +1452,12 @@ void FffGcodeWriter::addMeshOpenPolyLinesToGCode(const SliceMeshStorage& mesh, c

void FffGcodeWriter::addMeshLayerToGCode(
const SliceDataStorage& storage,
const SliceMeshStorage& mesh,
const std::shared_ptr<SliceMeshStorage>& mesh_ptr,
const size_t extruder_nr,
const MeshPathConfigs& mesh_config,
LayerPlan& gcode_layer) const
{
const auto& mesh = *mesh_ptr;
if (gcode_layer.getLayerNr() > mesh.layer_nr_max_filled_layer)
{
return;
Expand All @@ -1471,7 +1475,7 @@ void FffGcodeWriter::addMeshLayerToGCode(
return;
}

gcode_layer.setMesh(std::make_shared<SliceMeshStorage>(mesh));
gcode_layer.setMesh(mesh_ptr);

ZSeamConfig z_seam_config;
if (mesh.isPrinted()) //"normal" meshes with walls, skin, infill, etc. get the traditional part ordering based on the z-seam settings.
Expand Down Expand Up @@ -2259,8 +2263,9 @@ bool FffGcodeWriter::processInsets(

Polygons outlines_below;
AABB boundaryBox(part.outline);
for (const SliceMeshStorage& m : storage.meshes)
for (const auto& mesh_ptr : storage.meshes)
{
const auto& m = *mesh_ptr;
if (m.isPrinted())
{
for (const SliceLayerPart& prevLayerPart : m.layers[gcode_layer.getLayerNr() - 1].parts)
Expand Down
30 changes: 17 additions & 13 deletions src/FffPolygonGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,8 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe
Mesh& mesh = scene.current_mesh_group->meshes[meshIdx];

// always make a new SliceMeshStorage, so that they have the same ordering / indexing as meshgroup.meshes
storage.meshes.emplace_back(&meshgroup->meshes[meshIdx], slicer->layers.size()); // new mesh in storage had settings from the Mesh
SliceMeshStorage& meshStorage = storage.meshes.back();
storage.meshes.push_back(std::make_shared<SliceMeshStorage>(& meshgroup->meshes[meshIdx], slicer->layers.size())); // new mesh in storage had settings from the Mesh
auto& meshStorage = *storage.meshes.back();

// only create layer parts for normal meshes
const bool is_support_modifier = AreaSupport::handleSupportModifierMesh(storage, mesh.settings, slicer);
Expand Down Expand Up @@ -347,8 +347,9 @@ void FffPolygonGenerator::slices2polygons(SliceDataStorage& storage, TimeKeeper&
// compute layer count and remove first empty layers
// there is no separate progress stage for removeEmptyFisrtLayer (TODO)
unsigned int slice_layer_count = 0;
for (SliceMeshStorage& mesh : storage.meshes)
for (auto& mesh_ptr : storage.meshes)
{
auto& mesh = *mesh_ptr;
if (! mesh.settings.get<bool>("infill_mesh") && ! mesh.settings.get<bool>("anti_overhang_mesh"))
{
slice_layer_count = std::max<unsigned int>(slice_layer_count, mesh.layers.size());
Expand All @@ -369,7 +370,7 @@ void FffPolygonGenerator::slices2polygons(SliceDataStorage& storage, TimeKeeper&
std::multimap<int, size_t> order_to_mesh_indices;
for (size_t mesh_idx = 0; mesh_idx < storage.meshes.size(); mesh_idx++)
{
order_to_mesh_indices.emplace(storage.meshes[mesh_idx].settings.get<int>("infill_mesh_order"), mesh_idx);
order_to_mesh_indices.emplace(storage.meshes[mesh_idx]->settings.get<int>("infill_mesh_order"), mesh_idx);
}
for (std::pair<const int, size_t>& order_and_mesh_idx : order_to_mesh_indices)
{
Expand Down Expand Up @@ -432,9 +433,9 @@ void FffPolygonGenerator::slices2polygons(SliceDataStorage& storage, TimeKeeper&

spdlog::debug("Meshes post-processing");
// meshes post processing
for (SliceMeshStorage& mesh : storage.meshes)
for (auto& mesh : storage.meshes)
{
processDerivedWallsSkinInfill(mesh);
processDerivedWallsSkinInfill(*mesh);
}

spdlog::debug("Processing gradual support");
Expand All @@ -449,7 +450,7 @@ void FffPolygonGenerator::processBasicWallsSkinInfill(
ProgressStageEstimator& inset_skin_progress_estimate)
{
size_t mesh_idx = mesh_order[mesh_order_idx];
SliceMeshStorage& mesh = storage.meshes[mesh_idx];
SliceMeshStorage& mesh = *storage.meshes[mesh_idx];
size_t mesh_layer_count = mesh.layers.size();
if (mesh.settings.get<bool>("infill_mesh"))
{
Expand Down Expand Up @@ -513,7 +514,7 @@ void FffPolygonGenerator::processBasicWallsSkinInfill(
for (size_t other_mesh_order_idx = mesh_order_idx + 1; other_mesh_order_idx < mesh_order.size(); ++other_mesh_order_idx)
{
const size_t other_mesh_idx = mesh_order[other_mesh_order_idx];
SliceMeshStorage& other_mesh = storage.meshes[other_mesh_idx];
SliceMeshStorage& other_mesh = *storage.meshes[other_mesh_idx];
if (other_mesh.settings.get<bool>("infill_mesh"))
{
AABB3D aabb = scene.current_mesh_group->meshes[mesh_idx].getAABB();
Expand Down Expand Up @@ -553,7 +554,7 @@ void FffPolygonGenerator::processBasicWallsSkinInfill(
void FffPolygonGenerator::processInfillMesh(SliceDataStorage& storage, const size_t mesh_order_idx, const std::vector<size_t>& mesh_order)
{
size_t mesh_idx = mesh_order[mesh_order_idx];
SliceMeshStorage& mesh = storage.meshes[mesh_idx];
SliceMeshStorage& mesh = *storage.meshes[mesh_idx];
coord_t surface_line_width = mesh.settings.get<coord_t>("wall_line_width_0");

mesh.layer_nr_max_filled_layer = -1;
Expand Down Expand Up @@ -585,7 +586,7 @@ void FffPolygonGenerator::processInfillMesh(SliceDataStorage& storage, const siz
{
break; // all previous meshes have been processed
}
SliceMeshStorage& other_mesh = storage.meshes[other_mesh_idx];
SliceMeshStorage& other_mesh = *storage.meshes[other_mesh_idx];
if (layer_idx >= static_cast<LayerIndex>(other_mesh.layers.size()))
{ // there can be no interaction between the infill mesh and this other non-infill mesh
continue;
Expand Down Expand Up @@ -741,8 +742,9 @@ bool FffPolygonGenerator::isEmptyLayer(SliceDataStorage& storage, const LayerInd
return false;
}
}
for (SliceMeshStorage& mesh : storage.meshes)
for (auto& mesh_ptr : storage.meshes)
{
auto& mesh = *mesh_ptr;
if (layer_idx >= mesh.layers.size())
{
continue;
Expand Down Expand Up @@ -782,8 +784,9 @@ void FffPolygonGenerator::removeEmptyFirstLayers(SliceDataStorage& storage, size
{
spdlog::info("Removing {} layers because they are empty", n_empty_first_layers);
const coord_t layer_height = Application::getInstance().current_slice->scene.current_mesh_group->settings.get<coord_t>("layer_height");
for (SliceMeshStorage& mesh : storage.meshes)
for (auto& mesh_ptr : storage.meshes)
{
auto& mesh = *mesh_ptr;
std::vector<SliceLayer>& layers = mesh.layers;
if (layers.size() > n_empty_first_layers)
{
Expand Down Expand Up @@ -852,8 +855,9 @@ void FffPolygonGenerator::computePrintHeightStatistics(SliceDataStorage& storage
max_print_height_per_extruder.resize(extruder_count, -(raft_layers + 1)); // Initialize all as -1 (or lower in case of raft).
{ // compute max_object_height_per_extruder
// Height of the meshes themselves.
for (SliceMeshStorage& mesh : storage.meshes)
for (auto& mesh_ptr : storage.meshes)
{
auto& mesh = *mesh_ptr;
if (mesh.settings.get<bool>("anti_overhang_mesh") || mesh.settings.get<bool>("support_mesh"))
{
continue; // Special type of mesh that doesn't get printed.
Expand Down
11 changes: 6 additions & 5 deletions src/LayerPlan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,9 @@ Polygons LayerPlan::computeCombBoundary(const CombBoundary boundary_type)
}
else
{
for (const SliceMeshStorage& mesh : storage.meshes)
for (const auto& mesh_ptr : storage.meshes)
{
const auto& mesh = *mesh_ptr;
const SliceLayer& layer = mesh.layers[static_cast<size_t>(layer_nr)];
// don't process infill_mesh or anti_overhang_mesh
if (mesh.settings.get<bool>("infill_mesh") || mesh.settings.get<bool>("anti_overhang_mesh"))
Expand Down Expand Up @@ -282,7 +283,7 @@ bool LayerPlan::setExtruder(const size_t extruder_nr)
}
return true;
}
void LayerPlan::setMesh(const std::shared_ptr<SliceMeshStorage>& mesh)
void LayerPlan::setMesh(const std::shared_ptr<const SliceMeshStorage>& mesh)
{
current_mesh = mesh;
}
Expand Down Expand Up @@ -1187,9 +1188,9 @@ void LayerPlan::addLinesByOptimizer(
if (layer_nr >= 0)
{
// determine how much the skin/infill lines overlap the combing boundary
for (const SliceMeshStorage& mesh : storage.meshes)
for (const auto& mesh : storage.meshes)
{
const coord_t overlap = std::max(mesh.settings.get<coord_t>("skin_overlap_mm"), mesh.settings.get<coord_t>("infill_overlap_mm"));
const coord_t overlap = std::max(mesh->settings.get<coord_t>("skin_overlap_mm"), mesh->settings.get<coord_t>("infill_overlap_mm"));
if (overlap > dist)
{
dist = overlap;
Expand Down Expand Up @@ -1846,7 +1847,7 @@ void LayerPlan::writeGCode(GCodeExport& gcode)
const bool acceleration_travel_enabled = mesh_group_settings.get<bool>("acceleration_travel_enabled");
const bool jerk_enabled = mesh_group_settings.get<bool>("jerk_enabled");
const bool jerk_travel_enabled = mesh_group_settings.get<bool>("jerk_travel_enabled");
std::shared_ptr<SliceMeshStorage> current_mesh;
std::shared_ptr<const SliceMeshStorage> current_mesh;

for (size_t extruder_plan_idx = 0; extruder_plan_idx < extruder_plans.size(); extruder_plan_idx++)
{
Expand Down
5 changes: 3 additions & 2 deletions src/TreeModelVolumes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@ TreeModelVolumes::TreeModelVolumes(
coord_t min_maximum_area_deviation = std::numeric_limits<coord_t>::max();

support_rests_on_model = false;
for (auto [mesh_idx, mesh] : storage.meshes | ranges::views::enumerate)
for (auto [mesh_idx, mesh_ptr] : storage.meshes | ranges::views::enumerate)
{
auto& mesh = *mesh_ptr;
bool added = false;
for (auto [idx, layer_outline] : layer_outlines_ | ranges::views::enumerate)
{
Expand Down Expand Up @@ -103,7 +104,7 @@ TreeModelVolumes::TreeModelVolumes(
{
// Workaround for compiler bug on apple-clang -- Closure won't properly capture variables in capture lists in outer scope.
const auto& mesh_idx_l = mesh_idx;
const auto& mesh_l = mesh;
const auto& mesh_l = *mesh;
// ^^^ Remove when fixed (and rename accordingly in the below parallel-for).

cura::parallel_for<coord_t>(
Expand Down
Loading

0 comments on commit 9b5da0e

Please sign in to comment.