camera_speed.c rewrite reads the guest's heap and alias regions in 16 MiB pieces under mem_read_hold and skipped only
untouched lazy-heap runs. A piece holding pages the lazy write-back had armed (GPU-written buffers the CPU has not
read since) faulted into memory.c lazy_fault on each armed range, which fetches it from the GPU under frz_lock while
the game runs, disarms those buffers, and keeps the game's mapping calls waiting on the read hold meanwhile. This
happened at every change of the stick sensitivity with the lazy write-back on (the Windows default except on AMD's
driver).
A piece that mem_lazy_touches reports armed is now gone through in 64 KiB steps, and the armed steps are not read;
the camera table never lies in a GPU-written buffer. The step after a piece still starts a little before its end, so
a copy across two steps or two pieces is found as before. The first search that leaves memory out logs how much,
since with NX2NAVI_WB_PROBE every range counts as armed and the search then reports the table "not in memory". A
range armed between the check and the read still costs one fetch, as before.
Not reproduced before the change (no log of a sensitivity change under trace). tests/camera_search_check.py cuts
factor and rewrite from camera_speed.c over a 40 MiB stand-in heap with one armed 64 KiB step: the copies in plain
memory, across two pieces and across two steps are rewritten, the copy in armed memory is left alone and no read
touches it, the left-out memory is logged once, and with every range armed nothing is read. Against the previous
camera_speed.c it fails six of its checks. mouse_stick_check passes, and the compile check adds no warnings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A second reading of the commits taken in from pull requests found these, each traced in the code:
- heap_lazy: the camera speed's search read the whole heap, which with the setting on committed every page and undid what it saves; a scan now steps over the pages the lazy heap never committed (mem_untouched_run). tests/frame_step_check.py and tests/save_share_check.py no longer linked (frame_rate.c and fs_host.c call the new memory functions; the second also missed mem_probing before); both pass again. The settings text says that with the setting on a PC out of commit ends the game in play, not at start, and the census comment is back over its own function.
- Pipeline libraries on AMD's older Windows driver: the condition is the driver for RDNA 2 and older (RX 400 to RX 6000), not RX 5000 and RX 6000 only, and the texts named a price the code does not have. With libraries off a new pipeline is built by a worker while its draw is left out, and the start waits for every recorded pipeline instead of 20 s at most. The texts say so, and that the finding is one player's on one card. The menu strings nothing shows are as they were.
- Page file hint: it comes only when Windows sizes every page file, and it names the initial size and the automatic management that must be unticked first.
- Frame generation note: it keeps "needs an RTX 40 or newer" for the players it is right for and points the others to the log; the bridge's line says it is Streamline's general support check.
- Comments and settings texts that still described the old behaviour: the process commit bound, the wait with shadow storage, the scratch's least size, the action prompt under auto.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
(cherry picked from commit 19f03aa01b26d6e17fb5fc70ad987aa8c68e8225)
The action prompt at the top right of the HUD draws the four face buttons as a diamond in the console's places: A right, B bottom, X top, Y left. Under pad_layout = xbox, playstation or auto the A action is the bottom button, yet the diamond kept A on the right, so the prompt pointed at the wrong button. At start the runtime now edits the prompt's layout in the shared interface archive for such a layout (the buttons, the dots and the lit crosses move, and the bubbles of X and Y flip) and serves the result from the profile folder; with nintendo, the default, nothing is changed. Every field is found and checked before anything is written, so a layout a mod changed is left as it is, and the archive is packed again with the game's own dictionary at the same unpacked size. One SARC reader and dictionary lookup now serve this, the camera pack and the menu's assets. When the layout changes, the menu's Restart counts the diamond.
tests/action_prompt_check.py passes without game files and on the game's own archive (4 copies, 208 fields, 13 ms at start).
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
With the mouse camera in stick mode and a camera speed above 1, the mouse could never turn faster than a full stick does at camera speed 1, however high the mouse sensitivity was set. The mouse's counts were limited to full tilt first and divided by the camera speed afterwards, so at camera speed 1.5 the most the mouse could send was two thirds of full tilt, which the game's own factor brought back to the old top speed. The division now comes before the limit (runtime/input_map.c input_mouse_stick): a slow movement turns as far as before, and a fast flick reaches full tilt, which is the game's top speed with the camera speed in it. Direct mouse mode, the default, does not use this code. A camera speed of 1 or less behaves as before.
From pull request #424. tests/mouse_stick_check.py is new here: it builds input_map.c alone and checks the deflection at each camera speed without the game.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
NX2NAVI_STICK_SENS was served to the game as a multiplied camera pack at start only. A change during the run is now written into the game's memory: the StickSensitivity array as the game holds it, at the factor in effect, is looked for in the guest's heap and every copy is overwritten at the new factor. The game reads the array each time it steps the camera, so the speed follows at once. The copies found are remembered, so a later step of the menu's slider takes no search, and a search runs again a moment after the game opens the pack anew. On Ocarina 1.1.1 the first change of a run found 4 copies in about 2 s on its own thread, and the same stick push for a third of a second turned the camera about 30 degrees at 1, 90 at 3, 10 at 0.3 and 30 again at 1, all in one run.
NX2NAVI_AUDIO_CHANNELS was decided once. A change that gives another channel count now signals the device change events the game holds, as a console does when its output moves: the game asks GetActiveChannelCount again and mixes for the new count, and the mixer makes its SDL stream again with that count at its next render. On Ocarina 1.1.1 the centre input of the device sink went from 0.0006 rms to 0.013 within the 5 s after stereo became 5.1 and back to 0.0006 after stereo was set again, with no underrun. NX2NAVI_TRACE=audio logs the six inputs' levels with its level line.
Both rows lose their "after restart" note. The graphics card, widescreen, the resolution, the game's language, the button prompts and the game's native HDR still take a restart: the game or the Vulkan device reads them once while starting.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>