mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-04 22:31:02 +00:00
Faster Preview View (#15884)
Co-authored-by: Kris Austin <kris.austin@gmail.com>
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
# 3D Scene Benchmark: High Level Design
|
||||
|
||||
## Why it exists
|
||||
|
||||
Rendering changes, such as the realistic view, shadows or SSAO, need a number to compare
|
||||
before and after, and user reports of a slow viewport need a way to say how slow. The FPS
|
||||
overlay and the render timings overlay show live values while someone drags the camera,
|
||||
which varies from run to run with the model, the path of the mouse and the view.
|
||||
|
||||
The benchmark renders a fixed model along a fixed camera path in both 3D views, so two
|
||||
runs on the same machine differ only by the code or the settings, and prints a report that
|
||||
can be pasted into an issue.
|
||||
|
||||
## What it does
|
||||
|
||||
`run_scene_benchmark()` in `src/slic3r/GUI/SceneBenchmark.cpp` is reached from Help >
|
||||
Benchmark 3D Scene, the command palette and Preferences > Graphics. After a confirmation
|
||||
it starts a new project, which asks to save the current one if needed, loads the
|
||||
OrcaSliced Combo handy model and arranges it. A small dialog in a corner of the 3D view
|
||||
then shows the progress; every other window is disabled until the run ends, so a click
|
||||
cannot change the scene being measured. Cancel or Esc stops the run.
|
||||
|
||||
The run goes through these stages, driven by a timer while it waits and by idle events
|
||||
while it renders:
|
||||
|
||||
1. Loading: waits until the UI job worker is idle, so the arrange job has moved the
|
||||
objects. The orbit target is the center of the objects on the current plate, and the
|
||||
base zoom fits their bounding box in the viewport.
|
||||
2. Prepare: renders the scene in the Prepare view.
|
||||
3. Slicing: slices the plate and switches to Preview, then waits for the G-code preview
|
||||
to load. If slicing fails, the report holds Prepare alone.
|
||||
4. Preview: renders the scene in the Preview view, with the slicing progress notification
|
||||
hidden.
|
||||
5. Layers: renders the Preview view again while the layer slider moves, which is what
|
||||
makes dragging it feel slow on large prints.
|
||||
|
||||
The dialog then shows the report, with a button to copy it. A scene cut short, because its
|
||||
view was hidden, is left out of the report.
|
||||
|
||||
## Rendering a scene
|
||||
|
||||
Each scene renders 30 warm-up frames, then the camera path twice, 360 frames each time.
|
||||
|
||||
- The first pass times the frames. A frame's time is the interval between the starts of
|
||||
consecutive benchmark frames, so it includes the event loop between them.
|
||||
- The second pass averages the render timings. The frame profiler flushes the GL command
|
||||
queue after each section, which slows a frame down, so it only runs in this pass.
|
||||
`FrameProfiler::start_averaging()` flags every frame begun afterwards, and
|
||||
`finish_averaging()` waits for the flagged frames still on the GPU and returns the mean
|
||||
CPU and GPU time of each section per profiled frame.
|
||||
- A section's GPU time is taken between a timestamp before its commands and one after
|
||||
them. The first is only sent along with those commands, so when the GPU finishes a
|
||||
section before the CPU has issued the next one, the wait counts in neither.
|
||||
|
||||
The dialog renders one frame per idle event by calling `GLCanvas3D::render()`, which
|
||||
redraws the whole scene. While `GLCanvas3D::set_benchmarking()` is on, the canvas does not
|
||||
render from its own idle handler, so no other frame is drawn in between, and it skips the
|
||||
picking pass and the FPS and render timings overlays, which depend on the mouse and on
|
||||
preferences. The FPS cap does not apply, since it only paces idle redraws.
|
||||
|
||||
VSync is turned off for the scene through `wxGLCanvas::SetSwapInterval(0)`, so the frame
|
||||
rate is what the GPU and CPU can reach rather than the display's refresh rate, and the
|
||||
previous interval is restored afterwards. When the platform cannot report the current
|
||||
interval (EGL), it is left as it is and the report says so.
|
||||
|
||||
The camera path makes two turns around the target while the view rises three times from
|
||||
25 degrees below the plate to 85 degrees above it and the zoom goes twice between 0.6 and
|
||||
1.4 times the base zoom. The camera stays at the default distance, so the perspective is
|
||||
the same in every run. The camera the scene started with is restored at its end.
|
||||
|
||||
The Layers scene holds the camera at the start of that path and moves the top of the layer
|
||||
slider instead, from the last layer down to the first and back up in each pass. It goes
|
||||
through `IMSlider::SetHigherValue()`, as a drag does, so every frame applies a new layer
|
||||
range to the toolpaths and the objects before drawing them, including a new shadow map when
|
||||
the shadows are static. Its warm-up frames lead into the start of the path, so the slider
|
||||
moves in every frame. The slider position it started from is restored at its end.
|
||||
|
||||
## The report
|
||||
|
||||
The report is plain English text, so it reads the same in every language:
|
||||
|
||||
- The version and build commit, the GPU and OpenGL version, the viewport size and camera
|
||||
type, and the graphics settings that change the cost of a frame: MSAA samples as read
|
||||
from the framebuffer, FXAA, the scene cache, VSync and the realistic view options.
|
||||
- The printer and process presets the model was sliced with, marked when they have
|
||||
unsaved changes, and the toolpath vertices and layers they produced, since the Preview
|
||||
scenes cost more with more toolpaths.
|
||||
- For each scene, the average FPS and the average, median, 95th percentile, 99th
|
||||
percentile and maximum frame time. Percentiles are nearest-rank, so each is a measured
|
||||
frame (`frame_time_stats()`).
|
||||
- For each scene, the render timings table: the CPU and GPU milliseconds of each section
|
||||
of a frame, and their total. Without timer queries (OpenGL 3.3 or `ARB_timer_query`) the
|
||||
table says that the driver does not support them.
|
||||
@@ -65,8 +65,10 @@ closes the open gizmo, so neither tab ever shows a stale cut.
|
||||
as the plane faces; otherwise it is discarded. The cut face keeps the depth of the fragment it
|
||||
replaces, which is safe: along that ray everything else still shown lies behind the plane. The
|
||||
shader writes no `gl_FragDepth`, so early depth testing survives. Option markers are cut away
|
||||
whole, by their centres. The shadow casters share the segment shader, so what is cut away casts
|
||||
no shadow either. Preview shells are drawn by another shader and are not clipped.
|
||||
whole, by their centres. The shadow casters draw with a program of their own, which takes the
|
||||
plane and discards the fragments on the clipped side, so what is cut away casts no shadow either.
|
||||
Their cut faces are not drawn, since the part left behind casts the shadow of its own section.
|
||||
Preview shells are drawn by another shader and are not clipped.
|
||||
- **Picking.** `get_raycaster_clipping_plane()` returns the same plane, so hover, selection and
|
||||
the perspective pan anchor ignore what the user cannot see.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user