fix(vk): build every predicted pipeline before the game (the prediction found nothing on fresh builds; no 90 s budget; one progress bar) #2032

Merged
hckrman101 merged 2 commits from predict-all-in-prepare into main 2026-11-11 00:47:51 +00:00
hckrman101 commented 2026-11-11 00:35:17 +00:00 (Migrated from github.com)

The pipelines the prediction makes are meant to be built before the game. On a fresh build, though, none were predicted at all. Where they were, a 90 s budget left most of them to be compiled in play, each one a stall on its first draw. This PR builds every predicted pipeline in the preparation, on a progress bar that counts them from the start.

What changes

  1. fix(vk): the prediction sees the programs the preparation read in.
    • program_cache_load and program_cache_load_some take a key's records out of disk_records when they read a program in.
    • The preparation reads in every program the state list names (state_list_prepare) just before predict_run.
    • program_cache_each listed disk_records alone, so no note found its program. Every new build logged predicted 0 pipelines from 1261 notes for 0 program variants.
    • The records taken out are now kept in disk_taken, and program_cache_each lists both.
    • A played folder whose start did not run state_list_prepare (for example, a start after a driver update) predicted fine, which is why this went unnoticed.
  2. fix(vk): build every predicted pipeline in the preparation, on one progress bar.
    • No budget by default. RX_VK_PREDICT_S no longer defaults to 90 s; setting it still sets a budget.
    • Every CPU, normal priority. The workers now use every CPU at normal priority, as precompile_run already does; nothing else runs before the game. They used half the CPUs below normal priority. (#1610's job limit would apply here the same way.)
    • Closing the window stops them, through prepare_stopped(). What the driver has built is kept.
    • One bar. The start-up screen and the builder's --prepare-shaders bar now cover the programs, the predicted pipelines and the noted pipelines together (PrepareBar). The total holds all three from the start.
      • Until a part counts itself, it stands at a guess from the files on disk (prepare_guess: the seed's program count, the notes and the lists).
      • A pipeline weighs as two programs, the measured ratio.
      • The bar never goes back and never reads 100% while pipelines are still being built.
      • Before, the screen showed a second bar after a full one, and the builder gave the predicted pipelines a fixed 20% share.
    • Log. It now says how long deciding the predictions took, separately from building them.

Numbers

Setup: RTX 3090, Ryzen 9 7900X (24 threads), Linux, OoT 1.1.1, an empty NVIDIA shader cache, and the shipped 1,261-pipeline list.

Case Predicted Built in the preparation Time
main, fresh build 0 (the bug) 0 prepare 116 s with the program cache present
main, played folder after a driver update 43,406-45,882 8,634-10,858 (90 s budget, 12 threads) the rest in play, up to 205 draws a frame left out
this PR with RX_VK_PREDICT_S=90 43,414 13,941 93 s
this PR 43,414 43,414 7-11 s deciding + 306-320 s building
  • A whole cold preparation takes 457-581 s.
    • 457 s from nothing: translation 131 s, prediction 313 s, noted pipelines 10 s.
    • 581 s with the programs already translated but no compute list, so every compute pipeline was built.
  • A second preparation took 96 s, with the driver cache kept from the first.
  • Peak memory was 4.3 GB for the process.

Tests

  • tests/test_predict_sees_loaded.py (new): checks that both take-out sites keep what they take, and that program_cache_each lists those records too.
  • tests/test_startup_progress.py covers PrepareBar:
    • The finished programs leave room on the bar for the pipelines.
    • The bar holds while the prediction decides.
    • A part's count replaces its guess without the bar going back.
    • The bar stays under 1 until the last part is done.
    • A start with nothing to prepare fills the bar with its pipelines alone.
    • The screen shows the whole bar's share.
    • It also checks the source: predict_run has no default budget, and does not use half the CPUs or lower its priority.
  • tests/test_prepare_cache_save.py and tests/test_program_cache_cleanup.py: stubs updated.

Not tested: the Windows start-up screen and Windows builder bar (the logic is shared and tested here), and AMD or Intel GPUs.

The pipelines the prediction makes are meant to be built before the game. On a fresh build, though, none were predicted at all. Where they were, a 90 s budget left most of them to be compiled in play, each one a stall on its first draw. This PR builds every predicted pipeline in the preparation, on a progress bar that counts them from the start. ## What changes 1. **fix(vk): the prediction sees the programs the preparation read in.** - `program_cache_load` and `program_cache_load_some` take a key's records out of `disk_records` when they read a program in. - The preparation reads in every program the state list names (`state_list_prepare`) just before `predict_run`. - `program_cache_each` listed `disk_records` alone, so no note found its program. Every new build logged `predicted 0 pipelines from 1261 notes for 0 program variants`. - The records taken out are now kept in `disk_taken`, and `program_cache_each` lists both. - A played folder whose start did not run `state_list_prepare` (for example, a start after a driver update) predicted fine, which is why this went unnoticed. 2. **fix(vk): build every predicted pipeline in the preparation, on one progress bar.** - **No budget by default.** `RX_VK_PREDICT_S` no longer defaults to 90 s; setting it still sets a budget. - **Every CPU, normal priority.** The workers now use every CPU at normal priority, as `precompile_run` already does; nothing else runs before the game. They used half the CPUs below normal priority. (#1610's job limit would apply here the same way.) - **Closing the window stops them**, through `prepare_stopped()`. What the driver has built is kept. - **One bar.** The start-up screen and the builder's `--prepare-shaders` bar now cover the programs, the predicted pipelines and the noted pipelines together (`PrepareBar`). The total holds all three from the start. - Until a part counts itself, it stands at a guess from the files on disk (`prepare_guess`: the seed's program count, the notes and the lists). - A pipeline weighs as two programs, the measured ratio. - The bar never goes back and never reads 100% while pipelines are still being built. - Before, the screen showed a second bar after a full one, and the builder gave the predicted pipelines a fixed 20% share. - **Log.** It now says how long deciding the predictions took, separately from building them. ## Numbers Setup: RTX 3090, Ryzen 9 7900X (24 threads), Linux, OoT 1.1.1, an empty NVIDIA shader cache, and the shipped 1,261-pipeline list. | Case | Predicted | Built in the preparation | Time | |---|---|---|---| | main, fresh build | 0 (the bug) | 0 | prepare 116 s with the program cache present | | main, played folder after a driver update | 43,406-45,882 | 8,634-10,858 (90 s budget, 12 threads) | the rest in play, up to 205 draws a frame left out | | this PR with `RX_VK_PREDICT_S=90` | 43,414 | 13,941 | 93 s | | **this PR** | **43,414** | **43,414** | **7-11 s deciding + 306-320 s building** | - **A whole cold preparation takes 457-581 s.** - 457 s from nothing: translation 131 s, prediction 313 s, noted pipelines 10 s. - 581 s with the programs already translated but no compute list, so every compute pipeline was built. - **A second preparation took 96 s**, with the driver cache kept from the first. - **Peak memory was 4.3 GB** for the process. ## Tests - `tests/test_predict_sees_loaded.py` (new): checks that both take-out sites keep what they take, and that `program_cache_each` lists those records too. - `tests/test_startup_progress.py` covers `PrepareBar`: - The finished programs leave room on the bar for the pipelines. - The bar holds while the prediction decides. - A part's count replaces its guess without the bar going back. - The bar stays under 1 until the last part is done. - A start with nothing to prepare fills the bar with its pipelines alone. - The screen shows the whole bar's share. - It also checks the source: `predict_run` has no default budget, and does not use half the CPUs or lower its priority. - `tests/test_prepare_cache_save.py` and `tests/test_program_cache_cleanup.py`: stubs updated. Not tested: the Windows start-up screen and Windows builder bar (the logic is shared and tested here), and AMD or Intel GPUs.
Commenting is not possible because the repository is archived.
No description provided.