5 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| cbce585eb4 |
perf(cad): complete 2D and 3D LOD -- Phase 5
Some checks failed
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
nigig-build (CAD) / cad-widget-coverage (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
The first Phase 5 tranche correctly reduced sub-pixel 2D outlines, but it stopped short of the plan's full level-of-detail phase. Complete the phase by applying the same measured three-pixel policy to the 3D path. Visible 3D parts below the projected AABB threshold now use one shared unit-cube geometry with an axis-aligned world-bounds transform. Full-detail shape batches, proxy instance rows and proxy draw calls are reported separately. Wireframe and hidden-line overlays use the same policy, and selected or hovered parts remain full detail. Extend the host-testable projection and proxy policy tests, frame benchmark, source guards and documentation. Keep the real GPU/window visual check explicit: compilation, policy arithmetic, submission structure and coverage pass here, but this environment cannot execute Makepad's draw submission. |
|||
| a5ba719d8d |
perf(cad): add measured sub-pixel LOD to the 2D path -- Phase 5
Some checks failed
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
nigig-build (CAD) / cad-widget-coverage (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
Phase 4 reduced the number of tessellation calls, but it left the geometry volume unchanged: a zoomed-out 2,000-part plan still queued a full outline for every visible part. At the measured 200 m site view a 1 m part is only about 2.7 logical pixels across, so the remaining geometry was not resolvable detail. Add a pure lod policy that projects plane extents into logical pixels, keeps selected and hovered parts full detail, and conservatively falls back to a full outline for malformed state. The renderer and CadViewport::frame_budget call the same policy. Ordinary sub-pixel parts use one bounded 2x2 filled marker, while FrameBudget reports full outlines, markers, strokes and fills separately. Also fold the remaining 2D 1.2 margins into render_budget::VIEW_MARGIN, extend the structural benchmark and coverage harness, correct the phase documentation, and explicitly leave 3D mesh LOD deferred until a real GPU/window measurement justifies a second geometry policy. |
|||
| 42b1e7152a |
docs(cad): merge a second render review into the plan, and correct the hash both reviews got wrong
Some checks failed
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
nigig-build (CAD) / cad-widget-coverage (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
A second optimisation plan arrived (frustum culling, geometry merging, GPU instancing, octree/LOD). Rather than run two plans, every claim in it was checked against the tree at |
|||
| f27ace8b7f |
docs(cad): render optimisation plan — and a correction to the analysis it rests on
Some checks failed
repo hygiene / hygiene (push) Has been cancelled
Writing the plan meant checking the assumption the analysis rested on,
and the assumption was wrong.
I had called `draw_vector.stroke()` a "tessellation/flush point" and then
reasoned about the 2D path as though each cost a draw call — "~670 flush
points per frame where four would do". Reading
draw/src/shader/draw_vector.rs instead of inferring from a comment:
begin() clears CPU accumulation buffers
stroke() calls tessellate_path_stroke + append_geometry — no draw call
end() the ONLY place cx.new_draw_call appears, twice, both inside it
The whole 2D vector scene is **one draw call**. Makepad's DrawVector is
already a batching design and the CAD code uses it correctly in that
respect. The guard test's wording — "thousands of tessellations per
frame" — was accurate and literal, and I read "draw call" into it.
What survives: no culling anywhere, which was and remains the main
finding; and 3D issuing one draw call per part, which is where draw-call
multiplication is actually real. What changes: batching the 2D loops is
a CPU per-call-overhead win, not a draw-call win, so it drops from
second place to third in the plan and the document says plainly that it
is the small one.
The plan itself, ordered on the corrected facts:
0. Make it measurable. profile_benchmarks.rs has sixteen benchmarks
and none measures frame submission. Check whether Cx already counts
draw calls; if not, add a counting seam. This doubles as the first
test surface viewport_render.rs has ever had — it is 2,083 lines at
0.00% coverage.
1. Cull against the viewport, reusing the cached world AABB that is
already benchmarked at 4.72x and already wired to the mouse-move
path but not the per-frame one.
2. Key part_geoms by ParamHash instead of part id so identical parts
share geometry — the real draw-call win, and the one that matters
for drawings full of repeated columns.
3. Reduce 2D tessellation calls with the queue-then-stroke idiom the
axis grid already uses.
4. LOD, only if the Phase 0 numbers justify it.
Explicitly not doing: a BVH (a linear pass over cached AABBs is
microseconds at this scale) or a render-path rewrite (0% coverage).
One implementation hazard recorded in Phase 1: cull on the drawn extent,
not the model extent. Selection outlines and hover highlights exceed a
part's AABB, and culling on the AABB alone makes them vanish at the
viewport edge.
|
|||
| e6fbcc12da |
docs(cad): analysis — the renderer has no culling and no draw batching
Some checks failed
repo hygiene / hygiene (push) Has been cancelled
Asked whether the CAD viewport has the kind of minimal-drawcall strategy
a datagrid needs, and whether virtual-viewport techniques transfer.
Answer: the codebase already knows the technique, applies it in exactly
one function, and does not apply it in the two loops that run every
frame.
`draw_vector.stroke()` is the tessellation/flush point. `queue_dashed_line`
queues segments and issues ONE stroke for the whole axis grid, and a test
in viewport.rs enforces it — "the grid lines should share exactly one
stroke", with a comment warning that stroking per dash is "thousands of
tessellations per frame". The discipline is understood and guarded.
Two loops away from it:
- the base grid strokes once per line (~167 on a 1080p viewport,
where two would do: one for minors, one for majors);
- the parts loop strokes once per part;
- the 3D path issues one draw_mesh.draw() per part, each with its own
geometry buffer and uniforms. No instancing, no state sorting.
And there is no culling at all: grep for cull/frustum/offscreen/in_view
across the 2,461-line renderer returns nothing. Every part is submitted
every frame whether on screen or not.
The sharp part is that the broad-phase already exists.
SceneCache::world_aabb_for is cached by PlacedHash and BENCH_BASELINE.md
records it at 4.72x faster than recomputing. Its only caller is
pick_part — the mouse-move path, which is additionally throttled by
HOVER_PICK_MIN_MOVE_PX. The cheap visibility test is wired to the
occasional path and not to the per-frame one.
The grid, to be fair, IS virtualised properly: visible world bounds plus
20%, with a 1/2/5 nice-number step that adapts to zoom. That is the
datagrid technique done right. It just stops at the grid.
Also recorded: what does not transfer. Widget recycling has no CAD
analogue, and index-range virtualisation does not either — CAD is
continuous space, so it needs a spatial test rather than a row range. At
500 parts a linear pass over cached AABBs is microseconds; a BVH only
earns its complexity somewhere past ~50k parts and nothing suggests that
is the target.
Caveat stated in the document: no profiling was run, and there is no
frame-submission benchmark in profile_benchmarks.rs — its sixteen
benchmarks all measure CPU work. The structural claims are read off the
code and are solid; the consequence in dropped frames is not measured,
and measuring it needs a live Cx.
|