Skip to content

Recast compact later hotpaths - #6

Open
OursCodeur wants to merge 4 commits into
OpenMW:openmw-fixesfrom
OursCodeur:split/recast-compact-later-hotpaths
Open

Recast compact later hotpaths#6
OursCodeur wants to merge 4 commits into
OpenMW:openmw-fixesfrom
OursCodeur:split/recast-compact-later-hotpaths

Conversation

@OursCodeur

@OursCodeur OursCodeur commented Aug 18, 2026

Copy link
Copy Markdown

Putting the decision first, because it's the only permanent cost in this stack and it isn't mine to make. This adds four absolute neighbour indices per compact span, which is 16 bytes per span, allocated for the lifetime of the rcCompactHeightfield, plus one pointer in the struct. On my two measured examples that's about 500 KiB after compact construction, 513,792 B and 509,760 B, and the delta is exactly 4 * sizeof(int) * spanCount. Adding the field changes the public struct layout, so anything linking against Recast has to be rebuilt. The packed con connections stay where they are, so source compatibility is unaffected. If that trade isn't one you want in our fork, say so and I'll close this rather than argue it, the rest of the stack doesn't depend on it.

What it buys : everything downstream of rcBuildCompactHeightfield walks span connections constantly, and each hop currently rebuilds the neighbour's cell coordinates and decodes a packed offset to reach a span it will visit again from another direction a moment later. Erosion, the distance field, region building, contours and detail height traversal all do it. Paying once at construction and reading an index afterwards is the whole idea. Region work entries also stop carrying x and y that can be derived.

Separately, detail sampling recomputes the same per-triangle values, origin, edges, dot products and the inverse denominator, for every point query against that triangle. Those are cached per triangle and reused.

Four commits : build the neighbour table, then consume it in erosion, distance, regions, contours and detail height, then the detail triangle cache, then the benchmarks.

committed benchmark #5 #6 speedup
compact through polygon mesh 4.15862 ms 3.21121 ms 1.295×
detail mesh 143.754 ms 105.6775 ms 1.360×

Per stage it's a mixed picture : compact construction itself gets 6.7% slower on the single-layer terrain, which is where the table gets built, and comes out neutral on the multilayer one. Erosion gains 45.8% to 49.9%, the distance field 48.1% to 53.0%, regions 17.5% to 20.1%, contours 16.8% to 17.6%. Polygon mesh construction is unchanged source and stays inside 0.5% either way, which makes it a useful control inside the harness. Full synthetic pipelines land at 1.465× and 1.488×.

Per-stage tables, both workloads

192×192 undulating terrain, 32,112 spans :

stage #5 #6 speedup
compact 0.791 ms 0.844 ms 0.937×
erode 0.699 ms 0.350 ms 1.997×
distance 0.882 ms 0.415 ms 2.129×
regions 1.575 ms 1.258 ms 1.252×
contours 0.432 ms 0.356 ms 1.213×
polygon mesh 0.877 ms 0.878 ms 0.999×
detail mesh 1,277.378 ms 857.782 ms 1.489×
total 1,282.634 ms 861.882 ms 1.488×

112×112 terrain, three layers, 31,860 spans :

stage #5 #6 speedup
compact 0.765 ms 0.755 ms 1.013×
erode 0.507 ms 0.275 ms 1.846×
distance 0.628 ms 0.326 ms 1.926×
regions 1.209 ms 0.998 ms 1.212×
contours 0.340 ms 0.283 ms 1.201×
polygon mesh 0.395 ms 0.393 ms 1.005×
detail mesh 1,534.363 ms 1,047.038 ms 1.465×
total 1,538.207 ms 1,050.068 ms 1.465×

Same rig and protocol as #5. The detail workload uses 1.0-unit sampling with 0.1-unit error on purpose, which is what makes it that heavy; it proves the mechanism and the exactness for those shapes and nothing about a universal ratio.

Output is identical across 48 timing runs and 4 allocation-tracked runs : same contour, polygon and detail counts, and the same common-output hash in both arms, 6501ab981e7022d5 for terrain and 70ba6d7cfd4906cf for multilayer.

On memory, the allocator-level numbers above are the ones I'd trust. Process peak RSS didn't move on the default allocator, 43,236 KiB in both arms on terrain, because the detail stage's allocations dominate that high water mark and hide 500 KiB completely.

@OursCodeur
OursCodeur marked this pull request as ready for review August 18, 2026 21:08
@OursCodeur
OursCodeur force-pushed the split/recast-compact-later-hotpaths branch from 28cc437 to 70c9b04 Compare August 19, 2026 12:07
@OursCodeur
OursCodeur force-pushed the split/recast-compact-later-hotpaths branch from 70c9b04 to 1b6e37e Compare August 20, 2026 23:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant