Repository navigation
fix(prompts): the hint bars on screen take a change of the prompts at once - #2756
polackangry wants to merge 3 commits into
Conversation
… once The ocarina's, the pause menu's and the songbook's hint bars are boxes the game lays out and draws once, so a live change of Button prompts never reached them. Keep the boxes with button codes, mark them for a new layout when the font changes, and make the picture of those whose picture another thread makes at their next draw (f_80e6e0e0), with the guest's registers put back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ut Ctx in prompts.c test_mods_size_table builds prompts.c with a hos.h of its own, which has no Ctx. hos_hostcall.c now has hos_guest_x and hos_call_guest_kept (the call that puts every register back), prompts.c calls those with plain integers, and the test stubs them as it does hos_regions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Joey-Magnus
left a comment
There was a problem hiding this comment.
I merged this into current main, together with #2755. tests/test_mods_size_table.py (including the folder part on Linux), test_prompts_live, test_prompt_font_bind and test_menu_hooks all pass. The only conflict with #2755 is the tested-configurations row.
The marking half (shown_keep/shown_mark) is careful: a box is matched by vtable, text pointer and length before its status word is touched. The part I'd like a maintainer to weigh is shown_picture (host/prompts.c:1141). From the draw thread, it calls f_80e6e0e0 on boxes whose +380 bit 2 says UpdateTextBoxTextureThread owns their picture. Nothing stops that thread from rasterizing the same box at the same moment, and f_80e6e0e0 may rely on locks that f_8152b670 takes before its own call. Restoring registers covers neither case. A race there would show up as a rare crash in FreeType or the upload, so one clean run doesn't rule it out.
Could you check whether f_80e6e0e0 or its caller takes a lock or a per-box flag? The other option is to set whatever bit makes the texture thread redo the picture itself.
…'s and the hint bars' Review of NotRexed#2756: shown_picture calls f_80e6e0e0 from the draw thread on a box whose picture UpdateTextBoxTextureThread makes, and nothing kept that thread off the same box meanwhile. The game takes no lock around the call on either side (f_8152b670's own call, f_80e6dfe0's job). - nx2/oot_patches.py patch_text_picture: the texture thread's call (0x80e6e0a0 in f_80e6dfe0) goes through hos_text_picture_thread. - host/hos_hostcall.c: hos_text_picture_thread holds an SRW lock around it; hos_text_picture_lock / unlock for shown_picture, which takes it around its own call. The draw's own calls are left unlocked. - Tests: test_menu_hooks checks the patch, test_mods_size_table stubs the lock. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks, both points checked in the lifted code. A lock on the caller's side: none. The same box at once: a real gap, now closed. The texture thread's job ( The fix in 5eae6a5: one picture of a box at a time.
I tried your other route first, the texture thread making the picture again itself: after the relayout, clearing Tested on Windows 11, RTX 5060 Ti, a build of this branch (main 51da046), the Fire Temple save, headless through the control bridge: the ocarina bar Keyboard → Xbox → Keyboard as before, then 12 more switches 20 frames apart with the ocarina out, no fault. 🤖 Generated with Claude Code |
A change of Button prompts or of the controls while the game runs (#2366, #2435) reached every text shown after it, but the hint bars already on screen kept their old icons until they were shown again: the ocarina's bar ("Check songbook", "Play a note", "Cancel") while the ocarina is out, the pause menu's ("Rotate", "Select", "Back"), the songbook's ("Check song", "Listen to the melody").
Why
Each icon in those bars is a text box of its own with one code (the ocarina's bar:
e046,e044,e045,e043,e042,e040,e041). The game lays each out and draws it once, when the bar appears, and doesn't callf_8152aec0orf_8152b670for it again while the bar stays, sotext_rewritenever ran on them.Marking them to be laid out again isn't enough on its own. Their pictures are made by another thread (
UpdateTextBoxTextureThread, the box's+380bit 2), which the new layout doesn't ask for a new picture. With the codes rewritten and no new picture, the icons came out blank: the new codes' glyphs were never rasterized. (Found with a log of the guest call chain atft_smooth_render: the bars' glyphs are drawn from0x834a2ec8 → f_80df2680 → f_80e6dfe0 → f_80e6e0e0, other boxes' fromf_8152b670 → f_80e6e0e0.)What it does (
host/prompts.c)shown_keep(in the layout hook): keeps the boxes with button codes the layout has seen (up to 256), with their first word, text pointer and length.shown_mark(when the font changes,live_font): each kept box that is still the one seen gets the status bitshos_prompts_text_drawsets (0x20000 | 0x100000). Its next layout rewrites its codes on the game's own thread, as any box's. A box no longer the one seen (freed, or another text) is let go and never written.shown_picture(in the draw hook): a box marked and laid out again, whose picture another thread makes, has its picture made at that draw. It callsf_80e6e0e0(box, the draw's two words at +24), the callf_8152b670makes for the boxes whose picture it makes itself. The game's context is mid-call, so the call goes throughhos_call_guest_kept(new inhost/hos_hostcall.c, besidehos_call_guest), which puts every register (x0..x30, the vector registers, NZCV) back as it was;hos_guest_xreads the draw's x2. Boxes the draw renders itself are left to it.prompts.cstays free ofCtx:tests/test_mods_size_table.pybuilds it with ahos.hof its own, and stubs the two new calls as it doeshos_regions.f_80e6e0e0(inf_80e6dfe0, its job) goes throughhos_text_picture_thread(nx2/oot_patches.pypatch_text_picture,host/hos_hostcall.c), which holds an SRW lock;shown_picturetakes the same lock for its call. The game takes no lock around that call on either side, so without it the thread could make a box's picture whileshown_picturemade it too. The draw's own calls are left unlocked.The bar's spacing (the layouts' part) is the bar's as it was made: after Keyboard → Xbox with the ocarina out, Xbox's wider LB/RB sit closer than at a fresh start until the bar is shown again. The icons are right; moving panes already made is a further step.
Screenshots
Each bar while it stays on screen, with Button prompts switched live. "Before" is main with #2755's notes, "after" this branch. The "before" runs had the default keys, the "after" runs the tester's own, so the keys differ; what matters is whether a bar follows the switch.
Testing
In game, native Windows 11, RTX 5060 Ti, the v131072 game, a build of this branch on main (4678050), driven with the control bridge (headless), a save in the Fire Temple:
prompts: now the xbox icons in texts, 16 buttons on these controls; 10 texts on screen laid out againTests:
test_prompts_live,test_prompt_font_bind,test_prompt_auto_face,test_menu_hooks,test_prompt_skippass here;test_mods_size_table's folder part runs on Linux only (CI). After moving the guest call tohos_hostcall.cthe game was built again (v2.1.0-rc.3-260, main 51da046 with both PRs) and the same run repeated: every bar follows Keyboard → Xbox → Keyboard as before,10 texts on screen laid out again, the game plays on after the pause menu.The branch is rebased on main (51da046) after the run; the files it touches didn't change there, and the tests above pass on it again. A row for the run is in
docs/tested-configurations.md.It's independent of the keyboard notes PR (each applies to main alone); the run above had both.
🤖 Generated with Claude Code