The ability guard (runtime/ov_ability.c) checks the holder, the actor, its component and the reference word the game
writes, so it catches every bad target seen in the reports: -1, 0x80, an empty bounding box (FLT_MAX) and a vtable in
main's data. The optref site at main+0x1bd01c8 (1.2.1: 0x1622bf4) is dropped: set ability patches the same address and
must win there.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The setup wrote 64 patch folders: every prompts style for all 15 shaped game resolutions. The new shapes step
(installer/screens.py) writes romfs-patches-<w>x<h> only for the shapes of the connected displays, the output_res the
game defaults to on each and the totk.ini output_res, and the prompts' shaped folder only for the style totk.ini
selects. One folder per shape: the runtime maps the game resolution to its shape's size (cfg.c cfg_shape_size, the
closest ratio within 1%), and an exact-size folder from an older install still wins. The settings menu marks a game
resolution whose shape has no folder and can start the generator for it in the background, for the next start.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The three patch sets read their switch through cfg, so the keys already worked from totk.ini but logged as unknown and
were undocumented. They are now known keys with defaults (on), in [performance] of totk.ini.example; the settings menu
does not show them. The settings table reached 128 rows, the size of the menu's reset list, so that list grows to 256
and logs if the table ever outgrows it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#1092's pointer image (runtime/cursor_art.c: a gold arrowhead with a dark edge, a turquoise gem and a soft shadow,
drawn at the window's DPI) was left out of dev because it changed the pointer for every player with no way to keep
the system arrow. It now comes with pointer_image (input section, live, default 0): 0 leaves the window class's arrow
as dev has it, 1 shows the image while the cursor is not captured. Win32 reads the setting at WM_SETCURSOR (the
next mouse move after a change); SDL sets the image or its default cursor when the settings change (input_sdl_idle).
The setting has its row under the mouse rows of the Controls tab, its text in the four menu languages, and
totk.ini.example and docs/controls.md describe it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
By default the left button is Y, which opens the dialogue log in a dialogue box. While MessageDialog_00 is open the
left button now presses B, which advances the text and shows the rest of a scrolling line, and the right one A.
Dialogue choices keep the menu pointer, where a left click picks the choice under it, so clicking through a
conversation does not pick the choice the focus starts on. The setting is live and independent of menu_cursor.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The game grows grass blades only inside its near grass map, a 62.5 m square around the camera drawn into 256x256 and
128x128 textures, so on open meadows the grass appears a short way in front of the player. grass_range (percent, 50
to 400, default 100) scales the map's extent, step and both textures together through a new grass patch set (1.2.1
and 1.4.3) that loads them from patch page +128..+144, and grows the HeapDef grass heap and the application pool for
the larger textures. At 100 the set stays off and nothing changes. A row in the Display menu, text in all four menu
languages, and totk.ini.example describe it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Enable VK_NV_low_latency2 and VK_KHR_present_id with present ID features
- Add VkSwapchainLatencyCreateInfoNV to swapchain creation
- Link present and submission IDs with standard Vulkan latency types
- Insert latency markers: simulation start/end, input sample, render submit, and present
- Gate all extensions and latency chains on reflex != off (RESTART setting)
- Log graceful notice when Reflex is requested on unsupported hardware
- Add UI menu setting and translations for en, ru, pt-BR, zh-Hans
- Document reflex setting in totk.ini.example and docs/settings.md
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>
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>
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)
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.
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>
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>
A host thread adds each second in which the window has the focus and the game presents frames, keeps the total in
<profile>/playtime.txt (every 30 s and at exit) and the Game tab of the settings menu shows it with this run's share.
Texts in English, Russian, Brazilian Portuguese and Simplified Chinese. Closes#720.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Button prompts row gets a third choice, PC: every button glyph of the game's button font and every image of the
button guide is drawn as the key or mouse button the keyboard defaults press it with (E, Shift, Space, left click, Q,
R, right click, F, Tab, M, 1 to 4, W A S D, Ctrl, C) and the right stick as the mouse, whatever the pad layout. The
setup writes romfs-patches-pc next to the Xbox folders (make_romfs_patches.py --prompts pc, button_icons.py pc_icons);
--binds <totk.ini> draws the keys of its bind_ lines instead. At a game resolution of another shape the game takes
romfs-patches-pc-<w>x<h> (--prompts pc --aspect) in place of romfs-patches-<w>x<h> when it is there.
(cherry picked from commit 3f81cf02be664100bd9c569c53588d620d90b527)
#483 draws the stick glyphs on the wrong code points: U+E056 and U+E057 (the stick presses) get WASD and the mouse,
U+E05E and U+E05F (the sticks) get Ctrl and C, and both left-stick HUD images show Ctrl. #585 maps them by the game's
font and keeps each glyph's advance.
This reverts commit cd35ffa.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mouse_mode now defaults to direct: on 1.4.3 the camera turns by the raw mouse motion; 1.1.0 and 1.2.1 have no hooks
and keep stick emulation, and no setting changes the gamepad. The Controls tab gets a "Mouse in the game's menus" row
for menu_cursor, and the mouse rows are in all four catalogs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add keyboard and mouse button icons to tools/button_icons.py and
tools/make_romfs_patches.py --prompts keyboard, with a third 'Keyboard
and mouse' choice under Controls > Button prompts (prompts = keyboard).
Keycaps cut their labels out of the game's own text fonts, mouse clicks
and right-stick camera look draw clean mouse silhouettes, and
make_romfs_patches.py --ini reads any bind_ overrides from totk.ini.
The game stretches each decoded movie frame over the whole canvas, so the 16:9 movies were stretched on 32:9, 21:9 and
16:10 outputs. The host decoder now shrinks the picture inside the frame with a box filter and fills the rest with
black, so that the game's stretch gives the picture its own shape back. The new setting movie_aspect (TOTK_MOVIE_ASPECT,
keep or stretch, read when a movie starts) turns it off, and the menu has a row for it next to the picture shape.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
nvnWindowAcquireTexture holds the game until the image is free, which was one period after its present's display time, when the next frame reaches the display. The present is a copy queued by then, so with frame_queue = 1 the image is free from that time: the game draws the next frame while the previous one waits for its turn, and a frame that takes up to one period more still makes its slot. In the town at 4K at 60 fps on an RTX 5070, frames over 17.5 ms fell from 25-33 to 1-8 per 30 s, for up to one frame more input delay. Off by default; the menu switches it at once.
Conflicts in cfg.c (the key list) and main.c (the usage line) resolved by keeping dev's lines and adding the
Discord keys and --probe-discord.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The panel opens with the port version and the game update, so a screenshot in a bug report carries both. Under RAM,
after a gap, two rows on the same grid: FPS with the 1% and 0.1% lows, and the frame times. perfmon.c keeps a
histogram of frame times in 0.25 ms bins, one slice per second over the last ten seconds, and reads the lows from it
twice a second.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The game language row listed eleven languages. 1.4.3 also ships Brazilian Portuguese (Mals USpt), and every build
ships British English, Canadian French and Latin American Spanish (EUen, USfr, USes), which ov_language already
accepted. ui_text_game_langs lists them per game build: pt-BR from 1.4.3 on, since 1.2.1 has no USpt. A row selects
only its own code, so en-GB and es-419 no longer show as English and Spanish.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merged on top of #566 and #594, by hand in vk_dlaa.c:
- One dlss_preset key: default keeps #594's model per mode (K for DLAA, Quality and Balanced, M for Performance, L
for Ultra Performance); k, j or any other letter a..m takes that model in every mode, live, recreating the features
as #534 does. The menu texts say so, with pt-BR and zh-Hans added.
- The mask pass stays on #594's camera motion (the identity and the CPU-made reprojection in dlaa_mv.comp's two
blocks) and adds #534's outputs; it runs before the per-object pass. Where the reactive mask test
(TOTK_DLSS_REACTIVE) ran, DLSS gets that mask instead of the characters'.
- #566 dropped the scaler_skipped/scaler_missed report, so #534's reset of it goes too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merged on top of #566. The camera motion is #594's: its blocks in camb also feed the per-object pass, and
dlaa_mv.comp stays as on main, fed the identity and the reprojection made on the CPU in double. #566's
vk_usnap_host goes, vk_usnap_bytes serves the same. #566's scaling-draw swap, camera rune guard and output-size
scaling pass stay in vk_dlaa.c. Translator patch 0012 becomes 0015 after dev's 0012-0014.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Solid scene draws whose position reads an object's own uniform blocks (bones c5, place c7, c6) are drawn a second time
with a vertex shader variant (translator patch 0012) that computes last frame's position from last frame's blocks; the
game writes those into two copies that take turns, and the uniform snapshot keeps both (vk_mvprev.c). The draws are
listed during the replay and recorded through the recorder thread with repeated state skipped. Blocks whose last-frame
copies measured wrong (c9 and c11 of walls and cliffs) keep this frame's; positions without an object block (terrain,
grass) keep the camera's motion, which measured as good.
The camera motion is reprojected in double precision on the CPU: the float inverse made noise on far surfaces and a
still camera that DLSS followed into a wobble. DLSS gets Ultra Performance (a third of the output, also in the F1 menu)
and NVIDIA's recommended preset per mode (K, M for Performance, L for Ultra Performance; TOTK_DLSS_PRESET overrides).
Test switches: TOTK_MV_CHECK measures the motion vectors and DLSS's output against the picture, TOTK_DLAA_TIMES times
DLSS and the motion passes on the GPU. A reactive mask pass for transparents is included but off (TOTK_DLSS_REACTIVE):
its mask covers sky and fog too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A GPU without ASTC gets the textures decoded to RGBA8, four times the memory of BC3, and on a 4 GiB card
that fills video memory: a GTX 1650 went from 10-23 to 3-12 ms of GPU time a frame with astc_bc = 1
(#87). BC3 loses some precision (normal maps), so it stays off where memory is not short. astc_bc unset
now turns it on when the largest device-local heap is under 5 GiB and logs the choice; 0 and 1 still
decide. The menu row becomes Auto / Off / On, and the description says what Auto does in all four
languages.
On an RX 9070 nothing changes. The Radeon iGPU on Windows reports its shared 10.5 GiB as device-local,
so it keeps RGBA8 as well. All probes pass, probe-astc and probe-cfg included.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The settings menu offers 1920x1280, 2160x1440, 2256x1504, 2880x1920 and 3000x2000 (the 3:2 screens of Surface and
Framework laptops and tablets), and the setup builds romfs-patches-<w>x<h> for each, so the HUD moves to the top and
bottom edges as it does at 16:10 instead of being stretched.
A mod's folder name is drawn on the Mods tab (opt_text_row, menu.cpp) and as the Cheats tab's group heading (cheats_tab.cpp), and it comes from disk at runtime like a cheat name, so its glyphs were never in the atlas either.
Both sources are added in the same place in fonts_up(), so one pass covers the whole menu.
The motion vectors follow the camera only, so a character, animal or held item that moves on its own drags a faint
copy of itself through DLSS's history. TotK's G-buffer target 0 carries an object class in green: above 64/255 for
characters, creatures and held items (Link 253, others 125, held items 160), 0 for terrain and 32 for foliage, checked
in the field, in Goron City and on horseback. The motion-vector pass now also writes DLSS's bias mask
(DLSS.Input.Bias.Current.Color.Mask) where such an object is now or was the frame before, read through the motion
vector from the previous frame's class mask, so the history that holds the moving object is weighed down there.
dlss_char_mask (0, 35, 65 or 100 percent, default 65; F1 > Screen > "DLSS character trails", live) sets the strength.
A 640x360 pass of the G-buffer's shape, seen while loading, no longer replaces the scene's class buffer in a frame.
The status line also prints after 300 frames, with the frames that had the mask.