diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 255afc631..3f821ddce 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -59,6 +59,7 @@ // Enable G-Code viewer #define ENABLE_GCODE_VIEWER (1 && ENABLE_2_3_0_ALPHA1) #define ENABLE_GCODE_VIEWER_DEBUG_OUTPUT (0 && ENABLE_GCODE_VIEWER) +#define ENABLE_GCODE_VIEWER_GL_OPTIMIZATION (1 && ENABLE_GCODE_VIEWER) #define ENABLE_GCODE_VIEWER_STATISTICS (0 && ENABLE_GCODE_VIEWER) diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index db16354eb..64c027a7b 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -214,6 +214,11 @@ void GCodeViewer::refresh(const GCodeProcessor::Result& gcode_result, const std: } } +#if ENABLE_GCODE_VIEWER_GL_OPTIMIZATION + // update buffers' render paths + refresh_render_paths(); +#endif // ENABLE_GCODE_VIEWER_GL_OPTIMIZATION + #if ENABLE_GCODE_VIEWER_STATISTICS m_statistics.refresh_time = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start_time).count(); #endif // ENABLE_GCODE_VIEWER_STATISTICS @@ -345,7 +350,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) { #if ENABLE_GCODE_VIEWER_STATISTICS auto start_time = std::chrono::high_resolution_clock::now(); - m_statistics.results_size = gcode_result.moves.size() * sizeof(GCodeProcessor::MoveVertex); + m_statistics.results_size = SLIC3R_STDVEC_MEMSIZE(gcode_result.moves, GCodeProcessor::MoveVertex); #endif // ENABLE_GCODE_VIEWER_STATISTICS // vertex data @@ -363,7 +368,8 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) } #if ENABLE_GCODE_VIEWER_STATISTICS - m_statistics.vertices_size = vertices_data.size() * sizeof(float); + m_statistics.vertices_size = SLIC3R_STDVEC_MEMSIZE(vertices_data, float); + m_statistics.vertices_gpu_size = vertices_data.size() * sizeof(float); #endif // ENABLE_GCODE_VIEWER_STATISTICS // vertex data -> send to gpu @@ -424,7 +430,8 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) { buffer.data_size = buffer.data.size(); #if ENABLE_GCODE_VIEWER_STATISTICS - m_statistics.indices_size += buffer.data_size * sizeof(unsigned int); + m_statistics.indices_size += SLIC3R_STDVEC_MEMSIZE(buffer.data, unsigned int); + m_statistics.indices_gpu_size += buffer.data_size * sizeof(unsigned int); #endif // ENABLE_GCODE_VIEWER_STATISTICS if (buffer.data_size > 0) { @@ -526,7 +533,8 @@ void GCodeViewer::load_shells(const Print& print, bool initialized) } } -void GCodeViewer::render_toolpaths() const +#if ENABLE_GCODE_VIEWER_GL_OPTIMIZATION +void GCodeViewer::refresh_render_paths() const { auto extrusion_color = [this](const Path& path) { std::array color; @@ -551,6 +559,65 @@ void GCodeViewer::render_toolpaths() const Travel_Colors[0] /* Move */); }; + + for (IBuffer& buffer : m_buffers) { + buffer.render_paths = std::vector(); + for (const Path& path : buffer.paths) + { + if (!is_in_z_range(path)) + continue; + + if (path.type == GCodeProcessor::EMoveType::Extrude && !is_visible(path)) + continue; + + std::array color = { 0.0f, 0.0f, 0.0f }; + switch (path.type) + { + case GCodeProcessor::EMoveType::Extrude: { color = extrusion_color(path); break; } + case GCodeProcessor::EMoveType::Travel: { color = (m_view_type == EViewType::Feedrate || m_view_type == EViewType::Tool || m_view_type == EViewType::ColorPrint) ? extrusion_color(path) : travel_color(path); break; } + } + + auto it = std::find_if(buffer.render_paths.begin(), buffer.render_paths.end(), [color](const RenderPath& path) { return path.color == color; }); + if (it == buffer.render_paths.end()) + { + it = buffer.render_paths.insert(buffer.render_paths.end(), RenderPath()); + it->color = color; + } + + it->sizes.push_back(path.last.id - path.first.id + 1); + it->offsets.push_back(static_cast(path.first.id * sizeof(unsigned int))); + } + } +} +#endif // ENABLE_GCODE_VIEWER_GL_OPTIMIZATION + +void GCodeViewer::render_toolpaths() const +{ +#if !ENABLE_GCODE_VIEWER_GL_OPTIMIZATION + auto extrusion_color = [this](const Path& path) { + std::array color; + switch (m_view_type) + { + case EViewType::FeatureType: { color = Extrusion_Role_Colors[static_cast(path.role)]; break; } + case EViewType::Height: { color = m_extrusions.ranges.height.get_color_at(path.height); break; } + case EViewType::Width: { color = m_extrusions.ranges.width.get_color_at(path.width); break; } + case EViewType::Feedrate: { color = m_extrusions.ranges.feedrate.get_color_at(path.feedrate); break; } + case EViewType::FanSpeed: { color = m_extrusions.ranges.fan_speed.get_color_at(path.fan_speed); break; } + case EViewType::VolumetricRate: { color = m_extrusions.ranges.volumetric_rate.get_color_at(path.volumetric_rate); break; } + case EViewType::Tool: { color = m_tool_colors[path.extruder_id]; break; } + case EViewType::ColorPrint: { color = m_tool_colors[path.cp_color_id]; break; } + default: { color = { 1.0f, 1.0f, 1.0f }; break; } + } + return color; + }; + + auto travel_color = [this](const Path& path) { + return (path.delta_extruder < 0.0f) ? Travel_Colors[2] /* Retract */ : + ((path.delta_extruder > 0.0f) ? Travel_Colors[1] /* Extrude */ : + Travel_Colors[0] /* Move */); + }; +#endif // !ENABLE_GCODE_VIEWER_GL_OPTIMIZATION + auto set_color = [](GLint current_program_id, const std::array& color) { if (current_program_id > 0) { GLint color_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "uniform_color") : -1; @@ -702,6 +769,17 @@ void GCodeViewer::render_toolpaths() const } case GCodeProcessor::EMoveType::Extrude: { +#if ENABLE_GCODE_VIEWER_GL_OPTIMIZATION + for (const RenderPath& path : buffer.render_paths) + { + set_color(current_program_id, path.color); + glsafe(::glMultiDrawElements(GL_LINE_STRIP, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_INT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size())); +#if ENABLE_GCODE_VIEWER_STATISTICS + ++m_statistics.gl_multi_line_strip_calls_count; +#endif // ENABLE_GCODE_VIEWER_STATISTICS + + } +#else for (const Path& path : buffer.paths) { if (!is_visible(path) || !is_in_z_range(path)) continue; @@ -713,10 +791,22 @@ void GCodeViewer::render_toolpaths() const ++m_statistics.gl_line_strip_calls_count; #endif // ENABLE_GCODE_VIEWER_STATISTICS } +#endif // ENABLE_GCODE_VIEWER_GL_OPTIMIZATION break; } case GCodeProcessor::EMoveType::Travel: { +#if ENABLE_GCODE_VIEWER_GL_OPTIMIZATION + for (const RenderPath& path : buffer.render_paths) + { + set_color(current_program_id, path.color); + glsafe(::glMultiDrawElements(GL_LINE_STRIP, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_INT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size())); +#if ENABLE_GCODE_VIEWER_STATISTICS + ++m_statistics.gl_multi_line_strip_calls_count; +#endif // ENABLE_GCODE_VIEWER_STATISTICS + + } +#else for (const Path& path : buffer.paths) { if (!is_in_z_range(path)) continue; @@ -728,6 +818,7 @@ void GCodeViewer::render_toolpaths() const ++m_statistics.gl_line_strip_calls_count; #endif // ENABLE_GCODE_VIEWER_STATISTICS } +#endif // ENABLE_GCODE_VIEWER_GL_OPTIMIZATION break; } } @@ -840,6 +931,10 @@ void GCodeViewer::render_legend() const if (role < erCount) { m_extrusions.role_visibility_flags = is_visible(role) ? m_extrusions.role_visibility_flags & ~(1 << role) : m_extrusions.role_visibility_flags | (1 << role); +#if ENABLE_GCODE_VIEWER_GL_OPTIMIZATION + // update buffers' render paths + refresh_render_paths(); +#endif // ENABLE_GCODE_VIEWER_GL_OPTIMIZATION wxGetApp().plater()->get_current_canvas3D()->set_as_dirty(); wxGetApp().plater()->update_preview_bottom_toolbar(); } @@ -986,7 +1081,7 @@ void GCodeViewer::render_statistics() const static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f); static const float offset = 250.0f; - if (!m_legend_enabled || m_roles.empty()) + if (m_roles.empty()) return; ImGuiWrapper& imgui = *wxGetApp().imgui(); @@ -1020,6 +1115,20 @@ void GCodeViewer::render_statistics() const ImGui::SameLine(offset); imgui.text(std::to_string(m_statistics.gl_line_strip_calls_count)); +#if ENABLE_GCODE_VIEWER_GL_OPTIMIZATION + ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); + imgui.text(std::string("Multi GL_POINTS calls:")); + ImGui::PopStyleColor(); + ImGui::SameLine(offset); + imgui.text(std::to_string(m_statistics.gl_multi_points_calls_count)); + + ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); + imgui.text(std::string("Multi GL_LINE_STRIP calls:")); + ImGui::PopStyleColor(); + ImGui::SameLine(offset); + imgui.text(std::to_string(m_statistics.gl_multi_line_strip_calls_count)); +#endif // ENABLE_GCODE_VIEWER_GL_OPTIMIZATION + ImGui::Separator(); ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); @@ -1029,17 +1138,29 @@ void GCodeViewer::render_statistics() const imgui.text(std::to_string(m_statistics.results_size) + " bytes"); ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); - imgui.text(std::string("Vertices:")); + imgui.text(std::string("Vertices CPU:")); ImGui::PopStyleColor(); ImGui::SameLine(offset); imgui.text(std::to_string(m_statistics.vertices_size) + " bytes"); ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); - imgui.text(std::string("Indices:")); + imgui.text(std::string("Vertices GPU:")); + ImGui::PopStyleColor(); + ImGui::SameLine(offset); + imgui.text(std::to_string(m_statistics.vertices_gpu_size) + " bytes"); + + ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); + imgui.text(std::string("Indices CPU:")); ImGui::PopStyleColor(); ImGui::SameLine(offset); imgui.text(std::to_string(m_statistics.indices_size) + " bytes"); + ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); + imgui.text(std::string("Indices GPU:")); + ImGui::PopStyleColor(); + ImGui::SameLine(offset); + imgui.text(std::to_string(m_statistics.indices_gpu_size) + " bytes"); + imgui.end(); } #endif // ENABLE_GCODE_VIEWER_STATISTICS diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index 9688c5c4b..ec3bfc9a6 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -61,6 +61,16 @@ class GCodeViewer } }; +#if ENABLE_GCODE_VIEWER_GL_OPTIMIZATION + // Used to batch the indices needed to render paths + struct RenderPath + { + std::array color; + std::vector sizes; + std::vector offsets; // use size_t because we need the pointer's size (used in the call glMultiDrawElements()) + }; +#endif // ENABLE_GCODE_VIEWER_GL_OPTIMIZATION + // buffer containing indices data and shader for a specific toolpath type struct IBuffer { @@ -69,6 +79,9 @@ class GCodeViewer std::vector data; size_t data_size{ 0 }; std::vector paths; +#if ENABLE_GCODE_VIEWER_GL_OPTIMIZATION + std::vector render_paths; +#endif // ENABLE_GCODE_VIEWER_GL_OPTIMIZATION bool visible{ false }; void reset(); @@ -143,9 +156,15 @@ class GCodeViewer long long refresh_time{ 0 }; long long gl_points_calls_count{ 0 }; long long gl_line_strip_calls_count{ 0 }; +#if ENABLE_GCODE_VIEWER_GL_OPTIMIZATION + long long gl_multi_points_calls_count{ 0 }; + long long gl_multi_line_strip_calls_count{ 0 }; +#endif // ENABLE_GCODE_VIEWER_GL_OPTIMIZATION long long results_size{ 0 }; long long vertices_size{ 0 }; + long long vertices_gpu_size{ 0 }; long long indices_size{ 0 }; + long long indices_gpu_size{ 0 }; void reset_all() { reset_times(); @@ -161,12 +180,18 @@ class GCodeViewer void reset_opengl() { gl_points_calls_count = 0; gl_line_strip_calls_count = 0; +#if ENABLE_GCODE_VIEWER_GL_OPTIMIZATION + gl_multi_points_calls_count = 0; + gl_multi_line_strip_calls_count = 0; +#endif // ENABLE_GCODE_VIEWER_GL_OPTIMIZATION } void reset_sizes() { results_size = 0; vertices_size = 0; + vertices_gpu_size = 0; indices_size = 0; + indices_gpu_size = 0; } }; #endif // ENABLE_GCODE_VIEWER_STATISTICS @@ -246,6 +271,9 @@ private: bool init_shaders(); void load_toolpaths(const GCodeProcessor::Result& gcode_result); void load_shells(const Print& print, bool initialized); +#if ENABLE_GCODE_VIEWER_GL_OPTIMIZATION + void refresh_render_paths() const; +#endif // ENABLE_GCODE_VIEWER_GL_OPTIMIZATION void render_toolpaths() const; void render_shells() const; void render_legend() const;