Skip to content

Ocarina of Time: restore streamed terrain after GPU storage splits - #1876

Closed
nanotchec wants to merge 1 commit into
seedds:mainfrom
nanotchec:codex/terrain-split-pages
Closed

nanotchec wants to merge 1 commit into
seedds:mainfrom
nanotchec:codex/terrain-split-pages

Conversation

@nanotchec

@nanotchec nanotchec commented Nov 8, 2026 •

Copy link
Copy Markdown
Contributor

Ocarina of Time can develop flat or missing terrain after streaming through Hyrule Field. The captured 260×260 height tile contained valid CPU heights, while its Metal texture contained 67,600 zero floats: a stale GPU-ownership decision prevented the upload.

Splitting a GPU-written storage interval left a 2,560-byte remnant inside an originally protected 16 KB page. Rounding that remnant inward discarded every page, so it could never report a later CPU write. Preserve the original protected page bounds through splits and shared-buffer re-protection. A queried texture must still cover the entire boundary page; a write to a neighbouring partial-page texture does not authorize ownership. New GPU writes receive new bounds and stamps as before. No game-specific dimensions or formats are added.

Validation on Apple M3 Max, macOS 27.0.1:

  • The captured interval pattern fails ownership, upload classification and GPU-readback assertions before the fix. With it, t_cpu_storage passes all 67 checks, including re-protection and neighbouring partial-page isolation, with Metal validation enabled.
  • On main base d8b2b64a1fc5: t_nvn passes 259 checks; dirty-slot and dirty-race tests pass; documentation tests pass (11); generated symptom index and diff checks are clean.
  • Environment-table and synthetic Xcode preparation checks also pass on the new base (19 tests including documentation). Official main's CI repairs are retained. GitHub checks are rerunning; earlier analysis on the previous base is not claimed as a green check for this revision.
  • The combined installed-base host builds and loads a copy of the player's v131072 save, with a short walk through the affected area rendering terrain. This is a smoke test on base 028a263, chain 3f35b514643e, with existing local fixes, not a pristine-main gameplay comparison or proof that every long-session terrain fault is resolved.

Regression scope: regress.py impact identifies Breath of the Wild, Tears of the Kingdom and Pokémon Scarlet through shared NVN callers. A check requested for those games plus Ocarina cannot run: no standalone Mac builds remain in the local game folders (only packaged apps). No cross-game runtime or iOS validation is claimed.

This does not address the separately observed black ivy/rock patches in shadow, nor startup prewarm duration. The player's real saves and installed app were not changed for this test.

Front-ends: no changes required.

Finding and mechanism are documented in the game note and NVN objects reference. No game assets, binaries, keys or saves are included.

@github-actions github-actions Bot added nvn NVN on Metal and its tests (dm/gfx/nvn, dm/gfx/tests) docs Documentation game: 0400486024DEC000 A game labels Nov 8, 2026
@nanotchec
nanotchec force-pushed the codex/terrain-split-pages branch from 56a3f84 to 6552a8a Compare November 9, 2026 00:04
brad-n added a commit to brad-n/TVPort that referenced this pull request Nov 9, 2026
… RG11B10F non-finite clamp (white bloom), seedds#1876, DM_NVN_LEDGER
ivan-leschinsky pushed a commit to ivan-leschinsky/nxnative that referenced this pull request Nov 9, 2026
…carry: seedds#1876's split-span entry came along with seedds#1824's README context when the branch moved onto main, where seedds#1920 (c06d1e7) fixes the same terrain holes instead

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U35V38c6UYLbzyyPx6Up7P
Know-It-All-Brother added a commit to Know-It-All-Brother/nxnative that referenced this pull request Nov 9, 2026
# Conflicts:
#	dm/games/0400486024DEC000/README.md
@seedds

seedds commented Nov 10, 2026

Copy link
Copy Markdown
Owner

Thanks for tracking this down. The 2,560-byte remnant inside a protected 16 KB page is exactly what was going wrong.

It's now fixed on main by c06d1e7 (#1920), which landed after this PR's base (d8b2b64a). With gws_sliver, a GPU-written span that doesn't cover the texture, and whose overlap with it holds no whole page, no longer decides whether the texture belongs to the GPU. That covers the split remnant you found. It also covers a second case that keeping the original page bounds wouldn't: the span of a newer 260x260 RG8 normal map reaching 1,536 or 13,824 bytes into the next tile's height or hole map.

I applied your t_cpu_storage case unchanged on current main. All 146 checks pass, including your ownership, upload, GPU-readback and pool-buffer checks. With gws_sliver turned off, your three checks fail as you described. Main also already has a test for the sub-page remnant, and the reference entry credits this PR with finding the remnant case independently.

The rest of the change doesn't apply to main any more. gws_take no longer re-protects spans, and pool_buf reopens and re-protects its pages through nvn_dirty_open/nvn_dirty_close (#1591).

So I'm closing this as superseded by #1920. If you still see flat or empty terrain on a build that includes c06d1e7, please open an issue with the tile's first-use trace. That would be a different cause.

@seedds seedds closed this Nov 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Documentation game: 0400486024DEC000 A game nvn NVN on Metal and its tests (dm/gfx/nvn, dm/gfx/tests)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants