253 Commits
Author SHA1 Message Date
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
itaskaev2andClaude Opus 5.5 e8fd6fd7a5 Describe deswizzle, kspin_us, pcore, rec_async and rec_spin_us in docs/settings.md
tests/settings_doc_check.py failed on dev with these five names in known[] and described nowhere. The rows follow the
code: vk_deswizzle.c (TOTK_DESWIZZLE), kernel.c kspin_ns, main.c (rt_knob PCORE), vk_rec.c rec_submit and rec_main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 16:28:21 +01: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 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
Carlos DonatoandClaude Opus 5.5 fb34177cfd Make the Xbox prompts for every game resolution the setup lays the UI out for (#378)
The setup wrote romfs-patches-xbox and romfs-patches-xbox-label for 16:9 only, so prompts = xbox on a 21:9, 32:9,
16:10 or 3:2 screen (the Steam Deck's 1280x800 among them) kept the game resolution at 1920x1080 (cfg.c) or, with
output_res set to the screen's shape, fell back to the Switch prompts. #979 fixed this for prompts = pc; this extends
the same mechanism to both Xbox folders, the shared-files option of #378 by way of #979's --reuse.

- The setup builds romfs-patches-xbox-<w>x<h> and romfs-patches-xbox-label-<w>x<h> for each of ASPECT_SIZES, from
  their 16:9 folder with --reuse, as it does for romfs-patches-pc-<w>x<h>.
- romfs.c overlay_init: at a game resolution of another shape any prompts' folder loads from <folder>-<w>x<h> in place
  of romfs-patches-<w>x<h>, not only the PC one; without it the Switch prompts stay, and the log names the missing
  folder and the command that makes it. romfs_shaped_pc_ready becomes romfs_shaped_prompts_ready(folder, w, h).
- cfg.c: the display-shaped output_res default applies with prompts = xbox when the folder of the pad layout
  (romfs-patches-xbox with the Nintendo layout, romfs-patches-xbox-label with any other) is there for that size.
- The menu's note for a missing shaped folder reads "off at this game resolution (no layout made for it)" in every
  menu language, since 16:9 is no longer the only shape with prompts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 15:53:49 +01: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 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
itaskaev2 59eb026bd7 Merge branch 'dev' into carry/dynamic-res-100 2026-11-09 09:55:24 +01:00
itaskaev2 2e5d59df83 Merge remote-tracking branch 'origin/dev' into carry/sync-ahead
# Conflicts:
#	docs/architecture.md
#	runtime/cfg.c
#	runtime/vk_sync.c
2026-11-09 09:54:45 +01: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 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 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 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 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
Wintego 62b8e9dee5 Draw the PC prompts' Shift as an arrow over its name
The arrow alone read as a direction (review of #585). The key keeps the width of the game's own glyph, so the name goes
under a solid arrow rather than on a wider key.
2026-11-08 20:35:55 +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
ipavlin98 fd4427cb17 Run DLSS on the chunked replay
DLSS kept the replay on one thread: its decisions follow the passes in replay order, its jitter and camera are noted
draw by draw, and its evaluation reads the per-object motion list the scene's draws build. Now the scan takes DLSS's
decisions on its own state (vk_dlaa_plan, split out of vk_dlaa_pass) and notes the scene camera in replay order
(vk_dlaa_scan_draw), and the copy of the lit scene and the evaluation are records of the chunk that holds the op
(vk_dlaa_exec). A chunk's draws are jittered while they come before the op the scan ended the scene at. The
evaluation waits until the chunks before it are recorded, and the chunks after it wait for it (a hold), since they
sample its output. Chunks note their draws for the per-object motion one at a time (mo_lock in vk_exec_draw.c); the
uniform overrides of a motion draw and shader_for's last-frame variant flag are per thread, as the other chunks' draws
go on meanwhile; the FXAA shader table takes concurrent lookups. fxaa = 0 runs in chunks too.

With dlaa = 1 at 4K (DLSS Quality) on 1.2.1 and an RTX 5070, replay_workers = 4 takes the frame rate from 70 to 78
fps where the CPU is the limit, with no one-frame glitch in 241 consecutive frames.

(cherry picked from commit 04f8bb1b57)
2026-11-08 19:39:18 +03:00
ipavlin98 6b4d84ec50 Record large submissions in chunks on several threads
replay_workers = N (0, the default, keeps the sequential replay) records a submission of enough draws in chunks that start between passes, on N threads and in twice as many chunks, and submits them in order. In the town at 4K on an RTX 5070, 4 threads take the replay from 8.2 to 4.5 ms a frame and the frame rate from 71 to 79.

A sequential scan on the submitting thread applies only what is queue state (fixed-function and bind ops, render targets, render enable and conditions, samples-passed counting) and keeps a copy of it where each chunk starts, with how far its lists got: inline uniform updates, RENDER_COND results, contact shadow marches and the ops that drop uniform copies. A chunk takes those from the lists instead of from the chunks before it, starts with every image in GENERAL and ends with a full barrier, so its recording depends only on the copy and the lists.

Each thread records with a context of its own: the replay's memos, descriptor state, occlusion query segments and per-command-buffer state moved from file statics into VkExec and VkExecDraw, and the tables the contexts share (stand-ins, depth twins, views, mirrors, timestamps, completion callbacks, crumbs) take locks or atomics. The scan makes render targets live in replay order and notes the op (vk_texture_revive), since a chunk can sample a storage before the chunk that renders it got there or after the scan went past a later target there: a chunk's texture slots resolve as of its own op, and the chunks after a texture with no entry yet wait for the chunk that makes it. Uniform copies are dropped at the op that writes them (vk_usnap_drop_at).

Contact shadows plan their march in replay order (vk_contact_plan) and the chunk that holds its op records it; the HDR source keeps the copy that comes last in replay order. DLSS and fxaa = 0 act on the frame draw by draw and keep the replay sequential. TOTK_REPLAY_STATE_CHECK=1 compares the state after the last chunk with the scan's.

A draw or dispatch whose shaders write storage buffers drops the uniform copies they cover from its own op on, as the other GPU writes do (scan_writes). The scan still translates no shader: it reads the shaders the recording contexts translated from a table shared with them (vk_exec_draw_writes), and an op whose shader no context translated yet holds the chunks after it until it is recorded. Before, the chunk that recorded such a write dropped the copies for every position at that moment, so a later chunk recorded first bound the copy taken at the submit call: on an RX 7800 XT on RADV the grass near the camera came out dark or unshaded in some runs with 4 threads.

TOTK_TRACE=perf counts the chunks held per submission by reason and logs when each chunk of the last submission began. The settings menu has the thread count under Advanced, Scheduling, with the count this run uses under it.

The recorder thread begins, ends and submits the submission's open part (vk_rec.c rec_end_cb), so a chunk's mirror prologue stays off it: vk_sync_part waits until the recorder is idle, as the part pool allows one thread at a time, then records, ends and submits the prologue itself. Through the recorder the prologue could reach the queue before it was ended, and the GPU lost the device at the title screen.

(cherry picked from commit b94e2e9642)
2026-11-08 19:39:17 +03:00
Wintego ceece5683a Make the PC prompts for every game resolution the setup lays the UI out for
The setup wrote romfs-patches-pc for 16:9 only, so prompts = pc on a 21:9, 32:9, 16:10 or 3:2 screen kept the game
resolution at 1920x1080 (cfg.c) or, with output_res set to the screen's shape, fell back to the Switch prompts.

- make_romfs_patches.py --reuse <folder>: a file of an earlier overlay whose contents match is hard-linked (copied
  where links fail) instead of compressed again; the output is byte for byte the same.
- The setup builds romfs-patches-pc-<w>x<h> for each of ASPECT_SIZES from romfs-patches-pc with --reuse: only the
  Common archive is compressed, so the fifteen folders take about two minutes and 6 MiB each instead of 22 minutes
  and 73 MiB each.
- cfg.c: the display-shaped output_res default applies with prompts = pc when romfs-patches-pc-<w>x<h> is there
  (romfs_shaped_pc_ready); Xbox prompts keep 1920x1080 as before.
2026-11-08 13:20:17 +03:00
itaskaev2 a48416dcf4 Merge branch 'dev' into carry/dynamic-res-100 2026-11-08 08:36:47 +01:00
itaskaev2 9b5ca3670f Merge branch 'dev' into carry/sync-ahead 2026-11-08 08:36:44 +01:00
corne-acandClaude Opus 5.5 a733b94645 Keep shadow_snap off by default under Wine until it has been measured there
Shadow storage is on by default under Wine as well, and the region snapshots were only measured on a native Linux
host. TOTK_SHADOW_SNAP=1 still turns them on under Wine.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 22:20:03 +02:00
corne-acandClaude Opus 5.5 02752376f7 Sync shadow pools from the per-submission write-watch snapshots
Each 2 MiB region is now queried at most once per guest submission, shared with the texture checks, instead of once
per pool at every part of a submission. On a Steam Deck at Lookout Landing the replay thread's write tracking fell
from about 4.4 to 1.3 ms a frame and the frame rate rose about 7.5%. TOTK_SHADOW_SNAP=0 restores the old queries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 22:01:05 +02:00
Valiantsin Dzerakh ae30a61b7b Some PR review ruleset 2026-11-07 20:22:50 +03:00
ProSepandClaude Opus 5.5 a3d876e2d2 Let sync_ahead lag the 1.4.3 frame wait too
On 1.4.3 the per-frame wait is the second of the two nvnSyncWait calls in f_70002db8ac (return address 0x70002db99c). Like on 1.2.1, its sync comes from a two-entry ring indexed per frame; the first call waits on one object's sync behind a mode check. wdiasjunior found the site and measured it on an RX 7800 XT (#676): about 67-70 to 81-83 fps on Great Sky Island.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 10:55:56 +01:00
ProSepandClaude Opus 5.5 4624bf8076 Let the game run one frame further ahead of the GPU (TOTK_SYNC_AHEAD, off by default)
Each frame the game waits in one nvnSyncWait (1.2.1 lr 0x7000b23dfc) for the frame it presented last. On the Switch
that work is long done by then; here it is still in the replay and on the GPU, and on Great Sky Island the wait is
about 4.6 ms of a 13 ms frame. With TOTK_SYNC_AHEAD=1 that one wait waits for the frame before it instead, once the
replay thread submitted the asked value, so the game builds the next frame while the GPU runs the last one.

The game then writes guest memory that GPU work still in flight reads. Shadow storage makes that safe: a shadow update
of a pool with a reader in flight is queued and copied by the GPU in the next part's prologue, in queue order, instead
of memcpy'd under that reader (TOTK_SHADOW_DEFER=1, the default with the switch; 0 makes the replay thread wait for
the reader instead). The guard is read under the shadow lock and the wait takes that lock once after raising it, so no
sync that read the old guard is still copying when the game writes again. The switch needs shadow storage (Linux and
Wine by default, TOTK_SHADOW=1 on native Windows) and the 1.2.1 call site; otherwise it stays off with a log line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 10:55:55 +01:00
ProSepandClaude Opus 5.5 a6c33b072c Hold the game's dynamic resolution at 100 % and let the scene grow past 4096 wide
The game picks a scene tier of 100, 90 or 80 % mostly from a fixed cost model made for the Switch that grows with the
scene width squared, so on a wide output it drops to 80 % on any GPU: at 5120x1440 every frame drew 80 % of the scene.
Patch set fixres replaces the one instruction that moves the tier's scale into the controller's result (1.2.1
main+0xcc2c00, 1.4.3 main+0x5848a8 as MacNativeGames patches it) with 1.0. The new setting dynamic_res (menu toggle,
live) brings the game's stepping back and is on by default in the Steam Deck profile.

The scene cap goes from 4096 to 8192 a side, so render_scale above 80 works on a 32:9 output, and the scene also stays
within a DynamicTextureAllocatorMem under 2 GiB; the log says when it was made smaller. The memory selftest now maps
past the real pool size instead of a fixed 4 GiB, which a larger scene grows past.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 10:55:54 +01: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 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 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
Iker AcevedoandClaude Opus 5.5 90c14c9774 Lay the action prompt's diamond out as an Xbox pad with the xbox-label prompts
With pad_layout = xbox or auto, Switch A, B, X and Y are the buttons labelled so on an Xbox pad, but the diamond of
the action prompt (blyt/DoCommand_00.bflyt) kept the Switch positions: A on the right, where an Xbox pad has B.
make_romfs_patches.py --prompts xbox-label now moves each piece of the diamond to its partner's place (A with B, X
with Y): the button with its bar, the letters around it, the flashes of a repeated or held press, and the base image
that lights the button's side. X's bar reaches left, as Y's does on a Switch. The other prompt styles are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 23:11:33 -05:00
Claude 752e15bcc7 Record only the dynamic states that changed since the last pipeline state in the command buffer
Each change of pipeline state in prepare_draw re-recorded the whole dynamic state through vk_pipeline_set_dynamic:
about twenty commands, the vertex input packet rebuilt, and the blend enable, equation and write mask of every
attachment, however few fields differed. Every replay pipeline declares the same dynamic states, which a pipeline bind
leaves as they were, so vk_pipeline_set_dynamic_delta compares the values with what the command buffer already holds
and records only the commands that differ; the vertex input is rebuilt only when the vertex shader, attributes or
streams change. The record is per command buffer (B.dyn_valid, cleared with the rest of B on a new one or a split).
TOTK_DYN_DELTA=0 records the full set as before; ab alternates; TOTK_TRACE=perf counts calls, commands and calls that
changed nothing.

1.4.3, RTX 4070 Ti, 2560x1440 DLAA, standing still on Great Sky Island, TOTK_AB=10 (tools/ab_summary.py): 13.75 ms
a frame with the full sets, 12.59 ms with the deltas (-8.5%, 72.7 to 79.4 fps); replay 7.77 to 6.67 ms. An A/A run
with the same method moved the frame by 0.08 ms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BspNcezsiV8zT8wcnXrrME
2026-11-07 03:00:57 +00:00
Claude 49b2314dd8 Overlay uniform updates between passes too, so a run of them before a pass costs one barrier
An update between passes was copied at once behind a full barrier of its own, and the copy it recorded made the next
update or pass begin need another: a run of k updates before a pass cost k + 1 full barriers, about 250 updates a
frame on Great Sky Island. They now become overlays like the updates inside a pass; every GPU reader of the real
buffer after them comes behind barrier_to, which records the copies first. TOTK_UB_OVERLAY_OUT: 1, 0, ab; the perf
line counts the overlays made between passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BspNcezsiV8zT8wcnXrrME
2026-11-06 22:35:01 +00:00
itaskaev2andClaude Opus 5.5 5cd48ea696 Describe probe_movie_bench in docs/settings.md
tests/settings_doc_check.py failed on dev since 3cd2410 added TOTK_PROBE_MOVIE_BENCH to known[] without a row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 19:07:38 +01:00
Valiantsin Dzerakh 0d4c3555d5 Merge branch 'pr809' into task/hudshape 2026-11-06 20:24:03 +03:00
Valiantsin Dzerakh 257f6201a3 Merge branch 'pr835' into task/exefsdata 2026-11-06 19:56:29 +03:00
Valiantsin Dzerakh f594062a43 Merge branch 'dev' into task/uboverlay 2026-11-06 19:15:36 +03:00
fa94e36549 Store the data writes of mods' ExeFS patch files into main before the game runs
An IPS, IPS32 or pchtxt file for main that writes main's .rodata, .data or .bss was refused as a whole. Such writes
need no lifting: tools/exefs_patches.py now puts them in build-cache/exefs.data, and runtime/mods.c stores them into
the loaded main before any game code runs, as emulators and Atmosphere apply a patch file to the module before its
dynamic linker runs. A DT_RELR word gets main's base added; bytes over words an explicit-addend relocation fills change
nothing and are dropped; a write into the dynamic linker's tables, a lazily bound function pointer or outside main's
image keeps the file unsupported. A mod whose data lines do not all fit the build keeps its code patches off too.

The mods are applied from the bottom one up (mods_exefs_apply), so where two mods write the same bytes the higher one
wins, as it does for files. --probe-mods checks it with two mods writing one byte.

The lifted code reads some of main's bytes at lift time (the jump tables). recomp/gen.py lists those ranges in
<gen>/main/folded.txt, and the setup checks the data writes against them after the lift: a file that writes them
becomes unsupported, since the change would not reach the generated code. Generated C without mods is unchanged.

This is the data part of #790 (ericdallo's ExeFS work), split out on its own; the plugin part follows separately.

Co-Authored-By: itaskaev2 <165683571+itaskaev2@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 15:51:42 +01:00
itaskaev2andClaude Opus 5.5 8ac207f353 Grow the texture heap a mod's HeapDef asks for instead of serving that table
HD texture packs made for the emulators ship their own HeapDef with TextureHeap and its parent grown for the
emulators' 8 GB memory option (HDPacks.com's 4K pack: by 3,419,000 KiB). Served as it is, the game asked for room the
application pool does not have and crashed at start (#673); without the file it looped the panic Blood Moon.

Before mem_init sizes the pool, resolution.c reads the HeapDef of every switched-on mod (mods.c mods_peek_romfs, which
lists the mods' RomFS roots without the rest of the scan: mods_scan needs paths main sets later) and counts the largest
TextureHeap growth over the shipped 506,880 KiB like TOTK_TEX_HEAP_EXTRA_MB (the larger of the two, at most 4 GiB). The
pool and the heap cap grow by it, and romfs.c heapdef_overlay serves the game's own table grown by that amount in the
mod's place, so the other heaps keep the sizes of the game version that runs.

Tested with the HDPacks.com 4K Texture Pack v1.0 as players install it, on 1.4.3 and 1.2.1 (RTX 4080 SUPER): the game
loads a save and runs at 60 fps with 0 validation errors, and holds 4.5 GB of game memory pools against 1.2 GB without
the pack. docs/mods.md, README.md and totk.ini.example say so; other packs come with no guarantee.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 09:43:41 +01:00
Valiantsin Dzerakh 959033e1fb Merge the latest head of pull request #743 2026-11-06 11:25:30 +03:00
Valiantsin Dzerakh 4402b030fe Merge branch 'dev' into task/uboverlay
# Conflicts:
#	runtime/cfg.c
2026-11-06 11:25:30 +03:00
Valiantsin DzerakhandClaude Opus 5.5 a959eab275 Merge task/vrampress: drop released textures the game has overwritten under VRAM pressure (#754)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 10:08:32 +03:00
Valiantsin DzerakhandClaude Opus 5.5 895d202cce Let the recorder thread begin, end and submit the parts it records.
The part command buffers and their pool were used by two threads. The submitting thread still waits for the
submission, so the queue order is unchanged. TOTK_REC_END=0 brings the old split back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 10:07:45 +03:00