Skip to content

An IPA built with a Mac host carries the prewarm lists' pipelines made offline (R rows' bases and M rows' mesh pipelines), and Ocarina of Time's seed list gets an iPhone 17's own rows - #2674

Open
stan69b wants to merge 2 commits into
seedds:mainfrom
stan69b:pr/oot30-a-base-archive

Conversation

@stan69b

@stan69b stan69b commented Nov 14, 2026

Copy link
Copy Markdown
Contributor

Batch OoT-30, session A (pipelines compiled on the phone).

Why

The archive pso_offline.py bundles in an IPA holds the shader pairs' pulling bases and the compute pipelines. It holds no base with a vertex layout (a prewarm list's R row) and no native task / mesh pipeline (an M row). Both depend on what only the host knows: the descriptor pso_desc makes from a row's pso_skey and the shader's reflection. So an iPhone builds every listed one itself, at the prepare step of its first start, and keeps them in its own archive (pso_archive/).

An OS update makes Metal refuse that archive. On an iPhone 17 after iOS 27.2.1, every start logged 121 lines of [RED] pipeline archive file … not usable (deployment target for architecture applegpu_g18p … is not compatible with current OS). The bundled archive, made for the OS's major version, still opened.

In the owner's 30-minute play (pipelines up to frame lines), windows that compiled bases ran at 12-22 fps, for example bases compiled 17 / 12872 ms in one window and 4 / 45122 ms in Castle Town.

PR #2353 made these files for the Mac app (the host's prebuild tool in its bundle form, then metal-tt for other GPUs). The IPA did not get them.

The change

A-1: pso_offline.py --prewarm-host <Mac dmhost>

  • Host stage. Runs the Mac host as the prebuild tool's bundle form (DM_PSO_PREBUILD=tool, DM_PSO_PREBUILD_OUT) on the iOS libraries the app ships. A Mac's Metal loads and compiles a library built for iOS; I checked this with Ocarina of Time's iOS libraries on macOS 27.2. The tool gets the profile's tables less the pair lists (the pairs are the archive's, so the tool would otherwise build them all) and a list of the R and M rows alone (the C rows' compute pipelines are in the archive already). It writes one file per flush period, its index (.keys) and its pipelines script.
  • Compile stage. Compiles each script with metal-tt for every --gpu as <arch>-prewarm-<NN>.mtl4a, beside the period's index. A device computes the same keys. Groups of --batch-size are merged with metal-pack. A pipeline metal-tt refuses is left out by the halving compile_isolating already did, now shared as isolate().
  • Opening. The host opens the files with the archive, through the existing pso_bundle_open_prewarm. No host change.
  • Caching and failure. Both stages are cached in the work folder: the host run by its inputs, each compiled script by its bytes and the compiler's settings. A failure prints a red line and the app goes without these files, as before.
  • build_ipa.sh. Passes DM_PSO_HOST, else dm/host/dmhost when its last build was for this game (made current first). DM_PSO_HOST=none makes none.
  • NSP script. The library search by SHA-256 it had for the Mac app's other GPUs moved into pso_offline.py (script_libraries), and the NSP script calls it.
  • Seed list. Ocarina of Time's pso_manifest.tsv gets 10,415 rows (5,249 S, 4,447 R, 719 C) from the iPhone's own pso_user.tsv.

A-3: the M rows

metal-tt takes the mesh pipeline descriptors the tool writes, so the M rows go in too. This is #2642's open item.

