Repository navigation
Conversation
Capture the current development source, including memory and sparse texture fixes, HDR presentation, queue ordering, and opt-in diagnostics. Persistent iOS performance degradation remains under investigation.
|
Evidence comment for #1383 — post after run 4 confirms the menu visuals Cross-referencing, from tonight's independent MKW 1.8.0 build on the Duo (iPhone19,4, iOS 27.3, the user's own phone; build e8ac738 + four upstream NUP-script cherry-picks on scripts/ only):
Neither fork has upstream PRs open, so their evidence lives only in readmes; the README's community-credit section (PR #1581) now names them. No new upstream claims: everything above is from the note's own persisted configuration, checking that a from-scratch Duo installation reproduces the note's memory results and the pre-env failure. |
|
The driven lap is in on the same Duo (SDR pass, free-roam, auto-accelerate, ~4.3 min driving after the memory run above). Two findings, the second is new upstream as far as we can tell:
This is evidence, not a verdict: what pauses DSF is still unknown to us, and the clusters could be power-limiting rather than anything the host does. Fixed no code; offered for whoever is in this code (you, and the fork family). |
|
The driven session on the ported build (the last test of the night) closed the memory half of the iPhone question on this Duo:
The soft path itself is filed upstream as PR #1599 (Soft textures...) on side-by-side anchors of #1252/#1383's family, Co-authored-by the authors who got it to run: kartnative (pahorema) and plumber-racer-2 (cheemu21), where their own lines carry the same numbers (3.9 GB / 851 MB wrapped pools on an iPhone 18 Pro). #1599's body carries this run's log excerpts and the comparison against the no-switch build. The port will also apply to this PR's anchors verbatim as soon as this line moves (my fork's branch |
…its files is kept without its finest level, and its level-0 pages go back A first upload of such a texture makes a host texture of its level 1 (Mario Kart World keeps large BC formats from its files with a packaged layout; the host texture that skips level 0 is sampled through the same normalized coordinates), and the guest pages only level 0 holds go back after 300 frames (nvn_dirty_release) unless the game copies from that texture (soft_harden keeps it whole, as Mario Kart World copies source textures into its terrain arrays; the kartnative line notes a copied-from texture that lost level 0 drawing purple). iOS wires the whole memory pool behind a zero-copy buffer, so these uploads run on the CPU while the pool has none (mtl_pool_wrapped) instead of handing the pool a buffer it never addresses (the kartnative/plumber-racer-2 measurements: wrapped pools 3.7 GB -> 851 MB there). The mechanics: nvn_dirty_release gives back only still-protected whole pages whose bytes the host keeps (read-only again after the madvise dance, then given all-zero or left as-is); with the guest in files (DM_GUEST_FILE) there is nothing to give back (dm_guest_file_backed). The pipeline: tex_soft gates the descriptor (level shift sk) in tex_desc, and every upload reads the source one level down (pkg_upload_, CPU deswizzle included); the copy hooks (nvnCopyTexture t2t/t2b) harden the source first (soft_harden, then a pkg_upload of the whole levels); ReadTexels sees one lower level (tex_soft_level, an unmapped level-0 read reads 0). All default-off: the switches are DM_NVN_TEX_SOFT and DM_NVN_TEX_RELEASE, so no game changes until its profile names tex_soft; the sweep runs once a submission (mtl_sub_begin) and leaves a 300-frame grace (soft_sweep), as kartnative's does. Where it came from: the kartnative (pahorema) and plumber-racer-2 (cheemu21) forks (MIT) had this first, for Mario Kart World on an iPhone 18 Pro in LiveContainer at about 3.9 GB. The port keeps their behaviour and takes this tree's own anchors (tex_desc, pkg_upload_, the copies, ReadTexels, the dirty layer). Measured on an iPhone Duo (iOS 27.3) through the seedds#1383 family's same anchors: a full free-roam session at 3.7-3.9 GB where the same content without the switches sat at 4.5-5.3, and the whole-frame record lost its p95 spikes (51/81 ms p50/p95 with the switches as against 57/215 without). The tests in this PR run the CPU-only layer here; the GPU checks and the phone runs are recorded on the source lines.
|
More evidence from an iPhone 19,4 (2 Performance + 4 Efficiency cores) running this PR's Mario Kart World 1.8.0 build, 2026-11-07, plus two follow-up PRs.
Logs and the run record are kept in oliverames/anygame ( |
|
Follow-up PRs from the same runs, all marked as not fully tested: #1699 (DM_PCORE), #1700 (DM_RT60), #1701 (DM_ITV_LATCH), each opt-in and off by default. The device HDR peak change is a stacked PR on this head, at oliverames#8, because main has no HDR code yet. |
|
The slow state after about a minute (60 fps, then a plateau at about 3 times the GPU time) now has a measurement behind it. #1709 adds
So in that run the GPU clock fell to about a third and the scene was not the cause. Earlier runs had already ruled out HDR (on or off), the interval flips, the display-interval mode and the scheduler declarations. One run on one device, so a second run is still needed; the next test is a 30 fps cap from the start, to see whether a lower sustained load avoids the drop. |
…its files is kept without its finest level, and its level-0 pages go back A first upload of such a texture makes a host texture of its level 1 (Mario Kart World keeps large BC formats from its files with a packaged layout; the host texture that skips level 0 is sampled through the same normalized coordinates), and the guest pages only level 0 holds go back after 300 frames (nvn_dirty_release) unless the game copies from that texture (soft_harden keeps it whole, as Mario Kart World copies source textures into its terrain arrays; the kartnative line notes a copied-from texture that lost level 0 drawing purple). iOS wires the whole memory pool behind a zero-copy buffer, so these uploads run on the CPU while the pool has none (mtl_pool_wrapped) instead of handing the pool a buffer it never addresses (the kartnative/plumber-racer-2 measurements: wrapped pools 3.7 GB -> 851 MB there). The mechanics: nvn_dirty_release gives back only still-protected whole pages whose bytes the host keeps (read-only again after the madvise dance, then given all-zero or left as-is); with the guest in files (DM_GUEST_FILE) there is nothing to give back (dm_guest_file_backed). The pipeline: tex_soft gates the descriptor (level shift sk) in tex_desc, and every upload reads the source one level down (pkg_upload_, CPU deswizzle included); the copy hooks (nvnCopyTexture t2t/t2b) harden the source first (soft_harden, then a pkg_upload of the whole levels); ReadTexels sees one lower level (tex_soft_level, an unmapped level-0 read reads 0). All default-off: the switches are DM_NVN_TEX_SOFT and DM_NVN_TEX_RELEASE, so no game changes until its profile names tex_soft; the sweep runs once a submission (mtl_sub_begin) and leaves a 300-frame grace (soft_sweep), as kartnative's does. Where it came from: the kartnative (pahorema) and plumber-racer-2 (cheemu21) forks (MIT) had this first, for Mario Kart World on an iPhone 18 Pro in LiveContainer at about 3.9 GB. The port keeps their behaviour and takes this tree's own anchors (tex_desc, pkg_upload_, the copies, ReadTexels, the dirty layer). Measured on an iPhone Duo (iOS 27.3) through the seedds#1383 family's same anchors: a full free-roam session at 3.7-3.9 GB where the same content without the switches sat at 4.5-5.3, and the whole-frame record lost its p95 spikes (51/81 ms p50/p95 with the switches as against 57/215 without). The tests in this PR run the CPU-only layer here; the GPU checks and the phone runs are recorded on the source lines.
…ntry, so a project.yml that carries one prepares the app A project source a front end or a fork copy keeps can carry DMCommit in its Info.plist values; xcodegen writes it into Gen/Info.plist at the generate step, and the prepare then stopped at the stamp: "Add: :DMCommit Entry Already Exists", "[RED] build_ipa.sh exit code 1" (the Mario Kart World seedds#1383 snapshot on the Duo, 2026-11-06, its prepare_xcode.log). The built commit belongs in the stamp, so it now falls back to Set: the same prepare succeeds and the app logs the real source and chain. Gen/Info.plist is regenerated at every prepare, so the replaced value does not outlive the build. Checked: bash -n passes; the Mario Kart World prepare that failed before now stamps both keys and finishes with the same Xcode project output ('source: <built commit>' in its prepare_xcode.log).
…its files is kept without its finest level, and its level-0 pages go back A first upload of such a texture makes a host texture of its level 1 (Mario Kart World keeps large BC formats from its files with a packaged layout; the host texture that skips level 0 is sampled through the same normalized coordinates), and the guest pages only level 0 holds go back after 300 frames (nvn_dirty_release) unless the game copies from that texture (soft_harden keeps it whole, as Mario Kart World copies source textures into its terrain arrays; the kartnative line notes a copied-from texture that lost level 0 drawing purple). iOS wires the whole memory pool behind a zero-copy buffer, so these uploads run on the CPU while the pool has none (mtl_pool_wrapped) instead of handing the pool a buffer it never addresses (the kartnative/plumber-racer-2 measurements: wrapped pools 3.7 GB -> 851 MB there). The mechanics: nvn_dirty_release gives back only still-protected whole pages whose bytes the host keeps (read-only again after the madvise dance, then given all-zero or left as-is); with the guest in files (DM_GUEST_FILE) there is nothing to give back (dm_guest_file_backed). The pipeline: tex_soft gates the descriptor (level shift sk) in tex_desc, and every upload reads the source one level down (pkg_upload_, CPU deswizzle included); the copy hooks (nvnCopyTexture t2t/t2b) harden the source first (soft_harden, then a pkg_upload of the whole levels); ReadTexels sees one lower level (tex_soft_level, an unmapped level-0 read reads 0). All default-off: the switches are DM_NVN_TEX_SOFT and DM_NVN_TEX_RELEASE, so no game changes until its profile names tex_soft; the sweep runs once a submission (mtl_sub_begin) and leaves a 300-frame grace (soft_sweep), as kartnative's does. Where it came from: the kartnative (pahorema) and plumber-racer-2 (cheemu21) forks (MIT) had this first, for Mario Kart World on an iPhone 18 Pro in LiveContainer at about 3.9 GB. The port keeps their behaviour and takes this tree's own anchors (tex_desc, pkg_upload_, the copies, ReadTexels, the dirty layer). Measured on an iPhone Duo (iOS 27.3) through the seedds#1383 family's same anchors: a full free-roam session at 3.7-3.9 GB where the same content without the switches sat at 4.5-5.3, and the whole-frame record lost its p95 spikes (51/81 ms p50/p95 with the switches as against 57/215 without). The tests in this PR run the CPU-only layer here; the GPU checks and the phone runs are recorded on the source lines.
…its files is kept without its finest level, and its level-0 pages go back A first upload of such a texture makes a host texture of its level 1 (Mario Kart World keeps large BC formats from its files with a packaged layout; the host texture that skips level 0 is sampled through the same normalized coordinates), and the guest pages only level 0 holds go back after 300 frames (nvn_dirty_release) unless the game copies from that texture (soft_harden keeps it whole, as Mario Kart World copies source textures into its terrain arrays; the kartnative line notes a copied-from texture that lost level 0 drawing purple). iOS wires the whole memory pool behind a zero-copy buffer, so these uploads run on the CPU while the pool has none (mtl_pool_wrapped) instead of handing the pool a buffer it never addresses (the kartnative/plumber-racer-2 measurements: wrapped pools 3.7 GB -> 851 MB there). The mechanics: nvn_dirty_release gives back only still-protected whole pages whose bytes the host keeps (read-only again after the madvise dance, then given all-zero or left as-is); with the guest in files (DM_GUEST_FILE) there is nothing to give back (dm_guest_file_backed). The pipeline: tex_soft gates the descriptor (level shift sk) in tex_desc, and every upload reads the source one level down (pkg_upload_, CPU deswizzle included); the copy hooks (nvnCopyTexture t2t/t2b) harden the source first (soft_harden, then a pkg_upload of the whole levels); ReadTexels sees one lower level (tex_soft_level, an unmapped level-0 read reads 0). All default-off: the switches are DM_NVN_TEX_SOFT and DM_NVN_TEX_RELEASE, so no game changes until its profile names tex_soft; the sweep runs once a submission (mtl_sub_begin) and leaves a 300-frame grace (soft_sweep), as kartnative's does. Where it came from: the kartnative (pahorema) and plumber-racer-2 (cheemu21) forks (MIT) had this first, for Mario Kart World on an iPhone 18 Pro in LiveContainer at about 3.9 GB. The port keeps their behaviour and takes this tree's own anchors (tex_desc, pkg_upload_, the copies, ReadTexels, the dirty layer). Measured on an iPhone Duo (iOS 27.3) through the seedds#1383 family's same anchors: a full free-roam session at 3.7-3.9 GB where the same content without the switches sat at 4.5-5.3, and the whole-frame record lost its p95 spikes (51/81 ms p50/p95 with the switches as against 57/215 without). The tests in this PR run the CPU-only layer here; the GPU checks and the phone runs are recorded on the source lines.
…ntry, so a project.yml that carries one prepares the app A project source a front end or a fork copy keeps can carry DMCommit in its Info.plist values; xcodegen writes it into Gen/Info.plist at the generate step, and the prepare then stopped at the stamp: "Add: :DMCommit Entry Already Exists", "[RED] build_ipa.sh exit code 1" (the Mario Kart World seedds#1383 snapshot on the Duo, 2026-11-06, its prepare_xcode.log). The built commit belongs in the stamp, so it now falls back to Set: the same prepare succeeds and the app logs the real source and chain. Gen/Info.plist is regenerated at every prepare, so the replaced value does not outlive the build. Checked: bash -n passes; the Mario Kart World prepare that failed before now stamps both keys and finishes with the same Xcode project output ('source: <built commit>' in its prepare_xcode.log).
This draft collects the current iOS work for Mario Kart World 1.8.0.
Gameplay runs on a physical iPhone with HDR and Docked rendering. The previously observed waterfall jumps, transient water geometry and image-quality regression are resolved in the tested configuration.
The implementation includes:
Sustained performance remains open. Gameplay can maintain 60 FPS, but some sessions enter a persistent slow state. Measurements show periods of increased CPU submission cost followed by increased GPU execution time. Background/foreground transitions sometimes recover performance, but not reliably. No definitive cause or stabilization fix is claimed.
Validation includes physical-device gameplay, iOS Release builds and targeted Metal tests covering resource lifetime, sparse mappings, upload ranges, presentation ordering and timestamp feedback.
This is a development snapshot, including opt-in diagnostics.