mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-27 10:51:22 +00:00
Answer the Preview's Per-Frame Lookups From Cached Sums and Draw Segments From an Index Buffer (#15833)
* Answer the Preview's Per-Frame Time Query From a Cached Sum The G-code preview's cost is linear in the number of toolpath vertices, and on a tall multi-filament print the wipe tower dominates that count: it emits a roughly constant 160-180 moves on every layer whatever the object is, measured at 57-61% of all moves on a three-filament print. Four places scanned or allocated across the whole vertex array. None of them needed to. get_estimated_time_at re-accumulated the estimated time from vertex 0 on every call, and its caller is the tool marker tooltip, which ImGui re-renders every frame while the properties panel is unfolded. It now starts from a running sum kept at each layer's first vertex, built at load in vertex order, and adds only that layer's vertices: the same additions in the same order, so the float result is unchanged, at a cost of one float per layer and time mode rather than per vertex. At the 351k vertices of a 636-layer test print the call scanned the whole print (238us); it now scans one layer. update_view_full_range walked from vertex 0 to find where the layer range starts, on every slider tick. It now starts at the first vertex of that layer. The index is derived from the vertices rather than from Layers::Item::range, because Layers::update folds a vertex whose layer_id arrives out of order into whichever bucket is open, which makes that range the wrong answer in general; the index costs four bytes per layer, not per vertex. update_colors_texture allocated one float per vertex of the whole print on every slider tick. It now reuses a buffer. render_legend fetched the layer Zs and the per-layer times from inside loops over the custom G-code items, and built whole vectors only to test them for emptiness. The times are hoisted, the Zs are built lazily so a print with no colour change does not pay for them at all, and the emptiness tests use the existing counters. No rendering behaviour changes. * Draw the Preview's Toolpath Segments From an Index Buffer The preview's frame cost is dominated by one call: a single instanced draw of every visible toolpath segment. On a tall multi-filament print the wipe tower supplies most of those segments, which is why the preview of a large tower is slow and why shrinking the layer range speeds it up again. That draw is not fill bound. Shrinking the model to about a fortieth of its screen area moved the frame from 419 ms to 401 ms, so the cost is per segment, not per pixel, and it is paid in the vertex shader: five texelFetch calls plus several cross/normalize per invocation. Each segment is a box of eight corners, but it was submitted with glDrawArraysInstanced over a 24 entry array, so every corner was transformed once per triangle that touches it and the shader ran 24 times per segment. The same 24 entries are now an element buffer over the eight distinct corners, which lets the post-transform cache reuse them and drops the shader to 8 runs per segment. The triangles, their winding and the vertex_id each corner receives are unchanged. Measured over 100 frames on the 636-layer, 351k-vertex three-filament fixture, the segment draw goes from 381 ms to 322 ms per frame. That is a software rasterizer, where triangle setup dominates and understates the win; the drop in shader invocations is the transferable part. Verified by loading the same project in this build and in a build of the parent commit and comparing the canvas across three states - the default view, a rotated camera, and a reduced layer range: pixel identical in all three. The rotated case matters because the shader picks its corner offsets from the camera direction. The only pixels that differ anywhere on screen are in the G-code text panel, which prints a per-process object id that varies between any two runs.
This commit is contained in:
@@ -1698,7 +1698,7 @@ void GCodeViewer::render_scene(int canvas_width, int canvas_height)
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
render_shells(canvas_width, canvas_height);
|
||||
|
||||
if (m_viewer.get_extrusion_roles().empty())
|
||||
if (m_viewer.get_extrusion_roles_count() == 0)
|
||||
return;
|
||||
|
||||
render_toolpaths();
|
||||
@@ -3520,6 +3520,12 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
std::vector<std::pair<ColorRGBA, std::pair<double, double>>> ret;
|
||||
ret.reserve(custom_gcode_per_print_z.size());
|
||||
|
||||
// Loop invariant, but built lazily: this lambda runs once per extruder on every frame
|
||||
// and most prints reach neither colour change below, so fetching it up front would cost
|
||||
// more than the per-item fetch it replaces.
|
||||
std::vector<float> zs;
|
||||
bool zs_built = false;
|
||||
|
||||
for (const auto& item : custom_gcode_per_print_z) {
|
||||
if (extruder_id + 1 != static_cast<unsigned char>(item.extruder))
|
||||
continue;
|
||||
@@ -3527,7 +3533,10 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
if (item.type != ColorChange)
|
||||
continue;
|
||||
|
||||
const std::vector<float> zs = m_viewer.get_layers_zs();
|
||||
if (!zs_built) {
|
||||
zs = m_viewer.get_layers_zs();
|
||||
zs_built = true;
|
||||
}
|
||||
auto lower_b = std::lower_bound(zs.begin(), zs.end(),
|
||||
static_cast<float>(item.print_z - epsilon()));
|
||||
if (lower_b == zs.end())
|
||||
@@ -4680,6 +4689,8 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
|
||||
// ORCA: Get layer Zs as doubles
|
||||
std::vector<double> layer_zs = get_layers_zs();
|
||||
// loop invariant, same reason as the layer Zs above
|
||||
const std::vector<float> layer_times = m_viewer.get_layers_estimated_times();
|
||||
|
||||
for (Slic3r::CustomGCode::Item custom_gcode : custom_gcode_per_print_z) {
|
||||
ImGui::Dummy({window_padding, window_padding});
|
||||
@@ -4699,7 +4710,6 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
imgui.text(buf);
|
||||
ImGui::SameLine(max_len * 1.5);
|
||||
|
||||
std::vector<float> layer_times = m_viewer.get_layers_estimated_times();
|
||||
float custom_gcode_time = 0;
|
||||
if (layer > 0)
|
||||
{
|
||||
@@ -4748,7 +4758,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
std::string print_str = _u8L("Model printing time");
|
||||
std::string total_str = _u8L("Total time");
|
||||
float max_len = window_padding + 2 * ImGui::GetStyle().ItemSpacing.x;
|
||||
if (m_viewer.get_layers_estimated_times().empty())
|
||||
if (m_viewer.get_layers_count() == 0)
|
||||
max_len += ImGui::CalcTextSize(total_str.c_str()).x;
|
||||
else {
|
||||
if (m_viewer.get_view_type() == libvgcode::EViewType::FeatureType)
|
||||
|
||||
Reference in New Issue
Block a user