feat: optimize GUI rendering with GPU persistent textures, incremental dirty-region updates, and coordinate-aligned viewport mapping

This commit is contained in:
2026-07-12 03:45:41 +03:00
parent 2f9a3017ca
commit 266183a7ff
4 changed files with 124 additions and 77 deletions
+6 -2
View File
@@ -105,8 +105,12 @@ cargo test -p hcie-engine-api --test performance_stroke_4k -- --nocapture
| Effects cache reuse | `hcie-composite/src/tiled.rs` | Skips `apply_layer_effects` when `layer.effects_cache` is already populated. | Prevents re-running the full effect pipeline on every partial composite. |
| Incremental tile update | `hcie-tile/src/lib.rs` | Updates only the tiles that intersect the dirty rectangle and writes only the changed sub-rectangle when a tile already exists. | Avoids throwing away the whole 33MB dense-to-tile copy on every small dirty region. |
| Vector stroke anti-aliasing density | `hcie-vector/src/lib.rs` | Keeps circle-overlap density high enough along vector strokes and ellipses so shapes do not look jagged/pixelated. | Reducing step counts makes circles, stars, polygons and rounded rectangles visibly tırtıklı. |
| `iced::widget::Shader` partial upload | `hcie-iced-gui` (`shader_canvas.rs`) | Keeps persistent `wgpu::Texture` on GPU, updating only dirty tile bounds (8KB vs 33MB) via `queue.write_texture()`. | Crucial for keeping 4K document panning, zooming, and drawing at 100+ FPS; going back to `ImageHandle::from_rgba` drops frame rate to 1 FPS. |
| `RefCell` dirty bounds accumulator | `hcie-iced-gui` (`app.rs`, `canvas/mod.rs`) | Unions dirty bounds of all Elm event loop updates in the frame and consumes/resets them inside `view()`. | Prevents frame-drop race conditions where multi-event frames throw away dirty regions, causing missing tile gaps. |
| Viewport widget boundary mapping | `hcie-iced-gui` (`shader_canvas.rs`) | Sets custom wgpu render viewport matching the absolute layout bounds of the canvas widget. | Aligning wgpu NDC coordinates to layout coordinates is the only way drawing coordinates match mouse/pen position. |
| Nearest-Neighbor sampler filtering | `hcie-iced-gui` (`shader_canvas.rs`) | Sets magnification and minification filter modes to `wgpu::FilterMode::Nearest` on the GPU texture sampler. | Prevents linear interpolation sub-pixel sampling seams (black/transparent border lines) between 256x256 tiles. |
### GUI First-Frame Visibility (CRITICAL — Regression Prevention)
### GUI First-Frame Visibility & Iced GPU Acceleration (CRITICAL — Regression Prevention)
Two mechanisms together fix the recurring "default first document canvas is invisible until the tab title is clicked" bug. Removing either half makes the regression come back.
@@ -116,7 +120,7 @@ Two mechanisms together fix the recurring "default first document canvas is invi
| Extra repaint after new texture | `hcie-egui-app/crates/hcie-gui-egui/src/canvas/mod.rs` | Requests multiple repaints after `render_composition` creates a brand-new texture, because egui uploads GPU textures asynchronously. | A single repaint often leaves the canvas blank on the first frame; the second/third frame actually displays the texture. |
| `DrawingFinished` does NOT clear dirty flags | `hcie-egui-app/crates/hcie-gui-egui/src/app/mod.rs` | Leaves engine dirty flags intact so `render_composition` can upload the result on the next frame. | Calling `clear_dirty_flags()` inside `DrawingFinished` races with the next render pass and makes newly drawn vector shapes disappear. |
**AI AGENT WARNING:** Do not remove, shorten, or "optimize away" the startup active-tab setting, the multi-frame repaint requests, or the `DrawingFinished` no-op. These look like minor details but they are the only thing keeping the first canvas visible. Every past removal has re-introduced the bug. If a change you are making touches any of these three places, stop and verify with an actual app launch (or `HCIE_AUTO_SCREENSHOT`) that the default `Untitled` canvas is visible without clicking the tab title.
**AI AGENT WARNING:** Do not remove, shorten, or "optimize away" the startup active-tab setting, the egui multi-frame repaint requests, the `DrawingFinished` no-op, OR any of the `hcie-iced-gui` GPU-acceleration optimizations (RefCell union accumulator, viewport boundary mapping, Nearest filtering, or partial uploads). These look like minor details but they are the only things keeping the first canvas visible and Iced running smoothly at 100+ FPS. Every past removal has re-introduced regressions. If a change you are making touches any of these places, stop and verify with an actual app launch.
If a new feature conflicts with one of these mechanisms, extend the existing API by adding a new function or file rather than bypassing or duplicating the protected code.