Fix of incorrect color print preview due to the tbb::parallel_for

not respecting the grain size exactly.
Also the tool path generation has been optimized to launch less
threads and to produce larger vertex buffers.
This commit is contained in:
bubnikv 2019-06-24 15:27:32 +02:00
parent 8ffd79cdd8
commit 198600543d

View File

@ -4627,17 +4627,12 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
bool color_by_tool() const { return tool_colors != nullptr; } bool color_by_tool() const { return tool_colors != nullptr; }
size_t number_tools() const { return this->color_by_tool() ? tool_colors->size() / 4 : 0; } size_t number_tools() const { return this->color_by_tool() ? tool_colors->size() / 4 : 0; }
const float* color_tool(size_t tool) const { return tool_colors->data() + tool * 4; } const float* color_tool(size_t tool) const { return tool_colors->data() + tool * 4; }
int volume_idx(int extruder, int feature) const
{
return this->color_by_color_print() ? 0 : this->color_by_tool() ? std::min<int>(this->number_tools() - 1, std::max<int>(extruder - 1, 0)) : feature;
}
// For coloring by a color_print(M600), return a parsed color. // For coloring by a color_print(M600), return a parsed color.
bool color_by_color_print() const { return color_print_values!=nullptr; } bool color_by_color_print() const { return color_print_values!=nullptr; }
const float* color_print_by_layer_idx(const size_t layer_idx) const const size_t color_print_color_idx_by_layer_idx(const size_t layer_idx) const {
{
auto it = std::lower_bound(color_print_values->begin(), color_print_values->end(), layers[layer_idx]->print_z + EPSILON); auto it = std::lower_bound(color_print_values->begin(), color_print_values->end(), layers[layer_idx]->print_z + EPSILON);
return color_tool((it - color_print_values->begin()) % number_tools()); return (it - color_print_values->begin()) % number_tools();
} }
} ctxt; } ctxt;
@ -4670,7 +4665,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - start"; BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - start";
//FIXME Improve the heuristics for a grain size. //FIXME Improve the heuristics for a grain size.
size_t grain_size = ctxt.color_by_color_print() ? size_t(1) : std::max(ctxt.layers.size() / 16, size_t(1)); size_t grain_size = std::max(ctxt.layers.size() / 16, size_t(1));
tbb::spin_mutex new_volume_mutex; tbb::spin_mutex new_volume_mutex;
auto new_volume = [this, &new_volume_mutex](const float *color) -> GLVolume* { auto new_volume = [this, &new_volume_mutex](const float *color) -> GLVolume* {
auto *volume = new GLVolume(color); auto *volume = new GLVolume(color);
@ -4680,13 +4675,33 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
return volume; return volume;
}; };
const size_t volumes_cnt_initial = m_volumes.volumes.size(); const size_t volumes_cnt_initial = m_volumes.volumes.size();
std::vector<GLVolumeCollection> volumes_per_thread(ctxt.layers.size());
tbb::parallel_for( tbb::parallel_for(
tbb::blocked_range<size_t>(0, ctxt.layers.size(), grain_size), tbb::blocked_range<size_t>(0, ctxt.layers.size(), grain_size),
[&ctxt, &new_volume](const tbb::blocked_range<size_t>& range) { [&ctxt, &new_volume](const tbb::blocked_range<size_t>& range) {
GLVolumePtrs vols; GLVolumePtrs vols;
if (ctxt.color_by_color_print()) std::vector<size_t> color_print_layer_to_glvolume;
vols.emplace_back(new_volume(ctxt.color_print_by_layer_idx(range.begin()))); auto volume = [&ctxt, &vols, &color_print_layer_to_glvolume, &range](size_t layer_idx, int extruder, int feature) -> GLVolume& {
return *vols[ctxt.color_by_color_print() ?
color_print_layer_to_glvolume[layer_idx - range.begin()] :
ctxt.color_by_tool() ?
std::min<int>(ctxt.number_tools() - 1, std::max<int>(extruder - 1, 0)) :
feature
];
};
if (ctxt.color_by_color_print()) {
// Create a map from the layer index to a GLVolume, which is initialized with the correct layer span color.
std::vector<int> color_print_tool_to_glvolume(ctxt.number_tools(), -1);
color_print_layer_to_glvolume.reserve(range.end() - range.begin());
vols.reserve(ctxt.number_tools());
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
int idx_tool = (int)ctxt.color_print_color_idx_by_layer_idx(idx_layer);
if (color_print_tool_to_glvolume[idx_tool] == -1) {
color_print_tool_to_glvolume[idx_tool] = (int)vols.size();
vols.emplace_back(new_volume(ctxt.color_tool(idx_tool)));
}
color_print_layer_to_glvolume.emplace_back(color_print_tool_to_glvolume[idx_tool]);
}
}
else if (ctxt.color_by_tool()) { else if (ctxt.color_by_tool()) {
for (size_t i = 0; i < ctxt.number_tools(); ++i) for (size_t i = 0; i < ctxt.number_tools(); ++i)
vols.emplace_back(new_volume(ctxt.color_tool(i))); vols.emplace_back(new_volume(ctxt.color_tool(i)));
@ -4695,32 +4710,30 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
vols = { new_volume(ctxt.color_perimeters()), new_volume(ctxt.color_infill()), new_volume(ctxt.color_support()) }; vols = { new_volume(ctxt.color_perimeters()), new_volume(ctxt.color_infill()), new_volume(ctxt.color_support()) };
for (GLVolume *vol : vols) for (GLVolume *vol : vols)
vol->indexed_vertex_array.reserve(ctxt.alloc_size_reserve()); vol->indexed_vertex_array.reserve(ctxt.alloc_size_reserve());
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++idx_layer) { for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
const Layer *layer = ctxt.layers[idx_layer]; const Layer *layer = ctxt.layers[idx_layer];
for (size_t i = 0; i < vols.size(); ++i) { for (GLVolume *vol : vols)
GLVolume &vol = *vols[i]; if (vol->print_zs.empty() || vol->print_zs.back() != layer->print_z) {
if (vol.print_zs.empty() || vol.print_zs.back() != layer->print_z) { vol->print_zs.push_back(layer->print_z);
vol.print_zs.push_back(layer->print_z); vol->offsets.push_back(vol->indexed_vertex_array.quad_indices.size());
vol.offsets.push_back(vol.indexed_vertex_array.quad_indices.size()); vol->offsets.push_back(vol->indexed_vertex_array.triangle_indices.size());
vol.offsets.push_back(vol.indexed_vertex_array.triangle_indices.size());
}
} }
for (const Point &copy : *ctxt.shifted_copies) { for (const Point &copy : *ctxt.shifted_copies) {
for (const LayerRegion *layerm : layer->regions()) { for (const LayerRegion *layerm : layer->regions()) {
if (ctxt.has_perimeters) if (ctxt.has_perimeters)
_3DScene::extrusionentity_to_verts(layerm->perimeters, float(layer->print_z), copy, _3DScene::extrusionentity_to_verts(layerm->perimeters, float(layer->print_z), copy,
*vols[ctxt.volume_idx(layerm->region()->config().perimeter_extruder.value, 0)]); volume(idx_layer, layerm->region()->config().perimeter_extruder.value, 0));
if (ctxt.has_infill) { if (ctxt.has_infill) {
for (const ExtrusionEntity *ee : layerm->fills.entities) { for (const ExtrusionEntity *ee : layerm->fills.entities) {
// fill represents infill extrusions of a single island. // fill represents infill extrusions of a single island.
const auto *fill = dynamic_cast<const ExtrusionEntityCollection*>(ee); const auto *fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
if (!fill->entities.empty()) if (! fill->entities.empty())
_3DScene::extrusionentity_to_verts(*fill, float(layer->print_z), copy, _3DScene::extrusionentity_to_verts(*fill, float(layer->print_z), copy,
*vols[ctxt.volume_idx( volume(idx_layer,
is_solid_infill(fill->entities.front()->role()) ? is_solid_infill(fill->entities.front()->role()) ?
layerm->region()->config().solid_infill_extruder : layerm->region()->config().solid_infill_extruder :
layerm->region()->config().infill_extruder, layerm->region()->config().infill_extruder,
1)]); 1));
} }
} }
} }
@ -4729,33 +4742,32 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
if (support_layer) { if (support_layer) {
for (const ExtrusionEntity *extrusion_entity : support_layer->support_fills.entities) for (const ExtrusionEntity *extrusion_entity : support_layer->support_fills.entities)
_3DScene::extrusionentity_to_verts(extrusion_entity, float(layer->print_z), copy, _3DScene::extrusionentity_to_verts(extrusion_entity, float(layer->print_z), copy,
*vols[ctxt.volume_idx( volume(idx_layer,
(extrusion_entity->role() == erSupportMaterial) ? (extrusion_entity->role() == erSupportMaterial) ?
support_layer->object()->config().support_material_extruder : support_layer->object()->config().support_material_extruder :
support_layer->object()->config().support_material_interface_extruder, support_layer->object()->config().support_material_interface_extruder,
2)]); 2));
} }
} }
} }
for (size_t i = 0; i < vols.size(); ++i) { // Ensure that no volume grows over the limits. If the volume is too large, allocate a new one.
GLVolume &vol = *vols[i]; for (GLVolume *&vol : vols)
if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() / 6 > ctxt.alloc_size_max()) { if (vol->indexed_vertex_array.vertices_and_normals_interleaved.size() / 6 > ctxt.alloc_size_max()) {
// Store the vertex arrays and restart their containers, // Store the vertex arrays and restart their containers,
vols[i] = new_volume(vol.color); vol = new_volume(vol->color);
GLVolume &vol_new = *vols[i]; GLVolume &vol_new = *vol;
// Assign the large pre-allocated buffers to the new GLVolume. // Assign the large pre-allocated buffers to the new GLVolume.
vol_new.indexed_vertex_array = std::move(vol.indexed_vertex_array); vol_new.indexed_vertex_array = std::move(vol->indexed_vertex_array);
// Copy the content back to the old GLVolume. // Copy the content back to the old GLVolume.
vol.indexed_vertex_array = vol_new.indexed_vertex_array; vol->indexed_vertex_array = vol_new.indexed_vertex_array;
// Finalize a bounding box of the old GLVolume. // Finalize a bounding box of the old GLVolume.
vol.bounding_box = vol.indexed_vertex_array.bounding_box(); vol->bounding_box = vol->indexed_vertex_array.bounding_box();
// Clear the buffers, but keep them pre-allocated. // Clear the buffers, but keep them pre-allocated.
vol_new.indexed_vertex_array.clear(); vol_new.indexed_vertex_array.clear();
// Just make sure that clear did not clear the reserved memory. // Just make sure that clear did not clear the reserved memory.
vol_new.indexed_vertex_array.reserve(ctxt.alloc_size_reserve()); vol_new.indexed_vertex_array.reserve(ctxt.alloc_size_reserve());
} }
} }
}
for (GLVolume *vol : vols) { for (GLVolume *vol : vols) {
vol->bounding_box = vol->indexed_vertex_array.bounding_box(); vol->bounding_box = vol->indexed_vertex_array.bounding_box();
vol->indexed_vertex_array.shrink_to_fit(); vol->indexed_vertex_array.shrink_to_fit();