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>
The block below the module window stays 6 GiB, as on dev, and grows by the texture heap extra (tex_heap_extra_mb or
a mod's HeapDef) rounded up to a GiB. A player without an HD pack reserves nothing more.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HD texture packs made for emulators with 8 GB of DRAM, such as the HDPacks 4K pack, grow "TextureHeap" in their own
HeapDef table. Served as a mod, that table replaces the one the port grows for the resolution and the shadow map, and
the game crashes at boot; without it the pack's textures do not fit, and the game loads and then starts its panic
Blood Moon over and over.
tex_heap_extra_mb ([mods], 0 to 4096 MiB, read at start) grows TextureHeap and its parent ゲームグラフィックス in the
port's HeapDef, and the application pool and the heap cap by the same amount. LOW_SIZE goes from 6 to 10 GiB so the
stack and heap block holds the largest heap. At 0 the pool, the heap cap and the HeapDef are what they were.
The selftest's "beyond the pool" MapPhysicalMemory asked for 4 GiB, which a grown pool holds; it now asks for just
past the pool.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The map detection reads every open screen of eui::ScreenMgr every 100 ms, and each pointer it follows was checked
with plat_mem_readable, a VirtualQuery. That query costs tens of microseconds in this process, so each scan stalled
the game thread for milliseconds: on a Ryzen 5 4500 the mean frame rate fell from 59 to 50-54 fps and the 1% low from
44 to 23 fps. mem_guest_readable answers from the layout for the committed heap and the loaded modules, where the
game's objects and globals live, and asks the OS only for anything else. With it the same scene runs at 58-60 fps,
1% low 45-48 fps, as without the map detection.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Shared runtime code now goes through runtime/platform/platform.h, implemented by platform/win32.c and a new
platform/linux.c: futex locks, a userfaultfd and PAGEMAP_SCAN write watch, signal-based async preemption, our own
fiber switch, and a SIGSEGV handler for the thaw and crash hooks. The window, input, menu and software keyboard get
SDL3 back ends beside the Win32 ones, with the swapchain (gfx_present.c) and input merging (input.c) shared. SHA-256
replaces BCrypt, ELF builds get their own override sections, and the build tools gain Linux branches.
On Linux the selftest and the gfx-abi, astc, nvn and window probes pass. probe-vkmem still fails: imported guest
memory cannot be write-watched on Linux, which the shadow buffers in vk_memory.c will address.
Comments cited codes from local notes (port-lessons P1, backlog), task labels (T6c1-T6c3, M4), bare upstream commit
hashes and issue numbers, a file that no longer exists (nvn_api.c, now nvn_api_*.c), a generated file (main_0103.c)
and line numbers into upstream files that refs/ has moved past, so they pointed at unrelated code. Those now name the
file, function or project and say what the cited code does. Attribution of copied code keeps its pinned commits.
Corrected facts: TOTK_REPLAY_ASYNC defaults to 0, and the shader cache, pipeline cache and pipeline keys live next to
totk.exe, not in build/v121.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Write-watch queries skip frozen 2 MiB regions, but a region was frozen only when it lay wholly in imported pools and
wholly committed. NVN pools are small and not 2 MiB aligned, so most regions also hold other guest memory or reserved
holes: in town 340 of the 436 MiB queried every frame lay in regions nothing had written for 300 submissions. On the
GTX 1050 Ti laptop the queries took up to 2.2 ms a frame, 1.4 ms of it in queries that found no write.
mem_freeze now makes the committed pages of a region read-only when all of them are read-write and leaves reserved
holes alone; thaw_locked already restored such regions run by run. The pool rule is gone: the only kernel writes into
guest memory are file reads, which thaw their buffer first, and every user-mode write faults and thaws as before.
TOTK_FREEZE_IDLE defaults to 60 (in a fight 100 of 257 queried MiB lay in regions idle for 30-299 submissions; a thaw
by a write costs about 60 us on the RX 9070 machine), and import mode freezes too, for the texture checks of APUs.
RX 9070, per frame after load: town 436 -> 96 MiB queried, 0.68 -> 0.38 ms; fight 168 MiB, 0.45 ms (257 MiB, 0.57 ms
with the new rule at 300 submissions), about 20 thaws a second. TOTK_MEMORY=verify in the fight: 3.65 million pages compared, 0 mismatches. The gfx-abi probe
covers a region with reserved holes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The output and scene patch sets make the game read its output, swapchain and scene sizes from the patch page
(MacNativeGames' sites for 1.2.1 and 1.4.3); resolution.c picks them from TOTK_OUTPUT_RES and TOTK_RENDER_SCALE and
grows the HeapDef texture heap, its parent and the application pool to match. vk_fsr.c runs AMD FSR 1 EASU and RCAS
on the present when the window is larger than the game's output (TOTK_UPSCALER, TOTK_SHARPNESS).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The mirror and the texture checks queried about 930 MiB of write-watched memory per frame (0.96 ms on the RX 9070
machine, about 3 ms on an 8th-gen i7), at about 1 us per MiB, and 770 MiB of it lay in 2 MiB regions nothing had
written for two seconds. In mirror mode a region left unwritten for TOTK_FREEZE_IDLE submissions (300; 0 turns it off)
and lying wholly in imported pools is now made read-only (memory.c mem_freeze), and the snapshot and change queries
skip it. The first write faults and a vectored handler thaws the region before the write retries; file reads into
guest memory, which the kernel would refuse on a read-only page, thaw their buffer first and log a refusal, as do pool
init and finalize, and commits, decommits and protection changes thaw under the same lock. A region stays thawed for
5 s after a file read. Field: 66 queries over 380 MiB, 0.56 ms per frame; 0.38 ms of it are the queries that find
writes. The perf line `mem: write-watch` gives queries, bytes, time, frozen MiB, freezes and thaws. The gfx-abi probe
covers freeze, thaw by a write and the hold after mem_thaw. TOTK_MEMORY, TOTK_MIRROR_GAP and TOTK_FREEZE_IDLE are known
settings now.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Imported pools put vertices, indices, constants and storage buffers in system memory, so discrete GPUs read them over
PCIe on every draw. A pool now gets a device-local mirror on its first use as a vertex, index, uniform, storage or
indirect buffer; bindings, buffer copies, fills and uniform updates use it at the same offsets. The first access of a
submission syncs the pages written since (write-watch snapshots shared with the texture checks, plus
nvnMemoryPoolFlushMappedRange ranges) in a prologue command buffer before the part; what the GPU writes into a mirror
goes back to guest memory at the end of the submission. TOTK_MEMORY=import|mirror|verify overrides the device class;
verify compares sampled mirror pages with guest memory at the fence. The vkexec probe gains a mirror part.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>