100 Commits
Author SHA1 Message Date
Valiantsin DzerakhandClaude Opus 5.5 7a37fc3c34 Up version 0.4.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 19:25:38 +03:00
Valiantsin DzerakhandClaude Opus 5.5 bb8b4b1797 Turn the recorder thread on by default on AMD GPUs too; vk_recorder = 0 turns it off where the device is lost
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 19:25:37 +03:00
Valiantsin DzerakhandClaude Opus 5.5 396c4ae621 Describe the profile-guided build in docs/pgo.md: where and how to train, free play, merge, measure
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 19:07:38 +03:00
Valiantsin DzerakhandClaude Opus 5.5 27a63dfb0f Merge pull request #1065: Xbox prompts at every game resolution the setup lays the UI out for (cdonatom, #378)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 18:59:22 +03:00
Valiantsin DzerakhandClaude Opus 5.5 6f6704640a Merge pull request #1066: describe deswizzle, kspin_us, pcore, rec_async and rec_spin_us in docs/settings.md (itaskaev2)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 18:55:58 +03:00
Valiantsin DzerakhandClaude Opus 5.5 574c1ecc49 Merge task/climb: Link climbs walls and ladders at full speed above 60 fps (#35, #276, #1001)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 18:46:30 +03:00
Valiantsin DzerakhandClaude Opus 5.5 06811330e7 Extend the climb controller's frame-rate factor above 60 fps, so Link climbs walls and ladders at full speed (#35, #276, #1001)
The climb velocity step (1.4.3 main+0x1f49754, 1.2.1 main+0x1918220) multiplies the requested velocity by Nintendo's
factor for a movement loss that grows with the frame rate. 1.4.3 fits it at 30 and 60 fps and caps it at 2 from about
77 fps (63% climb speed at 120, 34% at 240); 1.2.1 has no 60 fps branch (78% at 60). Below a 1/60 s step the set climb
continues the factor with a curve fitted to a replayed ladder climb, taking the patch page's frame ratio without the
time scale, so 30 and 60 fps keep the shipping factor bit for bit, slow motion included. Only the player's climb
modules reach this code. Its own setting, climb_fix under [frame rate], with a menu toggle; off without the real-time
step. Ladder replay, 1.4.3: 1.665 / 1.663 / 1.669 / 1.681 m/s at 30 / 60 / 120 / 240 (shipping 120 1.046, 240 0.563).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 18:44:18 +03:00
Valiantsin DzerakhandClaude Opus 5.5 be7c27047a Keep the 4096-a-side scene of an output near 8K under the new heap bound
The heap bound in scene_for counts the output's own growth against the 2 GiB limit, so a 7680x4320 output at
render_scale game went from the 4096x2304 scene dev renders to 2712x1526, with no setting changed. The bound now
shrinks no scene below 4096 a side, the size dev gave; scenes the 4096 cap kept smaller still grow up to the bound.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 18:20:31 +03:00
Valiantsin DzerakhandClaude Opus 5.5 1c1ff975f3 Default dynamic_res to 1 so the game keeps its own dynamic resolution
With dynamic_res at 0 by default the fixres set held the scene at 100 % for every player, the reason #573 was turned
down. The default is now 1, so the set stays off unless a player turns dynamic resolution off in the menu or
totk.ini, and the Steam Deck profile no longer needs its own entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 18:20:31 +03:00
Valiantsin DzerakhandClaude Opus 5.5 b6738cf41b Merge pull request #916: dynamic resolution as a setting, on by default, and a scene past 4096 wide (#573 by ProSep, carried by itaskaev2)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 18:20:31 +03:00
Valiantsin DzerakhandClaude Opus 5.5 dfc0b57457 Keep the per-frame pass table's comment to what the code does
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 17:59:54 +03:00
Valiantsin DzerakhandClaude Opus 5.5 173462f33d Merge pull request #1040: keep the targets a frame renders in the per-frame pass table, so draws with a pipeline still building skip a frame instead of waiting 50 to 400 ms (ipavlin98)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 17:59:53 +03:00
Valiantsin DzerakhandClaude Opus 5.5 3e037f0044 Keep the shadow log of players without sync_ahead as it was, sort the new setting names, and fix the sync_ahead frame-time sentence
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 17:55:57 +03:00
Valiantsin DzerakhandClaude Opus 5.5 b2db7809b4 Merge pull request #917: let the game run one frame further ahead of the GPU, sync_ahead, off by default (#676 by ProSep, carried by itaskaev2)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 17:55:23 +03:00
Valiantsin DzerakhandClaude Opus 5.5 8da13aa9b4 Merge pull request #1006: stop the installer space check at an unavailable drive root (Luxury213)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 17:43:41 +03:00
Valiantsin DzerakhandClaude Opus 5.5 719196f183 Merge pull request #1061: let a validation run with DLSS finish, a valid OpSelect in the motion fragment shader and set 1 bound first for the motion draws (itaskaev2)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 17:43:41 +03:00
Valiantsin DzerakhandClaude Opus 5.5 fce6364236 Merge pull request #1060: take the feedback-layout images back to GENERAL before the contact shadows' march (itaskaev2)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 17:43:40 +03:00
Valiantsin DzerakhandClaude Opus 5.5 7f82a52da8 Merge task/gears: gear doors open above 30 fps on 1.2.1 (#330, #984)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 15:36:35 +03:00
Valiantsin DzerakhandClaude Opus 5.5 6433550e3d Scale the 1.2.1 gear rotation threshold by the AI update's frame delta, as 1.4.3 does (#330, #984)
ActorCheckRotateModule's update compared the angle a gear turned since the last update with one 30 Hz frame's worth,
so above 30 fps gears and water wheels read as stopped and the Riogok, Turakamik and Wind Temple doors stayed shut.
The new set gears keeps the update context's +8 (frames elapsed in 30 Hz units, the value 1.4.3 divides by) and
multiplies the threshold by it. Measured: the context is 0.25 at 120 fps with the real-time step and 0.5 at 60 fps
without it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 15:35:16 +03:00
Valiantsin DzerakhandClaude Opus 5.5 1503b17f7d Merge task/crash705: list the compound physics shape's children in the crash report (#705)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 10:20:07 +03:00
Valiantsin DzerakhandClaude Opus 5.5 4c4bd8c67a List the compound physics shape's children in the crash report for the 1.2.1 fault after the material lookup (#705)
On 1.2.1 the game asks a compound physics shape for its first child's material at main+0xe056d0 and reads the result
without a check. At the reported crash the shape had none of its 125 children left, although every child is filled
when the shape is built. The crash handler now prints that shape's live bits and each record's shape pointer and name,
which tells removed children from switched-off ones and names the object. It runs only after the crash.
--probe-kernel builds a fake shape in a crashing child and checks the listing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 10:19:50 +03:00
Valiantsin DzerakhandClaude Opus 5.5 3d386fe37e Merge task/inteluhd: dynamic alpha to coverage and vertex input off by default on Intel's Windows driver for integrated GPUs (#970, #992)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 09:13:52 +03:00
Valiantsin DzerakhandClaude Opus 5.5 905e2e720d Turn dynamic alpha to coverage and dynamic vertex input off by default on Intel's Windows driver for integrated GPUs (#970, #992)
UHD Graphics (i3-1215U, i3-1305U) and Iris Xe drew coloured noise on foliage with dynamic alpha to coverage and black
patches over the scenery with dynamic vertex input; players confirmed that vk_dyn_a2c = 0 and vk_dyn_vertex = 0 clear
both. vk_caps.intel_igpu_win marks Intel's proprietary Windows driver on an integrated GPU, and both defaults follow it.
An explicit ini value still wins. Arc discrete GPUs and Mesa's ANV keep both on: no report there, and the ANV report
(#989) had both off with its glitch still present.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 09:01:54 +03:00
Valiantsin DzerakhandClaude Opus 5.5 729b00a1c0 Merge task/sdl3420: ship SDL 3.4.20 in the release for pads without motion calibration (#912)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 08:58:32 +03:00
Valiantsin DzerakhandClaude Opus 5.5 2fe1ea1716 Bump the bundled Windows SDL to 3.4.20 (#912)
SDL 3.4.20 uses default Switch controller stick and IMU calibration when the
pad has none, which fixes the infinite gyro readings on the Beitong Asura 2 Pro+.
The pins in tools/make_release.py (version, zip and devel sha256, SDL3.dll sha256)
and the Windows rows of THIRD_PARTY_NOTICES.md follow. The sniper sysroot row stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 08:53:49 +03:00
Valiantsin DzerakhandClaude Opus 5.5 32f86a3296 Merge task/cheatc0: run cheat opcodes C0-C3 in the data cheat VM (#973)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 08:07:24 +03:00
Valiantsin DzerakhandClaude Opus 5.5 14b1b1aece Run cheat opcodes C0-C3 in the data cheat VM (#973)
The VM refused C0 (register conditional), so cheats like C046B400 FFFFFFFF were greyed out as unsupported. C0 now
runs with dmnt's operand types 0-5, widths and conditions; C1 and C2 save, restore and clear registers, C3 moves
registers to and from the static registers. tools/cheats.py gives the same opcode lengths and accepts the same opcodes.

skip() took the end of a nested block at depth 1 for the else of the failed outer block; it now counts depth the way
dmnt does, and 2x000000 is an else only for x = 1.

tests/cheats_vm_check.py runs tools/cheats.py and runtime/cheats.c on cheats of its own, the two from the issue
included.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 08:05:01 +03:00
Valiantsin Dzerakh 8aba3647e0 Up version 0.3.14 2026-11-09 19:57:07 +03:00
Valiantsin DzerakhandClaude Opus 5.5 0238f3069a Merge task/pgostale: warn when a PGO profile was trained with other runtime headers
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 18:50:36 +03:00
Valiantsin DzerakhandClaude Opus 5.5 2d2c6782af Record the runtime headers a PGO profile was trained with and warn when they change
The floating-point helpers in simd.h and simd_fp.h inline into every lifted function before llvm-profdata matches
the profile, so the fpcheap change left pgo-v143 with a fifth of its weight while recomp/ stayed the same and
make_release saw nothing. pgo.py merge now reads the instrumented build's Ninja deps log and stores the digests of
the runtime/ headers the generated objects include (cpu.h, simd.h, simd_fp.h); make_release warns when one differs
or a record has none. docs/building.md says to retrain after a change to those headers, and build_game.py names the
libiconv-2.dll that MSYS2's SDL3.dll needs in deps-mingw/bin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 18:50:36 +03:00
Valiantsin DzerakhandClaude Opus 5.5 bdcfb42c07 Add contributor and agent guides for pull requests, running and debugging
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 14:44:59 +03:00
Valiantsin DzerakhandClaude Opus 5.5 f9ed079614 Merge task/handheldscene: render the handheld scene at the asked size on 1.4.3
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 14:38:44 +03:00
Valiantsin DzerakhandClaude Opus 5.5 bed6962e09 Render the handheld scene at the asked size on 1.4.3
1.4.3 scales the scene size it reads from the patch page by canvas width over the console mode's base width, which is
1280 in handheld, not 1920. A handheld 1280x720 output at render_scale 100 put 1920x1080 on the page, so the game
rendered a 1920x1080 scene while the DynamicTextureAllocator heap was sized for 1280x720, and heavy scenes ran it out
(crash at main+0x1c2590). scene_scale now uses the mode's base for res_init and res_dlss_mode. In handheld the game
composes a 1280x720 canvas unless the output patch is on, so the output patch is switched on with the scene patch there
and the canvas is the output the factor and the heap assume. Docked is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 14:38:03 +03:00
Valiantsin DzerakhandClaude Opus 5.5 34b39ceca0 Merge task/memcommit: take 64 MiB blocks from the driver for buffers and other images
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 11:08:31 +03:00
Valiantsin DzerakhandClaude Opus 5.5 29cb79086f Take 64 MiB blocks from the driver for buffers and other images
Since the textures moved to a pool of their own, the default device-local
blocks hold mirrors and other buffers. With VMA's 256 MiB blocks one block
held 53 MiB of them after 10 minutes in the field, and the headroom thread
kept half a block of each device-local type ahead. TOTK_VMA_BLOCK_MIB
(default 64, 0 = VMA's 256) sets the size; the headroom spare follows it.

On the RX 9070, 10 minutes in the field: VMA blocks 3582 -> 3252 MiB,
process commit 8614 -> 8327 MB, slow frames 13 (2.8 s) -> 9 (1.1 s).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 10:51:49 +03:00
Valiantsin DzerakhandClaude Opus 5.5 a78268935a Merge task/memcommit: wait out a short out-of-memory spell instead of ending the game
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 10:15:50 +03:00
Valiantsin DzerakhandClaude Opus 5.5 cf44e9013c Merge task/memoom: wait out a short out-of-memory spell instead of ending the game
Conflicts: the image retry goes through vk_texture_image, sweep_pressure keeps the released-texture cap on the new
drop helpers, and vk_headroom_release also frees the texture pool's anchor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 10:12:55 +03:00
Valiantsin DzerakhandClaude Opus 5.5 4ea472e864 Merge task/memcommit: textures in a pool of their own with 64 MiB blocks
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 10:11:51 +03:00
Valiantsin DzerakhandClaude Opus 5.5 8e05d2b409 Give textures a pool of their own with 64 MiB blocks
Textures shared the default 256 MiB blocks with the mirrors and other buffers, and a block went back to the driver
only once everything in it was gone. On the RX 9070 after a few minutes of roaming the field, 3 of 9 device-local
blocks were 13-27% full, held by a hundred small textures and buffers each, and blocks held 0.8-1.4 GB more than their
allocations; where device memory takes process commit, that commit backs nothing.

Own-memory textures now go to a VMA pool with 64 MiB blocks (TOTK_TEX_BLOCK_MIB, 0 = the default pools). Images of a
quarter block or more, images the driver wants a dedicated allocation for, and images the pool's memory type does not
take get memory of their own; the requirements are read before the image is made, since VMA checks neither for a
custom pool. The headroom thread keeps the pool's next block ahead like the default pools'.

Same 10-minute route: 807 MiB of blocks beyond their allocations instead of 1037, most pool blocks 75-100% full, slow
frames not up. Probes pass on v143.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 10:11:44 +03:00
Valiantsin DzerakhandClaude Opus 5.5 a79ff17314 Merge task/memcommit: count device memory against system memory where it takes process commit, BC3 for ASTC on integrated GPUs, cap the released-texture cache by bytes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 09:58:10 +03:00
Valiantsin DzerakhandClaude Opus 5.5 0005c01cf5 Remove the stray brace in vk_mem_census that stopped vk_memory.c from compiling
79c6951 left the closing brace of a debug block in the per-heap loop, so the function ended early and the build failed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 09:57:32 +03:00
Valiantsin DzerakhandClaude Opus 5.5 34b340a208 Cap the released-texture cache by bytes
Released textures stayed until 2048 of them were kept or VRAM passed 90% of the budget. On the RX 9070 a 10-minute
field run kept 818 MiB of them, while almost every take-back came within a second. TOTK_TEX_RELEASED_MIB (default
256) runs the same drops as under VRAM pressure while the released entries hold more own memory than that. On the
same route the run ended with 1.1 GB less process commit and 1 GB less in VMA blocks; 15 dropped textures were
created again and the slow frames did not change.

Also documents TOTK_MEM_RESERVE_MIB.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 09:57:32 +03:00
Valiantsin DzerakhandClaude Opus 5.5 213bc6af6a Wait out a short out-of-memory spell instead of ending the game
Crash logs ended in fatal errors when the system's commit ran out for a moment: a staging buffer (-2), a guest commit
with the system at 24442 of 24447 MB, image creation (-2). Windows grows a system-managed page file and some drivers
charge device memory to the process commit, so the same request often succeeds a moment later.

oom.c holds the wait nvn_api_cmd.c realloc_wait already used: it requests a release, retries every 10 ms for up to
30 s, logs the first 8 with the commit numbers. rt_oom_request sets a flag that vk_texture_new_submit takes (one atomic
load per submit): it drops up to 256 released textures of the two kinds sweep_pressure drops (overwritten, clean
mirrored), never GPU-written content, and frees the headroom blocks. vk_oom_release does at once what needs no submit:
headroom blocks, finished upload batches and deferred objects.

- memory.c commit: waits and retries without frz_lock between tries; every caller waits, boot ones too.
- vk_staging and the draw-data chunks (vk_exec_draw.c scratch): release, then wait; the open upload batch is not
  submitted, its caller still records into it.
- create_tex: release and one retry; no wait under the texture lock, the texture is asked for again at its next use.
- the texture write-back buffer: release, then wait.
- the headroom thread keeps no spare block for 30 s after a failure.

TOTK_TEST_OOM=<site>:<n> (commit, staging, image, chunk) fails the first n attempts; probe-kernel forces 3 refused
commits, probe-vkexec 2 staging buffers, 1 image and 1 chunk, and both pass through them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 09:53:30 +03:00
Valiantsin DzerakhandClaude Opus 5.5 5e479f593b Remove the stray brace in vk_mem_census that stopped vk_memory.c from compiling
79c6951 left the closing brace of a debug block in the per-heap loop, so the function ended early and the build failed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 09:51:04 +03:00
Valiantsin DzerakhandClaude Opus 5.5 79c6951688 Measure whether device-local memory takes process commit instead of assuming it per vendor
c838d96 counted system memory for every discrete GPU but NVIDIA's, an assumption. An RTX 5080 log (#398) showed 10.4 GB
of process commit at frame 1200, about what the RX 9070 holds with its VRAM counted, and the RTX 3060 Ti in #670 ran
out of system commit (17.8 GB) at 4K with its VRAM full. vk_mem_host_probe now allocates 128 MiB of device-local memory
once after device creation and compares the process commit before and after; half the size or more turns the system
memory cap on. The log line carries the measured amount, so user logs show what each driver does.

RX 9070: "a 128 MiB device-local allocation took 128 MiB of process commit".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 09:39:54 +03:00
Valiantsin DzerakhandClaude Opus 5.5 a689922180 Decode ASTC to BC3 by default on integrated GPUs
The size rule for TOTK_ASTC_BC looked at the largest device-local heap only. On an integrated GPU that heap is system
RAM reported as VRAM (10.6 GiB on the Ally X, 14.9 GiB on the 880M), so RGBA8 stayed on exactly where memory is
shortest. vk_mem_uma() now turns BC3 on there as well.

7900X iGPU, field save, same exe, frame 1800: RGBA8 commit 7047 MB, GPU 49-53 ms, 16.8-18.4 fps; BC3 commit 6155 MB,
GPU 42.6 ms, 21.6-21.8 fps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 09:20:09 +03:00
Valiantsin DzerakhandClaude Opus 5.5 d8090a85fe Keep headroom blocks for device-local memory types only
Headroom woke for every memory type that got new device memory, the staging pool's own 64 MiB blocks included, and
then kept a 256 MiB spare block in that type's default pool. On the RX 9070 the default pools of host memory types 1
and 3 held 4 MiB, beside 512 MiB of spare blocks. Textures and mirrors, whose block allocations headroom moves off the
render thread, live in device-local types.

RX 9070, field save, 60 s: heap 0 VMA blocks 192 MiB instead of 704, driver usage 1384 MiB instead of 1896; 60 fps,
1% low 51.9.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 09:05:09 +03:00
Valiantsin DzerakhandClaude Opus 5.5 c838d9692f Count system memory in the device-local budget where device memory takes host memory
The paths that give memory back under pressure (headroom's spare block, released textures, pool mirrors) watched the
Vulkan heap budget only. On a UMA GPU that budget is gigabytes of the same RAM the game runs in, and on Windows the
AMD driver charges device-local allocations to the process commit one to one (RX 9070: VRAM use and private bytes
grew by the same 1164, 256 and 256 MiB). Crash logs show the result: the process at 4.4-10.5 GB of commit, 16 GB
machines at 80-94% RAM, std::bad_alloc inside amdvlk64.dll (#285), allocation failures on Intel UHD.

vk_mem_host_room (vk_memory.c) is what the system can still give beyond a reserve (TOTK_MEM_RESERVE_MIB, 1536):
commit, and on a UMA GPU physical memory too; Linux overcommits, so there only a UMA GPU's available memory counts.
NVIDIA is left out, not measured. vk_mem_vram caps the budget at use plus that room, and headroom keeps its spare
block only while four blocks fit in it.

RX 9070, field save, 60 s with the room near zero from the start (TOTK_MEM_RESERVE_MIB=21000): commit 7124 MB instead
of 8965, VRAM 2631 MiB instead of 3781, released textures 153 instead of 1866; mirrors refused for 423 MiB of pools,
GPU 4.45 ms a frame instead of 3.34 ms, 60 fps either way. Without pressure nothing changes. The census logs the
room, the device class line the mode.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 09:02:36 +03:00
Valiantsin DzerakhandClaude Opus 5.5 6e9ca1ebfd Log the process commit in crash reports and in the memory census
A driver that runs out of memory faults or throws std::bad_alloc instead of returning an error: #285's log shows
bad_alloc inside amdvlk64.dll under gpl_link, and nothing in the report told that apart from a driver bug. The crash
report now prints the process and system commit, as rt_fatal does for our own failed allocations; --probe-kernel
checks the line.

The census at frames 600 and 1800 logs the commit as a baseline and, per heap, VMA's blocks and allocations beside
the driver's usage and budget, so a report shows whose memory grew.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 08:53:57 +03:00
Valiantsin DzerakhandClaude Opus 5.5 717e68f601 Merge task/crashinfo: crash reports carry host registers, code bytes and memory at the register values
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 08:20:01 +03:00
Valiantsin DzerakhandClaude Opus 5.5 06d70d0dfa Report host registers, code bytes and memory at a crash
The crash report named the lifted function and printed the guest registers, but the lifted code keeps guest
registers in host locals and writes them back only at calls, so the dump showed stale values and the faulting
instruction stayed unknown. Logs from #1005, #967 and #998 could not be traced further than the function.

The report now adds the x86 registers of the faulting thread (Windows and Linux), 64 bytes of machine code around
rip with the offset into the lifted function, so the instruction can be found in a local build of the same version,
64 bytes of memory around every register value that points at readable memory, and the first 128 bytes of the
guest stack. --probe-kernel checks the new lines with a child that faults with known values in rbx and x19.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 08:19:31 +03:00
Valiantsin DzerakhandClaude Opus 5.5 7e440be7ca Merge pull request #978: draw amiibo file names in any script in the F1 menu (KyokoMiki)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 21:13:04 +03:00
Valiantsin DzerakhandClaude Opus 5.5 e17a27acba Merge pull request #623: report heap corruption from the vectored handler (ipavlin98)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 21:13:04 +03:00
Valiantsin DzerakhandClaude Opus 5.5 35968c1efb Merge pull request #990: Linux AppImage: ignore the user site-packages so installer.gui imports (jay23606)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 21:13:00 +03:00
Valiantsin DzerakhandClaude Opus 5.5 169d057add Merge pull request #660: keep DLSS off the inventory screen (mictony6)
Ported onto vk_dlaa_plan (#794): the scene end in the inventory also records its submission and op (end_fence,
end_pos) so chunked replays see it at the same point. DLSS-only: everything sits behind dl_active().

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 20:50:18 +03:00
Valiantsin DzerakhandClaude Opus 5.5 0704543249 Merge pull request #947: sync shadow pools from the per-submission write-watch snapshots (corne-ac)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 20:41:23 +03:00
Valiantsin DzerakhandClaude Opus 5.5 bdb41dff7e Merge pull request #979: PC prompts for every game resolution the setup lays the UI out for (Wintego)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 20:36:02 +03:00
Valiantsin DzerakhandClaude Opus 5.5 5e56bfc7f3 Merge task/chunked: record large submissions in chunks on several threads (#628, #794), off by default
replay_workers stays 0. On the 7900X 4 threads cut the replay by a quarter (town 6.7 -> 5.0 ms, fight2 5.3 -> 3.9 ms)
with no fps change: the game's own threads bound the frame there. Weak CPUs may gain.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 20:24:08 +03:00
Valiantsin DzerakhandClaude Opus 5.5 35b3d37ea3 Make a chunk's new texture entries follow replay order, and add a knob that records chunks out of order
entry_of decides at record time whether a new texture takes the content of a live GPU-written texture at its storage
(alias_copy) or the storage bytes. In a chunked replay the source's GPU ownership is set when a chunk records its
render, so the choice followed the order the threads got to the chunks: a later chunk could take the old bytes before
an earlier chunk recorded the render, and a mirrored texture keeps them. Now a chunk that makes an entry while a live
colour texture of its size sits at the storage waits until the chunks before it are recorded (vk_exec_chunk_settle,
the texture lock released for the wait), skips sources the scan revives at a later op, and ignores GPU ownership a
later chunk set in this submission. slot_resolve and vk_texture_by_id_locked no longer read tslots through a pointer
taken before the wait.

TOTK_REPLAY_SKEW_US (debug) makes the even chunks wait before they record, so the chunk after each one records
first in every submission. With it at 3000 us and 4 threads the field save runs clean (grass drawn, 0 validation errors); the alias path
did not fire there (0 copied, 0 filled from storage), so this does not reproduce the missing grass reported on
RADV, and the fix there stays unconfirmed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 19:53:12 +03:00
Valiantsin DzerakhandClaude Opus 5.5 4fcedda5e6 Merge task/fpcheap: cheaper FPCR checks in the FP helpers
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 16:03:20 +03:00
Valiantsin DzerakhandClaude Opus 5.5 922edb177d Cheaper FPCR checks in the FP helpers
FCMP and the vector compares no longer flush denormal operands under FPCR.FZ: rt_fpcr_sync keeps MXCSR.DAZ equal to
FPCR.FZ, and x86 compares under DAZ read a denormal as a zero of its sign, as ARM does under FZ. The directed RMode
check of FN(op) and FN(vop) moved into the result check's branch, and min/max skip it, since they do not round.

Hot lifted functions shrink by about 10% of their x86 instructions; the town camera-pan bench (1080p, two runs each)
goes from 10.25 to 9.78 ms per frame. simd.py (60000 encodings), lift.py and func.py report 0 failures.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 16:03:14 +03:00
Valiantsin DzerakhandClaude Opus 5.5 31630dee65 Merge task/vbbind: rebind only the vertex streams a draw reads that changed (#974)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 14:01:38 +03:00
Valiantsin DzerakhandClaude Opus 5.5 7c5f88d33c Rebind only the vertex streams a draw reads that changed, and leave the streams it does not read bound
With vb_used the streams a draw does not read got the zero buffer, so draws in a row that read different streams
bound all 17 slots again almost every draw. On an RTX 5060 Laptop that cost 16 % of the frame rate (issue #974). Now
only the read streams are compared, one bind covers the changed ones, and the others keep the buffer bound earlier
in the command buffer, which the deferred frees keep alive until the submission is done.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 13:50:32 +03:00
Valiantsin DzerakhandClaude Opus 5.5 6cf4aab5f0 Merge task/pcore4: no P-core preference on hybrid CPUs with fewer than 4 P-cores
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 12:11:06 +03:00
Valiantsin DzerakhandClaude Opus 5.5 0d9525ba4a Leave the P-core preference off on hybrid CPUs with fewer than 4 P-cores
An i5-1235U or Core 3 100U has 2 P-cores. Binding the five frame-critical threads there, with a spinning recorder
among them, crowds two cores and their hyperthreads while the E-cores stay idle. plat_perf_core_setup now counts the
allowed physical P-cores and selects nothing below PC_MIN_CORES (4), so the scheduler places those threads as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 12:11:06 +03:00
Valiantsin Dzerakh b16c4c8938 Merge task/pcore: frame-critical threads prefer the P-cores of a hybrid CPU
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

# Conflicts:
#	runtime/vk_rec.c
2026-11-08 12:03:08 +03:00
Valiantsin DzerakhandClaude Opus 5.5 87fefa8ade Merge task/recasync: the recorder submits without the submitting thread waiting, larger publish batches without the poll
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 12:03:00 +03:00
Valiantsin DzerakhandClaude Opus 5.5 90fa6e1788 Let the recorder submit parts without the submitting thread waiting for it
rec_submit queued each part's submission and then drained the ring until the recorder had submitted it: 0.29 ms a
frame in the town on a Ryzen 7900X, 0.34 ms on 4 cores. Now it publishes the submission and returns
(TOTK_REC_ASYNC=1, default). The queue order the present, uploads, readbacks and device waits rely on is kept by
vk_queue_lock: a thread's first lock waits until the recorder submitted what was queued before (rec_queue_wait).
The recorder itself and a thread that already holds the lock skip the wait. rec_submit reports the first failed
submission the recorder made. Town, in-run A/B: replay -4.1% on all cores, -2.9% on 4 cores / 8 threads; queue
users waited about 0.02 ms a frame. fight2 with TOTK_REC_CHECK and the town under sync validation are clean.

Where the recorder does not poll (fewer than 6 usable logical processors) the producer now publishes the ring head
every 8192 words instead of 64, as Savage Wind Recomp does (runtime/nvn/vulkan/record.c rec_init): each publish
there costs an event set and a wake-up. Town on 4 logical processors: frame interval -1.3%. TOTK_REC_PUB=ab
compares both; the perf log counts the recorder's wake-ups and the queue waits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 12:02:53 +03:00
Valiantsin DzerakhandClaude Opus 5.5 3a26046cde Let the threads every frame goes through prefer the P-cores of a hybrid CPU
On an Intel CPU with P-cores and E-cores a thread on an E-core runs at about 60% of a P-core's speed, and the frame
waits for its slowest critical thread. The game's main thread, the thread that presents, and the vk replay, recorder
and present threads now select the CPU sets of the P-core logical processors the process affinity allows. Nothing is
selected on a CPU with one efficiency class or when the affinity leaves only one kind of core. TOTK_PCORE=0 turns it
off; "power:" log lines say what was selected and which threads took it. LAS Recomp does the same for its game,
render and vsync threads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 11:46:10 +03:00
Valiantsin DzerakhandClaude Opus 5.5 1446f3b06b Merge task/hybrid: hybrid laptops ask for the dedicated GPU, Windows power throttling off
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 11:13:45 +03:00
Valiantsin DzerakhandClaude Opus 5.5 320a41e0dc Ask hybrid laptops for the dedicated GPU and opt out of Windows power throttling
The executable exports NvOptimusEnablement and AmdPowerXpressRequestHighPerformance, which NVIDIA Optimus and AMD
switchable graphics read at start to run it on the dedicated GPU; Optimus can otherwise hide its GPU from a program
it put on the integrated one. At start the process opts out of EcoQoS (E-cores and low clocks on hybrid Intel CPUs
when Windows deems it in the background) and of Windows 11 ignoring its timer resolution while the window is hidden.
One "power:" log line says whether Windows accepted it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 11:13:40 +03:00
Valiantsin DzerakhandClaude Opus 5.5 8b81beb98b Merge task/kspin: kernel waits and the recorder poll briefly before they sleep
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 11:05:38 +03:00
Valiantsin DzerakhandClaude Opus 5.5 2d92565ada Poll briefly before kernel waits and the recorder sleep
Guest waits and waits for a virtual core usually end within microseconds. A thread now polls for 20 us with the
global lock released before it sleeps on its condition variable, so a quick wake costs no OS wake-up
(TOTK_KSPIN_US, 0 turns it off). The recorder polls by the clock for 60 us instead of 4096 pauses, which last a few
us on Zen 4 and about 140 us on Coffee Lake (TOTK_REC_SPIN_US). Both stay off with fewer than 6 usable logical
processors. Savage Wind Recomp polls the same way before it parks.

Machine A, town save, in-run A/B: frame interval -1.8% on average for the kernel poll (5 of 7 block pairs), -0.7%
with the process limited to 4 cores / 8 threads; the recorder poll is neutral there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 11:05:33 +03:00
Valiantsin Dzerakh ae30a61b7b Some PR review ruleset 2026-11-07 20:22:50 +03:00
Valiantsin Dzerakh 214ba53a2a Up version 0.3.13 2026-11-07 20:22:35 +03:00
Valiantsin DzerakhandClaude Opus 5.5 8bbcf52709 Merge task/poolfree: pool memory and texture records kept until the submission being recorded is done (device faults under the synchronous replay)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 20:05:55 +03:00
Valiantsin DzerakhandClaude Opus 5.5 36a83bd78f Keep pool memory and texture records until the submission being recorded is done
vk_pool_fini freed import, physical and virtual pools right after vkQueueWaitIdle, which covers submitted work only;
with the synchronous replay another game thread may be recording a submission that names the pool. Every pool kind
now retires through the completion queue at the later of the recording's value and the next one.

destroy_tex freed the texture record while other threads still held &e->pub (render targets for a pass, storage
bindings writing wr_fence through it): they read a stale VkImage and cached views by that handle. The record is now
freed with its image's stamp (vk_defer_free), and views of a dropped entry are deferred at once instead of cached.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 20:05:49 +03:00
Valiantsin DzerakhandClaude Opus 5.5 9492315bac Merge task/deferstamp: deferred frees stamped with the submission being recorded (NVIDIA write-invalid faults, #788, #802) and the GPU address map for device faults
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 19:16:56 +03:00
Valiantsin DzerakhandClaude Opus 5.5 dc45de0e9a Stamp deferred frees with the submission being recorded, whichever thread destroys the object
With the synchronous replay (the default since 7be68ec) a game thread finalizing a texture destroys released texture
cache entries while another game thread records a submission that slot_resolve may already have handed one of them.
defer() saw the recording's value only on the recording thread and stamped the others with the last submitted value,
so the completion thread freed the image before the submission naming it ran: "write invalid" device faults on NVIDIA
(#788, #802). vk_sync_submit now notes the value at the start of the recording, and every deferral made from then on
waits for it. A fight run counted 10 such deferrals during the world load.

Device faults now log the deferred-free state, and with VK_EXT_device_address_binding_report the object that held the
faulting address and whether it was unbound before the fault (TOTK_ADDR_REPORT=0 turns the map off). The census line
counts deferrals made off the recording thread during a recording.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 19:16:50 +03:00
Valiantsin Dzerakh 6e5074e203 Merge task/pcsave: #911 (pipeline builds kept apart from the cache copy, the Intel crash at start, #681) and the cache save time in the log 2026-11-07 16:53:44 +03:00
Valiantsin DzerakhandClaude Opus 5.5 5b5273b541 Log how long each pipeline cache save copies and waits for builds
The copy time bounds how long a compute miss on the drawing thread can wait for the save now that builds and the copy exclude each other; a put-off autosave is logged too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 16:53:43 +03:00
Valiantsin Dzerakh d02a917af7 Merge #911: keep pipeline builds apart from the cache copy, so Intel's driver does not crash at start (#681) 2026-11-07 16:52:45 +03:00
Valiantsin DzerakhandClaude Opus 5.5 b7e72ae87f Merge task/gpuswz: block-linear textures deswizzle on the GPU (shorter stalls on entering new areas)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 16:38:33 +03:00
Valiantsin DzerakhandClaude Opus 5.5 57037ccc29 Deswizzle block-linear textures on the GPU when their storage is an imported pool
The replay thread deswizzled every block-linear texture on the CPU, and entering a new area stalled it for 50-236 ms. Now a compute pass reads the texture straight from the pool's imported buffer and writes a linear copy into a device-local scratch pool; the upload batch copies it into the image, or the ASTC decoder takes it. Large texture loads submit the batch early so the staging and scratch pools do not grow on the replay thread, and both pools are made at device creation.

On fight2 the render thread waits about 270 ms on textures per run instead of 900, and the load frame drops from 145 to about 80 ms. Mean fps is unchanged. TOTK_DESWIZZLE=cpu turns it off and check compares every upload with the CPU result (0 of 196k regions differ). Shadow mode (Linux/Wine) and textures outside the device's limits stay on the CPU.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 16:38:26 +03:00
Valiantsin Dzerakh 71d8b0cc61 Merge #900: lay the action prompt's diamond out as an Xbox pad with the xbox-label prompts 2026-11-07 12:38:12 +03:00
Valiantsin DzerakhandClaude Opus 5.5 561fe54c06 Merge task/crashinfo: crash reports name the driver frames, the C++ exception type and the host function called (#285)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 12:14:55 +03:00
Valiantsin DzerakhandClaude Opus 5.5 6e977280bb Name the driver code and the C++ exception type in crash reports
An exception no handler took (a fault in a GPU driver, a C++ exception a driver let escape) listed only the return addresses in totk.exe, and those match only the reporter's own build. #879 and #285 crash in the AMD driver with nothing in the log saying which driver code failed or what it threw.

The unhandled-exception filter now lists the frames of every module on the faulting thread with the module name and offset, up to 12 outside totk.exe so this executable's frames still fit. For a C++ exception thrown by MSVC-built code it reads the thrown type's decorated name from the ThrowInfo, and what() for a std::exception, with every read checked. The guest pc of a host function call is printed with that host function's name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 12:14:45 +03:00
Valiantsin DzerakhandClaude Opus 5.5 2f2bc6d9a3 Merge task/menumouse: #905 (T is Y's second default key, for the menus; a bind line takes its key from other buttons' defaults)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 12:08:37 +03:00
Valiantsin DzerakhandClaude Opus 5.5 469c528ffe Bind T to Y by default for the menus, and let a bind line take its key from the defaults of other buttons (#905)
While a game menu has the pointer the left mouse button is A, and it was Y's only default key, so keyboard and mouse players could not sort the inventory or press Y anywhere in the menus. T is now Y's second default key.

A bind line in totk.ini now also removes its keys from the defaults of buttons without a line, as the remapping rows already do: with bind_X = key:t, T presses X only, not X and Y.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 12:06:44 +03:00
Valiantsin DzerakhandClaude Opus 5.5 d2bb096cd6 Merge task/menumouse: #908 (the middle and side mouse buttons keep their bindings while a game menu has the pointer)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 12:03:22 +03:00
Valiantsin DzerakhandClaude Opus 5.5 61e8fd6bb9 Keep the middle and side mouse buttons bound while a game menu has the pointer (#908)
The bindings dropped every mouse button while the cursor was not captured, and the menu pointer releases the capture,
so side buttons bound to L and R turned the menu's tabs only in the frames before the pointer appeared. While the menu
pointer is shown and over the window, the middle and side buttons now count; the left and right buttons stay the
menu's A and B.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 11:58:03 +03:00
Valiantsin DzerakhandClaude Opus 5.5 fdf990957c Merge task/rtstamp: #795 (rebuild install-side objects and relink when the runtime contents change, whatever the file dates)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 11:46:01 +03:00
Valiantsin DzerakhandClaude Opus 5.5 1c59c98adf Merge #878: keep the native camera distance after aiming in direct mouse mode
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 11:21:19 +03:00
Valiantsin DzerakhandClaude Opus 5.5 2eb5adebd6 Merge #898: record only the dynamic states that changed since the last pipeline state
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 11:07:22 +03:00
Valiantsin DzerakhandClaude Opus 5.5 6c6f48c40d Merge #897: overlay uniform updates between passes too, and clear the overlays once their copies are recorded
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 11:07:22 +03:00
Valiantsin DzerakhandClaude Opus 5.5 f81dc57e9e Rebuild install-side objects and relink when the runtime contents change, whatever the file dates
The release zip dates every file 1980-01-01, so a new release extracted over an old Setup folder has sources and a
libtotkrt.a older than the objects and the totk.exe the last install left in temp\<name>\build. Ninja compares mtimes
only: it kept the old mouse_direct.o and romfs.o and linked them with the new library (undefined symbol
input_direct_mouse_shake on 0.3.11, romfs_shaped_ready on 0.3.12, #795), or skipped the link and kept the old exe
when the version string did not change.

With --runtime-lib, build_game.py now writes obj/runtime/inputs.sha256, one hash over the library, the INSTALL_SIDE
sources and every runtime header, rewritten only when the hash changes. The install-side objects and the link depend
on it. Builds without --runtime-lib are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 09:47:29 +03:00
Valiantsin DzerakhandClaude Opus 5.5 204f2843de Merge #861: load the NGX core through the platform layer, so vk_dlaa.c has no Win32 calls
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 09:39:34 +03:00
Valiantsin DzerakhandClaude Opus 5.5 316ba63619 Merge task/uborder: #896 (order overlapping uniform overlay copies), #859, #860, #862, #863 (checks that failed on dev)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 09:26:31 +03:00
Valiantsin DzerakhandClaude Opus 5.5 45b34ff4dd Merge #863: expect the base language in the probe's automatic menu language check
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 09:05:17 +03:00
Valiantsin DzerakhandClaude Opus 5.5 d9a789fb5f Merge #862: translate the speaker setting into Brazilian Portuguese and Simplified Chinese
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 09:05:17 +03:00