Prepare: compute programs laid out as play lays them out; every compute program and its texture variants; predicted graphics pipelines #772
No reviewers
Labels
No labels
accessibility
autorelease: pending
autorelease: tagged
bug
dependencies
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
invalid
question
testing wanted
wontfix
No milestone
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Hookshot!772
Loading…
Reference in a new issue
No description provided.
Delete branch "prepare-plus"
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?
The bug: prepared compute programs had the wrong storage buffers
--prepare-shaders(and a release build's first start, the sameprepare_run) translates each compute program of theshader census with nothing bound. A compute program's c0 layout tells where its storage buffers, textures and images
are, and
cs_layoutreads that layout from the bound program's control section. With none bound it fell back toMaxwell's table. The program was kept in
hookshot_programs.binunder its right key (the key comes from its code) butwith the wrong storage buffers, and play took it from there unchecked, because the key and texture answers matched. Main
has shipped this since
2a414f9, which put compute programs in the census.Evidence (origin/main
465e096, llvm-mingw make_game, RTX 5090): a cold play translates 123 compute programs on the testroute. After
--prepare-shaders, 32 of those 123 have a prepared record with the same key and texture answers butdifferent SPIR-V. With this PR all 123 are byte-identical to play's.
Fix: while the prepare translates a compute program,
cs_layoutreads the census's own control section(
vk_bank.cpp,seed_cs_control).The census reads agl's archives, networks and the movie upscaler
Main's census finds 31,985 programs (3,808 compute). On the test route it misses 25 of the 123 compute programs and 103
of the 893 graphics stages that play meets. This PR's census also reads:
ApplicationPackageand inLib/(agl, tera and gsys resources);It finds 38,809 programs (4,128 compute), a strict superset of main's, and covers 123/123 and 893/893.
Each compute program's texture variants
A compute program's texture questions (
Program::answers) are answered in play by the textures bound, which nothingknows before the game. So the prepare kept one variant of each, and play translated and compiled the others itself.
The questions are few: each is tried with every answer it can take, and an answer that changes the SPIR-V makes a
variant. Variants of two answers and more come fewest first, up to 64 per program (
seed_compute). Each variant is keptand its pipeline warmed as before. Result: 10,340 compute pipelines for 4,128 programs (main: 3,808).
Predicted graphics pipelines (needs local notes)
Most graphics programs are named by no note in
hookshot_pipelines.bin, so their pipelines were built when firstdrawn. After a prepare that prepared, each kept program variant that no note names takes the vertex layout and targets
the notes predict (
vk_predict.cpp): those of notes with the same vertex or fragment module, else those of programswith the same inputs and outputs. Its pipelines are built once, for the driver's own cache (
predict_run).mkw_vk_pipelines.bin, which every start reads whole, and they don't stay in memory: eachprogram is borrowed from
hookshot_programs.binand let go.--prepare-shadersshows them as a part of its progress (0.7 to 0.9).RX_VK_NO_PREDICT=1leaves them out.How to test
hookshot.exe --prepare-shaders(orbin\hookshot.exe --prepare-shadersin a folder with the launcher). The output isunchanged:
@@stage shaders,@@progress,@@done shaders, exit 0 (or@@errorand 3). Then start the game. The logshows:
vk: prepared N shader programs (... compute variants, ... programs with texture variants, ... at the limit);vk: predicted N pipelines from M notes ...when there are notes.Measurements
Method: RTX 5090, driver 0x9b404000. Clean llvm-mingw make_game builds of origin/main
465e096and of this branch on it.Each run had fresh caches and a unique exe name, so the driver's cache was cold for it, and played the same 150 s input
route from the same save. A had
RX_VK_PRECOMPILE=0; B and C ran--prepare-shaderstwice, then started the gamenormally.
--prepare-shaders--prepare-shadersCosts, B vs C (no notes):
--prepare-shaders, first run--prepare-shaders, second runhookshot_programs.binmkw_vk_pipelines.binWith 953 notes from one play, the prepare also predicted and built 39,877 pipelines in 239 s (420 s in all), and
mkw_vk_pipelines.binstayed at 516 MB.Notes
hookshot_pipelines_seed.bin;that release was checked), so it built 0 pipelines in A/B/C. It pays off once notes exist, from play or from a shipped
seed. A partial sign: with 953 notes from an earlier play, the play after the prepare had 1 ms of pipeline time and 8
new pipelines in its slow frames, against C's 58 ms and 94. The 953 noted pipelines were also precompiled in that run,
so the drop is not the prediction's alone.
follows the driver's compiler; it was not measured on AMD or Intel, where single culling compiles have taken
seconds.
465e096. Rebased onto45620e8, the prediction's record reader needed one fix: #640'srevert removed the mesh-as-compute fields (
449382e). The branch compiles there but was not measured again.translates them when it meets them, as before.
Independent check of the core compute-layout fix on Windows, using the actual bank parser and table lookup with identical synthetic control bytes:
0x60, count5, layout end0xc8.0x10,0,0x10.Small regression test and runner entry, based on this PR's inspected head, are available to cherry-pick. The test also checks clearing the override and thread isolation; removing production
thread_localmakes it fail. Runpython -I -B tests/run_all.py --strict prepare_cs_layout.Tested with Windows Clang/MSVC ABI. Linux and the full census, variant enumeration, prediction and GPU outputs were not tested here. The test contains no game data.
Tested on AMD (RX 9070 XT, Ryzen 7 5700X3D, Windows 11), with this PR's head
4ca308d. I built only its renderer and paired it with a v2.0.3 game exe, sincehost/is unchanged between them. The census came from this PR'sshader_census.py.It fixes a visible bug here. With stock v2.0.3 after the first-start preparation, in Hyrule Field from the same save and camera at the same frames:
With a fresh, play-only cache (no preparation), the same v2.0.3 build draws leafy trees and tall grass, as v2.0.2 does. With this PR's
--prepare-shaderscache, the trees and grass are correct again. So the wrong compute layouts this PR fixes are what removes foliage on AMD.But the preparation is much slower on this card.
--prepare-shadersexited 0 after 2,758 s (46 min). Stock v2.0.3's full first-start preparation took 197 s here, and you measured 249 s on an RTX 5090. Afterwards the caches werehookshot_programs.bin7.4 GB andmkw_vk_pipelines.bin611 MB, and each start's precompile built 10,107 compute pipelines in 5.6 s. It ran on the default 8 preparation threads (hardware_concurrency/2). I didn't keep the per-phase output, so I can't say yet whether the time is in the compute texture variants or in the driver step. I can re-run with per-phase timing if that helps.Confirmed on RX 9070 XT with the inspected renderer: preparation exits successfully, but cached compute precompilation reports two different invalid-module forms:
08737: integer sampled type with a floatOpImageSampleDrefExplicitLodresult.04965:OpTypeImageuses F32 with R32ui.Exact cached-record pipeline replays reproduce these in 0.313 s and 0.565 s, using about 100–123 MiB of working set. Both driver calls still return success, so successful preparation alone does not certify valid SPIR-V.
The underlying texture-pass constraints predate this PR; expanded variants expose them. #834 fixes the depth sampled type with a real pass/emitter regression (old fails, fixed passes; ordinary float shaders stay byte-identical). The unsigned storage-format path is separate work. These results do not establish a cause for the 46-minute preparation time or a corrected gameplay result.
Fresh-translation follow-up: with #834 and #848 together on the #772 renderer, the two real compute programs now build four variants each on RX 9070 XT with Khronos validation enabled and no VUIDs. All eight generated SPIR-V modules pass
spirv-val. These checks cover module/pipeline construction; draw output, full-game integration and total preparation time remain untested with this build.Tested v2.0.5 (includes #772) on RX 7800 XT / Windows 11: the prepare ends with
165 failed, alldoes not lower ... unsupported native ...:In play the failed count stays at 179 (165 + the usual ~10 upscale networks + a few) and no draw is skipped, so they look unused here (they come from the wider census). On v2.0.4 (31,985 programs) it was
0 failed. Also, the prediction built 0 graphics pipelines on the first start after the update (see #865).