mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-23 07:50:30 +00:00
075547b7b6
## Description: Incremental GPU border recompute — sequel to #4159. On 10 yo low-end chrome book this increased performance by ~5fps. I'm now able to get 40fps on GWM. `BorderComputePass` previously re-ran its fragment shader over every tile on the map every time any input changed (tile flip, highlight, relation, defense post). Cost was O(mapW × mapH) per invalidation, and tile flips invalidate it ~every render frame in live play. This PR adds `BorderScatterPass`, which runs the same fragment shader but rasterizes only one POINT per dirty tile (plus its 4 cardinal neighbors, to cover the cardinal-neighbor read in the border shader). Cost is O(dirty tiles) regardless of map size or spatial distribution. ### What changed - New `BorderScatterPass` — owns its own FBO, VAO, and instance buffer; shares the border fragment shader with `BorderComputePass` so the two paths can't diverge in output. - `BorderComputePass.draw()` now picks per frame: - **Full recompute** — when `globalDirty` is set by highlight / relation / defense-post changes (those affect tiles across the whole map). - **Scatter** — when only per-tile patches have been queued via `patchTile()`. - `TerritoryPass.flushTileTexture()` now returns `"none" | "full" | "scatter"` instead of `boolean`, so the renderer can pick the right downstream invalidation: - `"full"` → `borderPass.markGlobalDirty()` (full tile upload supersedes per-tile patches). - `"scatter"` → no-op; per-tile patches were already pushed via the wired `borderPatchConsumer` callback during drip drain. - Renderer wires `territoryPass.setBorderPatchConsumer((x, y) => borderPass.patchTile(x, y))` so every per-tile scatter write to `tileTex` also schedules an incremental border recompute for that tile + its neighbors. ### Known limitation Highlight-thicken rings (within `uHighlightThicken` of a changed tile) are NOT incrementally repainted — they'll lag visually until the next full recompute. In practice this is short-lived (the next highlight change or seek triggers a full recompute) and not visible during normal play; the trade is documented in the `BorderScatterPass` header. ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory ## Please put your Discord username so you can be contacted if a bug or regression is found: evan