perf: lag nelle zone di rilievo (terreno Z-displaced) #240
Labels
No labels
alpha:wave-0
alpha:wave-1
alpha:wave-2
alpha:wave-3
area:assets
area:combat
area:ecology
area:infra
area:render
area:scripting
area:ui
area:world
enhancement
epic
migration
post-alpha
roadmap
tech-debt
type:bug
type:chore
type:design
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
marco/IsoMmo#240
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Muoversi/teletrasportarsi nelle zone di rilievo autorato di asterra (le 64 elevation-chunk: il massiccio vulcanico ma anche i foothill rocciosi) lagga.
Correla col rilievo, non con l'animazione lava — anche il foothill roccioso (Z~1 vicino a Z≥20) lagga, quindi non è la lava. Sospetto: overdraw dalla mesh del terreno spostata in altezza (celle a Z diversi si sovrappongono) + ricostruzione mesh / ricalcolo finestra blend mentre la vista si muove.
Pre-esistente, non causato dalla base-Z (#238): un baseline uniforme non aggiunge overdraw — solo le differenze di Z (le montagne autorate) lo fanno; il rilievo c'era già (in 7b vedevamo solo lo spawn piatto).
Da profilare: è CPU (mesh/
GroundZAtper-frame) o GPU (overdraw)? Confrontare conmain/pre-relief. Possibili leve: limitare/cullare loZMargin, cache della mesh a vista ferma, ridurre l'overdraw.Root cause CONFERMATA (profiling)
Strumentato il client (tempi per-fase del Draw + dt reale tra frame +
IsRunningSlowly), misurato in 3 zone:ensureWin≈0,buildMesh≈0.5ms→ gli ~11 ms sono nel draw dello shader (DrawUserIndexedPrimitives).drops≈0, slow=0, ma il frame a ~12 ms sfiora il budget vsync (16.6 ms) → slip occasionali = micro-stutter, peggiore muovendosi (la camera scorre e tiene più gradiente in vista).Esperimento decisivo — appiattita la mesh del blend (
ToScreen(x,y,0)invece diGroundZAt), stesso identico punto (foothill 7523,4887):→ ~4x solo togliendo il dislivello. Causa = overdraw dalla mesh Z-spostata.
Meccanismo
Il ground SDF è disegnato come una mesh finestrata con
BlendState.Opaque+DepthStencilState.None(nessun depth-test). Con il Z, celle a quote diverse si sovrappongono sullo schermo; senza depth-buffer, lo shader SDF (costoso per-pixel: warp + noise + campionamento di più palette/weight/atlas) gira su tutti i frammenti sovrapposti, anche quelli occlusi dietro il terreno più alto. Costo ∝ gradiente di Z in vista (per questo la vetta a Z uniforme è economica e il piano-accanto-a-collina è caro). Non c'entrano né la lava animata né la base-Z (uno shift uniforme non aggiunge gradiente).Fix (direzione)
Renderizzare solo il visibile — scartare i frammenti occlusi:
Nota per #239 (hillshade): l'hillshade aggiunge costo per-pixel al ground, quindi conviene sistemare l'overdraw (depth-test) prima o insieme.
Tentativo 1 — depth-test single-pass: FALLITO (scartato)
Provato: depth nel vertice (ordine iso da
gx+gy), draw near→far,DepthStencilStateLessEqual + write; depth-buffer sul back-buffer e sul render-target ghost.Esito, misurato allo stesso punto (foothill 7523,4887):
Perché fallisce (evidenza, non ipotesi): su DesktopGL/OpenGL con effetto SM3 (MojoShader→GLSL vecchio), l'early-Z non si attiva automaticamente (serve
layout(early_fragment_tests), non emettibile via MGCB/SM3). Quindi il depth-test è late (dopo lo shader): lo shader paga comunque tutto l'overdraw, più l'overhead del depth. Un single-pass depth-test non può aiutare qui, a prescindere dal sign del depth.Approccio affidabile — depth pre-pass (2 pass)
DepthFunc = Equal(no depth-write) + lo shader SDF vero → ogni pixel viene shadato una sola volta (solo il visibile), overdraw eliminato indipendentemente dall'early-Z.Costo: richiede un cambio allo shader (
ground_blend.fxcon una tecnica depth-only) + rebuild MGCB dell'.xnb(vedi memoriamonogame-shaders). Cambio più grande e con più rischio del previsto.Nota di sequenza
#239 (hillshade) rilavora comunque lo stesso ground shader. Conviene fare l'overdraw-fix (pre-pass) insieme all'hillshade in un'unica rilavorazione del ground — un solo cambio shader/MGCB, testato insieme — invece di due interventi separati sullo stesso
.fx. Il lag attuale è micro-stutter (nessun drop netto), quindi tollerabile nel frattempo.Marco aiutami invece di farti le unghie a tema pokemon 💅
Risolta: deferred shading (fix overdraw zone di rilievo) su main (#243).