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>
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>
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>
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>
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>
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>
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>
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>
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>
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)
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>
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>
vk_memory.c: dev now keeps every finalized pool until retire_value (at
least the submission being recorded), which also covers a shadow with a
deferred copy, so shadow_had_deferred goes. The deferred shadow prologue
and dev's upload scratch pool both stay.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
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>
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>
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>
Storage-buffer stores, copies and fills land in imported guest memory without a fault or a write-watch bit, so a
region only the GPU wrote looked idle and was frozen while the GPU kept writing it. LAS Recomp never changes the
protection of imported memory because of NVIDIA. A possible cause of the NVIDIA "write invalid" device faults
(#788, #802), not proven.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Under pressure only clean mirrored entries could go, so once those ran out the render targets stayed: 1.7-2.0 GiB of released images with the use still over the line. Most of them sit on storage the game has since given to another texture, and they are never taken back. The pressure path now drops those first, 30 s after their release and when no finalized slot has bound them for 600 submits. Clean entries wait 5 s, which ends the re-creation churn in fights, and both kinds stop once the use is back under the line.
TOTK_TRACE=perf gains mem: released lines that split released memory by kind, age, overlap and dedicated memory, and count take-backs and re-creations. TOTK_VRAM_LIMIT_MIB caps the budget the port sees, so the path can be driven on a large card.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A VMA allocation that needs a new memory block costs 8-11 ms on the replay thread, so finished submissions now return their chunks to a pool that chunk_new draws from. Chunk sizes are powers of two so that one fits the next request.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
nvn_pool_flushed kept one span from the lowest to the highest flush of a pool and mirror_sync copied all of it. In
Kakariko one 252 MiB pool copied 22,121 MiB for 847 MiB flushed, in spans of up to the whole pool. Over PCIe 3.0 x8
(RX 6600, Ryzen 5 5500, issue #698) a typical span takes about 30 ms of GPU time, which fits the frame spikes there.
A pool now keeps up to 32 sorted ranges and merges the two nearest above that. Writes between ranges still reach the
mirror through the write watch. Over a walk in Kakariko the upload fell from 472.8 to 125.5 MiB and no flush range
reached 16 MiB. TOTK_FLUSH_SPAN=1 restores the span. The mirror summary gains a line with the upload by source, and
--probe-vkexec checks the range list and that two far-apart flushes copy only their pages.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In mirror mode the replay copied every range a shader wrote from the VRAM mirror back to guest memory at the end of the
submission. TotK's particle emitters write a new particle's whole record into a free slot of a buffer the simulation
shaders update, so the copy put the mirror's stale words over fresh spawns: the waterfall splashes and mist showed about
once a second and the falling rain drifted. Now each written range gets a snapshot in the prologue of the part that
first writes it, after the CPU-to-mirror copies, and at the end of the submission shaders/wb_merge.comp writes only the
32-bit words that differ from the snapshot. Words the GPU left alone keep what the CPU wrote. About 0.1 MiB and three or
four dispatches a frame in rain. TOTK_WB_MERGE=0 restores the copies. The merge's push descriptors go through rec_push
so they keep their place in the recorder's call order.
TOTK_REC_CHECK=1 searches the packets of the part being recorded for each image, view and buffer vk_memory.c defers or
destroys. A deferral stamped below the part's value, or a destruction of an object a packet names, is logged with the
packet op, both stamps and the GPU's value, and counted by kind and op in a summary at exit. put() zeroes each packet's
room while the check is on: packers reserve room for optional arrays they may leave unwritten, and those words held
handles from the ring's previous lap. TOTK_REC_DELAY_US=N makes the recorder wait N us before each batch, as on a slow
machine. rec_begin takes the part's value for the check. Both are off by default; off, the recorder pays one test per
batch and per packet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vk_memory.c defer stamped every deferred image, view and buffer with the last submitted timeline value. An object the
replay lets go of while it records a submission can be named by that submission too: vk_texture.c slot_resolve hands a
draw a released entry, and entry_of destroys released entries at that address later in the same submission. The
completion thread then destroyed the object once the GPU reached the earlier value, before the submission naming it
ran, and with the recorder thread behind, before the recorder made the call. The stamp is now the later of the last
submitted value and vk_exec_recording_fence, as LAS Recomp and Savage Wind Recomp stamp their deferrals
(runtime/nvn/vulkan/textures.c defer). TOTK_DEFER_STAMP=0 brings back the old stamp.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vk_pool_init gave a size-0 pool with storage a record: the host import of 0 bytes failed (the driver refuses the
memory, VK_ERROR_INVALID_EXTERNAL_HANDLE) and the record went into the pool index as the empty range [mem, mem]. A
lookup at that address then found the empty pool before the pool that starts there and reported it unbacked. TotK
makes such pools now and then (MacNativeGames d3407e29, 1.2.1). Such a pool now gets no record, as a GPU_NO_ACCESS
pool; vk_pool_fini finds none and does nothing. Removal by key already kept a neighbour's range safe at Finalize.
--probe-vkexec gains an empty pool part: a zero-byte pool at the start of another, lookups there before and after
its Finalize. It failed before ("a lookup at the start of a pool finds the empty pool there").
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The branch forked 79 commits before main and 98 before dev. Resolutions:
1. Aspect ratio: dev's implementation stays (camera patch at page +56 on 1.4.3, tools/ultrawide_layout.py layouts per
size in romfs-patches-<w>x<h>, the aspect = fit|stretch setting). The PR's second implementation is dropped: the
aspect sets of patches-v121.txt and patches-v143.txt (the 1.4.3 one patched the same viewport sites as dev's),
tools/aspect_layouts.py, the resolution.c shapes that limited game resolutions to 16:9, 16:10 and 21:9, and the
picture_fit setting. Its letterbox code (gfx_fit_rect) is kept and reads TOTK_ASPECT.
2. Code dev changed where the PR moved it: the stick dead zone, the test gamepad and the paddles go to input.c; the
DPI awareness, keep-awake and IME detach of gfx_window.c go to gfx_window_win.c; device fault reports and GPU
breadcrumbs to gfx_present.c. gfx_window_dpi gets an SDL version.
3. dev's Win32 calls in shared code go through platform.h: the shader cache pack reader (PlatFile), the romfs
overlay checks, the audio pacing waits, the motion, ASTC and device fault locks. plat_cpu_usable and
plat_commit_info get Linux versions; plat_cpu_count counts the machine's processors on both. dpi_probe.c becomes
dpi_probe_win.c.
4. assume_focus defaults to 1 as the PR has it (a load interrupted by a focus loss can stop for good) and stays live,
with dev's Game tab row.
5. The frame limits 40 and 45 join dev's list. The BC 3D storage fallback for Vega only runs with
TOTK_BLOCK_VIEWS_3D=1, since dev makes 3D BC images without block views by default.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AMD drivers lost the device at boot or at menu opens with the recorder thread; vk_recorder = 0 ended it for three
RX 9070 XT users (issue #5), and RADV saw an illegal opcode at the end of a command buffer (issue #40). It now
defaults to off on vendor 0x1002; TOTK_VK_RECORDER=1 turns it back on.
On AMD's separate driver branch for RDNA 1/2 ("AMD proprietary shader compiler") every device loss came with a cold
pipeline cache and draws waiting on fast-linked pipelines, and the recorder setting did not help there. TOTK_GPL now
has no fixed default: off on that branch, on elsewhere.
VK_AMD_buffer_marker breadcrumbs (vk_crumbs.c) mark the start and end of each submission part, upload batch, ASTC
decode chunk and present; on device lost the log names the last point the GPU reached and the last one it finished.
vk_fsr.c ensure_images held no queue lock around vkDeviceWaitIdle, which needs every queue externally synchronized.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vk_device_fault_report queries vkGetDeviceFaultInfoEXT once per process after VK_ERROR_DEVICE_LOST and logs the
description, the faulting addresses with type and precision, and the vendor codes. The submit, upload, occlusion
query and wait fatals call it before rt_fatal, and the present path calls it on a failed acquire, blit submit or
present. Threads that lose the device together wait until the report is written. The extension counts as usable only
when the driver reports the deviceFault feature. No cost unless the device is lost.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On Linux, write-protecting memory the GPU imported costs milliseconds per submit and the import's pinning clears the
write watch, so each CPU-visible pool gets a host-visible copy instead: the pages the CPU wrote since the last sync go in
right before each submit (skipping bytes the GPU still has to write back), and the replay's GPU writes are copied back
into guest memory at their fence (vk_gpu_written). In 1.2.1 play it costs about 0.2 ms a frame. TOTK_SHADOW=1 turns it
on under Windows too.
Also: build_game.py fetches the VMA header the Windows release pins when the system has none; plat_localtime and
plat_gmtime reject the times Windows rejects; the SDL text entry honours TOTK_SWKBD_TEST=cancel; probe-vkmem follows
the replay's protocol for GPU writes and syncs.
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>
Comments named the agent task (T1-T7, M2-M5, Task 2.x) that once owned each file or block, and pointed at local
notes the repository does not carry (backlog items, milestone plans, research notes). They now say what the code
does. gfx_stubs.c held weak stand-ins for functions that every build has defined for a long time.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1.4.3's GPU heap allocator creates a physical pool with flags 0x18c (CPU_CACHED, GPU_NO_ACCESS, COMPRESSIBLE): it
keeps the game's storage and gets device memory like the 0x189 pools of 1.2.1, which virtual pools alias. The CPU
never writes that storage (its hash was unchanged over 3600 frames of the intro), so nothing is synced.
nn::aoc::ListAddOnContent, which 1.4.3's main calls at start, returns no add-on content instead of running the SDK
on an uninitialized aoc client.
probe-ipc runs the 1.4.3 SDK's renderer semaphore constructor (sdk+0x221fb0) instead of the 1.2.1 sf heaps, and
expects SDK 20.5 to keep its audren:u manager session open. probe-services checks ListAddOnContent.
package_build.py takes --version.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>