Checked

  • A pilot of 60 R and 20 M rows from Ocarina of Time's list, through both stages for applegpu_g18p (iOS 27.0): 42 bases and 20 mesh pipelines, one file of 6 MB in 8 s, with a complete index of 62 keys.
  • Tests:
    • test_pso_offline.py: 60 tests. New: Prewarm with a fake host and metal-tt (the tool's environment and tables, the files and indexes per GPU, reuse with nothing run, a GPU dropped, new rows rerunning the host alone, groups merged with a pipeline left out, a failed or missing host leaving the archive). Also a real metal-tt compile of a mesh pipeline descriptor for applegpu_g18p, and build_ipa.sh passing DM_PSO_HOST.
    • Also run: test_nsp_mac_app.py (70), test_docs, test_env_switches, test_lint_python. lint_python --against upstream/main finds nothing new in these files.
  • regress.py: not run. The reach is the IPA build tool alone: no host, chain or runtime code changes, and the regress interface check uses pso_offline.plan, which is unchanged.

Phone (iPhone 17, iOS 27.2.1)

Pending. The phone build (the phone tree plus #2353's host part and #2539) and its first start after install will be added here.

…-row bases made offline, and Ocarina of Time's seed list gets an iPhone 17's own rows

The pipeline archive pso_offline.py makes for an IPA holds the shader pairs' pulling bases and the compute pipelines. A prewarm list's R row is a base with a vertex layout, which depends on the descriptor pso_desc makes from the row's pso_skey and the shader's reflection, so only the host can make it. An iPhone therefore built every listed one itself, at the prepare step of its first start, kept them in its own archive (pso_archive/), and lost that archive after an OS update: an iPhone 17 on iOS 27.2.1 logged 121 "pipeline archive file ... not usable (deployment target ... not compatible with current OS)" lines at every start. The bundled archive, made for the OS's major version, still opened. The Mac app already had the remedy (PR seedds#2353: the host's prebuild tool in its bundle form, then metal-tt for other GPUs); the IPA did not.

pso_offline.py --prewarm-host <Mac dmhost> now makes them for the IPA:
- the host stage runs the given Mac host as the prebuild tool's bundle form (DM_PSO_PREBUILD=tool, DM_PSO_PREBUILD_OUT) on the libraries the app ships (a Mac's Metal loads and compiles a library built for iOS: checked with Ocarina of Time's iOS libraries on macOS 27.2), with the profile's tables less the pair lists (the pairs are the archive's) and a list of the R rows alone, so it writes one archive file per flush period, its index (.keys) and its pipelines script;
- the compile stage builds each script with metal-tt for every --gpu as <arch>-prewarm-<NN>.mtl4a beside the period's index (the keys name libraries by their bytes or by their name in the library folder, which a device computes the same way), in groups of --batch-size merged with metal-pack, leaving out a pipeline metal-tt refuses (the isolation compile_isolating already did, now shared as isolate());
- both are cached (the host run by its inputs, each compiled script by its bytes, the architecture, platform, minimum OS and metal-tt version), and a failure is a red line, never a failed build: the app then has no prewarm files and the device builds the rows as before. Without --prewarm-host there are none (an earlier build's files are removed).
The library search by SHA-256 the NSP script had for the Mac app's other GPUs moved into pso_offline.py (script_libraries); the NSP script calls it.

build_ipa.sh passes DM_PSO_HOST, or dm/host/dmhost when its last build was for this game (made current first); DM_PSO_HOST=none makes none. docs/env_switches.tsv: the new row.

Ocarina of Time's pso_manifest.tsv: 10,415 rows (5,249 S, 4,447 R, 719 C) from the iPhone 17's own pso_user.tsv (Documents, 2026-11-14 06:00), the rows the seed list did not have after both lists' keys were parsed with pso_skey_parse and written again in the current layout (the phone's list held two layouts); every shader key is in shader_map.tsv with its stage. They go before the list's last block, away from PR seedds#2642's two changes to the same file (git merge-file of the two: no conflict). The pair archive's plan is unchanged by them (33,365 bases, 4,125 compute pipelines: the shader map already names every compute shader).

Tests: test_pso_offline.py 59 (new: Prewarm, five cases with a fake host and metal-tt: the tool's environment and tables, the files and indexes per GPU, reuse with nothing run, a GPU dropped, new rows rerunning the host alone, groups merged with a pipeline left out, a failed or missing host leaving the archive; IpaFallback: DM_PSO_HOST reaches pso_offline.py, none and no host make none), test_nsp_mac_app.py 70, test_docs, test_env_switches, test_lint_python (lint_python --against upstream/main: no new finding of these files).
… / mesh pipelines, which metal-tt compiles for an iPhone's GPU

PR seedds#2642's open item: pso_offline.py's pair archive leaves Ocarina of Time's 1,284 mesh pairs to the device (a mesh pipeline has no base), so every M row of the prewarm lists was compiled once on the phone, at the prepare step of a first start or, for one no list named yet, at its first draw (1.7-3.8 s each on an iPhone 17).

metal-tt takes a mesh pipeline descriptor as it takes a render one: the host's prebuild tool already writes the M rows' mesh_render_pipeline_descriptors into its pipelines scripts (with their object, mesh and fragment functions, threadgroup sizes, payload length and colour formats), and metal-tt compiled them for applegpu_g18p (iOS 27.0) beside the R rows' bases in the same file, with the same index. So --prewarm-host now hands the tool the M rows too (PREWARM_ROWS). Measured on a pilot of Ocarina of Time's list on the iPhone libraries: 42 bases and 19 mesh pipeline descriptors (20 M rows), one file of 6 MB in 8 s; the tool's own log counted the 20 mesh pipelines as captured.

Tests: test_pso_offline.py 60: the rows and the tool's list hold the M rows; new test_metal_tt_takes_a_mesh_pipeline compiles a real mesh pipeline descriptor (a mesh and a fragment function built with the iOS SDK) with metal-tt for applegpu_g18p through compile_script (skipped without Xcode or metal-tt).
@github-actions github-actions Bot added packing Building an IPA or a Mac app: the NSP script, extraction, the shader split, the packers ios The iPhone and iPad app (dm/ios) tools Tools and scripts (dm/tools, scripts) docs Documentation game: 0400486024DEC000 A game labels Nov 14, 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 ios The iPhone and iPad app (dm/ios) packing Building an IPA or a Mac app: the NSP script, extraction, the shader split, the packers tools Tools and scripts (dm/tools, scripts)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants