Repository navigation
feat: an optional item wheel for the R/L item row, Twilight Princess style - #2261
tapxgamestudio-coder wants to merge 4 commits into
Conversation
ea3c5dc to
e2dffe5
Compare
Joey-Magnus
left a comment
There was a problem hiding this comment.
The wheel itself looks great in the screenshots, and the host side is careful: the seqlock publish/read pair is correct, the renderer only ever reads the host's snapshot (never guest memory), and a stale row closes the wheel from the renderer's side. I focused on the parts that affect players who never turn the wheel on, on the repo rules, and on the input injection. I ran the touched checks on the PR merged with current main (no textual conflicts). I didn't review nn_audio.c's sound path or the ImGui drawing in detail.
blocking gpu/vk/vk_framegen.cpp:1131-1135, 1200: the "off by default" isn't true for the renderer. wheel_state() returns host->wheel(), which is never null (hos_wheel_state always returns &wheel_state), so framegen_on() || wheel_state() is always true. On every frame, for every player, whatever the Item wheel row says, framegen_hudless now builds the four HUD pipelines once, makes two scene-sized images, and records a vkCmdCopyImage of the gameplay upscale's output with two full_barriers. That's paid on every hardware tier, including the Deck and integrated GPUs, where a full barrier mid-replay is not cheap. Please gate it on the option (and the wheel being open), for example wheel_open() or opts.item_wheel, so the default path records nothing new.
blocking gpu/vk/vk_framegen.cpp:987, 1044 (and the hud_put calls): with frame generation on, the interpolated frames are now made from fg.hudless and the HUD is pasted back from the nearest real frame, for everyone, not just wheel users. The FSR 3.1 frame interpolation input (in.color) changes too. That's a separate feature ("HUD-aware frame generation") riding in an opt-in PR. It relies on a heuristic (scene vs. picture difference after pow(1/2.2), full weight at 1/8) that has only been seen on one RTX 3080, and it's on by default with RX_VK_FRAMEGEN_HUD=0 as the way out. Please split it into its own PR with before/after captures on AMD (FSR 3.1 FI) and NVIDIA, and keep this PR to the wheel's backdrop.
blocking: tests/test_framegen_resources.py fails at this head and merged with main (FAIL line 416: live.size() == 53 && barriers == 12 && framegen_on()), and passes on main. It compiles the real framegen constructors, and ensure_size now makes hudless/masks too. Your local run probably skipped it, since it needs Vulkan headers. Please update the check's expected counts in this PR, as AGENTS.md asks, rather than loosening it. CI has only run the title check here so far.
blocking nx2/wheel_icons.py:27, nx2/make_game.py:1890: CONTRIBUTING limits Pillow, texture2ddecoder, astc-encoder-py and fontTools to nx2/prompt_assets.py and nx2/prompt_draw.py. wheel_icons.py imports PIL and decodes through prompt_assets.decode (texture2ddecoder/astc). This needs a maintainer's explicit OK and a CONTRIBUTING update, or the icon decoding moved behind prompt_assets.py (for example a --wheel-icons output of the prompts step) so the dependency stays where it is allowed.
should fix host/oot_wheel.c:454, 569: R is kept held for the game for up to 4 s after the player lets go (the comment says 1.5 s), and while R is kept, a row that has stopped updating counts as open for ROW_STALL_NS (500 ms). If the game closes the row itself during that time (a text box, a cutscene, damage), the synthetic R and the D-pad taps reach gameplay for up to half a second. Your own comment notes that LEFT opens the pause menu there. You list this case as untested. Could you either drop the synthetic input as soon as the row's screen is gone, rather than after the stall window, or test it (for example opening the wheel as a Navi prompt fires)? Please also fix the comment.
should fix (docs): the new Gameplay row "Item wheel" needs a line in the readme's option table (#2105 adds a check that will fail without it). The new switches (HOS_ITEM_WHEEL, HOS_WHEEL_BACKDROP, HOS_WHEEL_SURVEY, HOS_WHEEL_TRACE, HOS_WHEEL_PROBE, RX_VK_FRAMEGEN_HUD) should go into docs/development.md's switch tables, as CONTRIBUTING asks.
coordination: MKWVK_API_VERSION 18 is also what #2317 uses for MkwVkHost.data_dir, so whichever lands second needs 19 and its field after the other's. The "(wheel mod)" tags in comments read like a fork's labels. The repo marks its own additions "(hookshot)".
… HUD-aware interpolation, icons in prompt_assets.py - gpu/vk/vk_framegen.cpp, vk_draw.cpp: the scene copy, its images and passes only with the Item wheel row on (framegen_wheel_on; with it off the upscale hook returns at once and nothing is made or recorded). It still copies every frame while the row is on: the game stops drawing its scene while its item row is shown, so the frame before the row opens is the backdrop. Pictures of an earlier size go when the timeline passes their retirement value (as vk_fsr3.cpp), and drop_size is main's again. - The HUD-aware frame interpolation is out: hudless/masks, the split and put passes, RX_VK_FRAMEGEN_HUD, and the FSR 3.1 FI input are main's again (test_framegen_resources passes with its counts as they were). - nx2/wheel_icons.py is gone: the icons are prompt_assets.py's write_wheel_icons (--wheel-icons), so Pillow and the texture decoders stay there (CONTRIBUTING.md). The file is byte-identical. test_wheel_assets.py checks it and that wheel_sounds.py imports none of the prompt-only packages. - host/oot_wheel.c: the row counts as closed once other screens have updated 60 ms without it (row_gone): the game closed it, so the R kept held and the D-pad taps stop at once, not 500 ms later. The comment on R's 4 s is right now. The probe (HOS_WHEEL_PROBE, HOS_WHEEL_SCAN) and HOS_WHEEL_SURVEY are gone. - RX_VK_WHEEL_BACKDROP (was HOS_WHEEL_BACKDROP: the renderer reads it), HOS_ITEM_WHEEL and HOS_WHEEL_TRACE in docs/development.md; the Item wheel row in the readme. "(wheel mod)" labels are "(hookshot)". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Joey-Magnus
left a comment
There was a problem hiding this comment.
Confirmed blockers:
wheel_state()(gpu/vk/vk_framegen.cpp:1131-1136) returnshost->wheel(), which is never null, soframegen_on() || wheel_state()at:1200is always true. Every player pays for the HUD pipelines, two scene-sized images, a copy and two full barriers, including Steam Deck and iGPUs.tests/test_framegen_resources.pyfails at the head (line 416: live.size() == 53 && barriers == 12) and passes on main.- HUD-aware frame generation is a second feature, on by default for everyone with frame generation (
RX_VK_FRAMEGEN_HUD=0turns it off). It changes FSR 3.1's input and was only seen on one RTX 3080. Please split it into its own PR. nx2/wheel_icons.py:27imports Pillow outside the two files CONTRIBUTING allows.MKWVK_API_VERSION18 is also claimed by #2317, #2459, #2478 and #2479.- Comments say "(wheel mod)" where the repo uses "(hookshot)".
|
This now conflicts with main in |
bbfa193 to
20b113f
Compare
… HUD-aware interpolation, icons in prompt_assets.py - gpu/vk/vk_framegen.cpp, vk_draw.cpp: the scene copy, its images and passes only with the Item wheel row on (framegen_wheel_on; with it off the upscale hook returns at once and nothing is made or recorded). It still copies every frame while the row is on: the game stops drawing its scene while its item row is shown, so the frame before the row opens is the backdrop. Pictures of an earlier size go when the timeline passes their retirement value (as vk_fsr3.cpp), and drop_size is main's again. - The HUD-aware frame interpolation is out: hudless/masks, the split and put passes, RX_VK_FRAMEGEN_HUD, and the FSR 3.1 FI input are main's again (test_framegen_resources passes with its counts as they were). - nx2/wheel_icons.py is gone: the icons are prompt_assets.py's write_wheel_icons (--wheel-icons), so Pillow and the texture decoders stay there (CONTRIBUTING.md). The file is byte-identical. test_wheel_assets.py checks it and that wheel_sounds.py imports none of the prompt-only packages. - host/oot_wheel.c: the row counts as closed once other screens have updated 60 ms without it (row_gone): the game closed it, so the R kept held and the D-pad taps stop at once, not 500 ms later. The comment on R's 4 s is right now. The probe (HOS_WHEEL_PROBE, HOS_WHEEL_SCAN) and HOS_WHEEL_SURVEY are gone. - RX_VK_WHEEL_BACKDROP (was HOS_WHEEL_BACKDROP: the renderer reads it), HOS_ITEM_WHEEL and HOS_WHEEL_TRACE in docs/development.md; the Item wheel row in the readme. "(wheel mod)" labels are "(hookshot)". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
20b113f to
919ba0e
Compare
… HUD-aware interpolation, icons in prompt_assets.py - gpu/vk/vk_framegen.cpp, vk_draw.cpp: the scene copy, its images and passes only with the Item wheel row on (framegen_wheel_on; with it off the upscale hook returns at once and nothing is made or recorded). It still copies every frame while the row is on: the game stops drawing its scene while its item row is shown, so the frame before the row opens is the backdrop. Pictures of an earlier size go when the timeline passes their retirement value (as vk_fsr3.cpp), and drop_size is main's again. - The HUD-aware frame interpolation is out: hudless/masks, the split and put passes, RX_VK_FRAMEGEN_HUD, and the FSR 3.1 FI input are main's again (test_framegen_resources passes with its counts as they were). - nx2/wheel_icons.py is gone: the icons are prompt_assets.py's write_wheel_icons (--wheel-icons), so Pillow and the texture decoders stay there (CONTRIBUTING.md). The file is byte-identical. test_wheel_assets.py checks it and that wheel_sounds.py imports none of the prompt-only packages. - host/oot_wheel.c: the row counts as closed once other screens have updated 60 ms without it (row_gone): the game closed it, so the R kept held and the D-pad taps stop at once, not 500 ms later. The comment on R's 4 s is right now. The probe (HOS_WHEEL_PROBE, HOS_WHEEL_SCAN) and HOS_WHEEL_SURVEY are gone. - RX_VK_WHEEL_BACKDROP (was HOS_WHEEL_BACKDROP: the renderer reads it), HOS_ITEM_WHEEL and HOS_WHEEL_TRACE in docs/development.md; the Item wheel row in the readme. "(wheel mod)" labels are "(hookshot)". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks for the careful review. Every point was right. All of it is addressed in the new head. Your second pass looks like it read the earlier head (e2dffe5): Blocking
Should fix
Coordination
Tested on Windows 11, RTX 3080, frame generation x2, with the row off, the row on, early-release picks and B mid-pick, then again on the wheel after rebasing onto current main (fce5345). |
919ba0e to
9e34c7d
Compare
… HUD-aware interpolation, icons in prompt_assets.py - gpu/vk/vk_framegen.cpp, vk_draw.cpp: the scene copy, its images and passes only with the Item wheel row on (framegen_wheel_on; with it off the upscale hook returns at once and nothing is made or recorded). It still copies every frame while the row is on: the game stops drawing its scene while its item row is shown, so the frame before the row opens is the backdrop. Pictures of an earlier size go when the timeline passes their retirement value (as vk_fsr3.cpp), and drop_size is main's again. - The HUD-aware frame interpolation is out: hudless/masks, the split and put passes, RX_VK_FRAMEGEN_HUD, and the FSR 3.1 FI input are main's again (test_framegen_resources passes with its counts as they were). - nx2/wheel_icons.py is gone: the icons are prompt_assets.py's write_wheel_icons (--wheel-icons), so Pillow and the texture decoders stay there (CONTRIBUTING.md). The file is byte-identical. test_wheel_assets.py checks it and that wheel_sounds.py imports none of the prompt-only packages. - host/oot_wheel.c: the row counts as closed once other screens have updated 60 ms without it (row_gone): the game closed it, so the R kept held and the D-pad taps stop at once, not 500 ms later. The comment on R's 4 s is right now. The probe (HOS_WHEEL_PROBE, HOS_WHEEL_SCAN) and HOS_WHEEL_SURVEY are gone. - RX_VK_WHEEL_BACKDROP (was HOS_WHEEL_BACKDROP: the renderer reads it), HOS_ITEM_WHEEL and HOS_WHEEL_TRACE in docs/development.md; the Item wheel row in the readme. "(wheel mod)" labels are "(hookshot)". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Rebased onto current main. The wheel is API version 20 now (#1930 took 19), and the wheel's sounds moved out of the source slices the new audio tests compile. Ready for another look. |
) **What this is for:** contributors rebuilding from source should not spend another minute drawing the same button prompts. **What is measured:** on an Intel Core i9-13900K running Arch Linux, the finish stage at main `c544828f` took 67.707 and 66.898 seconds; two unchanged runs took 0.603 and 0.651 seconds, and the final head took 0.616 seconds, clearing the run-time files as well. Other work was running throughout. **Not measured:** Windows, a packaged Builder update, a complete compile/lift, or gameplay performance. Refs #2636. ## Problem `nx2/make_game.py` removes the game folder's `prompts` directory and runs `prompt_assets.py` on every build when fontTools is available. Most source edits do not change anything those assets depend on. This avoids drawing unchanged assets; it does not make the drawing itself faster. #2636's A1 plans to measure the finish stage, but its A1–A10 items do not already propose this prompt cache. It complements #2674 and #2675, which address unnecessary retranslation rather than prompt generation. ## What changed - **`nx2/make_game.py`:** source-checkout builds request incremental prompt generation. Packaged builders still regenerate every time, using the finish stage's existing launcher distinction. `RX_RELEASE` cannot distinguish them: make_game sets it for source builds too. Missing fontTools still removes the replacement prompts, keeping the existing fallback to the game's icons. - **`nx2/prompt_assets.py`:** fingerprint the inputs before generating, draw into a fresh sibling directory, and record the successful outputs only if a second fingerprint still matches. Reuse requires both matching inputs and every recorded output's size and SHA-256. **A failed generation still removes the prompts, as before**, so the game shows its own icons. An interrupted builder can leave the previous complete set without a stamp; the next build regenerates it. The drawing, encoding and asset formats are unchanged. - **`tests/test_prompt_skip.py`:** game-free fixtures run the actual finish-stage prompt call and production cache/publication functions, with small authored files and a stand-in for expensive drawing. - **`docs/development.md`:** explain reuse, its limits, and `HOOKSHOT_FORCE_PROMPTS=1`. The force switch follows `env_on`: unset, empty, `0`, `false`, `off` and `no` are off, ignoring case and surrounding spaces. ### What prevents a wrong skip The input record covers: - The four prompt source modules, including controller, keyboard and binding tables. - The game's icon font and optional bold label font, compression dictionary, common texture/layout archives, and matching resource-size table names and contents. - The repository's controller and keyboard fonts, and added, changed or removed PNG overrides. - Python/platform; fontTools, Pillow, ASTC encoder, texture decoder, NumPy, zstandard and archspec availability and versions; Pillow's native library versions and the selected ASTC backend. - Generation parameters and relevant library switches, including `SOURCE_DATE_EPOCH`, `FREETYPE_PROPERTIES` and the encoder's custom CPU definitions. Languages and saved bindings are not build inputs here: the generator uses its source tables, and the runtime applies the selected controls. The output record includes files **and directories**: the keyboard directory itself is a runtime marker. Legitimately absent optional outputs stay absent; a missing, truncated or same-size-corrupted recorded file forces regeneration. The runtime's own compressed copies and control-specific keys are excluded before hashing, not mistaken for generator output. **The files the game derives at run time are still cleared by every build**, including an unchanged hit: their own keys do not cover changes to `host/prompts.c`. Only the known runtime filenames are removed; if one cannot be cleared, the build regenerates instead of keeping on doubt. An unreadable input cannot authorize reuse. The log gives the reason, even if a forced regeneration subsequently fails. A source edited during generation leaves no stamp, addressing the stale-input certification problem discussed in [#2674's review](#2674 (comment)). ## How it was tested 2026-11-12; Arch Linux, kernel `7.2.15-1-omarchy`, x86-64, Intel Core i9-13900K, 32 logical CPUs, Python 3.12.16. Base `c544828ff`; final head `2ec89de8`. No game or GPU program was launched for these checks. ### Finish-stage measurements These execute the real finish-stage statements through completion, including binary/image copies, the unchanged shader-list check, pipeline-list work and prompt generation, in a disposable copy of an existing built game folder. Compilation, translation and shader preparation are not included. They are **not whole rebuild times**. All optional prompt packages were present: fontTools 4.68.0, Pillow 13.0.0, astc-encoder-py 0.1.12, texture2ddecoder 1.0.6, archspec 0.2.7, NumPy 2.5.4 and zstandard 0.25.0. | Run | Source | Finish time | 1-minute load before → after | Top other work | |---|---|---:|---:|---| | Before 1 | `c544828f` | 67.707 s | 7.13 → 7.40 | Existing game 316 → 315% CPU; file indexing 66 → 79%; relay check also active | | Before 2 | `c544828f` | 66.898 s | 7.06 → 8.24 | Existing game 315 → 318%; terminal process about 41% | | First generation with cache | `63d5c965` | 66.400 s | 8.24 → 8.19 | Existing game 318 → 320%; terminal process about 42% | | Unchanged 1 | `63d5c965` | 0.603 s | 8.19 → 8.19 | Existing game 320%; terminal process about 42% | | Unchanged 2 | `63d5c965` | 0.651 s | 8.19 → 8.19 | Existing game 320%; terminal process about 42% | | Changed table source | `681208dd` | 63.147 s | 6.99 → 6.95 | Existing game 320 → 321%; terminal process about 42% | | Regenerate, final head | `2ec89de8` | 65.007 s | 5.77 → 5.86 | Existing game 317 → 316%; terminal process about 43% | | Unchanged, final head, with run-time files present | `2ec89de8` | 0.616 s | 5.79 → 5.79 | Existing game 316%; terminal process about 43% | Other work was running; none was a quiet measurement. CPU percentages are lifetime averages from snapshots, not interval measurements. The first generation is included to show that this is a skip, not a faster drawing algorithm. The unchanged runs print: ```text prompts: unchanged, kept ``` Adding a harmless comment to the button-table source forces a fresh generation: ```text prompts: regenerated (table changed) ``` The comment was removed afterwards. A timestamp-only touch does not regenerate: the key checks content. An additional run on the final head verifies an unchanged hit with all six runtime-derived files present: all six are removed, while the 16 generated originals and the stamp retain their sizes and SHA-256 values. The focused fixture also compares the retained originals byte for byte. The final timing rows above include that cleanup. **Asset parity:** all 16 regenerated files, 274,704,680 bytes, compare byte for byte with a full generation by main `c544828f`. Only the new stamp is excluded. Both sides used the same `SOURCE_DATE_EPOCH` because fontTools otherwise writes the current time into the OpenType header. This comparison setting is not introduced into normal builds. A development cache hit retains the earlier font timestamp; packaged builds retain their old full-generation behavior. ### Game-free checks - **23 focused tests pass** on the final change. They cover unchanged reuse, every input kind, package versions/presence, switch/parameter changes, missing/truncated/same-size-corrupted output, empty directories, clearing runtime derivatives while retaining byte-identical originals, regeneration when runtime cleanup fails, interruption, mid-generation edits, unreadable input, force-switch parsing, incomplete output, publication failure, and the packaged/no-fontTools paths. A non-zero generator result removes prompts for both source and packaged builds; interruption before that result leaves the old set unstamped. - The same unchanged-build test against main's finish stage fails behaviorally: `2 != 1: unchanged finish must not draw the prompts twice`. - Removing each of **18 guards/key components** in memory makes its corresponding behavior test fail on the final change. Three later corrections also fail against the earlier version of this patch: returned failure retained old prompts in both build paths, runtime files survived a hit, and an uncleared runtime file did not force regeneration. The unreadable-input diagnostic has a separate before-fails/after-passes proof. - The whole suite one commit earlier, at `f20ea58b` (before a failed generation was made to remove the prompts again and the run-time files to be cleared), `python -I -B tests/run_all.py --jobs 8`: ```text 472 passed, 0 failed, 20 skipped in 133 s (linux, 8 at once) ``` Load was 7.37 → 19.48. The first full run, at 32 checks at once, was **471 passed, 1 failed, 20 skipped**: a clang++ child compiling `texture_pass.cpp` for `nx2/test_depth_sample_types.py` died with SIGKILL. That fixture and its input trees are unchanged from main. No kernel OOM line was found, so the cause is not established. The complete run with eight workers passes, including that check. The failed run is retained, not counted as a pass. On the final head `2ec89de8` the focused checks, the baseline failure and all guard mutations were rerun, and the whole suite once more with eight workers: **471 passed, 1 failed, 20 skipped in 136 s** (load 11.14 → 22.62). The one failure is `tests/test_release_scripts.py`, `test_nightly_two_runs_at_once_end_at_the_newer_commit`, the intermittent race reported in #2626; this change touches none of its files. - No core dumps were recorded. Nothing generated from the game is in this change. ## Not tested - Windows filesystem behavior or a Windows build. - The packaged Windows Builder or Linux AppImage build/update end to end. Their always-regenerate selection is covered by a game-free test only. - A full compile/lift or a new gameplay run, other CPUs, or gameplay/frame-rate benefits. No screenshots: the regenerated asset bytes match, and no visual change is intended. ## Risks The input list must grow when the generator gains new file dependencies or outputs outside the prompt directory. A regression flags new local module imports, but it does not replace reviewing new file reads. Generation temporarily needs room for both old and new assets. Publication uses completed directories and rollback on a rename error; interruption cannot create a stamped half-set, though a process killed between the two directory renames may require regeneration on the next build. ## Overlaps The open-PR scan found 47 PRs touching one of these files. The actual conflict hunks were read: - **#2151:** adjacent item-button generation conflicts with the finish-stage prompt call/error branch. Preserve both steps and account for added prompt dependencies. - **#2261:** substantive overlap. It adds `--wheel-icons`, another input folder and output outside `prompts`. Keep that work outside this skip or extend the input/output proof and staging; accepting both hunks mechanically is not enough. - #1872, #1958, #2304, #2317, #2430, #2465, #2474, #2478, #2608, #2673, #2675 and #2686 share code files but merged cleanly in the scan. That is not proof that any newly added generator dependency is covered. Assisted-by: GPT-6 Astra Co-Authored-By: GPT-6 Astra <noreply@openai.com> Co-authored-by: GPT-6 Astra <noreply@openai.com>
…yle (Gameplay > Item wheel, off by default) Holding R or L shows the item row; with Gameplay > Item wheel on, the row is shown as a ring of all the items over the blurred, dimmed game instead. The left stick or the mouse points at an item and letting go equips it, as the row would. Off (the default), nothing changes: the game's own row, its sounds and the game's menus' mouse. - host/oot_wheel.c: the row's screen (vtable 0x84c0d430) read on each update, from host/oot_menu.c's menu tick (first; the menus' mouse leaves the row's screen alone while the wheel has it). Its items are learned from the panes the row loads; the ones not loaded yet are surveyed by turning the hidden row and back. The pick turns the row with D-pad taps and keeps R held until it gets there. Home settles for 200 ms after an opening (the row's first update after its items change still gives the old cursor), a same-length list change clears the cached names, and L holds the wheel as R does. - gpu/vk/vk_menu.cpp: the wheel drawn with Dear ImGui under the menu and the FPS counter (draw_wheel): one ring, or two from 17 items, the equipped item in gold, the pointed one ringed in white, the counts, and the focused item's name on a banner. The icons are the game's, one texture made from wheel/icons.bin. - gpu/vk/vk_framegen.cpp, vk_draw.cpp: the backdrop is the scene before the HUD (the gameplay upscale's output, whichever upscaler made it), blurred and dimmed, so the row, its hints and the HUD are gone from behind the wheel. With frame generation the HUD is kept off the interpolated frames' motion the same way. - host/nn_audio.c: the row's own open, select and close sounds play; its tick (once per hidden tap) is silent while the wheel steers, and the wheel ticks once per new slot instead, from wheel/sounds.bin. - host/display.c: the mouse is let go while the wheel is open, the pointer in its middle; a click picks and closes. - nx2/wheel_icons.py, nx2/wheel_sounds.py: make_game.py makes wheel/icons.bin and wheel/sounds.bin from the player's RomFS at every build, beside the button prompts (nothing of the game leaves the PC; without them the wheel shows names and its tick is silent). - Option 60 (HOS_OPT_ITEM_WHEEL), MKWVK_API_VERSION 16 (MkwVkHost wheel). Tests: test_wheel_assets.py (the files' layouts against their readers), the overlay order, the menu mouse and screensaver fixtures' stand-ins. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… HUD-aware interpolation, icons in prompt_assets.py - gpu/vk/vk_framegen.cpp, vk_draw.cpp: the scene copy, its images and passes only with the Item wheel row on (framegen_wheel_on; with it off the upscale hook returns at once and nothing is made or recorded). It still copies every frame while the row is on: the game stops drawing its scene while its item row is shown, so the frame before the row opens is the backdrop. Pictures of an earlier size go when the timeline passes their retirement value (as vk_fsr3.cpp), and drop_size is main's again. - The HUD-aware frame interpolation is out: hudless/masks, the split and put passes, RX_VK_FRAMEGEN_HUD, and the FSR 3.1 FI input are main's again (test_framegen_resources passes with its counts as they were). - nx2/wheel_icons.py is gone: the icons are prompt_assets.py's write_wheel_icons (--wheel-icons), so Pillow and the texture decoders stay there (CONTRIBUTING.md). The file is byte-identical. test_wheel_assets.py checks it and that wheel_sounds.py imports none of the prompt-only packages. - host/oot_wheel.c: the row counts as closed once other screens have updated 60 ms without it (row_gone): the game closed it, so the R kept held and the D-pad taps stop at once, not 500 ms later. The comment on R's 4 s is right now. The probe (HOS_WHEEL_PROBE, HOS_WHEEL_SCAN) and HOS_WHEEL_SURVEY are gone. - RX_VK_WHEEL_BACKDROP (was HOS_WHEEL_BACKDROP: the renderer reads it), HOS_ITEM_WHEEL and HOS_WHEEL_TRACE in docs/development.md; the Item wheel row in the readme. "(wheel mod)" labels are "(hookshot)". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ts' source slices test_audio_aux and test_audio_biquad (NotRexed#1544, NotRexed#2648) compile slices of host/nn_audio.c on their own: the reverb section up to the mixer, and #define FRAME up to mix_depth. The wheel's sounds sat in both, and their hos_game_path_a and MAX_PATH aren't there. The block now follows mix_depth, still before render_frame, which mixes its cues in. A move only; every tests/test_audio*.py passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
9e34c7d to
d41c166
Compare
Joey-Magnus
left a comment
There was a problem hiding this comment.
Thanks, the earlier blockers are fixed. With the row off, nothing is recorded or made (framegen_wheel_on). HUD-aware frame generation is gone. The icons are made in prompt_assets.py --wheel-icons. The readme and switch-table lines are in, and the labels say "(hookshot)". I merged it into current main and ran tests/run_all.py with the Vulkan headers: 469 passed. The only failures were test_lift_cache, which fails on main here, and a test_recorder_sync load timeout, which passes alone. test_framegen_resources and #2105's readme check pass too.
One bug: gpu/vk/vk_framegen.cpp:1038-1039 reads RX_VK_WHEEL_BACKDROP and HOS_ITEM_WHEEL with env_int, while host/oot_wheel.c:473 reads HOS_ITEM_WHEEL with env_on. With HOS_ITEM_WHEEL=on, the host turns the wheel on but the renderer follows the menu row and draws no backdrop. With =off and the row on, the wheel is off but the scene is still copied every frame. RX_VK_WHEEL_BACKDROP=off doesn't turn the backdrop off either. Please use env_on/env_value_off on both sides.
API version 20 is also claimed by #2317, #2566, #2594, #2600, #2604 and #2760, so whichever lands second has to bump it.
…P by the on/off rule gpu/vk/vk_framegen.cpp read both with env_int, host/oot_wheel.c read HOS_ITEM_WHEEL with env_on, so they disagreed on anything but 0 and 1: HOS_ITEM_WHEEL=on turned the wheel on but left the renderer on the menu's row (no backdrop behind the wheel), =off with the row on turned the wheel off but still copied the scene every frame, and RX_VK_WHEEL_BACKDROP=off did nothing. Both are read with env_value_off now (as vk_memory.cpp's RX_VK_SHADOW_STAGE), the same as the host. test_wheel_assets.py checks both sides read HOS_ITEM_WHEEL the same way and that no wheel switch is read with env_int. The docs point the two rows at the on/off rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks. Fixed in 2fb1ed9: the renderer reads |
Picking an item from the R/L item row means scrolling through it one item at a time, which gets slow with a full inventory. This adds an optional Twilight Princess style item wheel: hold R or L, point the left stick or the mouse at any item, and let go to equip it.
It is off by default (Insert menu > Gameplay > Item wheel), so nothing changes for anyone who does not turn it on. Off, the game's own row, its sounds and the menus' mouse support all work as before.
Screenshots
The wheel (2560x1152 scene on a 3440x1440 window, cropped to 16:9): every item in a ring over the blurred, dimmed game, the equipped one in gold, its name on a banner, counts as the HUD shows them.
The mouse pointing at an item (ringed in white); a click equips it and closes the wheel.
The setting, and the game's own row with the setting off (unchanged).
What changed
host/oot_wheel.c(new): reads the item row's screen (vtable0x84c0d430) on each update. It is called first fromhost/oot_menu.c'shos_oot_menu_tickand returns 1 while the wheel has the row, so the menus' mouse leaves that screen alone. The full item list is not in memory, so items are learned from the panes the row loads; slots not loaded yet are filled by briefly turning the hidden row and back (once per inventory change). A pick turns the row there with D-pad taps and keeps R held until it arrives, so letting go early still equips the item pointed at.gpu/vk/vk_menu.cpp:draw_wheeldraws the wheel with Dear ImGui under the menu and the FPS counter. It uses one ring, or two staggered rings from 17 items so slots stay large. The item icons are the game's own, put into one texture fromwheel/icons.bin. A short opening animation spreads the slots out.gpu/vk/vk_framegen.cpp,vk_draw.cpp: the backdrop is the scene before the HUD (the gameplay upscale's output, from TAAU, the temporal upscalers or FSR 3.1), blurred and dimmed, so the row, its hints and the HUD are gone from behind the wheel. Only with the Item wheel row on: off, the upscale hook returns at once and nothing is made or recorded. Frame interpolation is unchanged (the backdrop is painted onto the game's picture before it reads it).host/nn_audio.c: the row's own open, select and close sounds play as usual. Its scroll tick, which would play once per hidden tap, is silenced while the wheel steers, and the wheel plays the same tick once per new slot instead (fromwheel/sounds.bin).host/display.c: while the wheel is open the mouse is released and its pointer centred; hovering points, and a click picks the item and closes the wheel.nx2/prompt_assets.py,nx2/wheel_sounds.py: the build makeswheel/icons.bin(prompt_assets.py --wheel-icons, with the prompts' decoders, so Pillow and texture2ddecoder stay inprompt_assets.py; a run of its own at every build, about 3 s, outside the prompts' reuse from perf(build): keep unchanged button-prompt assets in source builds #2698, which covers only the prompts' inputs and outputs) andwheel/sounds.bin(standard library and zstandard) from the player's RomFS. As with the prompts, nothing made from the game leaves the PC. Without the files the wheel shows item names and its tick is silent; a failure does not stop the build.HOS_ITEM_WHEEL,HOS_WHEEL_TRACEandRX_VK_WHEEL_BACKDROPindocs/development.md.HOS_OPT_ITEM_WHEEL),MKWVK_API_VERSION20 (MkwVkHost.wheel, after upstream's 19, feat: add separate button mappings for the ocarina notes #1930; it moves up again if feat(paths): saves and settings in a per-user data folder, caches and logs in the game folder's cache/ and logs/ #2317, feat(audio): the microphone heard on audio interfaces, with a volume, a channel and a test on the Audio tab #2459, feat(mods): a Mods tab, merged resource size tables, ExeFS patches and Atmosphere cheats #2478 or feat(amiibo): read amiibo from your own figure dumps #2479 lands first), and window messageWM_APP + 20for the wheel's mouse.Testing
Windows 11, NVIDIA GeForce RTX 3080 (driver 621.01), 3440x1440 window, frame generation x2. In game:
Game-free checks:
tests/run_all.py, with the Vulkan and SPIR-V headers found (RX_CPM), fails the same 6 tests on this PC as cleanmaindoes (tools missing here), and passes the rest,test_framegen_resourcesandtest_present_source_cropincluded. Newtests/test_wheel_assets.pychecks that the build makes both files in the layouts their readers expect, and that every sound the host plays is one the build writes.test_fps_overlay_order.pynow covers the wheel's place among the overlays.Not tested:
temporal_rejected_network): there the backdrop falls back to the game's picture with its row.Assisted-by: Claude Code (Claude Opus 5.5)
🤖 Generated with Claude Code