Merge ScarletNX upstream #5

Merged
doughston merged 1049 commits from doodlylizz/upstream-sync-2026-11 into main 2026-11-11 09:18:58 +00:00 AGit
Collaborator

1046 upstream commits, build fixes

1046 upstream commits, build fixes
The text #1157 frees is read again by the one log's case after it (230f66be7): a use
after free the ASan job stops on at gui_sdl.c:12446 since both are on main. Freed with
the case's other names now.

Change-Id: I36e76b2c749e8bc95f460c53efd3659354415e1f
Signed-off-by: AO55 <AO55@reden-emu.dev>
Opening a game's box read its .ini once per program index, each read resolving its path
through every folder above the game: 0.3 s a box on Windows, 12 of gui_sdl_events' 26 s.

Change-Id: Ica1678f48be4f5680ddcb00ff5a474e1d2142c59
Signed-off-by: AO55 <AO55@reden-emu.dev>
SDL slept to the next 60th of a second at each of the menu's presents, a frame no screen
shows: about 750 a run, a third of it on Windows.

Change-Id: Ic970fd7f8144795abf4c5efc4793a7643972a1c5
Signed-off-by: AO55 <AO55@reden-emu.dev>
Windows refuses the removal while the test still has the file open, 1 step in 80 on the
runner: the file left was the next step too, and job_step waited 10 s for a past percent.

Change-Id: Ic89af8005a91bd35acc7ff4076aa8c41cfddbc0a
Signed-off-by: AO55 <AO55@reden-emu.dev>
A --seconds, --shot or other runtime option after the "--" is a game argument
that nothing reads, so a timed run given there never ended. The run now stops
with the option and says to put the runtime's options before the boundary, and
the game's own arguments after it.

runtime_unknown_option checks the message.

Signed-off-by: theGreatGreenStar <145512144+thegreatgreenstar@users.noreply.github.com>
The tools-only build has no snx_setting_known, -x and -r use -- before a file name, and
main.c's copy never ran. The check now guards the call, skips -x and -r, names the whole
option, and the test pins that a game's own --name=value still passes.

Change-Id: Iea677576b6ae434b2e2c81575672e0e4c36d32b8
Signed-off-by: AO55 <AO55@reden-emu.dev>
Under NCE, or past a smaller layout's end, a fault named only its host address.

Change-Id: I3d132ff0f5e5dd8a9ce5c41497fde2dcc53067bc
Signed-off-by: AO55 <AO55@reden-emu.dev>
Under NCE another owner's mapping over guest memory went unseen: the log now names it.

Change-Id: I6dcfa3536f27fef06bd8ea083741cdfdaff45cd7
Signed-off-by: AO55 <AO55@reden-emu.dev>
Under NCE a fault in the runtime's heap read as a layout too small to hold it.

Change-Id: I96ccca01f50d7f0078d2ed291876f3c1682216f3
Signed-off-by: AO55 <AO55@reden-emu.dev>
A mapping made over guest memory during play went unseen until a crash. Off by default.

Change-Id: I25555393b9fb885829793a4c50baee152582f758
Signed-off-by: AO55 <AO55@reden-emu.dev>
A fixed 10 s left no faster look while chasing a mapping, nor a slower one for a long run.

Change-Id: Ieda1ec19fef52ae63f9687c0594c407f33fd8928
Signed-off-by: AO55 <AO55@reden-emu.dev>
nce=1 on a 32-bit game made its code ahead of time without a word, where the
other games NCE does not take say why.

Change-Id: Ic0166ede62d4f9e7bf67f3311e743a41f847f2fb
Signed-off-by: AO55 <AO55@reden-emu.dev>
A base's 32-bit modules left beside an update's 64-bit ExeFS loaded as 64-bit code,
and the game died in its rtld instead of the recompile saying why.

Change-Id: I492bc948be19694f1f5509816805f904d77ceb83
Signed-off-by: AO55 <AO55@reden-emu.dev>
On iOS, the menu's Share Log saved the log and then opened a file:// URL
of the app's own folder. No app opens that URL there, so nothing showed.
The error box of a game saved the log and did not offer it to any app.

Both now give the saved file to the system's share sheet
(UIActivityViewController, snx_apple_share in dist/apple/Frontend.swift).
When the sheet does not open, the menu opens the folder as before, and the
error box says so. macOS keeps the folder that Finder shares from.

Verified on an iPhone 14 Pro (iOS 26.6.1) with the iOS app built and
installed: the menu's Share Log and the Share Log of a game's error box
opened the share sheet with scarletnx.log, and the log went to a
messaging app.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Its fallback, the app's own folder as a file:// URL, opens nothing there, while
SDL_OpenURL still says it did, so the menu said the log was opened.

Change-Id: Ic2f8e3bfd7407a8a8528481c95f3ce16b8dc3640
Signed-off-by: AO55 <AO55@reden-emu.dev>
An erase's setup stayed armed past a reset or another command, so a lone 0x30 erased
a 4 KiB sector of the save.

Change-Id: I121f8d4a26682bcc5d9c21f2248bddc2e828be03
Signed-off-by: AO55 <AO55@reden-emu.dev>
The AppImage jobs' get-debloated-pkgs asked api.github.com without a token and got 403 from the shared runners'
exhausted limit (run 41958750349, loongarch64). Pass the job's read-only token, which the script already sends on
GitHub URLs, to the appimage step and through docker exec into the cross job's target container.

The CPM cache was one entry per job and architecture: 11 entries and 1.19 GB for one dependencies.cmake hash. Share
it between the jobs that fetch the same sources, with the name before the hash as a restore key, so a bump downloads
only what changed. The Linux architectures differ by glslang-tools, the cross builds need SDL3's source, and ppc64
leaves out miniz with its GUI, so those keep their own groups. 11 entries become 6, about 0.70 GB.

Verified with tests/architecture_test.py, tests/tracked_material.py (its self-test and the checkout), tests/docs_test.py,
scripts/check-docs.py, tests/pr_builds_test.py, tests/trim_caches_test.py, and a YAML parse of build.yml. CI runs the
changed jobs.

Co-Authored-By: DeepSeek V4.1 Flash <noreply@deepseek.com>
Signed-off-by: GreenStar <145512144+thegreatGreenstar@users.noreply.github.com>
g_tracy_emit, g_tracy_started and g_tracy_stopped kept three states in three flags, which
RFC #142 rule 1 asks to keep as one value. The gate is still one load.

Change-Id: I04ca18aa4a8b5d4e1a9c74f9f097ed226483dcd4
Signed-off-by: AO55 <AO55@reden-emu.dev>
opened said what the index can say with 0 as none (RFC #142 rule 1). rendering stays: a
target can be open with its pass closed.

Change-Id: I77ed948722bb8f338b39641cf87af4865384c009
Signed-off-by: AO55 <AO55@reden-emu.dev>
hwopus_live kept beside the pool what its taken slots say (RFC #142 rule 1). The count and
the take share the audio's lock, and the pool holds the firmware's 24.

Change-Id: Iaf1788be2cf0d54f96a9d9af6e35780f63577e2a
Signed-off-by: AO55 <AO55@reden-emu.dev>
syncpt_add runs for every job increment on the GPU thread and scanned both ctrl
tables' 64 event slots each time, which is the common case for a game that waits
on none. An atomic count of armed slots, changed under nvev_lk with the slots
themselves, lets the scan return at once when none is.

The nvdrv service test arms its slot through the service now, so the count
follows the slot it checks.

Signed-off-by: theGreatGreenStar <145512144+thegreatgreenstar@users.noreply.github.com>
An atomic count skipped the scan with one load, but it added a counter update to the armed path. The local benchmark went from about 80 ns to about 83-85 ns per syncpt_add while one event was armed. A per-table bitmask and a summary of the tables with a bit keep the common no-armed check at one load, and make the armed scan proportional to the armed slots instead of all 64 slots of each table.

nvdrv_service passes. The same benchmark measures about 5.3 ns per syncpt_add with no armed slot and about 8.2 ns with one, down from about 80 ns before the branch and no slower in either case.

Signed-off-by: theGreatGreenstar <145512144+thegreatGreenstar@users.noreply.github.com>
gnu_extensions refuses __builtin_ctzll outside common/utilities/bits.h. The bitmap scan now uses snx_ctz64, which keeps the ISO C fallback in one place. Verified with tests/gnu_extensions.py and nvdrv_service.

Signed-off-by: theGreatGreenstar <145512144+thegreatGreenstar@users.noreply.github.com>
A save state holds g_hle and a load copies it back, so a slot armed in a loaded state
had no bit in the statics and syncpt_add never signaled it.

Change-Id: Id9a0dccf1dfb1b145662e888e95e4b4ae99f2abf
Signed-off-by: AO55 <AO55@reden-emu.dev>
An increment and an arm each store before reading what the other stores; release and
acquire let both reads miss, and the slot stayed armed. From the C11 model and clang's
codegen (ldapr on macOS arm64, no sync on POWER), not reproduced.

Change-Id: Iba4ea0b3a795a25030acbee53d15ca16438c0bf4
Signed-off-by: AO55 <AO55@reden-emu.dev>
NvEvent.armed said what each slot's bit in armed_mask says, so the bit stays and the flag
goes, with the scan's branch for a bit whose slot was not armed.

Change-Id: I21569a8626025fcab0fd3909178a0cd0844c27e7
Signed-off-by: AO55 <AO55@reden-emu.dev>
syncpt_add tests it without the lock in one load, 0.96 ns, where reading the 64 words of
armed_mask takes 8.1 ns (x86-64 microbenchmark): a summary kept as RFC #142 rule 1's
exception.

Change-Id: If2c4a996cf5d09de1553da9c367eead9a94d0244
Signed-off-by: AO55 <AO55@reden-emu.dev>
g_own_any said what g_nown != 0 says: the count is stored atomically now, and own_any
reads it in one load without the lock, as the flag was read (RFC #142 rule 1).

Change-Id: I4917a8ca2fc54ae0e046ac071bd326ca811a192d
Rebased-by: AO55 <AO55@reden-emu.dev>
Signed-off-by: AO55 <AO55@reden-emu.dev>
g_ww_open_n counted the published slots, which a scan then searched all 32 of: a bit per
published slot replaces the count and busy's 2, one load as before, and a scan reads only
the open slots. A close takes its bit with fetch_and, so two closes of one range free two.

Change-Id: I17874905f80f6215defe0f296746b885ca89f58b
Rebased-by: AO55 <AO55@reden-emu.dev>
Signed-off-by: AO55 <AO55@reden-emu.dev>
The list had a NULL end and, on Windows, a count of it too (RFC #142 rule 1). The NULL end
stays, as argv's and envp's do in the same command line.

Change-Id: I6122411142bb9eb853786ab9220b076d35ef9d7f
Signed-off-by: AO55 <AO55@reden-emu.dev>
From eXxe's patch (Discord, 2026-11-04), its build.yml merged over #1075.

Change-Id: If101b3e7752e264eb3a18da2c3ab1c5c5d0d1258
Co-authored-by: eXxe-elcior <eXxe-elcior@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
The link names' type came only with elf_object.h, and the stub took one
argument fewer than its call.

Change-Id: I9c596bd7842f57c6046f392c4813505e2c0496c3
Signed-off-by: AO55 <AO55@reden-emu.dev>
LLVM makes large or variable copies calls to memcpy and memset, which the
runtime library defines and no module's IR declares.

Change-Id: Ibf69d2aa1633a08bbc701708323f3808c8e9a5e1
Signed-off-by: AO55 <AO55@reden-emu.dev>
Their FP fast paths assume round to nearest, no flush and no trap, as x86-64's
and AArch64's do; the differential now steps with the host rounding upward.

Change-Id: I4739339b7cfb7fa46091241ecf6c22187535ea49
Signed-off-by: AO55 <AO55@reden-emu.dev>
A literal load at PC reads its own word, which a big-endian host's --reference
run stored byte-reversed.

Change-Id: I08c38d9b1c5d48225acb088c8da5664b73e9d08c
Signed-off-by: AO55 <AO55@reden-emu.dev>
LLVM reads no PowerPC host features, so ppc_vsx was never set and the VSX
fast paths, rounding and permutes never ran on a PowerPC64 host.

Change-Id: I87a55a04fa26662bb0d4b5b6806021c262003a6a
Signed-off-by: AO55 <AO55@reden-emu.dev>
The patch moves about 60 ops a host on them, and the summary checked none.

Change-Id: I5b27b42f3c478347e7ba838f4c993b3cf84a31b5
Signed-off-by: AO55 <AO55@reden-emu.dev>
GNU C on MIPS predefines mips as 1, so ir.h and ir_vec.c did not build there.

Change-Id: I83b8325ca6139104b1e70163da74a54c3a331fee
Signed-off-by: AO55 <AO55@reden-emu.dev>
An LDAPUR or STLUR on SP read start->x[31], past the 31 X registers (UBSan's
index 31 out of bounds).

Change-Id: I1ced9f6c84a1e1317e14d7dd89064987f360bae0
Signed-off-by: AO55 <AO55@reden-emu.dev>
Windows and Apple hosts skip it at once, where -Werror refused object_of as unused.

Change-Id: Id3c0dbf62ec534d1ceb78a3cb6ce707f05633843
Signed-off-by: AO55 <AO55@reden-emu.dev>
Every target's links had it, and Clang names a RISC-V or LoongArch program's loader by its
-mabi too (ld-linux-riscv64-elfv2.so.1), which qemu-user and every system lack.

Change-Id: Ifd7c54bef98447031fdafe63402961aee66c2903
Signed-off-by: AO55 <AO55@reden-emu.dev>
Its LLVM compares the operand's whole 32-bit register after lbarx or lharx, so the bits
above the byte or halfword chose the value LDUMAX and LDUMIN stored.

Change-Id: I26a63934d25f6364e29f2ef2f96c2cea4c271fd9
Signed-off-by: AO55 <AO55@reden-emu.dev>
A crash in the generated code or the harness printed nothing under --quiet, as it did on
big-endian PowerPC64 under qemu-user.

Change-Id: I1c5dc461552ffbd5da62816274b0907b09a5fa83
Signed-off-by: AO55 <AO55@reden-emu.dev>
The first failing form ended the step, and its examples stayed in the container's /tmp.

Change-Id: I4182e8364ad3dcc7e5ddf1f6aadc358b0e299838
Signed-off-by: AO55 <AO55@reden-emu.dev>
An STXP of doublewords calls RtAPI.cas128 on RISC-V, LoongArch, MIPS64 and PowerPC64
before POWER8, which the test left NULL: big-endian mips64 segfaulted in its STXP case.

Change-Id: I91cad378ad4b4fd479048616c3b2f9a151c68145
Signed-off-by: AO55 <AO55@reden-emu.dev>
ppc_target read the module's triple again, the one new_ir sets SnxIr.ppc from.

Change-Id: Ic08ed98fb8d800b0abcc1b306f7998e1b50dc3ba
Signed-off-by: AO55 <AO55@reden-emu.dev>
Six flags held what a triple names once, and --triple compared them one by one.

Change-Id: I6de3cb6f2e889e9325368112cbf0d8ec3387c069
Signed-off-by: AO55 <AO55@reden-emu.dev>
Its results, changes and bytes were three blocks, which snx_qref_clear would half free;
a first pass counts them, as snx_qref_run's parse does.

Change-Id: Idc93eb0da7cdfba886e5a1e384503a067623e5f7
Signed-off-by: AO55 <AO55@reden-emu.dev>
C99's own conversion, in place of a cast to unsigned long on each.

Change-Id: Id35c851afe91a9a748e3bb83ed8c34b37ad65d86
Signed-off-by: AO55 <AO55@reden-emu.dev>
It passed the doublewords as the host reads them, which a big-endian host's snx_cas128
swaps again: the compare never matched, and CASP's retry loop spun for good.

Change-Id: I96432cbb057ad6a44b75a6e13fe0c0d659d63b64
Signed-off-by: AO55 <AO55@reden-emu.dev>
A big-endian CASP that spun for good held the job to its 3-hour limit, saying nothing.

Change-Id: Ia20f2d4be790613a086ac71548f3e0518a40b863
Signed-off-by: AO55 <AO55@reden-emu.dev>
A big-endian host's CPU keeps them little-endian (ir.h), and the states copied each
doubleword as a number: 731 groups differed on ppc64 and mips64.

Change-Id: I8349130ab40b03768deaddaac821d2005116e1e5
Signed-off-by: AO55 <AO55@reden-emu.dev>
Its flags came in the second register's high half (PowerPC64's ELFv2, MIPS64's n64) or
through memory (ELFv1, s390x), and read as 0: no FP exception reached FPSR there.

Change-Id: If79a9f9a4ed56aa38fcfa09cc3ea743e23d5e57f
Signed-off-by: AO55 <AO55@reden-emu.dev>
The colours of the sites' themes, each palette light and dark, on YoRHa's layout; the
files come from wimsy-dist's palette file, so the sites and the menu change together.

Change-Id: Ia10b6e89b64ec2790b494bdba5c5cf08d75df81f
Signed-off-by: AO55 <AO55@reden-emu.dev>
The message said "default or yorha" while there are seven to build on.

Change-Id: I4d2f5d1d8424f648ece821bce8968f17f4d03155
Signed-off-by: AO55 <AO55@reden-emu.dev>
Each theme shows as the focus reaches it, Enter keeps it and ESC goes back,
so a theme is picked by seeing it rather than by stepping through them.

Change-Id: I01b3c05500d5969f853806a6545899072f081e63
Signed-off-by: AO55 <AO55@reden-emu.dev>
A game named in its own script came out of a shared log as one '?' a byte: the text goes
into a file of share/, not a Java string, so valid UTF-8 stays and a bad byte is U+FFFD.

Change-Id: I32cfdc874ab2f55fe891dd9a9631cac9c50a8677
Signed-off-by: AO55 <AO55@reden-emu.dev>
In the default's dialog it went in the middle of the screen and covered the
row, its line over the row's value; it goes under the row now, or over it.

Change-Id: Ibfa3d9253e0b6c131f8cb6d3e7425b704552e459
Signed-off-by: AO55 <AO55@reden-emu.dev>
eXxe's ask: the AVX-512 hosts get their instructions back, each where an emitter reads it.

Change-Id: Ia7b1832d47fa4fca01a35971a610c5f00f8889f9
Co-authored-by: eXxe-elcior <eXxe-elcior@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
The x86 path is a Zen 4's again and x86-avx2 the one before AVX-512; the class does not
show VPERMI2B or an unsigned conversion, so a small table checks them.

Change-Id: Ib8774de661c117925ac2186566b6d99a25f40a43
Co-authored-by: eXxe-elcior <eXxe-elcior@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
--without-avx512 takes AVX-512 out of the emitters and the target machine alike, so an
AVX-512 runner checks the AVX2 path too; a host without AVX-512 skips it.

Change-Id: I697de50eff18590617885131733c10f874e115f1
Co-authored-by: eXxe-elcior <eXxe-elcior@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
GitHub lets the author of a pull request open it ready or mark it ready, and no setting
holds it: one made ready by someone without write access now goes back to a draft, with
one comment saying so.

Change-Id: Ibafd434068120eebfdcfee1f42835fa8dc86e9ae
Rebased-by: AO55 <AO55@reden-emu.dev>
Signed-off-by: AO55 <AO55@reden-emu.dev>
The name read as part of the line, and the line already says what the box
is; YoRHa's box keeps its tab.

Change-Id: Ibc5e1add85fe728d591a43967fb1c0e4438ab9ba
Signed-off-by: AO55 <AO55@reden-emu.dev>
At 1280 by 688 and at a phone's size too, beside the room left to the Theme
row it changes.

Change-Id: Ic67d35f0c46c4c33f6096a1570d4e6c66e86870e
Signed-off-by: AO55 <AO55@reden-emu.dev>
A first compile and R's recompile got only Debug's SLP vectorizer of the game's settings
-r takes, so NCE Off never reached them and the game was made for NCE again.

Change-Id: I19150181ca588c545bf9e95336a0cd6d278533d6
Signed-off-by: AO55 <AO55@reden-emu.dev>
compile(), the slow path, inlined into lookup gave every dispatch its error buffer's
frame and stack canary. arm_dispatch_frame checks arm.c's object for them.

Change-Id: I9700b32a8de3a99f3c6c2e5cf05ae4523c93553b
Signed-off-by: AO55 <AO55@reden-emu.dev>
Exceptional AdvSIMD lanes still went to scalar helpers, and some baseline x86 shifts and estimates had no vector
lowering. This adds exact vector masks, bounded shifts, conversions and estimate fixups. Wide exceptional min/max and
rounding fixups are shared within each IR unit. Unrelated guest registers stay in SSA, and the audited FP environment
leaf is imported into the module. CPU results, FPCR and FPSR stay exact. SNX_ABI stays 17 and SNX_IR_OBJECT_VERSION
goes to 5. Recompile game modules to use the new paths.

It also adds a Linux CPU sampler (tools/cpu_sample.c, tools/profile_cpu.py), statistics checks, decoder-row fuzzing
and an incoming-edge index for register promotion.

This is #1179 as one commit on current main. The merge of main into it needed these changes:

- shl_helper runs on the variable_shifts hosts and on every x86 host, because lane_shift gives SSE its per-lane
  counts.
- The RECPE and RSQRTE table path stays on little-endian x86 and AArch64, and on half lanes. The other host_fp_vec
  hosts take the table-free estimate.
- ir_fp_reply_call reads the byte order of the reply from the target's data layout, not from big_endian.
  llvm_vfp_compare sets big_endian on a little-endian host to run the big-endian lane paths, and main's big-endian
  reply then read the helper's flags from the wrong half. On a real target the two agree, so the generated code does
  not change.
- The lowering census's x86 paths name +cx16 in their target-features. The attribute replaces the target machine's
  features, so the imported snx_fp_env.inline had a feature that its callers did not, and LLVM did not inline it.
  Game modules set no target-features on their functions. llvm_lowering_expected.txt is regenerated with --update.

Verified on an x86-64 host with AVX-512 and LLVM 23.1.4. The tree builds with no warnings, and 674 of 675 ctest
entries pass. gamepad fails its keyboard focus check on this desktop with or without this change. #1179, with the
same change on main through e93afa9a, passed every CI job.

Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Thumb BX PC two bytes past a word lands in ARM state with bit 1 of the PC set. The
ARM7TDMI keeps R15's bits 1 and 0 at zero there; the recompiler refused that block, and
seven games of the coverage survey stopped on it.

Change-Id: Idd4d2b28cf67641b6d59a114c7ba8732fe90efec
Signed-off-by: AO55 <AO55@reden-emu.dev>
Timer 0 has no timer before it, so the console ignores its count-up bit. The board left
such a timer stopped, and three games that set the bit and play their sound FIFOs at
timer 0's rate were silent.

Change-Id: Idff770ef0c72435bb1b7ca267583b4e0e78c3c28
Signed-off-by: AO55 <AO55@reden-emu.dev>
GNU C defines mips as 1 on MIPS, so TexGeom's member stopped the MIPS64 build of
scarletnx-common (gnu23). The test, built as C99, takes the same name.

Change-Id: Ib2780c3104760cd5ed101718648c8172f48e116f
Signed-off-by: AO55 <AO55@reden-emu.dev>
Big-endian PowerPC64 builds for Clang's default CPU, yet cross.cmake still documented
the option, the G5 preset set it to 970 for nothing, and two comments named it.
preset_variables checks that the build reads every SNX_ variable a preset sets.

Change-Id: I4ed6776100cb872406ce27b6f6ca2295f5ec1137
Signed-off-by: AO55 <AO55@reden-emu.dev>
An STXP or CASP of doublewords calls RtAPI.cas128 on RISC-V, LoongArch, MIPS64 and
PowerPC64 before POWER8, which every test but the differential left NULL, so the ported
cases' 128-bit exclusive pair would crash there. rtapi_cas128 checks each RtAPI in tests/.

Change-Id: I66b26271ed6ec7dcbaa6aa39057ed61c055362e8
Signed-off-by: AO55 <AO55@reden-emu.dev>
Where page protection tracks writes (macOS, iOS, FreeBSD, Android, old Linux), a page
written in every epoch faulted in every epoch. write_tracking_hot=1 leaves one written
twice in a row writable for 32 scans; a target cools its pages before each baseline.

Change-Id: Id0840bc76a62f60e1734b666d95548e32c8e8f70
Co-authored-by: eXxe-elcior <eXxe-elcior@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
The ways the cool step can lose the GPU's pixels: two targets over the hot pages, a
page going hot at the target's own baseline, one hot at its other address, the CPU
beside the GPU in one frame.

Change-Id: I0299451292a4596bccd9f4741b63c478c11f64e1
Co-authored-by: eXxe-elcior <eXxe-elcior@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
A render target baseline that forgets to cool its pages fails one of them.

Change-Id: Ief10a05d3c0ce56eeb8ac0b4d33e5500c7b816fe
Co-authored-by: eXxe-elcior <eXxe-elcior@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
Cooled before the take-in, it stays hot past the baseline: 39 of 40 draws here.

Change-Id: I86c366b25795526c963dac4163d82323a7e68d21
Co-authored-by: eXxe-elcior <eXxe-elcior@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
Run at once by ctest, they wrote, read and removed one file: a ReadFile met the
other's remove.

Change-Id: I5c10482ffb92f69c059df9673dd6d178a2d2cd02
Signed-off-by: AO55 <AO55@reden-emu.dev>
The BIOS's IntrWait waits with the I/O base in r12 and its interrupt stub hands it to the
handler in r0; the HLE call left the game's registers, so a handler flagging the vblank
through r12 wrote elsewhere and two games of the coverage survey froze in the wait.

Change-Id: I6e6c9dfda228e9f34b8bb45b7e57c35baa3124c0
Signed-off-by: AO55 <AO55@reden-emu.dev>
Keep narrow dirty ranges and equal bindings out of repeated draw preparation,
reuse descriptor buffer addresses and recent storage results, and index larger
descriptor tables. Avoid promise waits for records with no CPU-visible effects.

Implement missing fixed state, patch metadata, evaluation-only tessellation,
masked stencil clears, copy transforms and GPU transform-feedback controls.
Correct array layers, cube views, sampler defaults and zero-instance draws.
Map the supported advanced blend subset and native color coverage modulation.

Add generated-state and exact Vulkan-output regression fixtures, standalone
rendering checks and paired preparation benchmarks. Document remaining feature
limits and keep synthetic CPU measurements separate from game performance.

Validation: both descriptor paths on NVIDIA RTX 5050 Laptop and AMD Radeon780M,
native/Python regression checks, draw/copy/frontend ASan and UBSan, four generated
control-stage SPIR-V modules, and deliberately broken shader/output variants.
AMD coverage modulation is explicitly skipped. The full CTest run passed 444,
skipped 3 and failed 3: SDL dummy keyboard focus and two UMA placed-view checks.
Both UMA failures reproduce on unchanged upstream.
The machine stopped on a software interrupt whose number the BIOS does not have, where
mGBA's HLE BIOS logs it and returns; a game of the coverage survey calls swi 0xFF0099.
The runner names such a call and where it was made.

Change-Id: I8169d688d35e8ff80f8457be220d1eb7911c9b51
Signed-off-by: AO55 <AO55@reden-emu.dev>
A DMA took no time: the CPU ran on while it moved memory. The CPU now waits 2N + 2(n-1)S
+ 2I by region and WAITCNT, as on the console; games ran ahead of mGBA without it.

Change-Id: Ia82a40968853546ae4f37b148c22e803179207c5
Signed-off-by: AO55 <AO55@reden-emu.dev>
An HLE BIOS call took no time. It now takes its entry and return (45 cycles, as mGBA's HLE
BIOS counts them) and the cycles of the memory it reads and writes, by region and WAITCNT.

Change-Id: I9096e71afb1871d2f1e98610b154362461fa50f1
Signed-off-by: AO55 <AO55@reden-emu.dev>
Every instruction cost 2 cycles wherever it ran. A block now costs its fetches by region,
the cartridge's with WAITCNT's prefetch buffer, and a pipeline refill at its branch.

Change-Id: I22ba8ac9802cc594a5dfb65f7343503bd1d2590c
Signed-off-by: AO55 <AO55@reden-emu.dev>
logscan.c includes common/utilities/ascii.h since #831, and the workflow's
sparse checkout lacked it: every issue since got no log summary.

Change-Id: I5d2c25a9f39e5ebfff3633338e7d2f8132552d26
Signed-off-by: AO55 <AO55@reden-emu.dev>
game_reports_workflow copies only the files game-reports.yml checks out and
runs its build step on them, so an include the list lacks fails a pull request.

Change-Id: I2456a28f8090337ff494085eb8e899a8f13ef4f5
Signed-off-by: AO55 <AO55@reden-emu.dev>
The workflow builds snx-logscan from six files since ascii.h, and a count
goes stale with the next include.

Change-Id: Ib9a0f16eb827f9da2e6dd8f23651cc09abf15eca
Signed-off-by: AO55 <AO55@reden-emu.dev>
The resources line of an iOS run gave the footprint and the memory the system still lets the app take. A game ran
out of GPU memory at 72 s while the system still offered it 1.5 GiB, and VMA counted under 1 GiB of its 4 GiB budget.
Metal's own count holds what VMA does not: MoltenVK's descriptor pools, pipelines and internal buffers. The line now
gives currentAllocatedSize and recommendedMaxWorkingSetSize of the system's default device, which MoltenVK uses.

Verified: apple.m compiles with no warnings for iOS 16 and macOS 13. The next lab pass on the phone runs it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A game ran out of GPU memory at 72 s on an iPhone. The app's own log
stops when the system ends the process, so it cannot say why the run
ended. MetricKit gives that later: crash, hang, CPU exception and disk
write exception diagnostics, and the counts of exits for memory in the
exit metrics of a metric payload. MetricKit has no diagnostic for an
exit for memory.

gui_apple_log_start now subscribes to MXMetricManager after the banner.
It also reads pastDiagnosticPayloads and pastPayloads, because iOS can
give the payloads of an earlier run at a later start. Each payload goes
as its JSONRepresentation to logs/metrickit-YYYY-MM-DD_HHMMSS.json in
Documents. The name is the end of the time that the payload covers, so
a past payload that iOS gives again at each start has the same name. A
file that holds the same bytes is not written again. A different payload
with the same name gets -2, -3 and on. The console log gets one line for
each payload, with the file name and the count of each type of
diagnostic, or the memory exit counts of a metric payload. The iOS app
links MetricKit. macOS does not use this code.

Verified: apple.m compiles with no warnings with xcrun clang
-fsyntax-only -fobjc-arc for iOS 16 and macOS 13, with the include
flags of the macOS build. Nobody ran this change on the phone yet, and
the system decides when it gives a payload.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A lab probe found the cause of a GPU out-of-memory on MoltenVK: the
heap's use was 495 MiB above the VMA blocks, and the descriptor pools
held that memory. This makes the probe a permanent part of the log.

At the first three VK_ERROR_OUT_OF_DEVICE_MEMORY or
VK_ERROR_OUT_OF_HOST_MEMORY results that VK_OK sees, vk_ok_ logs one
line for each heap. The line gives the use and budget of the heap, the
VMA blocks and allocations (count and MiB), and the heap size. A last
line gives the count of descriptor pools that exist. cmd.c counts the
pools that vk_desc_pool_new makes, with an atomic, because the GPU,
recording and compute threads make them. Any
thread can fail, and VMA takes its own lock for the statistics.

Checked: device.c and cmd.c compile for macOS and with SNX_IOS, and
snx-test-astc-vulkan links. Nobody ran the change on the phone yet, and
no run made an out-of-memory with it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
iOS killed a game for memory at about 71 s. The log stopped with no
error, and its last resources line was 2.6 s before the end. In an
earlier run, SDL_EVENT_LOW_MEMORY came only 0.1 s before the kill,
because SDL sends it through the run loop of the main thread.

Now each warning writes one "memory:" line. The line gives the
footprint and the free memory of the app on iOS (gui_apple_stats), the
use and budget of each GPU heap with its VMA blocks, and the count of
descriptor pools. The warnings are SDL_EVENT_LOW_MEMORY on all systems,
and on iOS also a dispatch source for the memory pressure of the
system, at the warning and the critical level. The source runs on a
global queue, so the main thread cannot delay it. A run writes 6 of
these lines at most.

The new renderer entry memory_text (vk_memory_text) takes no Vulkan
lock. VMA locks its budget data itself, and its budget update calls
vkGetPhysicalDeviceMemoryProperties2, which needs no external
synchronization. The threads read g_vk.vma only after an atomic flag
that the device setup sets after vmaCreateAllocator.

After the line, log_sync flushes the game log, stdout and stderr, and
calls fsync on their descriptors. logf_ already flushed each line and
stderr has no buffer, so no complete line waited in a buffer. Only
stdout keeps a line that is not complete. A kill keeps what the
process wrote, so fsync is for a loss of the system only.

gui_apple_stats now gets the Metal device with dispatch_once, because
the main loop and the queue of the warning can call it at the same
time.

Checked: device.c, renderer.c, plat.c and sdl3.c compile for macOS and
with SNX_IOS (check_compile.py). sdl3.c and apple.m compile with
-fsyntax-only for iOS 16 and macOS 13, and the iOS build of sdl3.c
contains the dispatch source. Nobody ran the change on the phone yet,
and no run made a low memory warning with it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
iOS ends a game for memory with no line in its log. One game's cutscene took
1 GiB in less than a second, between two resources lines 5 s apart. At log
level 2, which iOS always uses, the log now has these lines:

- A "resources:" line each second, on every system. iOS keeps its line from
  the frontend, with Metal and the thermal state. The other systems give the
  footprint and the free memory that the system reports.
- On iOS, a "memory:" line with the GPU heaps the first time that the memory
  the system still gives the app falls under 1024, 512, 256 and 128 MiB. The
  main loop checks it at each tick. The warnings of the system can come too
  late, and one came 0.1 s before a kill.

Checked: main.c compiles for macOS and with SNX_IOS (check_compile.py), and
with -fsyntax-only against the iOS 16 SDK, where MODULE_PACK is set. Nobody
ran the change on the phone yet.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Three things that today's reports of iOS could not tell:

- An Objective-C exception that nothing catches now writes its name,
  reason and stack to the console before the abort, and then calls the
  handler that was there before. A MetricKit crash report went through
  libobjc and libc++abi to abort() with no reason. libc++abi writes the
  type and what() of a C++ exception to stderr already.
- The iOS resources line now gives the bytes of VMA's blocks beside the
  Metal total. What Metal holds past them is MoltenVK's own memory
  (descriptor pools, pipelines, argument buffers). The renderer has a new
  entry, memory_blocks, which takes no Vulkan lock.
- At log level 2 on Apple systems, a "threads:" line each 5 s gives the
  three host threads with the most CPU time since the last line, with
  their names. iOS reported a CPU exception of 90 s of CPU in 93 s that
  named no thread. A thread is known by its id from thread_info.

Checked: device.c, renderer.c and main.c compile for macOS and with
SNX_IOS (check_compile.py). main.c and apple.m also compile with
-fsyntax-only against the iOS 16 SDK. Nobody ran the change on the phone
yet.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
SNX_THREAD_NAME named the GPU, audio, Vulkan and guest threads only for
Tracy, and the build without Tracy dropped the name. The "threads:" line
of the log then gave "?" for each of the three busiest threads. On Apple
systems the macro and snx_tracy_thread_name now also call
pthread_setname_np, which the system's tools and crash reports read too.
Linux and Windows keep no name here yet.

Checked: the ten files that use the macro compile with -fsyntax-only for
macOS and against the iOS 16 SDK. Nobody ran the change on the phone yet.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Fixes from the review of the memory log lines:

- The compute queue made its 4 descriptor pools with its own copy of
  the create info, so vk_desc_pools left them out of the out-of-memory
  line. compute.c now makes them with vk_desc_pool_new, which gives the
  same pool.
- snx_memory_available took a reference to the host port at each call
  and never gave it back. macOS now calls it each second at log level 2.
- oom_report reads the allocator after the same flag as the other
  readers, and the "threads:" line ranks no thread past a full table.
- The MetricKit writer holds a lock, because the subscriber's queue and
  the main thread can write at the same time. gui_apple_stats drains its
  objects in an autorelease pool. Metal links on iOS only, where its
  one caller is.
- sdl3.c takes gui_apple_stats from apple.h, not from a second copy of
  its declaration.

Checked: the changed files compile with -fsyntax-only -Wall -Wextra for
macOS and against the iOS 16 SDK. Nobody ran these fixes on the phone
yet.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A payload is the only record of a memory exit: its line names the file and the system's
reason, or the names already taken, in place of "(not written)".

Change-Id: Ie0af64231d114cc5f8579d2752456ec3b37386a1
Signed-off-by: AO55 <AO55@reden-emu.dev>
The handler used the GNU ?: form, which apple.m did not use before.
A plain conditional gives the same text. Checked with clang
-fsyntax-only -fobjc-arc against the macOS SDK.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
snx_threads lists the process's threads with their time and names: /proc/self/task on
Linux and Android, a thread snapshot on Windows, sysctl on FreeBSD, and the Mach calls the
line used on Apple. The window's arithmetic moves to resources.c, where a test drives it.

Change-Id: Icf63fcb87348b9c5e20ec978d9fc485a26ec7abd
Signed-off-by: AO55 <AO55@reden-emu.dev>
SNX_THREAD_NAME named them on Apple alone. snx_thread_name does it on Linux and Android
(prctl), FreeBSD and Windows too, so the threads line, a debugger and a crash report have
the names there.

Change-Id: Iec8926d30efa3a8c02d30079fb9e219d66ab35ab
Signed-off-by: AO55 <AO55@reden-emu.dev>
The display, state compression, memory traps, power watch and profiler threads, and a
guest thread resumed from a save state, so the threads line names them too.

Change-Id: I705f552d80b6b882960b1dcefefdb3e24083eb90
Signed-off-by: AO55 <AO55@reden-emu.dev>
The "memory:" lines at 1024, 512, 256 and 128 MiB ran on iOS alone; elsewhere they take
the system's free memory, which Linux's OOM killer and Android's low memory killer act on.
Every resources line ends with the VMA blocks, with "?" for a free memory not told.

Change-Id: I04c1d1e0b5ccce158355e12bd6663c7b1ebe83d2
Signed-off-by: AO55 <AO55@reden-emu.dev>
The line took the footprint from iOS's frontend alone; Android's SDL event said only the
GPU heaps. It takes the resources line now, and macOS watches the memory pressure as iOS.

Change-Id: I81f9b2c13d4e1ff55d3fde3921d64bd7db86b444
Signed-off-by: AO55 <AO55@reden-emu.dev>
snx_memory_available had no FreeBSD branch, so its resources line and floors had no free
memory to say: the free and inactive pages, as macOS counts them.

Change-Id: Ibda4ffb5b28fe00671a81ad73dac8607d167c6b6
Signed-off-by: AO55 <AO55@reden-emu.dev>
log_sync gave its fsync to every system but Windows, where _commit is the same call.

Change-Id: I5c3d7fd8491b8db3c3d75b2e7adf567635c68af4
Signed-off-by: AO55 <AO55@reden-emu.dev>
A low memory line came on iOS, macOS and Android alone. Linux's pressure stall trigger
and Windows' low memory notification wake a thread of their own for the same line.

Change-Id: I514f18aa7d8418c8815f1409b914202462d0c83b
Signed-off-by: AO55 <AO55@reden-emu.dev>
The lines at log level 2 and the low memory line, and which system gives which warning.

Change-Id: I18f306931762ee70b430c9da14f2c5b9df31cd4a
Signed-off-by: AO55 <AO55@reden-emu.dev>
The memory watch's words made a line of 156 columns; clang-format reflows no comments.

Change-Id: Ia5678ed0df09ac14f751af740003b0ea6fcfe1e6
Signed-off-by: AO55 <AO55@reden-emu.dev>
A thread that did not start left g_psi_say set beside started at 0; one state, cleared
on that failure as plat_win32.c's, and the test forces the failure past RLIMIT_NPROC.

Change-Id: I23833268d6d93ea9186c617b2a785d11f5ebad51
Signed-off-by: AO55 <AO55@reden-emu.dev>
plat_win32.c's memory watch says the system's reason through snx_os_error, which the
test's link lacked (the Windows job's undefined symbol); its thread name stand-in goes.

Change-Id: I41682e9384dc05192ccc3a845fe3e3cf66661d95
Signed-off-by: AO55 <AO55@reden-emu.dev>
gui_sdl_events and gui_setup run on a Mac too, with TMPDIR at /private/tmp: the Mac's own
wraps the paths the screens show, and its links into /private differ from those compared.

Change-Id: I31ecf11be6e07907c011f816cece2fa1b8fa22f6
Co-authored-by: GreenStar <145512144+thegreatGreenstar@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
Another clang first on PATH, as the NDK's, finds no macOS SDK, and FFmpeg's host checks
then find no libc headers.

Change-Id: I36a26d1502959a6abacdc2185d0704bfc4c47173
Co-authored-by: GreenStar <145512144+thegreatGreenstar@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
A Mac's data folder, under Library/Application Support, leaves its row no room for
default: the folder stays and default goes, as the row's rule says, so the check reads
the row drawn.

Change-Id: I87cdccc71bb6703cc221bd4152ca7c618dfca770
Signed-off-by: AO55 <AO55@reden-emu.dev>
The trap's thread went round again once the page was let go and landed the owner
the woken reader had published next (a VIC job over the picture it had just read),
which no access asked for.

Change-Id: I4237bfd57c9466efc37d5de6f6ae38536f8a2102
Signed-off-by: AO55 <AO55@reden-emu.dev>
nanosleep is POSIX, which glibc leaves undeclared under -std=c99 (c99check).

Change-Id: Icac118aaa9e10da992958e66366961c059f60701
Signed-off-by: AO55 <AO55@reden-emu.dev>
From the build tree's working directory the VIC test made the 269 pipelines that the
other tests' runs had left there, under its validation layer: twice its time.

Change-Id: I2582c32cc4f07b942ecfbe9330d3e79265db67a5
Signed-off-by: AO55 <AO55@reden-emu.dev>
An issue whose run failed gets its summary from a run that names it. The
script refuses a number that is no issue's, a pull request or an issue
without a log, so a run by hand never ends green having done nothing.

Change-Id: I5bfa288b11da35f770860f56a6d07ef09665055e
Signed-off-by: AO55 <AO55@reden-emu.dev>
An Old 3DS gave 64 MiB whatever the ExHeader's system mode (0x20E bits 4-7) asked for.
It now lays FCRAM out by that mode as Azahar does (64, 96, 80, 72 or 32 MiB), the config
page naming mode and regions; a New 3DS keeps mode 6, and modes 1 and 6-15 are refused.

Change-Id: Idf98674f0fa08575b464d409385aee7086368abc
Co-authored-by: archetype-admin <olivier.stuber@archetype-eu.fr>
Signed-off-by: AO55 <AO55@reden-emu.dev>
gh writes its message on stderr and GitHub's answer on stdout, and the error
kept stderr alone: already_exists was never seen, so every triage with a log
failed at its labels. The error now holds both, and the label its code.

Change-Id: I9b94cabbbaaddd2134217a21091c6ec2754ab968
Signed-off-by: AO55 <AO55@reden-emu.dev>
The run's summary gives each screen's frames decoded, the bytes the GPU read and wrote of
the board's RAM and the CPU's accesses its pages trapped: in place, a discrete GPU's bus.

Change-Id: Ie7f7f6a3a12b372c0b726b578c5b61527571f9a1
Signed-off-by: AO55 <AO55@reden-emu.dev>
The Switch's choice of UMA, resizable BAR or a small window moves to vk_common.c, so the
3DS's device can choose its path for guest memory by the same rule.

Change-Id: Idf0756752c06d7c9ed80bcc586ea8aedaa2c8b39
Signed-off-by: AO55 <AO55@reden-emu.dev>
A frontend can copy into memory a recording reads after the commands that read it are
recorded, without ending a rendering pass: the 3DS's copies of guest memory on a dGPU.

Change-Id: Ia50d2e809a5fb1e19c08458b20c5569d2d124017
Signed-off-by: AO55 <AO55@reden-emu.dev>
A GPU that does not share the system's memory reads and writes a copy of the board's RAM,
kept in step by page through write tracking, instead of each byte across the bus.

Change-Id: Ie9a402f11687dc7b2d1112eeff30a8c59a9814ab
Signed-off-by: AO55 <AO55@reden-emu.dev>
Each GPU test, the validation modes too, runs again on each path whatever the device would
choose (SNX_TEST_CTR_VK_PATH), so lavapipe checks the copy and a discrete GPU in place.

Change-Id: I5a8a6977f175c06ce35508dce764829a802ca861
Signed-off-by: AO55 <AO55@reden-emu.dev>
On macOS the window finds the Vulkan driver beside the program through scarletnx-common:
a program that links only snx_vk_common, as vk_ring_uploads does, links there too.

Change-Id: I9b973ca7f675e6178745f0e7b2c61fa2453c1f9e
Signed-off-by: AO55 <AO55@reden-emu.dev>
One setting, one meaning: 0 the copy unless the device shares the system's memory, 1 the
copy, 2 in place; a copy the device cannot hold is refused, its line naming both values.

Change-Id: Iefc2e1d3a280fdf0b93733233d270de141ca865f
Signed-off-by: AO55 <AO55@reden-emu.dev>
The launcher's Debug pick reaches scarletnx-3ds as --vk_memory=N, beside the 3DS tables'
own settings, and no other Debug setting does.

Change-Id: Id88284448c72bbef7751213c0f5a4488e7fd4384
Signed-off-by: AO55 <AO55@reden-emu.dev>
The homebrew they were measured on is named by its target page, as games go unnamed in the
text upstream.

Change-Id: I4380662223cd246e8190550764bdda915feb18f8
Signed-off-by: AO55 <AO55@reden-emu.dev>
The schedule restarted from now only when it was more than a refresh behind, so
after a frame that ran long a numeric limit let the frames after it run at once
until the schedule caught up and presents went above the limit. A numeric limit
is a ceiling, so a frame already due starts the schedule again at once.

runtime_present checks that a slow frame under fps_limit=30 is followed by a
frame that waits its whole period.

Signed-off-by: theGreatGreenStar <145512144+thegreatgreenstar@users.noreply.github.com>
A DMA or a BIOS call that held the CPU past a run's end ran over it, so the next frame ran
short: a fifth of a frame's sound in some, and captures off the machine's frame end.

Change-Id: I3df34f26b8ee5963a0ecc72ec577631d925180f5
Signed-off-by: AO55 <AO55@reden-emu.dev>
A setting's name after the -- was refused, so a game could not get its own --log=1 or
--seconds=5; the runtime's options go before the --, and the help and USAGE.md say so.

Change-Id: If43ca7f9ba41365bcf18d1bd02577be6ccb5ce09
Signed-off-by: AO55 <AO55@reden-emu.dev>
Any store cleared it, so a spill to the stack between LDREXD and STREXD failed each STREXD
and the loop never ended. A store clears it now only where it overlaps the reserved bytes;
SNX_ARM_ABI 5 has the 3DS, Vita, GBA and 32-bit Switch code made before recompiled.

Change-Id: I96134afdddc21ba7c7243383ab363aa4dea82095
Co-authored-by: archetype-admin <olivier.stuber@archetype-eu.fr>
Signed-off-by: AO55 <AO55@reden-emu.dev>
The trap thread's unlock of the landing before could take the hold first,
and the read it had to land waited behind it (memory_own.c:129 in CI).

Change-Id: I784344d0ba87e76b331535f75d5d51411c2a12c7
Signed-off-by: AO55 <AO55@reden-emu.dev>
The game's driver has nothing to wait for there and answers FAILED whatever the timeout.
Sleeping out the timeout instead held one game 4.3 s on every frame.

Change-Id: Ic91f7489d06abd31e311e0a2dd1747e7e9b00a0f
Signed-off-by: AO55 <AO55@reden-emu.dev>
The 3DS renderer makes its pipelines on workers too, so pipeline_threads's count of them
moves to vk_common.c, for every frontend; its comment and test said a quarter of the CPUs.

Change-Id: Icc53455acd8b3e26eac8999f3f9cad2189491cd0
Signed-off-by: AO55 <AO55@reden-emu.dev>
A new pipeline paused the game while the driver compiled it. With the Switch's
async_pipelines=1, pipeline_threads workers make it and its draws are skipped until it is
ready, as on the Switch; scarletnx-3ds takes both keys, and the run ends with the count.

Change-Id: I3bf69e66a30ad869d1cca4786826fda5dd2b6a50
Co-authored-by: archetype-admin <olivier.stuber@archetype-eu.fr>
Signed-off-by: AO55 <AO55@reden-emu.dev>
A submit that finds the device lost calls fatal() on the recording
thread. The window release that follows drains the ring (vk_rec_sync),
and the recording thread drains the ring: it waited for itself, and the
process spun at full speed instead of showing the error. This is what
Super Mario Bros. Wonder's opening cutscene left on MoltenVK after a
firmware lockup of the GPU.

vk_rec_sync returns at once on the recording thread now. Every packet
before the caller's is already recorded, and the caller's own packet is
the one that this thread runs.

The check needs a call on the recording thread, and no public path but
the fatal one makes one, so vk_rec_run puts a call there.
tests/vulkan_headless.c uses it to call vk_rec_sync from that thread,
and ctest's vulkan_recorder runs only that check. It needs no shaders,
so it runs on any driver, and a hang fails it at the 20 s timeout. It
passed on MoltenVK 1.4.1, KosmicKrisp 26.2.6 and lavapipe, and it hangs
with the guard removed, so the check catches the bug.

The GPU lockup itself is not fixed. docs/APPLE.md records its rates and
what the measurements rule out.
Super Mario Bros. Wonder's opening cutscene locks MoltenVK's GPU up
(the gpuEvent report says "firmware-detected lockup"). The rates of the
builds that were tried show what it is not: not the descriptor limits,
not the Metal argument-buffer path, not compute, and not a barrier
alone. KosmicKrisp did not lock up on the same route, in 4 runs.

The section in docs/APPLE.md keeps the route, the table and what each
row rules out. It also says that the order between draws is where the
evidence points and that it is still open, and it records the recorder
self-wait that made a device loss hang the process.

CLAUDE.md's lessons gain the trap: a workaround that does not lock up
may only skip the over-limit draws, so count the skips, and measure an
intermittent GPU fault over 8 runs of one route on one save.
check-docs.py checks that each section of a document is in its index,
and docs_check failed in every CI job on the section that the previous
commit added. The line is the one that check-docs.py --index writes.
The headless job runs a named list of the Vulkan tests, and
vulkan_recorder was not in it: the check ran inside vulkan_headless,
but its own 20 s timeout, which is what a regression fails, did not.
It is in the list now.
Each bind drained the GPU: it waited for all submitted work, then for its own fence.

Change-Id: I8457e725e3d1fd152b2e20859e1a21585651ff4b
Signed-off-by: AO55 <AO55@reden-emu.dev>
Its check counted every allocation in the heap, so a staging ring its upload made counted
too: 16 MiB over the limit when no check before it had made one in that frame slot.

Change-Id: Iabb9196c4b753933ec81dd5418cc0bc8d54c4f10
Signed-off-by: AO55 <AO55@reden-emu.dev>
A check marks the pages it takes in with the clock's next value: a baseline read before it
took the same write in again at the next check, hashed again or its blocks loaded again.

Change-Id: I2725469ff08fa17cfb110aa6513a990ef1e06452
Signed-off-by: AO55 <AO55@reden-emu.dev>
The renderer's clear takes it; without it, a landing of GPU-owned memory on the memory
traps thread recorded in the frame's command buffer while the clear did.

Change-Id: Ib2a3927bd20f1db63c5ae66f042b20e2910f15e7
Signed-off-by: AO55 <AO55@reden-emu.dev>
A write of a page of a big block linear texture loaded all of it again. The blocks of the
pages write tracking and the GPU's records name now load alone, as a sparse texture's do.

Change-Id: I1a73d07b867efc1b3cc42a3718fd058ff689fa34
Signed-off-by: AO55 <AO55@reden-emu.dev>
GNU's builtin has bits.h's helper as its ISO counterpart, which tests/gnu_extensions.py
holds every file but bits.h to.

Change-Id: I5b484911cccfa5e5a4df9dba25818cec64b0b4c6
Signed-off-by: AO55 <AO55@reden-emu.dev>
Past alloc_cap (256 MiB, an 8K RGBA8 level) it was dropped: the texture read zeros.
A block linear source reads only the rows of blocks it gives; a failure names its bytes.

Change-Id: Ic7bbafb7d1a4837511e91b712fa0df9875b5fda3
Signed-off-by: AO55 <AO55@reden-emu.dev>
Past alloc_cap no readback buffer could be made, and its pixels never reached memory.

Change-Id: I5f8942231c1be76604ff13ed79f10cbde0e4cb16
Signed-off-by: AO55 <AO55@reden-emu.dev>
A 2D blit whose planes passed alloc_cap was refused and its destination kept its bytes;
each band now reads only the source rows its rows sample, through the DMA's bands.

Change-Id: Ife6aedd6b89b1d016c7f4ae3b404576c890b138e
Signed-off-by: AO55 <AO55@reden-emu.dev>
A job past alloc_cap or the storage range was refused; each band of the target's rows
now stages only the rows of each plane it reads and writes.

Change-Id: Id0b815e499c47c4b197e558cb2b247a025620084
Signed-off-by: AO55 <AO55@reden-emu.dev>
The DMA's bands and the readback's parts had no case with blocks deeper than a slice,
nor for a multisampled target.

Change-Id: I390936cea92355674ba1cfc847e895514d474446
Signed-off-by: AO55 <AO55@reden-emu.dev>
lavapipe reads a wrong byte in it while RADV passes; #1278 brings it back with the fix.

Change-Id: I1ce732d0c652bed00f37bdeabe7afa745edec902
Signed-off-by: AO55 <AO55@reden-emu.dev>
Each mapped piece is asked as for a texture with holes; one without holes was hashed every
epoch, then sampled, with tracking on.

Change-Id: I4244b66fc3544613afaff470e58c70cfb3c6fbc5
Signed-off-by: AO55 <AO55@reden-emu.dev>
The samples serve only checks the tracking can't answer; a stable buffer the CPU rewrote
took them at every write.

Change-Id: I8798b477c999d3aedb6eceb766321b34d942db65
Signed-off-by: AO55 <AO55@reden-emu.dev>
Where the host tracks nothing the caches still compare; a pending result is compared only
once its range was written.

Change-Id: Idd1a9747129f1a2681a20a0b1b5984d925cbfc06
Signed-off-by: AO55 <AO55@reden-emu.dev>
check_tex_partial leaves 0xA000000 to 0xC000000 past HEAP_BASE mapped: leaves 17 to 19.

Change-Id: Ibefcc71f20ba100e8abc81ab88e74b68eba29a39
Signed-off-by: AO55 <AO55@reden-emu.dev>
With #1288 a binding of whole pages stays on the GPU as their owner: nothing to compare.

Change-Id: I056884b751dd26ba2d6533f4999a66b490883e8b
Signed-off-by: AO55 <AO55@reden-emu.dev>
Each binding, read and composition compared every result pending in the frame; an index
by guest page gives it only the results on its range.

Change-Id: I54ad215e36636deaaf679ddfb0322a8d7675d671
Signed-off-by: AO55 <AO55@reden-emu.dev>
Faults, the handler's time and the scans with no game, for the default #1237 asks about;
timings are printed, the reports and the fault counts checked.

Change-Id: Id6ac2c7d2e64ed8f3eaefff2ffa1b6746e982af6
Signed-off-by: AO55 <AO55@reden-emu.dev>
0.8.0 and 0.9.0 add the tex8k suite, of the graphics family these mode words leave out.

Change-Id: I46d94ab34631c143c2ec15cc7d0e36589e1b2640
Signed-off-by: AO55 <AO55@reden-emu.dev>
Its reference and support suites run under any mode words; 11 new cases pass on lavapipe.

Change-Id: Ib5038f92fa0ed553c35965070a44bf5c3c33b2bc
Signed-off-by: AO55 <AO55@reden-emu.dev>
Its first bind read the whole image on the CPU, and each release copied it back to merge.
The span is GPU-owned from the bind on, published at the release, merged only if touched.

Change-Id: I97758fdbbb116bf043d73cc5725770e0721c65f8
Signed-off-by: AO55 <AO55@reden-emu.dev>
A copy's compute pass between two draws unbound them: the validation layer found the
second draw's offsets set with no descriptor buffer bound.

Change-Id: I5e934a3b0fec1dec613a5c294339a789f71681f6
Signed-off-by: AO55 <AO55@reden-emu.dev>
check_pass_breaks (#1283) runs first and keeps 8 MiB from HEAP_BASE + 0x5800000 mapped.

Change-Id: I2346e10c49bac97f94d4e2e4d9d2f18f03343605
Signed-off-by: AO55 <AO55@reden-emu.dev>
A write of a region of a big pitch linear texture loaded all of it again. The rows of the
pages written load alone now, the rows of a region as one copy.

Change-Id: I7920dfe1a74e24b0c3c13a5a3729f81555f517c7
Signed-off-by: AO55 <AO55@reden-emu.dev>
GNU's builtin has bits.h's helper as its ISO counterpart, which tests/gnu_extensions.py
holds every file but bits.h to.

Change-Id: I0f1196fe533d79009b89d634db44360564ebd5d2
Signed-off-by: AO55 <AO55@reden-emu.dev>
A read of guest memory with more than 16 owners landed them all, a wait for the GPU and
a readback; it now copies them on the GPU, as many at a time as it notes.

Change-Id: I2641b2238cbd35307de776f5ca08622d0b8d2545
Signed-off-by: AO55 <AO55@reden-emu.dev>
A copy into a block linear surface read, rewrote and took over whole rows of blocks (in an
8192 wide RGBA8 one, 32 times a 256x256 copy's); now the blocks of its GOB columns alone.

Change-Id: Ic104809c30811dc78230f158428be1d5b0dbea73
Signed-off-by: AO55 <AO55@reden-emu.dev>
A DMA or blit source was hashed whole each submission even when reused; now only pool
pages, which can be written where the tracking doesn't look, are compared.

Change-Id: I6c8978ea302d7361be9aaf4a5dfda78407aaa705
Signed-off-by: AO55 <AO55@reden-emu.dev>
Tiles cut a surface into many owners, which the read before a copy over them landed.

Change-Id: Ib8c1023cd98fa2b725217bdd8a30607346c36768
Signed-off-by: AO55 <AO55@reden-emu.dev>
A function that no symbol names, in one build of one game, can now take a hook. A line
`[BUILDID:OFFSET] hook NAME(ARGS)` names it by its module's build ID, as an IPS patch is named or an
IPSwitch patch's @nsobid- gives it, and its offset in that module. Each game's address hooks are a
spec of their own in src/nx/patches/, read with hooks.hook into one table, and NAME is the handler's.

The hook's key, the build ID in lower case without its ending zero bytes and the offset in hex,
stands for its symbol in the table and the route list. The loader makes each key of a module's own
build a function seed and a routed function, so the recompiler compiles the function at that entry
and every direct call to it goes through its slot. hook_install puts the hook in the module whose
build ID the key names, and NCE stubs it as it does any hook. Two helpers serve handlers that work
around the function's own code: hook_site gives where a hook went, and hook_run_original runs the
function's code to its return, as verify mode does. hookgen refuses an address hook with @version,
with = HANDLER, at an offset that isn't 4-aligned, with a build ID that is short, odd or zeros, and
the same function twice in any spelling. With no patch, the route list is the one before.

Verified with tests/hook_address.c (two specs in one table, the keys and their adapters),
tests/hook_routes.c (the keys in the route list and the build IDs they name) and seven new
hookgen_refuses_* cases. ctest on Windows x86_64 (llvm-mingw, RelWithDebInfo): 556 of 559 pass. https
needs curl, which didn't build on this machine, and fatal_screen and runtime_architecture fail the
same way without this change. Run in Bayonetta 3 1.2.0 with a patch of four address hooks on its
main module, kept out of this change: each was installed at its offset and routed, its handler ran
from the main loop's direct calls, and hooks_off turned the family off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PyVhBdCXs59iQ4uPnRtRnA
Each part unpacked its whole layer into one image, bound in pieces when the layer is past
the cap; lavapipe draws into such an image in another layout than it copies from.

Change-Id: If1d55e87f7d44c2974d319dfd96a07689f7341a2
Signed-off-by: AO55 <AO55@reden-emu.dev>
The app ships no file per driver: libscarletnx-run.so runs libscarletnx.so's, the
driver's name first, as Windows does. The build lists them for the menu; Linux's, left
out, says so.

Change-Id: Ib298b56ae1cbbe70248feace77a9081dc9632210
Signed-off-by: AO55 <AO55@reden-emu.dev>
A write of a page of an ASTC texture decoded all of it again, and encoded it as BC7. The
runs of blocks of the pages written decode alone now, on whole 4x4 blocks for BC7.

Change-Id: Ic0dec924f23518e652b38e5b6ffd3b56008a1f0a
Signed-off-by: AO55 <AO55@reden-emu.dev>
GNU's builtin has bits.h's helper as its ISO counterpart, which tests/gnu_extensions.py
holds every file but bits.h to.

Change-Id: I1a9a2e5e3b6e529fcc3227a41d6a8fa27d6a5cb4
Signed-off-by: AO55 <AO55@reden-emu.dev>
The compare worked each texel's offset out from NVN's layout, all levels' over, and filled
16 MiB a case: 5 s of the checks' 5.4 here, 18 s on the CI's lavapipe. Now 0.45 s here.

Change-Id: I51338e70a3e3bb9a476ab65d7a4259de7f29febb
Signed-off-by: AO55 <AO55@reden-emu.dev>
Their ASTC cases, which lavapipe decodes and encodes as BC7 in software, took
vulkan_headless past 60 s on the CI: apart now, 300 s, a quarter of the texels.
The CI runs them; the ASTC ones only with the host's own tracking.

Change-Id: I2c5247c7c61044b6748b7cc15b00875394499bc5
Signed-off-by: AO55 <AO55@reden-emu.dev>
The SDK of 18.0.0 and later calls them, and a failed result sends its wrapper to a call
that does not return.

Change-Id: I7e795310bd314b7a22d0c957cabfd5d7d5e00715
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
A program that encodes a BC7 or BC1 texture's levels on the GPU binds them as targets,
and no target format takes a compressed one: those draws were dropped.

Change-Id: Ib04b6ed7d48b7abb97a056aa882c2951afc7efa9
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
A compute pipeline was made at its first dispatch, on the GPU thread under vk_lock: after
an update of the runtime or the driver, a cold compile held the threads behind it seconds.

Change-Id: I278179e8107d26b4539a1b783d352e2df9d6c404
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
A page table change writes no guest memory: stamped as a write, it rebuilt the index of
mappings by guest address at every change.

Change-Id: I294cef496241d1702a132ddc012597f66edd4165
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
As RGBA8, one game's ASTC textures took a 5.7 GB budget whole and were evicted each frame;
as BC7, 2.5 GB. astc_bc's 0 was Exact, so Auto takes a new key: an old astc_bc is read
while astc_mode has none, 1 as Auto and the 0 every .ini had written as the default.

Change-Id: I3b9bdf9e7a61c05a6ea178b6be2a2d4d78dcf1d1
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
Main stopped building: #1272 removed astc_bc as #1266 landed checks that set it.

Change-Id: If5e869bb59305cc457726f213d943be577c82d03
Signed-off-by: AO55 <AO55@reden-emu.dev>
Its tiled levels, mip tails and layers bind as a sparse volume's bricks do: an 8192x8192
RGBA8 one with a region mapped takes 3.6 MiB, not 341 MiB.

Change-Id: If8d02020a65c35f304a7610603f569eccf0cacc5
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
A tile mapped in a frame whose staging ring was not made yet counted its 16 MiB.

Change-Id: If10a3135b11d446648d9e9e65a02d72607e86a9e
Signed-off-by: AO55 <AO55@reden-emu.dev>
The graphics queue's busy time over the last second, from each command buffer's begin and
end timestamps, read at its slot's reuse with no wait; nothing written while it is off.

Change-Id: I0348be4afe8776a9fb1166a54d8d76ba48241f10
Signed-off-by: AO55 <AO55@reden-emu.dev>
The device-local heap's use and budget as VK_EXT_memory_budget tells them; ? without it,
where VMA's numbers are its own guess.

Change-Id: I2af31f93d5b8aa13ed817a33921e79bc91f98435
Signed-off-by: AO55 <AO55@reden-emu.dev>
The box sat over the game in the menu's letters, hiding as much of it as the menu does.
It takes the menu's scale less one, 1 at least: 1 where the menu has 2.

Change-Id: I574ecad69455723db48c8146ba2e27872806fb16
Signed-off-by: AO55 <AO55@reden-emu.dev>
Gauge and cpu from the menus' set, and new glyphs after Lucide's gpu and memory-stick.
The box widens by the icon's three columns, so a 24 GiB card's line keeps its margin.

Change-Id: Icfd98d7d4b7249e0ebdc9786c313f68db27c4be9
Signed-off-by: AO55 <AO55@reden-emu.dev>
The process's memory of the machine's and the video memory's each on a line (layers);
the graph titled frame time, its guides labelled 16.7 ms and 33.3 ms at its right.

Change-Id: Ic1ea8a3f5cf2bbaefd2895b1664f91595b4ff2fe
Signed-off-by: AO55 <AO55@reden-emu.dev>
Redefining windows.h's TEXT stopped the Windows build (-Werror, -Wmacro-redefined).

Change-Id: I8fe36eea1d105e18f9c3bbafa99ac70dec826811
Signed-off-by: AO55 <AO55@reden-emu.dev>
glslang inlines every call: the encoder's copies made the GPU spill, and an 8192x8192
level took seconds to encode. The blocks it writes are the same.

Change-Id: I95c7163bbca17f677b93d5a9d7cd5d8fd9d6a94d
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
The table's size depends on the shape tried, so each weight was an integer division,
for three weights of every texel of every line tried.

Change-Id: I6b687797471bf0c8030d61c1cbc49be5c2178522
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
A change of guest memory waited for the renderer's lock with its core held, and landed
every pending result, where it changes none of their bytes.

Change-Id: Icb403e4effdd6b3527d68a2e6aa66290e9914c26
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
The 600-present report and --bench-storage-buffer show what each binding costs.

Change-Id: Ia7b6c4bee15c1cfde537aad709887f3da5745f2e
Signed-off-by: AO55 <AO55@reden-emu.dev>
Each binding copied its range twice on the CPU, read the result back and merged it.
The draws now write the range's owner in place; the trap lands it after them.

Change-Id: I808675a08a3f8aa7e89f394645a03a4549f17c0b
Signed-off-by: AO55 <AO55@reden-emu.dev>
Lavapipe takes unified memory there, so only this entry keeps them on the GPU.

Change-Id: I9e3a89cc514cd56490e194ddf745a880098aa4eb
Signed-off-by: AO55 <AO55@reden-emu.dev>
Main's Vulkan tests stopped building: vk_astc_upload took an origin as the bench came in.

Change-Id: I38511e2054b94f63b6ad44af20a3b7432945fd16
Signed-off-by: AO55 <AO55@reden-emu.dev>
The copy ended the pass of the draws before it, about 100 a frame in one game (6142 of
15150 pass ends in 2 s). It goes in an upload command buffer the submission runs first.

Change-Id: I521e6591988bf6a921cc07a081c62e0b0477a7b4
Signed-off-by: AO55 <AO55@reden-emu.dev>
A draw over bytes more than one owner holds ended the pass for their copy in every
submission that read them. Written before the submission, they are copied before it.

Change-Id: I3f7bdf10034383156896d5b40aab07ddecf95a39
Signed-off-by: AO55 <AO55@reden-emu.dev>
A run that drew nothing failed on a halves check that named only its line.

Change-Id: I4c2e37c8c0a3f51c971f858e27b2a4cea8591549
Signed-off-by: AO55 <AO55@reden-emu.dev>
The first draw's frame check submits them after 1 ms of recording, which a slow run
reaches: they are then read inside the pass, and the case wanted a break.

Change-Id: Ie6f8f4484c8512b02cfe031d1455200702ea2368
Signed-off-by: AO55 <AO55@reden-emu.dev>
Main's map check maps inside the 8 MiB it kept, so vulkan_headless failed with both.

Change-Id: I0cad2288f3529aa5ac96126318fa9f963ccf3f6c
Signed-off-by: AO55 <AO55@reden-emu.dev>
Its 4x4 blocks' 64 KiB tile is a BC7 block: each mapped tile is bound and decoded alone.

Change-Id: I18ab6c5cf239ff7d43d3b61818a6f6efa4e0e8a1
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
A sparse texture checked by its contents read its holes, up to hundreds of MB of zeros.

Change-Id: Idebf7c4395d85fc854f11c0f22f1286d4acb0034
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
They set g_settings.astc_bc, which #1272 replaced with astc_mode (0 Auto, BC7).

Change-Id: I9b2cc2c280d4242ec5bb8276798bba3d8d42edce
Signed-off-by: AO55 <AO55@reden-emu.dev>
The cross jobs need only llvm_qemu_reference.bin from the linux job, but
they waited for all of it, with its ctest step of about 7 minutes. A
qemu-reference job now builds the differential and its runner, records
the reference and uploads it. It restores the caches of the linux job
and saves none. appimage-cross needs this job in place of linux.

Fixes #1234. Measured on the fork in Build run 42046136838, together
with the next commit. All four cross jobs passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The host and generic forms ran one after the other under qemu-user, and
on riscv64 they took 17 to 22 minutes. Each form now runs in the
background with its own output folder, log and status file. The step
prints the two logs, and the mismatches of a form that failed.

Fixes #1233. In Build run 42046136838 on the fork, the differential on
riscv64 took 6.5 minutes (upstream median 20.5) and the job 13.2 minutes
(27.8). This is one run, so the noise between runs is not known.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The command fell to the stub answer, 0 whatever the console. It now answers 0 on an Old
3DS and 1 on a New 3DS, as Azahar's TargetPlatform numbers them.

Change-Id: Ib87fe0776b53eb5d6cc6d0840f909617f78b1039
Co-authored-by: archetype-admin <olivier.stuber@archetype-eu.fr>
Signed-off-by: AO55 <AO55@reden-emu.dev>
The errors named no number, nor the dump that leaves an expanded .code flagged. They now
give the bytes, the footer's expansion and the segments' size, and that likely cause.

Change-Id: I4bfb9bf866f38512b318f689adf5e638ccf2e0cd
Co-authored-by: archetype-admin <olivier.stuber@archetype-eu.fr>
Signed-off-by: AO55 <AO55@reden-emu.dev>
A frame waited with no time limit for a swapchain image, which stops the game for as long
as the display holds them all (a locked or remote session). It now takes one only if one
is free, as the Switch and the Vita do; the run's report counts the frames not shown.

Change-Id: Ib556fae5d55ad37f4c5c2da3d20f67b9c9e965af
Co-authored-by: archetype-admin <olivier.stuber@archetype-eu.fr>
Signed-off-by: AO55 <AO55@reden-emu.dev>
So one recorded play drives a game the same way on every build, for A/B runs.

Change-Id: I53f1e6d82ad7c8cc81af1d1a6d5fac1068009406
Signed-off-by: AO55 <AO55@reden-emu.dev>
In text mode Windows wrote each newline as CR LF, and unattended_script compared bytes.

Change-Id: I826f77e82a45c03ce1d8ff7a6451faa3eabb26b3
Signed-off-by: AO55 <AO55@reden-emu.dev>
A full ring doubled up to the allocation limit and kept it for 300 frames: one 341 MiB
upload allocated 0.75 GiB and left 256 MiB in its slot. Chunks of 16 MiB and big buffers
by size class go back to a shared pool after the slot's fence, kept to recent frames' use.

Change-Id: Icf9f24445ec7cb602a3abb6225972803d8372cbb
Signed-off-by: AO55 <AO55@reden-emu.dev>
In strips of a 16 MiB chunk an 8192x8192 pitch linear level took 254 ms to copy into new
chunks against 36 ms into new 64 MiB buffers; those bands take pooled big buffers.

Change-Id: Ib9608b875c2f148d75b5219b47968e42d650862f
Signed-off-by: AO55 <AO55@reden-emu.dev>
windows.h defines near and far as empty macros, and cmd.c stopped compiling there.

Change-Id: I0a44893860b5f561099f968f174dba6313903311
Signed-off-by: AO55 <AO55@reden-emu.dev>
On a GPU that shares system memory every buffer is device memory the CPU maps, so a big
output buffer never matched a request outside the window and was made again every frame.

Change-Id: I23a3537cc1036b360c958eed0da117c638e6d37c
Signed-off-by: AO55 <AO55@reden-emu.dev>
A request of a smaller size class made a new buffer beside a pooled bigger one, and its
first writes cost several times more than into memory written before (28 -> 43 ms).

Change-Id: Ic03e7a1c65e896490f491d28bdaa48ec17b56113
Signed-off-by: AO55 <AO55@reden-emu.dev>
An ASTC upload's strips took new chunks beside the ring's pooled big buffers (40 ms, main
17). The pool keeps a ring's bytes, the most its last frames took, in buffers of any size.

Change-Id: I45661953d255da2f39b28bfda63ffdbf3c0ae2e3
Signed-off-by: AO55 <AO55@reden-emu.dev>
A big buffer handed out as a chunk left the next big request without one, a new buffer
each frame (check_big_uploads, check_big_reuse). Chunks and big buffers count apart again.

Change-Id: I5b8141ba3ceac29f1cd5796d960cd342cb77e075
Signed-off-by: AO55 <AO55@reden-emu.dev>
The pool kept one frame's chunks: after a frame that staged nothing, the other slot's
recycle gave its share up and that slot's next frame made new ones.

Change-Id: I09531172d179d309542851ee2f8b848487703830
Signed-off-by: AO55 <AO55@reden-emu.dev>
An ASTC texture's strips after a texture's bands made new chunks beside the
big buffers the pool kept; their first writes cost several times as much.

Change-Id: I228cae09bb5068d416ae872af356b6fbb43fc4a8
Signed-off-by: AO55 <AO55@reden-emu.dev>
A range its owners held whole took staging it never wrote; the CPU's first write
there later faulted page by page, 7 ms for an 8 MiB copy source.

Change-Id: I8a04ff94caf56765eba83aaadda7104b552d3f16
Signed-off-by: AO55 <AO55@reden-emu.dev>
The CPU's first write to each page of a chunk faults: a chunk a frame barely filled came
first, and a 16 MiB copy source took 14 ms in it, 0.6 ms in one written whole.

Change-Id: I775253b27063025fa0f3832575757a5bc333d26e
Signed-off-by: AO55 <AO55@reden-emu.dev>
The script's, the clock's, the shots' and the input record's state, one global per file.

Change-Id: Id49321a08aafdb1a83ddd89d857284f20d568b70
Signed-off-by: AO55 <AO55@reden-emu.dev>
input_record=N and input_replay=N name the game's slot N, as save states do; recording
a slot again replaces it, and the log says what it held.

Change-Id: Ic9313ca727e9a5d87b055fc70cb7a050bbee7079
Signed-off-by: AO55 <AO55@reden-emu.dev>
Add descriptor heaps with buffer/set fallback, exact texture offset lowering, expanded blending and mixed-sample coverage. Reuse immutable encodings, reduce cache metadata and use compact validity images while preserving source precision and GPU ownership.

Retain upstream pooled staging, ordered upload submissions, sparse residency and graphics-storage retention.

Validation: full Clang build; 67 selected CPU tests; 37 CPU/GPU harness jobs across NVIDIA and RADV, all descriptor backends and recording modes; four storage-buffer retention runs; 147 generated SPIR-V modules; Linux and MinGW syntax checks.
Preserve whole indexed, indirect and programmable-stage draws with a guarded GPU-only D32F/S8 shadow. Extend portable mixed coverage to seven color targets, retain original-alpha coverage before software alpha-to-one, and guard source export masks and depth feedback aliases.
Reuse one immutable empty descriptor set on buffer-to-heap transitions to explicitly disturb old graphics offsets before activating heaps. Keep ordinary heap draws and cached buffer bindings unchanged. Reject all validation diagnostics in the rendering harness, including multiline messages.
Windows and macOS compile the descriptor address fixture as strict C99, where _Static_assert is rejected. Use negative-size typedef checks to retain the 32-byte resource, 28-byte key and 16-byte sampler layout guarantees without a C11 requirement.

Validation: six descriptor tests pass. The address fixture passes strict C99 syntax checks with Linux Clang and the Windows llvm-mingw compiler.
The 3DS input read both, but no run could set them: scarletnx-3ds and the launcher
now pass them as a Switch game's, with the same meaning.

Change-Id: I141078c859b5a7da36d9f5860879ebdec7b44fac
Co-authored-by: archetype-admin <olivier.stuber@archetype-eu.fr>
Signed-off-by: AO55 <AO55@reden-emu.dev>
A gamepad's buttons were fixed to their places. The map goes over them as on the Switch,
in its button names (Plus is Start, Minus Select); a button the 3DS lacks is said.

Change-Id: Ic8d2c585a7c15d56490e1572edf3058682d05315
Co-authored-by: archetype-admin <olivier.stuber@archetype-eu.fr>
Signed-off-by: AO55 <AO55@reden-emu.dev>
Only the mouse reached the touch screen, whatever the setting. A finger does now, one
pointer at a time as on the console, and touch picks them as for a Switch game.

Change-Id: I8a4d2fca76583b85ff48cde664fceab6c065a34f
Co-authored-by: archetype-admin <olivier.stuber@archetype-eu.fr>
Signed-off-by: AO55 <AO55@reden-emu.dev>
It answered success with nothing, so a game saw them always released. Ported from
Azahar's ir_rst.cpp; the input is the Switch's keys (1, 3, IJKL) and a pad's triggers
and right stick, through gamepad_map and gamepad_deadzone.

Change-Id: Ie8a5cf13d279955f7b2d5f52062437b0e65d6b16
Co-authored-by: archetype-admin <olivier.stuber@archetype-eu.fr>
Signed-off-by: AO55 <AO55@reden-emu.dev>
They gave a console held still whatever the player did. The Switch backend's sensor
reading moves to pad_sdl.c, and the 3DS takes it in Azahar's axes and raw units.

Change-Id: I7400edbd6247f14858ed645e0c60bbcdbdc500ff
Co-authored-by: archetype-admin <olivier.stuber@archetype-eu.fr>
Signed-off-by: AO55 <AO55@reden-emu.dev>
The Switch's rule (FIFO, else mailbox, else immediate) moves to swapchain.c, so the 3DS's
and the Vita's swapchains can take vsync; the Switch picks the same as before.

Change-Id: I2393aa94b8cffe2114db17730fe5f5e07e74744f
Signed-off-by: AO55 <AO55@reden-emu.dev>
The window always waited for the display's refresh. vsync=0 shows the newest image at the
next refresh, or at once, as for a Switch game; the run says at start which it got.

Change-Id: I32a2c83830d766c77d754504dbbe7cbe5c8d42c7
Co-authored-by: archetype-admin <olivier.stuber@archetype-eu.fr>
Signed-off-by: AO55 <AO55@reden-emu.dev>
The window could not go fullscreen. fullscreen=1 starts it so but for a timed run, and F11
or Alt+Enter switches the window it is pressed in, as for a Switch game.

Change-Id: Iab32299dedc1ca91bf7e8bf3ab6eb0f302cf05d6
Co-authored-by: archetype-admin <olivier.stuber@archetype-eu.fr>
Signed-off-by: AO55 <AO55@reden-emu.dev>
The samplers filtered as the game asked, whatever the setting. anisotropy=N raises a
mipmapped linear texture's filtering to N, held to the device's most, said at start.

Change-Id: Icfcc9650e37b484a30f76793d186b2563daf3ea7
Co-authored-by: archetype-admin <olivier.stuber@archetype-eu.fr>
Signed-off-by: AO55 <AO55@reden-emu.dev>
A 3DS game ran at the console's pace only. Every deadline and tick is now on one clock
that fps_limit paces: N/60 of the console's for N, as fast as the host goes for 0.

Change-Id: Ie921eb61b07a9eee09ae142e967df6ffd6eaaefd
Co-authored-by: archetype-admin <olivier.stuber@archetype-eu.fr>
Signed-off-by: AO55 <AO55@reden-emu.dev>
The wait added the gap to the clock, and a read of the same host second right after (a
coarse timer's, as on Windows) could round under the deadline: 3ds_clock failed there.

Change-Id: I42c103e38d4e16c378e33609d6dc0bb8859dc124
Signed-off-by: AO55 <AO55@reden-emu.dev>
The ordered blend's storage had made the image its linear twin; blits convert by the
image's format, so the presentation encoded sRGB twice and every game came out pale.

Change-Id: Ibca0d1b5a35d9ab0ccef2941de4a463f022b4483
Signed-off-by: AO55 <AO55@reden-emu.dev>
Only the Linux checks of signals sent to a thread read g_reports. On other hosts it is a
global that is set and never read, and clang 23's -Wunused-but-set-global stops the build of
snx-test-platform-posix under -Werror. Both the count and its update now sit under the guard
of those checks.

Verified with clang 23 on FreeBSD 15: the whole tree with tests builds, and the platform_posix
ctest entries ran.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each stage's set holds a uniform buffer for each of the 18 constant buffer slots and for the
renderer's own data, 20 or 22 in all. A GeForce device gives a stage 15, and 90 across the
sets. The validation layer reports VUID-VkPipelineLayoutCreateInfo-descriptorType-03017 and
-03029 at startup, and the driver is free to refuse those layouts.

The slots past what the limits hold are now read-only storage buffers over the same memory.
One function gives the type of a slot, so the layouts, the pools, the descriptor writes and both
SPIR-V translators agree, and the shader files take the count in their key. A device whose
limits hold all the slots gets the same layouts and SPIR-V as before.

Verified on a GT 1030, which keeps 11 slots as uniform buffers. Two games ran through 40 s of
their menus under the validation layer with core, synchronization and best practices checks,
and the two errors are gone. A local build that made every slot a storage buffer also gave no
errors, and its last frames match hashes of runs before this change, so that path draws the
same. The new shader_direct case checks both forms and passes the second through spirv-val.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each new epoch starts a pass of the scanner thread over every 4 MB leaf below the highest one a
check ever needed. The check of a leaf reads two atomics. A temporary counter showed one game
with 15 leaves ever needed under a top of 18090, about 9 wanted in a pass, and gprof gave that
loop 16 percent of the runtime's samples on it and 12 percent on another game.

The checks now set a bit for each leaf they need, with a second level for each word that has a
bit, and a pass jumps between those. The bits are a hint in the same way as g_wleaf_used: a leaf
that a pass misses is scanned by its check.

Verified by running two games for 40 s through their menus with no frame limit on a GT 1030.
Their frame rates are within the spread of the runs before (one about 1960 FPS against 1890 to
2010, the other 778 to 810 against 790), because the scanner has a thread of its own. The gain
is the CPU that thread stops using.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With page protection, which FreeBSD, macOS, Android and older Linux use, a scan reads the state
of each page of the leaves that checks need. In one game a scan read about 1370 pages to find 6
written, in another about 3990 to find 13, and a group of 64 pages held a written page only 6 to
8 percent of the time. gprof gave these reads 16 and 19 percent of the runtime's samples.

A byte per group now says that a scan has something to do there. wp_unlock sets it, and every
state but the lock's goes through wp_unlock, so a page that becomes written can't miss it. The
state is stored before the mark, and a scan of a whole group takes the mark before it reads the
states, so a write that a scan misses leaves a mark for the next one. A scan of a part of a group
leaves the mark. A page with a hot count marks its group too, because a scan must see it
unwritten for its count to start over.

Verified with the platform_posix ctest entries, which race writers on four threads against
scans, with a new check of the marks of whole and partial scans. Two games ran on a GT 1030 to
fixed frame numbers with input timed in frames, with write_tracking_hot off and on. One showed
only the two images it alternates between in the build before. The other matched at frames 4000,
8000 and 12000, and its earlier frames differ from run to run in the build before too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A draw that changes pipeline mostly goes back to one of a few. Each of those lookups still
hashed the whole key, which gprof gave 3.8 percent of the runtime's samples in one game, two
thirds of its hash calls. The lookup now compares the key with the last four entries first. An
entry in the table is never freed, so they stay valid.

Verified by gprof over 60 s of that game's menus on a GT 1030: 9 hashes for 551926 lookups, and
the lookup at 0.1 percent of the samples. All of ctest ran on FreeBSD 15, and the only failure is
3ds_memory_adopt, which links none of this code.

With the scan commits before this one and no frame limit, four 40 s runs of each build against
the main branch gave one game 1982 FPS against 1942 at 5 percent less user CPU. The other game,
this one, gave 768 FPS (743 to 785) against 803 (759 to 832) at 3 percent less user CPU. Its
faults a frame rose from about 70 to 74 before the rebase, which suggests that a scanner that
keeps up protects more pages again, though it was not isolated. write_tracking_hot=1 on this
series gave 3137 and 845 FPS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each time a command buffer looks at what it has written, spill_back walks the bucket of each
page of that range. A heavy game keeps over 30000 pieces there, most of them short recordings
on a few pages of pools gigabytes apart, so they lay in 637 of the 4096 buckets. A temporary
counter showed 519 pieces walked a call and 13 percent of them in its range, and gprof gave the
function 10 percent of the runtime's samples in that game's world.

The buckets now go by the 256 bytes that hold an anchor, and a multiplicative hash spreads the
pools, which plain modulo kept folding together: without it, 69 percent of what a call walked
was another pool's. The search for pieces whose anchor aligns to a JUMP's address looks at both
buckets such an anchor can be in, which a page boundary could also split before.

Verified by gprof over 160 s of that game on a GT 1030, 11.6 to 5.5 us a call and 10.3 to 7.1
percent of the samples while it was called more often. Frame rates there can't show it: the GPU
limits them, and another program on the same GPU moved them between 14 and 36 FPS. All of ctest
ran on FreeBSD 15, and the only failure is 3ds_memory_adopt, which links none of this code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
timeline_wait logged VK_ERROR_DEVICE_LOST from vkWaitSemaphores and went on as if the wait had
ended. The next Vulkan calls then crashed in the driver, and the report named an invalid memory
access by the game. It now stops with the same message as the submissions do.

Verified with a heavy game on a GT 1030, in the texture load that can lose this device. Before,
4 of 6 runs ended in a crash at address 0x108 after the wait failed. Now 2 of 3 runs lost the
device, both with the message and no crash. This does not stop the loss itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A lost device says nothing about its cause, and on this FreeBSD machine the kernel's log has no
Xid either. vk_checkpoints=1 turns on VK_NV_device_diagnostic_checkpoints: each ASTC decode, BC7
encode, copy, deswizzle, conversion, game dispatch, rendering pass and submission's end leaves a
marker, an index into a ring of what it was. On a loss the report gives the submissions the GPU
hasn't finished with what they hold, and the marker each queue's stages reached. It is off by
default and costs nothing then, and a driver without the extension gets a warning.

Verified on a GT 1030 over more than 20 runs of a heavy game that lost the device. The reports
named the work in each, which showed that the loss doesn't follow any one shader: the same small
submission of deswizzles died at different dispatches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The encoder takes a small GPU about a second for 256 thousand blocks, and a load of many
textures queued up tens of seconds of it. On a GT 1030 that lost the device in most runs of one
heavy game, and in the runs that lived the load stopped everything else on the GPU's queue. It
took BC7 to do this: with astc_mode=1 none of 26 runs lost the device.

An upload now submits and waits for the GPU each time that many blocks are queued. The wait
lands nothing, so it can run while a draw is set up, as the draw starts its setup again on the
new submission number.

This treats the trigger and not a known cause. Why the queue's depth loses the device is inside
the driver: the validation layer reports no error, the kernel's log has no Xid, and the last
marker can be a cheap dispatch. Smaller dispatches, more submissions with no wait, const tables
out of function scope, no sparse images and compute=0 did not stop it.

Verified on that GPU in 8 runs of 170 s from two saves: none lost the device, against 3 of 3 and
1 of 4 on the main branch. The game now plays on BC7 at about 38 FPS. The big loads take about
47 s where they took 36 s, a cost of the wait. All of ctest ran, and the only failure is
3ds_memory_adopt, which links none of this code. Another program was using the GPU in these runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The encoder tried every block in all its modes, for 2.5 million core cycles a block on a GT 1030
by a rough count, and it reached 54 to 62 dB on a game's frames. Most of that precision can't be
seen, and encoding held loads for tens of seconds.

A block now takes no more modes once its squared error over its texels and channels is 16 or
less, a mean squared error of a quarter. That is a floor for each block that stops, so it doesn't
depend on the content, and a hard block still gets the whole search. 16 is the most that keeps
every PSNR bc7_glsl holds the encoder to. Within a fit, Eval now leaves as soon as it can't win
and a second least squares runs only on weights that changed, neither of which changes a block,
and a line the box leaves far behind the best block gets no least squares, which changed few.

Checks of a block a mode holds coming back exact now use the encoder with the threshold at 0, a
new check holds the picture to the whole search, and the digest of its blocks changed with them.

Verified on that GPU with one game: the first load fell from 36 s to 25 s, the second from 47 s
to 35 s, and 5 runs from two saves lost no device. The gain is below the CPU's: 3.3 times over a
mix of frames and made images, 5.5 on a frame, as real textures stop less often. A frame looked
right by eye. Without the wait of the commit before, 4 of 4 runs still lost the device, so it
stays. All of ctest ran, and the only failure is 3ds_memory_adopt, which links none of this.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keep indirect and direct compute launches exclusive, resume BC7 uploads with a live command buffer after throttling, and link checkpoint support into the ASTC test target.

Freeze checkpoint publication before reports and reject overwritten marker generations. Remove an unproved BC7 refinement heuristic after an independent prior-search reference finds four degraded blocks. Retain the bounded error stop and exact early exits.

Validation: full Clang build, 14 focused CPU tests, strict quality references, checkpoint ThreadSanitizer run, and NVIDIA/RADV indirect and multi-strip upload checks with validation. Both original command-recording bugs are rejected by mutation tests.
The capture binding now follows the eight buffer images; the cap was still the old nine,
which reaches it.

Change-Id: Ic2731ea47afe162e722b70c69abafe4f26643ba6
Signed-off-by: AO55 <AO55@reden-emu.dev>
The skip followed vk_descriptors' value, so with its default of 3 a device
with neither descriptor buffers nor heaps dropped them too.

Change-Id: I14e6bb1e9589e0a382b3391c0b0534f7457e34bf
Signed-off-by: AO55 <AO55@reden-emu.dev>
Each primitive costs a clear, a draw and a resolve: past VK_CAPTURE_PRIMITIVES_MAX a draw
is skipped as before, with its primitive count and the cap in the log. The cap, 256, is a
proposal for novesce: 512 primitives took 11.7 ms here, one run (RX 6700 XT, 4x4 target).

Change-Id: Idce887888de049a3a36c5798287ca67a53278175
Signed-off-by: AO55 <AO55@reden-emu.dev>
device.c reads both as heaps, else buffers, else sets; the help and docs told them apart.

Change-Id: Ib90218b24b7b9b0bfcff56b89f4c19614ef12483
Signed-off-by: AO55 <AO55@reden-emu.dev>
Heap setup failed with no line, and a device without heaps said only the backend left.

Change-Id: I9a7cc2b4ac2cbdc9b5fd53ea94a9ab99a9e249e7
Signed-off-by: AO55 <AO55@reden-emu.dev>
A fragment program samples a generic's x / w and y / w, the vertex program having written
that generic as its position mapped onto [0, 1]: each fragment reads its own pixel.

Change-Id: I01da502756d92c054fa9e3dd48123b75e51d7c99
Signed-off-by: AO55 <AO55@reden-emu.dev>
A draw reading its targets through such a generic copied them whole before each draw,
where one open world's frame spent most of its GPU time; the viewport covers the target.

Change-Id: I45cbaed64d799f6bf62f2f45097f493cbef25f05
Signed-off-by: AO55 <AO55@reden-emu.dev>
RenderDoc's program puts its library in a game it starts; a look for it must not load it.

Change-Id: I65b65c0aec4ce4bad00d19a30b2e11e728c2ee7f
Signed-off-by: AO55 <AO55@reden-emu.dev>
TracerPid and the tracer's comm on Linux and Android, kinfo_proc on FreeBSD, ? for a name
the system doesn't give (Windows, macOS): for the stats and F1's help.

Change-Id: I0111eb7bc82eb475a023688a978e7fa9552aefc1
Signed-off-by: AO55 <AO55@reden-emu.dev>
Lines while they apply: a capture can be taken, what the last one wrote or that it failed,
and the debugger tracing the game; the box widens for a line that needs it.

Change-Id: Icdefd011547c5364abce2fb33d5c436c069b7e00
Signed-off-by: AO55 <AO55@reden-emu.dev>
A present number set at launch can't be found while playing. Also in a game RenderDoc's
program started, its captures where it keeps them; its keys stay off, F12 is the stats'.

Change-Id: Ia862f2fba4827a5b2b47695662351f60da9ef90b
Signed-off-by: AO55 <AO55@reden-emu.dev>
The text moves to help.c, beside its test, and keeps following sdl3.c's keys.

Change-Id: I1b15fa4f508b911503a2f47c1063bb1cf71011f9
Signed-off-by: AO55 <AO55@reden-emu.dev>
The test named librenderdoc.so where Windows looks for renderdoc.dll, and failed there.

Change-Id: I240f2570b64291f919c4d62d86efbb061f57f1aa
Signed-off-by: AO55 <AO55@reden-emu.dev>
runtime_architecture refuses a library a sanitized test loads that is built without them.

Change-Id: I97fddefff6d7be6ee6285b1e69a42b1892c9ec4f
Signed-off-by: AO55 <AO55@reden-emu.dev>
A game turning its save backup on waits on the license check's event, and the
stand-in gave it no object to take that event from.

Change-Id: I7e4c1af285e27ba48e9753b2f3c6bd3a3d2d15bf
Signed-off-by: AO55 <AO55@reden-emu.dev>
The stand-in for caps:su answered success and kept nothing, so a picture the game
said it saved was lost.

Change-Id: I1b996f0fe1565904ef264897ee8d356b21ae5059
Signed-off-by: AO55 <AO55@reden-emu.dev>
A game committing its saves through IMultiCommitManager never wrote their notes, and
the extra data's buffer kept whatever the game had left in it.

Change-Id: I96b46c71e404130fcb8938873522700a12b72e46
Signed-off-by: AO55 <AO55@reden-emu.dev>
No restriction is set, which the console answers with success.

Change-Id: I0a2c4647ffd7dd6b6b37e70d1a5bd2630c8905a9
Signed-off-by: AO55 <AO55@reden-emu.dev>
Nobody is blocked and no presence is sent anywhere, now declared rather than stand-ins.

Change-Id: Ia71426a178af71763807357dd77352225b4d797a
Signed-off-by: AO55 <AO55@reden-emu.dev>
A game's SDK opens the system's ssl:s and sets its interface version there.

Change-Id: I7e583bfedb115018c51db16bacb54345b26d4d87
Signed-off-by: AO55 <AO55@reden-emu.dev>
No public source names olsc's own, so the license check keeps acc's answer for an online
service that is not there.

Change-Id: I792eb598593983e5dee294e24668280111198783
Signed-off-by: AO55 <AO55@reden-emu.dev>
A picture saved to captures/ as a PPM is no album a player can copy to a PC: it is now a
JPEG on the SD card under the console's folders and name, with its time in EXIF.

Change-Id: If582b540c3237aadc41fbeb9736869ec225a6f29
Signed-off-by: AO55 <AO55@reden-emu.dev>
No public source names olsc's own result for no license: 2124-5113 is the closest public
one, and it tells the player backups need a membership.

Change-Id: Iad6319d036f3b0098b9f68438c25130e0530edcd
Signed-off-by: AO55 <AO55@reden-emu.dev>
A RetroArch overlay (its .cfg and PNGs) gives each control its place, size, hit area and
images, and a two-frame APNG its pressed look; the built-in look stays the default.

Change-Id: Ifefd2de811956b6dcbc7e24c09a620d40b9ade90
Signed-off-by: AO55 <AO55@reden-emu.dev>
The launcher's yorha theme on the controls, drawn as SVG by scripts/build-skins.py with
the menus' font; a RetroArch overlay with pressed looks, held to the script by --check.

Change-Id: I7caebe5607d35969367fad3a62c4a44f174ec195
Signed-off-by: AO55 <AO55@reden-emu.dev>
Empty for the built-in look, yorha, or a RetroArch overlay's path; the shipped skins
compiled in; a change makes the atlas again, with the controls at once; a menu row.

Change-Id: I7c11f4abc9b410812f0074333f7be93f6e5a1956
Signed-off-by: AO55 <AO55@reden-emu.dev>
Move, sliders, refresh, arrow-left, x, check, trash, pencil, clipboard-paste, panel-right
and eye, after Lucide 1.61.0's, in the menu font's stroke as the others.

Change-Id: I6340cf3ca2cd1d2e76c27c228bcfa80ee0d25490
Signed-off-by: AO55 <AO55@reden-emu.dev>
The screen darkened under it, a row a key with its icon, the keys as the foot draws them,
OK under them; Up/Down and the wheel go over the rows a short window cannot show.
The wheel no longer moves the screen under the box.

Change-Id: Idcd859b0d09eaef3a1225929d2b78e2001c8ce2f
Signed-off-by: AO55 <AO55@reden-emu.dev>
Under the title Every screen go the keys every screen has (moving, picking, the pages,
ESC, Tab, F2), so a screen's own keys are read first.

Change-Id: Ia746e623dbe1d828343b15aa9c67392adc5c7329
Signed-off-by: AO55 <AO55@reden-emu.dev>
Up/Down, Arrows and a pad's D-pad said select on Games, where Enter and A select:
one word now for each action, in the foot and in F1's box.

Change-Id: I583e14d45f416f0dc6a50c86b525f58611e185d2
Signed-off-by: AO55 <AO55@reden-emu.dev>
One spelling for the key, which takes F1's box two columns narrower; PgDown goes
from the keys a foot's word presses.

Change-Id: I751c1409a2b8cecce503266bbc56190f97953244
Signed-off-by: AO55 <AO55@reden-emu.dev>
B is ESC there, which asks to exit ScarletNX; it said back.

Change-Id: Idecb6b520f3c81608b65a69ced943c78bf3902b2
Signed-off-by: AO55 <AO55@reden-emu.dev>
The system's box, which took the game out of fullscreen, becomes the menu's look: a row
a key with its icon; Up/Down go over them, any other key, button or tap goes back.

Change-Id: I5865bed2c469ee72e58ddd294635542974ae5e72
Signed-off-by: AO55 <AO55@reden-emu.dev>
They shared one phrase, so a language translated F1's title as the key files:
pt-BR said Chaves, and Chinese named cryptographic keys.

Change-Id: I425764783f106393fd205a5e86a024451a432aa2
Signed-off-by: AO55 <AO55@reden-emu.dev>
An update's or a DLC's package installed into a game is no game's source, its own .ini
names it: its recent entry stayed in the list, hidden, holding one of its five places.

Change-Id: I3f4ce406d89fa6e2611176aaeca34a9928e56728
Signed-off-by: AO55 <AO55@reden-emu.dev>
With the games one group alone, which had no heading, a game's row read as a second recent
row of it: the group gets its own heading there, Recompiled or Dumps.

Change-Id: I327d7b767c03188d52493685bf89c88888910181
Signed-off-by: AO55 <AO55@reden-emu.dev>
Eden's Modern Console: by the order they come, a player kept 45 s for the one that left,
the game paused after 3 s until it returns or + goes on, and a notice for each.

Change-Id: Id6810369ce318cbbf5f1880bba0b96cc84681a12
Co-authored-by: John <john@eden-emu.dev>
Signed-off-by: AO55 <AO55@reden-emu.dev>
The console mode's checks attach a 17th pad, past the 16 motors: UBSan's out of bounds;
the motors are 32 now, and a pad past them fails its check.

Change-Id: I3c89483b658de6923527baa9e82d509506cc58e3
Signed-off-by: AO55 <AO55@reden-emu.dev>
16 bytes only the remap binds split an 8K RGBA8 level and doubled a 4K level's scratch.

Change-Id: Id41679435c8d26329d6825d1e2f896ad0fae6ebc
Signed-off-by: AO55 <AO55@reden-emu.dev>
The moves' pipeline and the scratch buffer, one global for the file's state.

Change-Id: I14670f7529b4fdaef25fe04e04089d8ce3327399
Signed-off-by: AO55 <AO55@reden-emu.dev>
The scratch buffer never shrinks: one DMA upload of a 16K BC1 texture kept 256 MiB of it.

Change-Id: I4e508f783baeca11e12361d7061e31b5e27a88d9
Signed-off-by: AO55 <AO55@reden-emu.dev>
The scratch buffer never shrinks: a 4K RGBA8 level asked for 64 MiB and 64 bytes and kept
128 MiB of it. Strips take a quarter of the cap at most.

Change-Id: Ic0ecdff19bf6b26597d163333159ca192c8d7fe6
Signed-off-by: AO55 <AO55@reden-emu.dev>
The scratch buffer never shrinks: a blit that fit the cap went whole and kept what it
asked for.

Change-Id: I5dc6ccd800d37074e4eac9bc9b49d29a0c4d9b0d
Signed-off-by: AO55 <AO55@reden-emu.dev>
It was a stand-in that answered zeros, so IsSampling never said a started sampling ran and
GetBufferFullEvent gave no event. Ported from Azahar's mic_u.cpp.

Change-Id: Ib554d07965ca986eef1d08c4041ef28b54c220e7
Co-authored-by: archetype-admin <olivier.stuber@archetype-eu.fr>
Signed-off-by: AO55 <AO55@reden-emu.dev>
It was a stand-in that answered zeros: no receiving ever finished and no vsync came.
Ported from Azahar's cam.cpp, whose blank camera gives black frames at the frame rate's
pace.

Change-Id: Ia9e34e1a88d682632d3243ed835300ada4192f34
Co-authored-by: archetype-admin <olivier.stuber@archetype-eu.fr>
Signed-off-by: AO55 <AO55@reden-emu.dev>
Android's headers bring signal() into cam.c, so a static signal() of its own does not
build there.

Change-Id: I6542043f2bc4546a3b1ccb9a8bd5aa15c8e8490a
Signed-off-by: AO55 <AO55@reden-emu.dev>
It was a stand-in that answered zeros, so a game's CSND channels made no sound. Ported
from Azahar's csnd_snd.cpp and csnd.cpp: the command lists drive 32 channels, rendered
each DSP frame and mixed into its output.

Change-Id: I0d320093bc7338c02eb0066b132afe8b9d6cdd89
Co-authored-by: archetype-admin <olivier.stuber@archetype-eu.fr>
Signed-off-by: AO55 <AO55@reden-emu.dev>
KDE's Ctrl+F12 shows the desktop, so the game never saw it; Ctrl+Shift+F12 is free in
KDE, GNOME, Windows and Steam.

Change-Id: I3a9c5904638cc855b16aa7ef20aa4733ac27751c
Signed-off-by: AO55 <AO55@reden-emu.dev>
A RenderDoc capture where no key reaches the game (a phone): the item closes the menu and
asks for the next frame, and shows only while RenderDoc can capture.

Change-Id: I7d5c2840a0f549cedd186bff687dd0d65b9f4cd6
Signed-off-by: AO55 <AO55@reden-emu.dev>
settings.txt's Shortcuts: a key as SDL names it after Ctrl+, Alt+, Shift+ or GUI+, empty
for none; a name SDL doesn't know is refused with the key in effect. F1's help, the stats
box's RenderDoc line and RenderDoc's log name the keys as set.

Change-Id: Ied60ae6a2fd9bae3df325ce065b4dc0f1977689f
Signed-off-by: AO55 <AO55@reden-emu.dev>
A row a key: Enter, then the key with its modifiers, saved in the game's .ini; Esc
cancels, Backspace puts the default back, and a key another row has is refused, said.

Change-Id: I616a04216b176fd61db65493e246055e542c370e
Signed-off-by: AO55 <AO55@reden-emu.dev>
RenderDoc writes a capture inside its present, the game stopped a minute on a large frame:
a notice says so as one starts (asked a present early, so it shows), a thread logs the
seconds, and the log and a notice give the time, the file and its size, or the failure.

Change-Id: I8c22e7ae5b2ceb6a3c075de6670701ef4b97638d
Signed-off-by: AO55 <AO55@reden-emu.dev>
At -O0 the compiler keeps calls into svc.c and surface.c that an optimized build drops,
and neither test links them: stubs that abort if a case ever reaches them.

Change-Id: I333d803a678ab04a4a13055f9c51997d23aa749b
Signed-off-by: AO55 <AO55@reden-emu.dev>
A white spot in the iris toward the outer corner, in games and in the pictures.

Change-Id: Ie6a530b70c038426839a4a9eae2493b607235db3
Signed-off-by: AO55 <AO55@reden-emu.dev>
Sixteen locks around the head, pointed at their tips, where the edge was one smooth line.
Mid keeps two columns a lock so they stay pointed; the archive takes up to 6 MB.

Change-Id: Iafc580ac598a0e0a963672d22c004492651052b8
Signed-off-by: AO55 <AO55@reden-emu.dev>
The two curled twin-tail styles get twin drills: thick under the root, each turn of the
ringlet a cone, wound down to a point below the shoulders.

Change-Id: If04898f21d579d5216e9e5d25767ba8be580fa7b
Signed-off-by: AO55 <AO55@reden-emu.dev>
The pictures were flat at the 24 to 96 pixels they show at: a line where a part meets
another or the background, lighter in small pictures, and a shine across the strands.

Change-Id: Iceec04acc570b51b75e0935066ecd23ff0338881
Signed-off-by: AO55 <AO55@reden-emu.dev>
Shaped after a reference picture: three rings out from the temples read as drills at the
size a game's Mii icon has, where long ones hanging to the shoulders read as a thick tail.

Change-Id: I075156676d3282d94daaa6a87e11bc79c864cfff
Signed-off-by: AO55 <AO55@reden-emu.dev>
A lock standing up from the crown, on hair 112 alone, so the two drill styles stay apart.

Change-Id: Ia760ab2c4d598437a5b2353efe536deb022d6ad3
Signed-off-by: AO55 <AO55@reden-emu.dev>
Shaped after reference pictures: wide flat locks out from their ties read at a game's
icon size, where the thin tubes they were did not.

Change-Id: I6d08cd78918d2233b8257a3a58d207b9dfb9e0e0
Signed-off-by: AO55 <AO55@reden-emu.dev>
Picked after a reference picture: the common colors nearest its hair and its eyes, the
eyes the darker of the two nearest so they stand apart from the hair.

Change-Id: Ic7515f3955a79f4b8234b0baa13cb6d54b33dd59
Signed-off-by: AO55 <AO55@reden-emu.dev>
Every Mii looks like a plush: a wide round head, thick hair falling straight to the jaw,
big eyes set low and the mouth close under them, in the game and in the picture.

Change-Id: I4bc15bd29f6b5ddf1ca8b4f632f9ae9ed4b2c7c6
Signed-off-by: AO55 <AO55@reden-emu.dev>
The tail styles a plush's look is measured on: thick drills near a cylinder at the
eyes' height, the high twin tails out wide and long, the side tail close to the hair.

Change-Id: I4a721e77e695e9a2ab90732451bc6e270f3393ae
Signed-off-by: AO55 <AO55@reden-emu.dev>
The other tail styles take a plush's look too: wide flat locks for thin round tails, and
bows and clips big enough to show over the thick hair.

Change-Id: Ie69a56879c06cac37674b1b2218c581a3d74fc01
Signed-off-by: AO55 <AO55@reden-emu.dev>
result_codes.inc gives each result one row, with the name public sources use and the
source, and result.c looks a result up, so logs and the error applet can say
"2124-5113 MembershipRequired". The services move to it in the commits after this one.

Change-Id: I5ae2bae5bf6a0ec0f2b84d01fdf1c19726628599
Signed-off-by: AO55 <AO55@reden-emu.dev>
The SVCs, the waits and ipc.c had their own defines, InvalidPointer three times and
InvalidNewMemoryPermission twice; each now uses its one row.

Change-Id: I381a78d889ce718df43f65b7d1e2bb90197797b4
Signed-off-by: AO55 <AO55@reden-emu.dev>
fs.c defined 16 of its results and wrote 5 more as RC() where it answered them,
PartitionNotFound 18 times; each now uses its row.

Change-Id: Ic843916e872a1acc3dc3cdf172fe4b6621e625da
Signed-off-by: AO55 <AO55@reden-emu.dev>
sm, set, time, acc, am, vi, hid and ro drop their defines and RO_ERROR(); sm's
OutOfHandles and am's InvalidHandle are the kernel's rows.

Change-Id: Id4c135af6ba22c82e3c83341b675df538085ceac
Signed-off-by: AO55 <AO55@reden-emu.dev>
friend, caps, nfp, nfc, bcat, aoc, mii, audin and olsc drop their defines. aoc's
NoInternetConnection and TitleIdNotFound, and audin's NotFound, were second copies of
nifm's, am's and audio's; they share those rows now.

Change-Id: I502a2bbe0f240bf0d8aa2d9cfc57edf3f93db548
Signed-off-by: AO55 <AO55@reden-emu.dev>
audio.c drops its defines; audren.c names InvalidUpdateInfo and InsufficientBuffer where
it built them as RC(153, -rc). audren_host checks RequestUpdate's results.

Change-Id: Idc826359d844a6134e50bc5e807582c67b9170bf
Signed-off-by: AO55 <AO55@reden-emu.dev>
ssl's description enum and SSLSRV_RC() go: a fatal alert's result comes from a table of
TLS alerts and their SslAlert rows, which ssl_service checks for every alert number.

Change-Id: I566134b3681144bc7ebdb270f41bb389dd44c306
Signed-off-by: AO55 <AO55@reden-emu.dev>
result_codes_sources fails on an RC() outside result.h and on a result written as a
number in the HLE: on main's sources it lists the 149 spellings this series moved.

Change-Id: I3893440a3638a2fd218cb41434f3645c25c2f88f
Signed-off-by: AO55 <AO55@reden-emu.dev>
The scratch buffer never shrinks: loading an 8K RGBA8 target kept 256 MiB of it, and a
target past the cap did not load at all.

Change-Id: I38c6469124f2936aedf1af78039a86487e478431
Signed-off-by: AO55 <AO55@reden-emu.dev>
The scratch buffer never shrinks: writing back an 8K RGBA8 target, which fits the cap and
went whole, kept 256 MiB of it.

Change-Id: Iae408d5e2c0c41662d8989b994e043fe0ae139c6
Signed-off-by: AO55 <AO55@reden-emu.dev>
acc's objects answer through a lock no state table named, so no save state could be made.

Change-Id: I3f29408e7b8ec7792e7a4aa0e4c9eeeca05d740b
Signed-off-by: AO55 <AO55@reden-emu.dev>
A game holding an ldr:ro or ro:1 session could not be saved: no table named ro_dispatch.

Change-Id: I0cb315e85312cd793ccd06bb4951bc5498ed33e6
Signed-off-by: AO55 <AO55@reden-emu.dev>
The check acc and ldr:ro would have failed: a stored dispatcher or destructor unnamed.

Change-Id: I10dddf5ef7f1a57348037fb4965bfd56e2b0095e
Signed-off-by: AO55 <AO55@reden-emu.dev>
A 3DS game played only its own files. Its update and DLC CIAs are now recorded beside it
and checked in its addons=, read where they lie when it plays, and am:app answers for a
DLC as Azahar does for an installed one.

Change-Id: Ifbb232aa6b8d448a66ab5761affafe5c1558ee7f
Co-authored-by: archetype-admin <olivier.stuber@archetype-eu.fr>
Signed-off-by: AO55 <AO55@reden-emu.dev>
The box listed an update only with a program of its own, which a 3DS update never has, so
it hid one. It is listed by its TMD's version and Play runs the game itself.

Change-Id: I2baf46a755ef327631194a76476ef8f6c239f32e
Signed-off-by: AO55 <AO55@reden-emu.dev>
On macOS the folder is under /var, a link to /private/var, and the driver prints the
resolved path, so the test's own path never matched it.

Change-Id: I453c96c189744510ac3822c1ad4aab211747225d
Signed-off-by: AO55 <AO55@reden-emu.dev>
An unloaded driver's once-made memory read as a leak of an unknown module (lavapipe's).

Change-Id: I0b086f15b57ad7e4a80b54469376af604b8ed5e1
Signed-off-by: AO55 <AO55@reden-emu.dev>
MoltenVK and KosmicKrisp have no VK_EXT_transform_feedback. One game's
skinned models then exploded into huge flat triangles, and its first
cutscene ran at about 2 fps on MoltenVK. This ports #812 to current main:
the vertex program stores the captured words into the guest buffers,
bound as writable storage. Begin and resume now set the capture state
on this path too, so each begin starts the buffers at 0 again.

Tested on macOS 27.0.1, Apple M4 Max. shader_direct passes (3 tests).
On MoltenVK 1.4.2 the cutscene went from about 2 to 45.6 fps, and a walk
through the city ran at 49.6 fps with whole models. KosmicKrisp ran the
walk at 50.7 fps. No "could not run" control lines in the log.
Not tested: indexed and indirect draws (no capture), DrawAuto, iOS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebased-by: AO55 <AO55@reden-emu.dev>
A program can declare a transform feedback buffer that the guest leaves
off for a draw. That buffer got a 16-byte placeholder from the staging
ring, and the shared vertex limit came only from the enabled buffers.
So the vertex program stored up to limit * stride bytes past the end of
the placeholder, into staging data of other copies.

The parameters now give the mask of the enabled buffers, and the store
block of each buffer runs only when its bit is set, as on the hardware.

Tested: the macos preset builds with no warnings. shader_direct_structure,
shader_direct_regressions and vulkan_driver, vulkan_release and
vulkan_backing pass. The new check fails without the change (0 masks in
the SPIR-V) and passes with it (2). Not tested: a game run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A review found these defects of the capture by stores:
- A resume went on from the CPU's last end of the owner, not from the
  counts in its control memory. So a pause, another capture on the same
  owner and a resume wrote over the wrong bytes.
- Begin wrote no stride and End and Pause wrote no byte counts, so a
  DrawAuto read stale guest bytes. Begin with control 0 was accepted.
- The legacy fog word took the .z of its generic, not the .x.
- The guard of the bound mask put OpINotEqual between OpSelectionMerge
  and its branch, which spirv-val refuses.
xfb_control_stores now uses the layout of xfb.c: the stride at Begin,
the 4 byte counts at End and Pause, and the counts read back at Resume.
The range math of xfb_bind is snx_xfb_range in xfb_stores.h, so that a
test can check it.

Tested: the macos preset builds with no warnings in the changed files.
shader_direct_structure, shader_direct_regressions and vulkan_driver,
vulkan_release and vulkan_backing pass. The new checks (fog word, ranges
over begin, 2 draws, pause and resume, and vulkan_nvn_xfb in stores
mode) each fail on a mutant of their fix. check_nvn_xfb passes in stores
mode on MoltenVK, and spirv-val passes the capture's SPIR-V. Not tested:
a game run, and a driver with the extension.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Avoid equal NVN geometry updates, update only changed viewport slots, use
exact pending-page occupancy bitmaps and batch removal of sorted owners.
Retire completed ASTC encoder uploads from the outstanding work budget,
keep CPU-only texture and target input in host staging, defer pipeline
cache snapshots around active compilation and preserve 30 fps at 350 Hz.

Add slow-frame resource/internal-pipeline/wait attribution and regression
coverage. Add isolated paired game runs and test-only compilation probes.
No shader quality reduction, draw skipping or native NVN speed claim.

Verified before the rebase with 26 selected CPU tests, later 10 CPU
checks, ASTC exact-output/default/pieces/wait/retire tests, partial texture
updates and full headless default/heaps/UMA configurations on RTX 4090.
NVN draw, ownership and pending-page checks passed ASan and UBSan.
TotK 1.4.3 was run interactively with explicit descriptor heaps. Manual
routes and cache states differed, so they do not establish gameplay gains.
Publish all 102 synthetic CPU samples with timing methods and fixture provenance. Separate component gains from configuration experiments and uncontrolled game observations. Record post-rebase checks, local toolchain failures, prerequisite skips and platform limits.
Compile the cache saver fixture from the same focused production implementation as pipeline.c. ASan retains constant callback tables from the complete pipeline translation unit, which pulled unlinked shader and Vulkan dependencies into the fixture despite section garbage collection.

Move the activity and saver bodies unchanged into a private include and remove the fixture section-GC options. Keep ASan and UBSan enabled. Reproduced the original instrumented link failure, then passed the CMake SNX_TEST_SANITIZERS=ON test, ordinary cache/file tests and the full Vulkan headless regression after rebuilding the runtime.
Run fake Python runtimes through sys.executable while retaining the real subprocess runner, timeout handling and evidence checks. Use a native absolute test source path and hash the original settings bytes so Windows CRLF does not break the fixture.

Require each rejected fake run to report its intended failure, preventing a launch error from masquerading as timeout or mutation coverage. All 14 unit tests and the CTest documentation/material checks pass locally. Record the sanitizer fixture fix and native Windows verification limit in the measurement report.
misc.c's caps_save reads it since the album change: an -O0 build keeps that
reference, and the test failed to link.

Change-Id: Ia340ece2da4e7b3754b029b79a7ad7e4b3045eb0
Signed-off-by: AO55 <AO55@reden-emu.dev>
A player's document picker on iOS did not give the file back. The picker
opened and showed the dumps, but a tap on Open did nothing. The launcher
logged nothing of it, so the log could not tell where it stopped. The
cause was the host: the app ran in LiveContainer, and its Fix File Picker
option made the picks work.

With Debug's Log level at 2, the launcher now logs these lines on iOS, and
on macOS where the system has them:

- picker: each step of the iOS document picker. An open with no answer
  after it is a pick that the system did not end.
- dialog: the answer of each picker, or the error of SDL.
- lifecycle: the iOS app going to the background and back, and the low
  memory warnings, with what the menu had going.
- run: and recompile: each start and end, with the command, the status,
  the time, the free disk space, and on iOS the memory of the app.
- state: each change of the thermal state and of the low power mode.
- folders: the names and sizes in dumps/, keys/ and recompiled/ at the
  start. Of a key file, only its name and size.

The iOS banner now always gives the free disk space, the bundle and the
program of the process (they differ under a host such as LiveContainer).
It also says if the last start did not end with exit(), from a mark in
logs/.running.

Verified: the ios and macos presets build with no new warnings. The gui_
and runtime_architecture tests pass. Not run on a device yet.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A player's document picker gave no file back. The cause was LiveContainer,
which ran the app in its own process: its Fix File Picker option made the
picks work. The banner gave the bundle and the program of the process, but
a reader had to compare the two paths.

Now the banner adds a host: line when the program of the process is not in
the bundle of the app, and names the option of LiveContainer. The docs tell
LiveContainer users to enable it.

Verified: the ios preset builds with no new warnings. Not run on a device,
in LiveContainer or out of it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A review found that the new logs said wrong things on iOS:
- A game ends the app's process with plat_exit_now, and _exit runs no
  atexit handler. So logs/.running stayed, and the next start blamed a
  crash or the memory limit after each normal end. plat_exit_now now
  calls apple.m's snx_apple_exit (weak, as snx_apple_power_watch) first.
- A game start on iOS went through play() and wrote no run: line.
- SDL_Quit cleared the lifecycle event watch before the game ran. The
  UIKit observers of gui_apple_state_watch now cover the whole process.
- A second picker that the Swift side refused cleared the callback of
  the picker on screen.
Also: picker_done was a copy of folder_picked, run_said wrote the argv
that run_out already writes, the new paths give ~ for the home
(snx_home_short), the disk line says unknown when the query fails,
localtime_r has its check, and apple.m keeps its new state in one struct.

Tested: the macos preset builds with no warnings in the changed files,
check_compile.py passes main.c and plat_posix.c for macOS and SNX_IOS,
apple.m and Frontend.swift type-check for iOS, ctest -R gui passes 25 of
25. Not tested: a run on a device.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Vita loader had the only zip reader, private to vpk.c. The Android app driver reads APK members again and
again (DEX files, resources, assets), so the reader moves to src/common/utilities/zip.c. It now reads the
directory once, sorts the names for lookup, and reads members by index. The Vita loader extracts and reads
param.sfo through it.

Verified: the Vita tests pass (ctest -R vita), and the new driver reads and inflates every DEX member of an APK
through it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Android driver's native bridge runs an app's arm64 libraries. They
are built for every phone, so they sign return addresses with PACIASP
and check them with AUTIASP, which are HINT-space NOPs on a CPU without
pointer authentication. The max target decodes them as FEAT_PAuth
instructions, which have no emitter, so each library stopped at its
first function.

SNX_RECOMPILER_A64_ANDROID is Armv8.2 with LSE, RDM, FP16, the dot
product and LRCPC, without pointer authentication: a64.profile's
`target android`. The other targets are as before, so the modules made
for them still match. docs/LIBRARY.md drops its old claim that the
backend runs only the Cortex-A57's instructions:
llvm_qemu_differential checks the max target's emitters.

Verified: llvm_qemu_differential and recompiler_library pass. With the
new target, the bridge loads 20 of a game's 24 arm64 libraries and runs
their constructors (the other four import objects it lacks yet). The
three tried before the change stopped at their first PACIASP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A process ran one guest thread: clone with CLONE_THREAD returned ENOSYS, a futex wait
without a timeout returned ENOSYS, and signal handlers were recorded but never entered.
Threaded programs and anything that relies on a signal handler could not run.

The Linux AArch64 signal ABI (the rt_sigframe at the kernel's offsets, its restore,
the alternate stack, the default actions) is now src/common/runtime/linux_signal.c,
which the Android bridge will share. Threads, futexes and signals are a library of
their own (src/gnuabi/kernel/) over a memory interface, so a second runtime can use
them: guest memory through checked reads and writes, and a base that may be 0.

A thread runs on its own host thread with CLONE_SETTLS, the tid words and CLONE_CHILD_
CLEARTID. The futex is a table of FIFO waiters with WAIT, WAKE, the bitset forms,
REQUEUE, CMP_REQUEUE and WAKE_OP. The JIT, the memory map, the VFS and epoll take locks,
and a fork holds them in a fixed order and makes them again in the child. A signal is
delivered only where every guest register is in the CPU structure: at RtAPI.poll and at
the end of a system call. Its handler returns through SA_RESTORER or a sigreturn page,
and an interrupted call restarts or returns EINTR by the arm64 rules. Network waits
wake on a signal through a pipe for each thread (SnxNetWake).

Faults in generated code still end the process, since their registers are not exact,
and 32-bit guests get EINTR instead of handlers. docs/GNUABI.md lists the limits.

Verified: ctest gnuabi, linux_signal, gnu_extensions and claude_ste100 pass (13 tests).
tools/gnuabi_diff.py --suite all matches qemu-aarch64 in all 7 cases (new: threads,
signals, restart, sigsuspend), each fixture 15 times without a failure. A static glibc
program with 8 threads, a condvar, __thread, pthread_kill, pthread_cancel and
sem_timedwait prints the same as under qemu, and a program that forks while 3 threads
run was correct in 5 of 5 runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebased-by: AO55 <AO55@reden-emu.dev>
The Android bridge answered its own syscall() numbers (prctl, getrandom, membarrier,
getcpu, the clocks) and the GNU ABI runtime had another copy of each. The calls that
need no loader, file system or descriptor table are now src/gnuabi/kernel/system.c,
which both runtimes reach through gnu_kernel_syscall: the clocks, times, getrusage,
sysinfo, uname, the rlimits, prctl, getcpu, the ids, the priorities, the sched calls,
madvise (through a hook of the runtime), getrandom and membarrier. syscalls.c keeps
only the memory map calls. Random bytes come from getentropy, not OpenSSL. The kernel
library has its own directory, so a build without the GNU ABI runtime can link it.

rt_sigprocmask and rt_sigaction now check their arguments in Linux's order: the size,
the read of the new value, its validity, then the write of the old one. An app probes
rt_sigprocmask with an invalid how and an unmapped set and expects EFAULT, where the
kernel library gave EINVAL and the app then crashed.

Verified: ctest gnuabi, linux_signal, gnu_extensions, claude_ste100 and
recompiler_library pass (14 tests). tools/gnuabi_diff.py --suite all matches
qemu-aarch64 in 7 of 7 cases, each fixture and a glibc pthreads program 5 of 5 times.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebased-by: AO55 <AO55@reden-emu.dev>
The Android driver is to decode an APK's images with FFmpeg. FFmpeg's PNG
decoder and encoder need zlib, and the build had only libdeflate and miniz,
which have no zlib stream interface. zlib 1.3.2 is now a CPM package (the
release archive and its SHA-256), built static as libz.a in a folder of its
own, which FFmpeg's configure finds with --enable-zlib and its include and
library paths. The FFmpeg build step depends on it, and its hash is in the
key of the dependency cache.

FFmpeg now also builds libswscale (FFmpeg::swscale), the PNG, JPEG (mjpeg),
WebP, GIF and BMP decoders and the PNG and JPEG encoders. It builds also for
a tree with only the Android driver. All of it stays LGPL (CONFIG_GPL 0 in
the built config.h). zlib's license is installed with the others.

Verified: a configure and a build of the whole tree, FFmpeg's config with
CONFIG_ZLIB, CONFIG_SWSCALE and the new codecs, and ctest -R
"android|runtime_architecture|gui|languages|claude_ste100" (31 passed).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A program's vertex and fragment stages each have a default uniform block,
and glslc put each at the first free binding of set 0. Two stages with the
same other resources then had their default blocks at one binding, and a
Vulkan binding holds one descriptor for both stages. With
GlslcOptions.map_default, the binding map places the default block too, as
a uniform block with an empty name and its size, so a backend can put the
two blocks apart.

Ran: ctest -R glslc (9 tests); glslc_emit checks the new option and the
old behavior without it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A backend that draws OpenGL ES's window with a negative viewport height
gets Vulkan's gl_FragCoord.y, counted from the top, and a backend that
draws framebuffer objects upright gets gl_PointCoord.y the other way up.
zink lowers both in the shader. With GlslcOptions.flip_y, main's start
copies the two inputs into Private variables that the shader reads, with
y as y * flip.x + flip.y and y * flip.z + flip.w, flip a vec4 at offset 0
of a push constant block.

Ran: ctest -R glslc (9 tests). glslc_emit checks the variables with and
without the option, and glslc_shaders runs spirv-val on each fragment
shader compiled with it, es300_window.frag new among them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A signal that ended a wait of the kernel (a futex, a sleep, rt_sigsuspend) took the
thread's interrupt and left its network wake set, so each later network wait of the
thread returned EINTR at once and restarted, forever.

Change-Id: Icb1e2f8ffc75e3bfc50b1642ef87e7633270be74
Signed-off-by: AO55 <AO55@reden-emu.dev>
The socket calls, ppoll, pselect6 and epoll used the descriptor's object after the
table's lock: a close() of another thread freed the socket (or the epoll) under them, so
a waiting recvfrom read freed memory and failed with EBADF where Linux takes the byte.

Change-Id: I5bed80b199623c0282737961a62b575bbeb3db5b
Signed-off-by: AO55 <AO55@reden-emu.dev>
On macOS and FreeBSD the barrier was a fence on the calling thread alone, and a Linux
host's refusal fell back to it too: the guest was told the barrier worked when it did
not. Without the host's barrier membarrier is ENOSYS again, so the guest takes its own.

Change-Id: I86d0e35ec84f2004137d6d17bd40b8eed030f2c5
Signed-off-by: AO55 <AO55@reden-emu.dev>
snx_zip and scarletnx-gnuabi-kernel are new libraries the tests reach: without them in
the list, runtime_architecture --sanitizers fails in the ASan + UBSan job.

Change-Id: I3d195525f5d39454dd809b588797a3b08a40833b
Signed-off-by: AO55 <AO55@reden-emu.dev>
On macOS, which has no real-time signals, the kick is SIGUSR2: a guest's handler for it
took the kick's place, and its SIG_DFL made the next kick end the host process.

Change-Id: I2d8bf19d246ce6cfde9938690ac0c5a4db402b0b
Signed-off-by: AO55 <AO55@reden-emu.dev>
The calls the kernel library answers without a loader had no test, nor the order in
which rt_sigprocmask and rt_sigaction check their arguments: an app relies on its EFAULT.

Change-Id: I1ae5ec69d834a520d615cbf638f550e92ee4c6e1
Signed-off-by: AO55 <AO55@reden-emu.dev>
The target exists for them, and only its setter had a test.

Change-Id: I00a533c18a56be4ad1c1511084d6444082759b67
Signed-off-by: AO55 <AO55@reden-emu.dev>
The first part of an Android app layer that runs an app's code on OpenJDK with ScarletNX's own framework
(docs/ANDROID_APPS.md). DEX classes become version 52 class files with stack map frames. Each Dalvik register
gets JVM locals of fixed types, one for each way the code reads it. Every branch target then has one frame, and a
dataflow pass decides the cases that the bytecode does not tell (if-eqz on numbers or references, int or float
arrays, new-instance before its <init>, a constructor's this).

The rewrites for what ART allows and the JVM does not: synthetic constructors for the calls of an ancestor's
<init> that R8's constructor inlining leaves, receiver casts for protected members that R8 rebinds to their
declaring class, and invoke-super through the superclass.

scarletnx-android --translate=DIR APK translates every class ahead of time. Verified with an Android 16 era
Compose app: its 3725 classes translate in under a second, and every class whose dependencies outside the app
exist links in HotSpot with verification on (3030 now, the rest wait for android.*).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebased-by: AO55 <AO55@reden-emu.dev>
scarletnx-android APK now loads libjvm (JAVA_HOME, or the JDK the build found) and starts it with the
framework's jar, which the build compiles from src/android/framework/. The app's classes load through
snx.dalvik.AppClassLoader, whose native translates each class from the APK's DEX code when the JVM first asks
for it. Binary XML (the manifest now, layouts and drawables later) is read by the HLE of libandroidfw's
ResXMLParser in C (res/axml.c) behind android.content.res.XmlBlock's natives, as Android's own framework reads
it.

Verified with an Android 16 era Compose app: the runtime reads its manifest, finds its launcher activity, and
translates and links the activity's superclasses until android.app.Activity, the first framework class that does
not exist yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebased-by: AO55 <AO55@reden-emu.dev>
The Android app driver's doc moves to docs/android/README.md. INTERFACES.md lists each layer of Android an app
reaches, from DEX bytecode to the kernel and the native libraries, and whether the runtime translates it, maps
it onto a host interface, emulates it at a high level, collapses the subsystem onto one host facility, or
implements it because apps subclass it. It also records what the baseline app references.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Jetpack Navigation reads @Navigator.Name through reflection, and the
translated classes had no annotations. The runtime-visible ones now
become RuntimeVisibleAnnotations and RuntimeVisibleParameterAnnotations.
dalvik.annotation.Signature becomes Signature, and AnnotationDefault
becomes each element's AnnotationDefault.

Compose's view classes call View.setMeasuredDimension (protected) on a
register that holds this. The receiver was cast to View, and HotSpot's
verifier refused the protected access. ART verified that the register's
type is assignable to the member's class, also when the chain between
them goes through framework classes. So a receiver whose static type is
a class of the app (not an interface) is now cast to that type.

Verified: each of the baseline app's 3725 classes translates, and all
of them link against the framework jar with no VerifyError (11 refer to
android.view.RenderNode and RippleDrawable, for API levels below 29).
The app now runs past Navigation's setup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ScarletNX's own android.* now covers what the baseline app reaches on
the way to its first frames. It is not AOSP's framework. Apps subclass
Activity, View, ViewGroup and their callbacks, so those are implemented
with Android's callback order. The system is HLE in the process, as
docs/android/INTERFACES.md lists:

- snx.android.Main boots as ActivityThread.handleBindApplication does:
  the main looper, the manifest (snx.android.app.Package), the
  AppComponentFactory, the Application, the content providers before
  Application.onCreate, then the launcher activity. An uncaught
  exception ends the process, as RuntimeInit's handler does.
- ContextImpl maps the data folders onto a folder of the host, with
  preferences in Android's XML format. The package manager, content
  resolver, window manager and system services answer in the process.
- The libandroidfw HLE gets resources.arsc: configuration matching,
  style bags with parents, themes and AOSP's style resolution
  (src/android/res/arsc.c).
- Native libraries do the work behind thin JNI: SQLite 3.54.1 for
  android.database.sqlite, HarfBuzz 15.0.0 for shaping and metrics,
  with the Noto Sans JP subset beside the program. The build fetches
  them only when the Android driver is on.
- Canvas, RenderNode and Paint record display lists in a little-endian
  byte format, for the Vulkan renderer that comes next.

Verified: SNX_ANDROID_HEADLESS=1 build/scarletnx-android on the
baseline APK starts the Application, WorkManager with its Room
database, and the app's backup worker (which reports success). It then
stays in its main loop. With SNX_ANDROID_TRACE_FRAMES=1, Compose draws
about 60 frames a second, 33 render nodes each, until the timeout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The display lists that Canvas and RenderNode record now reach the
screen. render.c reads each frame's list on the CPU, keeps the
transform and clip stack, and makes shapes into triangles in device
pixels. Convex shapes are fans. Paths, strokes and glyphs (HarfBuzz
outlines) go through the stencil and a cover rectangle, so overlaps
draw each pixel once. The GPU draws with 4x MSAA into the SDL window's
swapchain, or into an image of its own when there is no display.

The main looper's wait now reads the window's events in steps of
4 ms: the left button as a finger, and keys as a US keyboard. The path
record lost its padding, which was relative to a segment that Frame
then joins at any offset. endian.h gets snx_ld_lef32 for the
little-endian floats of the list.

docs/android/HWUI.md gives the format and what the renderer does not
draw yet (bitmaps, gradients, clips to rounded outlines, layers).

Verified: with lavapipe and no display, SNX_ANDROID_SHOT saved frame
60 of the baseline app. Its Material 3 first screen shows correctly:
the title, the card, the outlined and filled buttons and their labels.
Its logo, a bitmap, is a gray square. The rest of the tree builds as
before (only the old -Wpsabi errors of the fp_host tests remain).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Compose caches each vector icon in a Bitmap through a Canvas, so every
icon was missing. A Bitmap is now a GPU image, as a hardware bitmap
is. What a canvas records into a bitmap is drawn into its image before
the frame, through a multisampled image of its own that keeps what was
drawn. Pixels that the app sets go up whole, premultiplied.
createBitmap of a part, a matrix or a scale draws the source through a
Canvas, in place of the CPU loops it had. A bitmap draws with the
paint's alpha, and a SrcIn color filter tints it, as Compose's Icon
does. A Bitmap that the app lets go frees its images.

For runs without a user, SNX_ANDROID_TAPS and SNX_ANDROID_KEYS script
taps and typed text, and SNX_ANDROID_SHOT saves several frames. Keys
come 4 frames apart: the baseline app makes and focuses a new line a
few frames after Enter, as a person's typing gives it time to, and two
frames put the next key on the old line.

Verified with lavapipe and the validation layer (no messages): the
first screen shows all its icons, tinted. A tap on Create file opens
the editor, and typed lines show their results (price = 25,
tax = price * 8% gives 2, a sum line 54), saved in its Room database.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Play bundle (an XAPK or an APKS) is a zip of a base APK and its split
APKs: an ABI split with the native libraries and an asset pack with
the game's data. The driver now installs one as Android's package
manager does. Each APK goes into android/app/<package>/ of the data
folder as base.apk or split_<name>.apk, by its manifest's split
attribute. The arm64-v8a libraries are extracted into lib/arm64/ for
the native bridge. A stamp of the bundle's path and size makes the next
run skip the copy. The app's data moves to android/data/<package>/.

The app opens all its APKs: assets and members come from the base,
then each split. ApplicationInfo gets the splits and nativeLibraryDir.
snx_zip_extract copies a stored member in pieces, so a 532 MB asset
pack is never held in memory.

Verified: a three-APK bundle installs in 4.5 s, and its next run reads
the stamp. Its base boots through the Application and its SDKs to the
Unity activity. The baseline app still types and computes its lines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A large Unity game's Java code (its SDKs: Firebase, Crashlytics,
ReLinker, a vendor login SDK) now runs to the point where Unity loads
its engine library. On the way it needed:

- the library loads of the app's own code. The translator gets a remap
  table, and System.loadLibrary, System.load and Runtime's versions now
  go to snx.dalvik.Runtime, which looks in the app's native library
  folder and calls the native bridge (still to come, so the load fails
  with Android's UnsatisfiedLinkError). HotSpot's loader searched the
  host's library path.
- org.json and android.util's JsonReader and JsonWriter, written from
  their documented behavior,
- AsyncTask on executors with its callbacks on the main thread,
- StatFs over the host's file system, Debug, TrafficStats, shortcuts
  kept in the process, Icon, Person and LocusId,
- sensors and telephony as Off: no sensor and no phone, as a tablet
  without a modem reports. The rotation helpers of SensorManager follow
  their documented definitions.
- PackageItemInfo.loadXmlMetaData, which FileProvider reads its paths
  with.

Verified: the game's Java side runs until Unity reports that it can't
load its engine library. The baseline app still works.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An Android app's lib/arm64-v8a/*.so are AArch64 code for bionic. The
native bridge (src/android/bridge, docs/android/NATIVE.md) loads them
into the JVM's own process and runs them through the recompiler
library. A guest pointer is a host pointer (each CPU's memory base is
0), so libc is mostly the host's own and Vulkan can pass through
later.

- The linker maps a library into a code window, loads its DT_NEEDED,
  applies RELA, packed (APS2) and RELR relocations, and runs its
  constructors. dlopen, dlsym, dladdr and dl_iterate_phdr use it.
- The JIT compiles on a dispatch miss, as the GNU ABI runtime's does,
  with a lock, since guest threads are host threads. The window sits at
  a fixed address, because the cache is keyed by the code's addresses.
- Each thread gets its own CPU state, guest stack and bionic TLS slots
  (the stack guard in slot 5). pthread_create, key destructors,
  pthread_once and pthread_getattr_np (the guest stack) run guest code.
- The HLE of libc, libm, libdl and liblog is table-driven: one adapter
  calls the host's function with x0 to x7, and typed ones do the math.
  Bionic's own types are converted: struct stat, the open flags,
  sysconf's names, epoll_event, addrinfo, sigset_t, mallinfo (through
  x8) and the syscall numbers. The guest's printf and scanf read
  AAPCS64 variadic arguments and va_lists.
- setjmp and longjmp are AArch64 code in the window, which the JIT
  compiles as guest code.
- OpenSL ES and libmediandk give their objects (interface IDs, format
  keys) and report that their engines are not there yet.

--native-test LIB [SYMBOL...] loads a library and calls its functions.

Verified: all 24 arm64 libraries of a Unity game load, and their
constructors run. Its 362 MB engine library's 864 constructors take
170 s on the first load and 1.8 s from the cache. A small library's
exported functions return their values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebased-by: AO55 <AO55@reden-emu.dev>
The native bridge now runs between the JVM and the guest's libraries.

- The guest's JNIEnv and JavaVM are tables of exports over the host
  JVM's own functions. One adapter, hle_call, passes x0 to x5 and v0 to
  v7 as the host's integer and floating registers: AAPCS64 and the
  System V ABI fill each kind in order. So a function of any signature
  needs only its result's kind. The calls with variable arguments read
  them by the signature that GetMethodID recorded, then call the A form.
- FindClass looks in the app's class loader after the framework's, as
  Android's looks in the loader of the class that loaded the library.
- RegisterNatives records the guest's functions. The DEX translator
  gives each native method a body that calls NativeBridge.invoke* with
  a key, the object and the parameters: primitives as bits in a long[],
  references in an Object[]. The bridge finds the function by
  RegisterNatives or its JNI name, and calls it as AAPCS64 passes them.
- NativeBridge.load maps the library and calls its JNI_OnLoad.

Verified: a Unity game's Java side loads its native libraries with
System.loadLibrary. Their JNI_OnLoad functions run, the crash
reporter's native side reports its handler installed, and the run
reaches the engine's SurfaceView. The translated native methods call
the bridge with their keys (javap). The game's 30396 classes translate
with no failure.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebased-by: AO55 <AO55@reden-emu.dev>
The game's native side and its SDKs now get what they ask for after
JNI_OnLoad:

- libandroid as HLE: ANativeWindow is the SurfaceView's surface, the
  host window at the view's size. AAssetManager reads the assets of the
  APK and its splits through the driver. A stored asset (the asset
  pack's blocks) opens as its APK's file descriptor with the asset's
  place in it, as on Android, without a copy. The looper is an epoll
  set, and the sensor manager has no sensors.
- SurfaceView and SurfaceHolder, whose surface the callbacks report
  once the view is laid out, as Android's do.
- libcore.io.Memory, the ART internal that native code finds with
  FindClass.
- android.webkit as Off: no web engine. A WebView loads a blank page
  and reports it started and finished, so an SDK's flow goes on.

Verified: the game's activity reaches onCreate, and its SDKs set up
their WebView module and billing (which reports no service). The run
stops on framework members that are still missing. The baseline app
still starts and shows its files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Android driver runs an APK, or installs and runs a bundle (XAPK,
APKS), so the launcher gets an entry for it after Load GBA ROM. It runs
scarletnx-android on the file, with no game made of it, as a Linux
program runs. The helper runs_as_is now names both, in place of five
checks of the Linux entry. Games lists .apk, .xapk and .apks files and
runs them. R says that an Android app is not recompiled. An APK picked
on another entry is refused with the entry that opens it, as a VPK is.

Verified: the 25 GUI tests pass, with new ones for the entry, the
recent file's "android" word and the launch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebased-by: AO55 <AO55@reden-emu.dev>
An app's SDKs contacted their servers from the computer: crash reports,
analytics, a vendor's login service. The Android driver now follows
ScarletNX's Network setting (network in settings.txt, 0 by default), as
the launcher keeps it in settings.ini for every run, on both sides:

- Java: offline, the JDK's name resolver is snx.android.net.
  OfflineResolver (named in the jar's META-INF/services), which
  answers localhost only, so no name goes to a DNS server. A proxy
  selector refuses connections to other hosts. ConnectivityManager
  reports no network, so SDKs don't try.
- The guest: offline, connect, sendto and sendmsg reach loopback and
  local sockets only (ENETUNREACH else), and getaddrinfo and
  gethostbyname resolve localhost only, as the Switch runtime's bsd
  service does.

Verified: with the setting off, the game's run logs "the network is
off", and its SDKs' connections are refused. In a plain JVM with the
jar, the resolver refuses example.com offline and resolves it online.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The native bridge's libvulkan is a pass-through. Each vk* command the
guest names (dlsym, vkGet*ProcAddr) is an export that calls the host
loader's command of that name, resolved through vkGetInstanceProcAddr
for the guest's instance, so it dispatches by the handle. Structures and
pNext chains pass as they are: a guest pointer is a host pointer, and
the layouts agree on a little-endian LP64 host. hle_call_wide passes up
to 12 integer arguments, the guest's stack slots past x7, as Vulkan's
commands take up to 11.

What changes on the way:
- VK_KHR_android_surface in the instance becomes SDL's surface
  extensions, or VK_EXT_headless_surface without a display.
  vkCreateAndroidSurfaceKHR makes the SDL window's surface on the
  guest's instance, and ScarletNX's renderer gives the window up.
- The guest's allocation callbacks and debug messengers (its code) are
  left out.
- The device is a Mali-G52 with ARM's vendor and driver IDs, in
  vkGetPhysicalDeviceProperties and Properties2 (driver properties
  too), with the host's limits and features.

EGL reports no display and GLES does nothing, on purpose, so that an
engine takes Vulkan.

Verified: it builds. It has not run yet: the game's Java side stops
on a missing framework member before its engine starts its graphics.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bsearch was passed through to the host's libc with the guest's comparator, which the host then
called as host code: the engine of a Unity game died with SIGSEGV at the comparator's address in
the code window, under libc's bsearch. qsort had no entry at all. Both now run the host's
function with a host comparator that calls the guest's through bridge_call. The guest comparator
is kept per thread and restored after the call, so a comparator can sort too.

Verified: the game, which crashed in bsearch during the engine's start, now runs for the whole
150 s of the run without a crash.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An engine's stack capture sends signal 30 to its threads and waits for each handler,
but the bridge only recorded handlers, so the engine stopped at its start. It also
mapped the guest's masks onto the host's, in a process the JVM shares.

The guest's signals, futexes and every syscall() number now go to the GNU ABI
runtime's kernel library over the bridge's memory (base 0, checked through
process_vm_readv and process_vm_writev), so there is one copy of each system call.
bionic's functions only convert: sigaction from bionic's LP64 layout, -1 and errno
from the kernel's results, EINTR or a restart by Linux's rules. The host's dispositions
and masks never change. A handler runs where every guest register is in the CPU
structure: at RtAPI.poll, as an HLE call returns, or, for a thread parked in a
blocking HLE call or outside guest code, from the handler of a host real-time signal
the sender kicks it with, never while the thread holds a kernel lock. New threads start
with their creator's mask. The exports live in a table reserved whole, so a call reads
it while another thread adds one.

SNX_ANDROID_SIGNALS=1 logs each action, send and delivery, and SNX_ANDROID_SAMPLE=1
prints each guest thread's pc, x30 and HLE call every 5 seconds, which found the stall.

Verified: in 5 runs of a Unity game, its signal 30 handlers run (4 to 6 each run),
before and after the engine makes its Vulkan swapchain. No syscall() number is left
unanswered. ctest gnuabi, linux_signal and recompiler_library pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An engine names the GPU with a throwaway EGL context's glGetString(GL_RENDERER) before
it chooses an API, and allows Vulkan only on the GPUs of its own list. With no EGL
display the name was empty, so it took GLES, failed, and blocked on an error dialog.

EGL now gives a display, initializes, and makes contexts without a config
(EGL_KHR_no_config_context) or a surface. glGetString answers in such a context with the
device that Vulkan reports. Nothing draws through GLES: eglChooseConfig finds no
config, window surfaces fail, and the other GLES functions stay absent. The device is a
Mali-G710 now, which such lists hold, where a Mali-G52 is on none of them.

Verified: the engine logs the device Mali-G710, takes Vulkan, makes its instance,
device and a swapchain on the window, and then crashes in the host's driver (lavapipe)
after an image it could not make, the next defect.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Unity game's engine made its swapchain and images 4294967295 pixels wide, and the
host's driver crashed after the image it could not make. The host's surface (headless
here, Wayland's too) reports a current extent of 0xFFFFFFFF, which leaves the size to
the swapchain, and the engine used it as it was: an Android surface always reports its
window's buffers. vkGetPhysicalDeviceSurfaceCapabilitiesKHR and its 2KHR form now give
the native window's size in that case, in the surface's bounds.

SNX_ANDROID_SAMPLE=1 now also prints the count of the guest's vkQueuePresentKHR calls,
and sets each thread's CPU.poll before it samples, so a thread in a loop writes the pc
of the loop at its next backward branch rather than showing the return of its last call.

Verified: with the validation layer, the swapchain and image errors are gone, the run no
longer crashes, and the engine presents about 800 to 1000 frames in its first seconds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Unity game's script failed with ClassNotFoundException for a class of its own APK.
It looks Class.forName(String) up by reflection (Unity's ReflectionHelper), takes its
ID with FromReflectedMethod, and calls it from native code. That form loads with its
caller's loader, which for a JNI call is the loader of the running native method's
class: on Android the app's, here NativeBridge's, the framework's.

A method ID of Class.forName(String) that the guest gets, from GetStaticMethodID or
FromReflectedMethod, is now snx.dalvik.Runtime.forName(String), which loads with the
app's loader. FromReflectedMethod also records the method's signature, for the calls
with variable arguments, from the Method object.

Verified: the game's scripts get past the SDK's start without the exception and reach
the engine's first frame.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Unity game spent minutes after its first frame in the JIT on every run, though the
cache held its code: in two runs, 296 of the 410 units that compiled slowly in the
first compiled again at the same entries in the second. A JIT step explored calls from
its entry breadth first and left out what the process had compiled already, which
depends on which thread reached what first, so the same entry made a different unit,
and a different cache key, from run to run.

A step now explores only inside the aligned 64 KiB block of the code window that holds
its entry, and a call out of the block goes through the dispatch table. A later miss in
the same block compiles the block's functions it reaches again, at most a block.

Verified: three runs in a row. Of the units the earlier runs compiled, 29 and then 18
compiled again, and each run went further (the first frame, then the game's data
index). The game still reaches about 1100 new units in each run, about 440 s in LLVM.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Unity game's engine, tested on Mali and Adreno drivers, made three calls that the
validation layer refused on the host's driver: SPIR-V that writes a Buffer storage
image without the ImageBuffer capability, a vkCmdClearAttachments rectangle of zero
width, and a render pass whose depth and stencil attachment has the color format
R8G8B8A8_UNORM. The pass-through now gives the host the valid call with the effect the
phone's driver gives it: the capability (ImageBuffer, or SampledBuffer for a sampled
Buffer image, both core in Vulkan) added at the start of the module's instructions,
the empty rectangles left out (and no call when none is left), and no depth attachment
for that subpass, with the attachment kept for the framebuffer. Each repair is said on
stderr the first few times.

Verified: with the validation layer at --jit-opt=0, all three errors are gone, and the
three repairs are logged (3 shaders, 1 clear, 1 render pass). In a run without the
layer, the game renders steadily through its login screen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Android driver read its switches from environment variables (SNX_ANDROID_HEADLESS,
_SHOT, _TAPS, _KEYS, _SAMPLE, _SIGNALS, _JIT_VERBOSE, _LINKER_VERBOSE, _FRAMEWORK,
SNX_LOG_LEVEL, JAVA_HOME), which src/ may not do, and the runtime_architecture test
failed on them. The driver has no settings table, so each is now an option of
scarletnx-android: --headless, --shot, --shot-frame, --taps, --keys, --key-frames,
--trace-frames, --log-level, --sample, --log-signals, --jit-verbose, --linker-verbose,
--framework and --java-home. The C parts take theirs through setters before they
start, and the framework's Java side reads its own as snx.android.* system properties.

--jit-opt=LEVEL sets LLVM's optimization of the code the JIT compiles: 2 stays the
default, and 0 compiles several times faster, to test the JIT itself. The cache keeps
each level's code apart.

Verified: runtime_architecture passes. A run with --headless --sample --jit-opt=0
--jit-verbose drew no window, printed the samples and each JIT unit (about 34000 at
-O0), and presented frames steadily for six minutes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The bridge worked only on Linux. It called Linux-only APIs (mmap's MAP_FIXED_NOREPLACE,
gettid, tgkill, SIGRTMIN, process_vm_readv, epoll, signalfd, mallinfo2,
pthread_getattr_np), and its HLE passed bionic's calls to the host's libc as they were,
which is right only where the host has Linux's numbers. On Windows x64, hle_call put
floating arguments in the System V registers, where the Microsoft convention passes
arguments by position.

host.c gives each host its version: the code window at a fixed address (MAP_FIXED_
NOREPLACE, FreeBSD's MAP_GUARD|MAP_EXCL, a checked hint on macOS, VirtualAlloc), the
thread id and the kick of a parked thread (tgkill, thr_kill, pthread_kill, an APC), the
checked guest memory (process_vm_readv, mach_vm_read_overwrite, a pipe's EFAULT,
ReadProcessMemory), and an epoll set (epoll, kqueue, WSAPoll). The carrier is
SIGRTMIN+4 on Linux and FreeBSD and SIGUSR1 on macOS, neither of which HotSpot takes.

Off Linux, the guest has its own errno, set from the host's after each HLE call, and
the adapters translate bionic's values: open and fcntl flags, struct flock and stat,
statfs, dirent, the ioctls, the mmap flags, socket families, levels, options, msg
flags, sockaddr (with sa_len) and poll events. The maps are gnuabi's, now shared: the
errno table goes both ways (and maps the socket errnos, which became EIO), and the stat,
open flag and socket conversions moved into linux_file.h and linux_net.h for both
runtimes. linker.c reads ELF through the recompiler's own elf_defs.h, not <elf.h>.
getaddrinfo and its kin go through the network stack on every host; on Linux the
pass-through gave bionic's AI_ flags to glibc and glibc's EAI codes to the guest.

On Windows, hle_call and hle_call_wide take the order of integer and floating
parameters, given by the JNI and Vulkan entries that have them, and the CRT,
winpthreads, Winsock or Win32 answer the POSIX calls, or an error does.

Verified on Linux: the full build, and ctest gnuabi, linux_signal, runtime_architecture,
recompiler_library, gui, network and languages (43 tests). A Unity game presents frames
steadily for 300 s at --jit-opt=0, as before. Every changed file compiles for
x86_64-w64-mingw32 with -fsyntax-only and the mingw-w64 headers. No compiler here saw
the FreeBSD and macOS branches, and nothing was linked or run on Windows:
docs/android/NATIVE.md lists the limits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On FreeBSD an app crashed in its library constructors, before any window: libthr's
pthread_rwlock_destroy freed a pointer it never made. Off Linux, the bridge kept the
address of a host object at offset 8 of the guest's object, and pthread_rwlock_init
dropped what that slot held, which in an object nobody zeroed was garbage. The scheme
broke too for an object the guest copied and for bionic's static initializers that are
not zero (the recursive and errorcheck mutexes). The host's types themselves don't fit:
FreeBSD's and winpthreads' are pointers to heap objects, and macOS's mutex (64 bytes)
and rwlock (200) are larger than bionic's (40 and 56).

The bridge now implements bionic's mutexes, condition variables, rwlocks, spinlocks,
barriers, semaphores and pthread_attr_t itself, in bionic's LP64 sizes and initializers
inside the guest's storage, with no host object behind them, written from POSIX and
bionic's public headers. Each waits on the GNU ABI kernel library's futex, so a guest
signal runs its handler during the wait; only sem_wait returns EINTR, as POSIX lets
it. They return Linux's error numbers, which differ from FreeBSD's. pthread_create and
pthread_getattr_np convert bionic's attributes to and from the host's.

Verified on Linux: the full build, and ctest gnuabi, linux_signal, runtime_architecture,
recompiler_library, gui, network and android (43 tests), with the new android_bionic_
sync: contention, recursion, errorcheck, timeouts on both clocks, broadcasts, readers
and writers, semaphores, a barrier, spinlocks, the static initializers and a copied
object, 100 runs without a failure and 5 under ThreadSanitizer without a warning. A
Unity game presented frames to the end of a 300 s run at --jit-opt=0. The changed
files compile for x86_64-w64-mingw32 with -fsyntax-only. Not run on FreeBSD, where the
crash came from.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A user's run on FreeBSD died 4 minutes in with SIGBUS (BUS_OBJERR, trap 9: a general
protection fault) at a load in generated code through the address 0x419d143ce333293f,
which is no pointer. The JVM's report gave only the host's registers: nothing named
the guest library or function.

A handler the bridge installs after the JVM's (at the first native library's load, and
for --native-test) now says, for a fault on a thread in generated code, the guest
function or block whose compiled code holds the faulting host instruction, found as
the nearest compiled start below the host pc in the JIT's units, with its library and
offset, then the pc and registers the code stored last and a backtrace by the guest's
frame records. Then it gives the fault to the JVM's handler, as it gives it every other
fault (the JVM's own null checks among them). Windows gets the same through a
vectored exception handler.

Verified: a test library whose function loads through that same address, run with
--native-test, reports the function (libcrash.so+0x432c). A Unity game ran 240 s
without a report and kept presenting frames, so the JVM's own faults still reach it.
fault.c compiles for x86_64-w64-mingw32 with -fsyntax-only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A user's run on FreeBSD crashed a minute in, in an engine's il2cpp code: a string
builder's ToString loaded its first chunk's link to the previous one, found 0x11 for
null, and read 0x31. The guest crash report named the function, and the field is one
il2cpp never writes, as its collector hands out zero memory. The collector gives free
pages back with madvise(MADV_DONTNEED) and takes them again as zero: Linux's advice
replaces a private anonymous range with zero pages, but FreeBSD's and macOS's keep the
contents, and Windows had none. On Linux, making MADV_DONTNEED keep the contents gave
the same crash in the same function.

The HLE of mmap, mprotect and munmap now records the guest's private anonymous mappings
with their access, and off Linux MADV_DONTNEED maps fresh zero pages over the recorded
parts of its range with that access (a new anonymous MAP_FIXED mapping, or a decommit
and a commit on Windows), which also frees the old ones. Linux keeps its own advice.

Verified: on Linux with MADV_DONTNEED sent through this path instead, the game ran
300 s without a crash and presented frames to the end. The new test
android_host_anon checks zero pages, the access of a part protected apart, a range
forgotten after munmap and a cut inside one part. ctest gnuabi, linux_signal,
runtime_architecture, recompiler_library, gui, network, android and languages pass (44
tests). host.c and the test compile for x86_64-w64-mingw32 with -fsyntax-only. Not run
on FreeBSD.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A user's run on FreeBSD crashed 72 s in, in an engine's reader of its .blk asset files:
the offset at +0x28 of a header held the bits of a double, and the load through it
faulted. The header is decrypted in place, with a table its code makes from rand()
after a fixed seed. The bridge passed rand and srand to the host's libc. bionic's
rand() is random(), the BSD additive feedback generator, and so is glibc's, which is
why Linux decrypted the files right. FreeBSD's rand() is another generator, as is
macOS's, and Windows had a stand-in of its own.

rand, random, srand and srandom are now the bridge's own on every host: 31 words of
state with the feedback 3 apart, seeded by the Park-Miller recurrence and run 310
times, a seed of 0 taken as 1, under a lock.

Verified: the generator gives glibc's rand() for 11 seeds (0, 1, 2, 42, 2836, 12345,
127773, 0x7fffffff, 0x80000000, 0xdeadbeef, 0xffffffff), 100000 numbers each. An
AArch64 library run through --native-test gets the same hash of 1000 numbers after
srand(12345) as glibc does natively. On Linux the game reaches its network login as
before, and ctest android, runtime_architecture and gnu_extensions pass. hle_libc.c
compiles for x86_64-w64-mingw32 with -fsyntax-only. Not run on FreeBSD, and the
decryption's use of rand() is the strongest explanation found, not one traced to the
call.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
--shot saved only the frames ScarletNX's own renderer draws, which stops presenting
once an app makes its Vulkan swapchain on the window. A run without a display could
count a game's presents, but not show whether they drew anything, and a player's
report of a black screen could not be checked against a run here.

The pass-through now records each device's physical device, each queue's family, and
each swapchain's format, extent and images, made with TRANSFER_SRC as well when shots
are asked for. At a present that --shot-frame lists, a submission on the presenting
queue waits for the present's semaphores, copies the image into a host-visible buffer
and signals a semaphore that the present waits for instead. After the present the
bytes go to the PPM file. It is a test's readback, at those presents only.

Verified: a Unity game run --headless at --jit-opt=0 with --shot-frame=100,500 saved
two 600x1066 images, the second the publisher's splash screen as the game draws it,
through lavapipe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A user's run on FreeBSD still crashed in an engine's reader of its .blk assets, with
the network on: the decrypted header held a count of 0x06aa6448 and an offset made of
a double's bits, the same in every run. Before it decrypts, the game's protection
reads /proc/<pid>/cmdline, /proc/<pid>/status and the /proc/<pid>/exe link. FreeBSD
mounts no /proc, the reads failed, and the game went on with a wrong key. On Linux the
bridge passed them to the host, which answered with the JVM's own process. Making
every guest /proc read fail on Linux gave the same crash in the same function.

The bridge now answers the app's process files itself on every host, from
/proc/self, /proc/thread-self and /proc/<the app's pid>: cmdline (the package), comm,
status (no tracer, Seccomp 2, an app's uid), stat, maps (each loadable segment of the
guest's libraries, at an APK's library folder) and the exe link
(/system/bin/app_process64). open, __open_2, fopen, stat, lstat and access get a
temporary file of the bytes, and readlink the link. Other /proc paths stay the host's.

Verified: on Linux with every other /proc read failing, as on FreeBSD, the game got
past the asset reader to its network login, where this machine's memory ended the
run. ctest android, runtime_architecture, gnu_extensions and claude_ste100 pass.
hle_proc.c and hle_posix.c compile for x86_64-w64-mingw32 with -fsyntax-only. Not run
on FreeBSD.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A file dropped on Load Android APK/XAPK went into the Compile queue instead of
running, and gui_sdl_events failed at the Android launch. The queue for a game not made
yet (4877b705) tested only the Linux entry for a program that runs as it is, and the
recent rows' made program did the same. Both now use runs_as_is(), which names Linux
and Android, as the rest of the menu does.

Verified: ctest gui and languages pass (25 tests), gui_sdl_events among them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A user's run on FreeBSD, whose LLVM is 19, died in LLVM itself: a trap in the DAG
combiner's getZExtOrTrunc while the JIT compiled a unit, a minute after an engine's
login started. Nothing said which unit, as --jit-verbose said each one only once it
was compiled.

--jit-verbose now also says a unit's entry before it compiles, so the last such line
of a run that LLVM crashes is the unit. --jit-keep-ir=DIR saves the LLVM IR of each
unit through the recompiler library's keep-IR folder, so that unit can be compiled
again by itself.

Verified: a 40 minute run under LLVM 19 printed a compiling line before each of its
25301 units and its result after.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A user's run on FreeBSD died in LLVM 19 itself, a trap in its DAG combiner while the
JIT compiled an engine's code at its login. The Android driver compiles an app's
native code at run time with the LLVM the build links, and FreeBSD's llvm package is
19. The other drivers keep building with it.

docs/BUILD.md's FreeBSD section and docs/android/README.md now say to build the
Android driver with LLVM 22 (FreeBSD's llvm22, through -DSNX_LLVM_CONFIG), and the
configure step warns when the Android driver is built with an older LLVM.

Verified: configuring a tree against LLVM 19.1.7 prints the warning.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Once a game made its Vulkan swapchain on the window, ScarletNX's renderer of the app's
Java windows (HWUI) gave the window up and drew nothing more, so a dialog its SDK
showed (the notice that the network is off) never appeared. And the frame was only the
root that drew last, so a dialog replaced the activity under it.

As Android's compositor does it, the app's surface is now under its windows. After the
game takes the window, HWUI draws each frame of every attached root, the first at the
bottom, into a ring of 3 images cleared to transparent, and SurfaceView clears its
area, the hole the game shows through. The images are exported (an opaque fd on Linux
and FreeBSD, a Win32 handle on Windows) and imported on the game's device when both are
the same physical device by UUID. At each present with visible content, a submission on
the game's queue waits for the present's semaphores, blends the newest finished layer
over the swapchain image (one triangle, premultiplied alpha, a render pass that loads
the image) and signals the semaphore the present waits for. A present never waits for
HWUI: it takes the newest layer whose fence is done, and HWUI never writes a layer that
a blend still reads. With nothing visible over the game, the present is the game's own.
--shot saves the blended image. macOS has no export here: its game frames show alone.

Verified: a test overlay drawn in SurfaceView (since removed) blended over the game's
frame in a --shot image with the right premultiplied colors, the game showing through
elsewhere. Without content, no blend ran. The validation layer reported no message the
change added, and memory over a run matched a run without it. ctest android,
runtime_architecture, gui and languages pass. The offline notice itself was not seen:
this machine's memory ends each run before the game's login.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebased-by: AO55 <AO55@reden-emu.dev>
An app stopped at "undefined instruction 0xcec08000" (SHA512SU0) in its
libcrypto while it loaded. OpenSSL's armcap.c finds the CPU's extensions by
running an instruction of each one under a SIGILL handler that longjmps
out. The bridge aborted on each undefined instruction instead, and the
recompiler's Android target has no SHA-512 (getauxval's HWCAP has no
SHA512 bit either).

RtAPI.undef is exact: the generated code has every guest register in the
CPU structure at the call, with pc at the instruction. So the bridge now
raises the guest's SIGILL there, as Linux's force_sig_fault does: the new
gnu_signal_fault of the GNU ABI kernel queues it for the thread, with
ILL_ILLOPC and si_addr, when the guest has a handler for it that the thread
does not block, and the delivery runs the handler at once. A longjmp out of
the handler ends the host's call into guest code, as bridge_run_handler
already handles. Without a handler the app ends with the message, as
before.

Verified: the app's libcrypto passes its probes and the app goes on to
load its libraries and unpack its data. ctest -R "linux_signal|android"
passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An SDL app waited forever with "Waiting for screen orientation to change to
landscape". It asks for a landscape orientation with
setRequestedOrientation and polls Display.getWidth() >= getHeight(). On
Android the window manager turns the display for the top activity's
requested orientation. Here setRequestedOrientation only kept the value, and
the display stayed 600 by 1066.

Device.rotate now swaps the display's width and height for a landscape
orientation on a display taller than wide, and for a portrait one on a
display wider than tall, as Android turns it. The SDL window takes the new
size (nativeResize, its size event follows with the same size). The
display, every Resources (a registry, as Android's ResourcesManager has)
and the roots of the windows take it at once. The manifest's
screenOrientation turns the display before the activity starts. A change of
the display's size goes to the application and to each activity on the
main thread: onConfigurationChanged with the views when the activity's
configChanges names every changed field, and recreate otherwise, as Android
relaunches it.

Verified: the app now sees 1066x600 (DemoRenderer.onWindowResize) and goes
on to make its GL context. ctest -R
"android|runtime_architecture|gui|languages|claude_ste100": 31 passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An SDL app's native code stopped at four of bionic's functions that the HLE
did not have:

- chdir: the app's SDL changes to its data folder, then its libraries open
  their data by relative paths. ICU found no data there, and OpenTTD's
  Textbuf dereferenced the null BreakIterator. The host's chdir is right:
  the working folder is the process's, which the JVM shares, as on Android.
- getifaddrs: it returned 0 without a list, and the game's LAN search read
  a null pointer. It now gives the loopback interface alone in bionic's
  struct ifaddrs, as a device without Wi-Fi has.
- __fread_chk, __fwrite_chk and __strlcpy_chk: the plain functions with
  bionic's size checks.
- isupper_l and the other ctype functions of a locale: bionic has only the
  C locale, so each is the ASCII class (common/utilities/ascii.h).

Verified: the app now runs past these calls to its video mode and its main
loop. ctest -R "android|runtime_architecture|gui|languages|claude_ste100"
passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An SDL app stopped with NoClassDefFoundError for
javax.microedition.khronos.egl.EGLContext: its GLSurfaceView makes its
context and window surface with Java's EGL10, and its native SDL draws with
libGLESv1_CM (textures, glTexSubImage2D, glDrawTexiOES, glDrawArrays). The
EGL had no config and no surface, and no GLES function drew.

- javax.microedition.khronos.egl and .opengles are in the framework.
  snx.android.opengl.Egl10 is JSR 239's EGL over the bridge's EGL
  (hle_egl.c), so a context and surface that Java makes current are current
  for the native GLES calls of the same thread, as on Android.
- hle_egl.c has GLES 1.1 configs (RGBA 8888, RGB 888 and 565, with the
  depth and stencil sizes apps ask for), eglChooseConfig's match and order,
  window surfaces, eglSwapBuffers and the queries. A context without a
  config still answers glGetString for an engine's GPU probe, and an engine
  that asks for GLES 2 or 3 still finds no config and takes Vulkan.
- hle_gles.c is GLES 1.1's fixed function over Vulkan. It is a Vulkan app
  of its own on the host window, made through the pass-through's commands
  (hle_vulkan.c now has host-side forms of its instance, surface, device,
  queue, swapchain and present commands), so its presents get the
  renderer's layer and --shot as a guest's Vulkan presents do. A frame is
  one command buffer: draws in a render pass, texture uploads between
  passes, client arrays converted into one vertex format, GL's bottom-left
  origin by a negative viewport height. A GL_RGB texture of bytes on a
  device without that format is RGBA8, written by a compute shader
  (gles_rgb.comp) from the packed rows.

Not done yet: GLES 2 and 3, depth and stencil, lighting, fog, alpha test,
mipmaps, a second texture unit, pbuffers, and glReadPixels (zeros).

Verified: the app makes its context and surface, sets its 1066x600 video
mode and presents its frames on lavapipe in a --headless run. ctest -R
"android|runtime_architecture|gui|languages|claude_ste100" passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An SDL app's libapplication links libz.so, which the HLE knew as a system
library but had no function of: zlibVersion and every other call returned 0.
OpenTTD then could not read its zlib-compressed title savegame, and made a
new random map for its title screen instead, which took minutes of JIT time
(2 presents in 240 s).

hle_zlib.c gives zlib's functions, the gz files' too, from the build's
static zlib (snx_zlib, now with gz*.c and Z_HAVE_UNISTD_H off Windows). On
an LP64 host z_stream has the guest's layout, so they are called with the
guest's arguments as they are. A stream's allocator, when the guest gives
one, is the guest's code: the init functions put host functions that call
it through the bridge in its place, and the end functions put it back.
Windows' uLong is 32 bits, so the guest has no zlib there yet.

Verified: the same --headless run now presents 8556 frames in 280 s and
the shots at presents 60, 300 and 900 show OpenTTD's main menu over its
animated title game, with the first-run survey question. ctest -R
"android|runtime_architecture|gui|languages|claude_ste100" passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Engines that ask EGL for GLES 2 or 3 found no config and could only take
Vulkan. EGL now offers the configs with EGL_OPENGL_ES2_BIT and
EGL_OPENGL_ES3_BIT_KHR, and pbuffers, and a context of version 2 or 3 gets
a GLES 3.0 state (gles2*.c), drawn over Vulkan 1.3 with no host GL.

gles_vk.c holds what GLES 1.1 and GLES 2 share, moved out of hle_gles.c:
the device, the swapchains and the frames, with a serial for each
submission and a flush that waits, for glReadPixels, glFinish and
glClientWaitSync. Between passes an acquired image is in PRESENT_SRC_KHR,
so GLES 1.1's render passes and GLES 2's dynamic rendering share a frame.

Shaders go through glslc. The link compiles each stage with a binding map
that puts the two default uniform blocks and each named resource apart,
and moves the fragment inputs to the vertex outputs of the same names.
The loose uniforms are flattened from the module's block type. Pipelines
come from the draw's state and a cache by its hash, with the rest as
Vulkan 1.3 dynamic state. The window is drawn with a negative viewport
height and framebuffer objects upright with the front face turned, so
textures keep GL's row order. GL's clip depth goes through
VK_EXT_depth_clip_control. 3-component texture formats that the device
does not have are expanded by gles_expand.comp on the GPU, and
glReadPixels blits on the GPU into host-cached memory.

hle.c makes one export of each name that both GLES libraries have, which
calls the current context's.

Ran:
- ctest -R "android|runtime_architecture|gui|languages|claude_ste100|glslc":
  42 tests pass, with the new android_gles2 (a triangle, textures, blend,
  depth, an FBO sampled back, instanced draws with a divisor, a uniform
  block, client arrays, a line loop, a blit, a copy into a texture on
  lavapipe) and android_gles2_validation (the same under Khronos
  synchronization validation, no errors).
- OpenTTD headless with shots at frames 60, 300 and 900: the main menu
  shows as before. Its SDL still asks for a GLES 1 context.
- Genshin: a short run. Its throwaway context is GLES 3 without a config,
  and it still takes Vulkan (its swapchain and pipelines are Vulkan's).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebased-by: AO55 <AO55@reden-emu.dev>
An engine that finds GLES 3.1's functions by eglGetProcAddress got the
HLE's missing stubs. These are now there: compute shaders and their
indirect dispatch, shader storage buffers, image units, glMemoryBarrier,
glDrawArraysIndirect and glDrawElementsIndirect, the vertex attribute
bindings, multisample textures, glGetTexLevelParameter*, the sample mask,
the depth and stencil texture mode, the program interface queries and
GLES 3.1's limits. The vertex arrays now keep their bindings apart from
their attributes, as GLES 3.1 has them. A texture bound to an image unit
rests in GENERAL from then on. A buffer that the GPU writes in the frame
being recorded is read back after a flush of that frame.

A context still names itself GLES 3.0: separate shader objects are not
there yet.

Ran: ctest -R "android|runtime_architecture|gui|languages|claude_ste100|glslc"
(42 tests). android_gles2 now also checks a compute shader's storage
buffer read back through glMapBufferRange, an image written by an
indirect dispatch and sampled by an indirect draw, a storage block's
binding from glGetProgramResourceiv, and two interleaved attributes of
one vertex binding. android_gles2_validation reports no errors. No game
run: neither OpenTTD nor Genshin draws with GLES 3.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebased-by: AO55 <AO55@reden-emu.dev>
GLES 3.1's program pipelines were missing, the last large part of its
API. glCreateShaderProgramv makes a separable program of one stage with
its shader kept, and a program pipeline's stages draw through a hidden
program that links their shaders together, so the binding map and the
link by name work as for one program. Each draw copies the stages'
default blocks, sampler units and block bindings into it.
glProgramUniform* writes a named program's uniforms, and glUniform*
writes the pipeline's active program when no program is in use.

A context of version 2 or 3 now names itself GLES 3.1 (GL_VERSION,
GL_SHADING_LANGUAGE_VERSION, GL_MINOR_VERSION), and EGL takes a context
of 3.1. Atomic counters are not there, as glslc has no atomic_uint: their
limits are 0.

Ran:
- ctest -R "android|runtime_architecture|gui|languages|claude_ste100|glslc":
  42 tests pass. android_gles2 now draws through a program pipeline of
  two separable programs, with a uniform of each set by
  glProgramUniform*, and changed between two draws; and checks
  GL_MINOR_VERSION. android_gles2_validation reports no errors.
- Genshin: a short run. Its throwaway context now reads
  "OpenGL ES 3.1 ScarletNX", and it still takes Vulkan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Engines look up GLES 3.2's functions, and their EXT and OES forms, when
the extensions are there: those calls reached the HLE's missing stubs.
These are now there: glDrawElementsBaseVertex and its range and
instanced forms, glCopyImageSubData as a copy on the GPU between
textures and renderbuffers, glGetGraphicsResetStatus, glReadnPixels,
glGetnUniform*, glPrimitiveBoundingBox, and the debug calls, which do
nothing. A context still names itself 3.1: glslc has no geometry or
tessellation stage.

Ran: ctest -R "android|runtime_architecture|gui|languages|claude_ste100|glslc"
(42 tests). android_gles2 now draws with a base vertex from an index
buffer, and samples a texture that glCopyImageSubData wrote;
android_gles2_validation reports no errors. No game run: neither OpenTTD
nor Genshin draws with these calls.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
calloc(packages + 1) wrapped to 0 for 2^32 - 1 packages and the first package was read
into no room; a table chunk under 12 bytes had its header read past its end.

Change-Id: I12c1ca359dfd2f4e8f4011b5c2c2f6d58b80dcce
Signed-off-by: AO55 <AO55@reden-emu.dev>
The ids' count wrapped and an attribute's resource was read from past the document.

Change-Id: I848049de1aedecd2c76284e539e04842d0c4c89d
Signed-off-by: AO55 <AO55@reden-emu.dev>
They become folders and files of the data folder: a / or a .. in one put them elsewhere.

Change-Id: I8382f8cfccc304adc376508643d6e336b3bc7149
Signed-off-by: AO55 <AO55@reden-emu.dev>
Nothing confines it, and the docs said nothing of it.

Change-Id: I2ccec0f05438cc4e7cf30a980df9f8c06b3b41da
Signed-off-by: AO55 <AO55@reden-emu.dev>
The driver found only the build's JDK or --java-home, which the launcher could not give.
A JDK named that does not load is now said with its path and where to set it, not skipped.

Change-Id: I3b6f062e8f5d559f646b2d5bdf040e95c8929122
Signed-off-by: AO55 <AO55@reden-emu.dev>
Only its image codec uses them, and every other build compiled them. Without the driver,
libavcodec.a goes from 25.0 to 21.3 MB, and libswscale.a (7.6 MB) and libz.a are not made.

Change-Id: I4c24f1c9f87fec75f02d32d5398ee227e229c57e
Signed-off-by: AO55 <AO55@reden-emu.dev>
A Unity game with a large Java SDK layer stopped at its first missing framework member
(Messenger(IBinder)), and a coverage scan of its five DEX files found 466 missing classes and
532 missing members in classes we had. This adds all of them, across android.app, view,
animation, transition, widget, text, graphics, os, content, media, util, database, net,
location, hardware and the system service packages. Each member has its Android 16 signature
and a body written from the documented behavior.

Services a desktop lacks report themselves absent as a device without the feature does: no
camera, location turned off, no Bluetooth or NFC manager, ad services and credentials report
errors, a download fails at once. The new managers are registered in SystemServices, with the
Context names they lacked. The app's class loader is now a dalvik.system.PathClassLoader, as on
Android, so the BaseDexClassLoader.findLibrary that apps call gives the native library folder.
A Spinner click opens nothing, since there is no popup window to show its list.

Verified: the coverage scan over the game's DEX files now finds every android.* class and
member, and the jar builds. The game runs past onCreate of its Application into the Unity
engine's native start (RuntimeInitialize, ApplicationInfo).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An app stopped in its activity's onCreate: Drawable.load knew only color
resources and threw for the PNG of a drawable resource. BitmapFactory read
images through javax.imageio, which has no WebP, and gave no nine-patch
chunk.

src/android/hwui/image.c is the codec now, the HLE of Skia's codecs. It
finds the format from the file's signature (PNG, JPEG, WebP, GIF, BMP),
decodes the whole file as one packet with FFmpeg's decoder, and converts the
frame with libswscale to AV_PIX_FMT_RGB32. That format is a 32-bit
0xAARRGGBB in the host's byte order, so it is the layout of a jint on a
big-endian host too. The same pass does the sample size (rounded down, up
for a JPEG, as Skia's codecs do) and the density scale of a resource, with
area averaging. It encodes PNG and JPEG (a quality of 0 to 100 as the
quantizer) for Bitmap.compress. snx.android.hwui.Image has its natives.

BitmapFactory decodes through it and keeps its Options: bounds alone, the
sample size, inDensity and inTargetDensity with inScaled, the preferred
config, inBitmap and inMutable. A PNG's npTc chunk becomes the bitmap's
nine-patch chunk in a device's byte order, as Android's NinePatchPeeker
makes it, scaled with the bitmap, and its padding is the decode's padding.
Bitmap.compress writes PNG and JPEG, and gives false with a warning for
WebP. Drawable.load inflates an XML file by its root tag (a new
createFromXml), and decodes an image file at the resource's density into a
BitmapDrawable, or a NinePatchDrawable when it has a chunk. Canvas.drawPatch
draws the nine parts of a nine-patch, where it stretched the whole bitmap.

Verified: the new android_image test (a PNG round trip with and without
alpha, a JPEG within 24 of its values, a sample of 2, a BMP of known pixels
and the signatures). The app now passes onCreate and loads its libraries.
ctest -R "android|runtime_architecture|gui|languages|claude_ste100": 31
passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebased-by: AO55 <AO55@reden-emu.dev>
An app's call names the SDK's descriptor, which returns Inet4Address, and found no method.

Change-Id: Ia4eba5d409a6bef9b77e88b034dffbcdea97dbc0
Signed-off-by: AO55 <AO55@reden-emu.dev>
@SafeVarargs made it final, where the SDK's is not: such an adapter did not load.

Change-Id: Iae2600cfa29cfc52fb101dcf00b7d9f135e38210
Signed-off-by: AO55 <AO55@reden-emu.dev>
It was final, where the SDK's is not: a class that overrides it did not load.

Change-Id: Ic8f839be8e70f4705c3a3351cc290162bccadc9c
Signed-off-by: AO55 <AO55@reden-emu.dev>
A layer at a time each small encoder dispatch waited for the last: 667 ms for one array.

Change-Id: Ib7a7827858a1b8446d4ccad6d0205054c3acac0f
Signed-off-by: AO55 <AO55@reden-emu.dev>
A transition that names none takes them, and a chained barrier drained the recording ring.

Change-Id: Ie24316c820a7ba100dcad8ffbc805898f48a536d
Signed-off-by: AO55 <AO55@reden-emu.dev>
A load put the game's memory back beside the running session's g_nvn, whose record
memory then cut new recordings over the state's. g_nvn now has a section of its own
with a schema; work waiting on the GPU refuses the save, naming its queue.

Change-Id: I2ccc4e5fa47ce854b564d5582ee88625c4229c9c
Signed-off-by: AO55 <AO55@reden-emu.dev>
The syncs, queues and windows in the game's memory hold plat_ns times, which count from
the process's start: a state from a longer run made a later process wait out the gap.

Change-Id: Idf91dd9f4ab82f78a5d7917a772730e355df254f
Signed-off-by: AO55 <AO55@reden-emu.dev>
A state loaded as the game starts (the launcher's Play from a state) went on calling
the driver's own functions, whose slots that process had not taken yet.

Change-Id: Ib1a19f569b5fda5acab8361d95d592cc3a3e40cb
Signed-off-by: AO55 <AO55@reden-emu.dev>
Every look at 50%: a skin at 100 stood far above the built-in one, whose grey
is already faint.

Change-Id: I3a16a399fd1a941413544dd112e591c88a1c360a
Signed-off-by: AO55 <AO55@reden-emu.dev>
A RetroArch overlay keeps its sticks on other pages than its D-pad (libretro's
retropad: landscape-both-analog); each page is weighed, and the log says why.

Change-Id: Iefcf2e5b55d126000b14dafec010c3631dae6692
Signed-off-by: AO55 <AO55@reden-emu.dev>
White lines alone, after libretro's flat retropad, drawn by scripts/build-skins.py
for every control: sticks, L3, R3, Capture and Home in the same lines.

Change-Id: I2e81478c231630642857f36bdd7c37ca892ca14c
Signed-off-by: AO55 <AO55@reden-emu.dev>
controls_skin is line unless the .ini says otherwise; empty is still the
built-in look, so a .ini that gives it empty keeps that.

Change-Id: Ibb54bbd19389caee78dd62016b7450c3558d3ed3
Signed-off-by: AO55 <AO55@reden-emu.dev>
Exception messages and method bodies in these files match AOSP's (Apache-2.0), which
asks for its copyright lines, its license text and its notice to go with them.

Change-Id: I0e03642cc3eecbf9295eb9dc179ac5b08c4051a4
Signed-off-by: AO55 <AO55@reden-emu.dev>
The launcher and a game hold .running-<pid> beside their log until their exit, and the
next start says one nobody holds, with the reason Android 11 and later keep for that
process. Its path has no limit, where apple.m's lost one past 1024 bytes without a word.

Change-Id: Idd43d484d67c7810ce4fbba32b6e21d376d752cb
Signed-off-by: AO55 <AO55@reden-emu.dev>
At Log level 2 each run and recompile has its start and end line on every system, as the
Apple apps had, and every start says the data folder's disk: its MiB free and its size.

Change-Id: I73b46ad3b62db0e7a06514a864a6417d9c40c827
Signed-off-by: AO55 <AO55@reden-emu.dev>
Android gets the Apple apps' state: line, at the start and at each change. Its seven
thermal statuses keep Android's names, and below Android 10 the line says it gives none.

Change-Id: I14f10ea60a1a4c8125315abf8c546881fadd91ef
Signed-off-by: AO55 <AO55@reden-emu.dev>
A child's exit() runs LeakSanitizer, which counted the parent's two paths as leaked
and turned the clean exit into a failure under the sanitizers.

Change-Id: I24bb1842f27577c476417b2974b82d273191a03a
Signed-off-by: AO55 <AO55@reden-emu.dev>
Without a JDK 21 with include/jni.h every configure stopped unless it was told
SNX_BUILD_ANDROID=OFF; now the driver is off and the configure says why.

Change-Id: I35af46371c078689fdd35bba98a58e7c89439ce1
Signed-off-by: AO55 <AO55@reden-emu.dev>
The CPU part of 83d85a5d on feat/ounce ("Bring up an Ounce game on the NVN
loader"), without its NVN, shader, service and memory changes.

- a64.profile: the switch_extended target, the Switch's features with
  FEAT_LSE, FEAT_LRCPC and FEAT_PAuth.
- ir_int.c: the PAuth instructions with SCTLR's EnIA, EnIB, EnDA and EnDB
  clear. PAC* and AUT* keep the pointer. BRA*, BLRA* and RETA* branch to
  the register. XPAC* strip the code for a 39-bit address space.
- ir_codegen.c: ir_int.c's ops are legal under switch_extended.
- The cpu_extensions setting selects switch_extended for the recompile
  (module_llvm.c, the NCE analysis in recompile.c) and for the runtime JIT
  (guest_jit.c). snx_nx_codegen_analyze takes the features.
- cpu.h: stx's local "this" is "requested", a name C++ can include.
- codegen_test: cpu_extensions_test runs the PAuth, LSE and RCpc words in
  the step JIT and the AOT path, and checks that the A57 still refuses them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PACGA computes a code of Xn under the generic key, with Xm or SP as the
modifier, into bits 63 to 32 of Xd, the low half zero. Unlike the other
pointer authentication instructions it has no enable in SCTLR, so it
can't run as a NOP. One game's SDK signs a fiber's context with it, and
the translator had no case for it.

It is now a fixed mix of Xn and Xm or SP, the low half zero. No key is
modelled: what the game signs it checks later with the same instruction,
which gives the same code.

Run on a Radeon 890M host: the recompiled game gets past its fiber's
initialization, where it stopped before. All 775 tests pass or are
skipped (two of the 3DS), the Vulkan ones on RADV.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 2b4f45b5b9d71961942bab0ab7d764b2d55210eb)
The CPU part of bce9db47 on feat/ounce ("Make the NPDM the one Ounce flag,
for the CPU, memory and GPU"), without its memory and GPU changes.

loader/ounce.h has the one test, snx_npdm_ounce: the ACID magic at 0x300,
past the Ounce's 0x180-byte signature and key. The loader puts it in
SnxNpdm.ounce. The recompile (module_llvm.c, the NCE analysis in
recompile.c) takes switch_extended from it. The runtime's npdm_layout sets
g_ounce from the same test, and the runtime JIT (guest_jit.c) takes the
same features from it. An Ounce game so needs no cpu_extensions=1, and the
code made ahead of time and the code the JIT makes agree.

Tests: loader_test parses an Ounce NPDM, a Switch one and one whose magic
lies past the ACID's end. runtime_variants defines g_ounce.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tools/decodetree reads QEMU's .decode files, as QEMU's
scripts/decodetree.py does, in strict C99, so the build needs no Python.
It has two outputs:

- QEMU's: arg_ structs, static trans_NAME(DisasContext *ctx, arg_NAME *a)
  declarations, the format extractors and the decode function, a switch
  tree. Its options are decodetree.py's: --decode, --static-decode,
  --translate, -w, -o. Not supported: --varinsnwidth. For a32.decode,
  a32-uncond.decode, t32.decode, t16.decode and a64.decode of QEMU commit
  a19f59a, its output is decodetree.py's, line for line, but for the order
  of a run of field assignments, which decodetree.py takes from a set and
  changes from run to run.
- --a64-profile, --a64-header, --a64-decoder: the A64 tables that
  tools/a64dec made, from the same parse. a64.c is a64dec's backend, which
  load_rows feeds from decodetree.c's patterns. A pattern's fields keep the
  order of its line, with its format's where @format is. Two rows can
  overlap only when the innermost group they share is a { } group, as
  a64dec's one level of groups allowed. Its output is a64dec's, byte for
  byte, but for the tool's name in the notice, which changes
  SNX_A64_DECODE_HASH and so the JIT and unit cache keys, one time.

tools/a64dec and cmake/a64dec.cmake are gone. cmake/decodetree.cmake has
snx_decodetree_a64(target) in place of snx_a64dec(target), and
snx_decodetree(target OUTPUT ... DECODE ... OPTIONS ...) for the QEMU
output.

Tests: a64_decode, native_codegen, llvm_module, docs_check and
runtime_architecture pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
src/common/cpu/arm/decode/ has QEMU's a32.decode, a32-uncond.decode,
t32.decode and t16.decode, unmodified, from commit a19f59a, the commit
of a64.decode. tools/decodetree makes their decoders in the build.
a32.c and thumb.c include them, as QEMU's translate.c does, and define
the trans_ functions:

- a32.c: each A32 instruction's trans_ function gives its SnxA32Kind
  after the checks of UNPREDICTABLE operands the decoder had, or
  SNX_A32_UNDEFINED. The vector decoder still comes first.
- thumb.c: each T16 and T32 instruction's trans_ function fills the
  SnxThumb operand model. A T32 instruction with an A32 twin is built as
  that A32 word, which a32.c's decoder judges. The coprocessor, VFP and
  Advanced SIMD space still goes to the vector decoder first. unmatched32
  keeps the encodings that t32.decode has no pattern for and that the
  backend ran: the reserved data processing ops and the store-release
  forms with a nonzero Rd field.
- decodetree --argsets writes only the argument sets of a file, which
  thumb.c takes from a32.decode and a32-uncond.decode (t32.decode and
  t16.decode name them !extern) without the A32 decoders.

The hand-written decoders move to tests/support/ as references.
arm_decode_tree checks every T16 halfword, every T32 pair, and the A32
words at a stride of 13 against them (--full: every A32 word). One
difference is on purpose: T32 CLREX with an option other than 1111 was
the A32 word 0 (AND r0, r0, r0) to the old decoder, and is now
UNDEFINED, as the A32 decoder has it.

Tests: arm_decode_tree --full: 4,697,679,872 instructions, 0 differ but
those 30 CLREX words. The ARM, Thumb, ARM7TDMI, ARM11, AGB (gba-tests
ARM and Thumb), 3DS pipeline and nx_runtime_arm32 tests pass, 64 in
all. No game was run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The sanitizers build failed at the first generated decoder: LeakSanitizer
found main's array of argument set and format indexes, which no path
freed, the --argsets one included.

Tests: every decodetree mode (the A32, T32 and T16 decoders, --argsets,
--a64-profile) runs clean under ASan, UBSan and LeakSanitizer on Linux;
before the fix the same run reports the leak at main's xalloc.
arm_decode_tree, a64_decode and arm_isa_profiles pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A heavy frame's 2.1 MB filled the 1 MiB slot and went on in the other one mid-frame:
1142 times in 600 frames of 2.3 million tables; with 8 MiB, 12 in 600 of 3.1 million.

Change-Id: I8528ff3a0a7e336a5ffff7143cc82cc956c54f49
Signed-off-by: AO55 <AO55@reden-emu.dev>
The built-in art was 60% opaque in itself; drawn twice as opaque, its 50% is
the old 100%, and controls_opacity is read as controls_alpha, half of it.

Change-Id: Icf549a46b1691b69650b1f0c3e499d631e43f15f
Signed-off-by: AO55 <AO55@reden-emu.dev>
50 was the default new games' .ini wrote, not a choice: controls_alpha keeps its
own 50 rather than the half, 25.

Change-Id: I7d8b701ae7ebcf93962fcc7d07bd90e221f8fe57
Signed-off-by: AO55 <AO55@reden-emu.dev>
Twice the alpha left 4% of the art up to 26 of 255 off; the art over 0.6 and a
curve that gives 0.6 at 50 match it to rounding, and skins stay linear.

Change-Id: I2993222e80fb3f6331c86b5a579ba60de346cc72
Signed-off-by: AO55 <AO55@reden-emu.dev>
The pressed drawables are a dark cross: alone, the middle sank into a dark game.

Change-Id: Iced43ee9cd3b4bc3d2bdabd0d1a0eae9e1fc3488
Signed-off-by: AO55 <AO55@reden-emu.dev>
MinGW's assert expands so clang saw the surface possibly unset and -Werror stopped
the Windows build; the assignment now stands on its own line.

Change-Id: I603e9cbbf7657253f30cb6afcc2e349f2a8deef0
Signed-off-by: AO55 <AO55@reden-emu.dev>
A full two-way set read 5 to 6 of a frame's draw programs again, 0.33 ms a frame.

Change-Id: I8f93ccd349b3748f2b92c9a10bd1d8421096afa5
Signed-off-by: AO55 <AO55@reden-emu.dev>
The bare 0x9E3779B97F4A7C15 read as a magic number in review; it is 2^64 over
the golden ratio, whose product spreads every bit of a key into the top bits.

Change-Id: I9d24ab3dd42231b1614a515145b95f9b789c9161
Signed-off-by: AO55 <AO55@reden-emu.dev>
Heaps write each draw's descriptors on the GPU thread: on a discrete GPU one open world's
frames went from release to present 1.2 to 1.6 ms later than with sets.

Change-Id: I632a705f4ffa38035c6a3e02cb09f7b7008377ef
Signed-off-by: AO55 <AO55@reden-emu.dev>
Main.exit quit the main looper, whose queue refuses to as Android's does, so every app
ended with status 1. Main runs the main loop itself and stops it at exit.

Change-Id: If1c44b3e4f57c74f02820c378537468ab7c9c2c5
Signed-off-by: AO55 <AO55@reden-emu.dev>
isLoggable followed the least level printed, DEBUG by default, where Android answers false
for DEBUG until a log.tag property says otherwise. --log-level is that property here.

Change-Id: Id7f45f590d1c4192935879416621226e4572eb6e
Signed-off-by: AO55 <AO55@reden-emu.dev>
setDataSource took any path, where Android opens a path or a file: URI first, so a
missing file is FileNotFoundException and the player stays idle.

Change-Id: I8a7e2bc1356f8aa03eb0f587d966ffef820c0ed6
Signed-off-by: AO55 <AO55@reden-emu.dev>
Java's resolver gave the host's answer for localhost, ::1 too where its /etc/hosts has it.
Android's names localhost 127.0.0.1 and ip6-localhost ::1, online or not.

Change-Id: I53fb1401182e712ae8a90c80c15bbd1cd6ea2f50
Signed-off-by: AO55 <AO55@reden-emu.dev>
getQuantityText read the bag with each quantity's attribute ID one off (other as zero, one
as two), so a plural of one and other had neither, and took 0 as zero in every language.
PluralRules now selects the category from CLDR's rules, as ICU does on Android.

Change-Id: I145207a501d571ad59a015a3711f2b328a9f59bb
Signed-off-by: AO55 <AO55@reden-emu.dev>
Both constructors dropped the AttributeSet, so an inflated view had no id, visibility,
padding or background, and a TextView no text. They read them as Android's do.

Change-Id: I3d29dc2c7883b138643851b8822af9faa44b787a
Signed-off-by: AO55 <AO55@reden-emu.dev>
LayoutParams read layout_width as an integer, so a dimension such as "10px" became
wrap_content, and MarginLayoutParams dropped the margins. Both go through TypedArray now.

Change-Id: I9f3f851da8486a3ea1b1f2c614b4fe76d1bb410b
Signed-off-by: AO55 <AO55@reden-emu.dev>
openFd copied any asset out to a file, where Android refuses a compressed one with
FileNotFoundException, as a descriptor reads the APK's bytes in place.

Change-Id: I952dee2dd458cbad872c696fde0d64dbda19378c
Signed-off-by: AO55 <AO55@reden-emu.dev>
writeTo wrote each page blank. A page's display list becomes PDF paths, clips, images and
text, with the subset of its font that the page draws, as Skia's PDF backend writes them.

Change-Id: I5c42278dfb7dc9d08658bc5b9ad8fc0ef3b599c2
Signed-off-by: AO55 <AO55@reden-emu.dev>
setDataSource read "C:\..." as a URI of scheme C and took it unopened, so a missing
file on a Windows host returned instead of throwing FileNotFoundException.

Change-Id: If0a2034e5ce381a72cd764d43d6a5ef606e427ee
Signed-off-by: AO55 <AO55@reden-emu.dev>
Straight to BC7 held the game 50 to 90 ms when arrays came in: RGBA8 shows at once.
astc_mode=2 is BC7 always; Auto is Exact with a budget of 8 GB or more, else BC7.

Change-Id: I2e8e0621b538b8aec837af07fd0641d6a3d2af64
Signed-off-by: AO55 <AO55@reden-emu.dev>
The why starts with the fake opt's path, so a build tree named like build/main-O0 matched
-O[023] and the test failed there.

Change-Id: I0c76cd03176761d64b18defe0ff7b9ccf19157aa
Signed-off-by: AO55 <AO55@reden-emu.dev>
A 3DS game's face library built heads from the stand-in's empty parts (a flat quad face,
no hair); it now gets CFL_Res.dat written from the Switch MiiModel's plush shapes.

Change-Id: I9d62c18bd2aa7b8a3c63eec9188f05b198714990
Signed-off-by: AO55 <AO55@reden-emu.dev>
A part file can take its meshes from a model made in a 3D program, through cgltf: the
node named for a part, in its world space, with its places as child nodes.

Change-Id: Ib9b7b8376b518dee7da294d1c1ef504fbaca86f9
Signed-off-by: AO55 <AO55@reden-emu.dev>
The same sources as the 3DS's file (a glTF model's parts, ours where it gives ours), each
part kept within the console's largest of its kind, which a game's Mii heap is sized for.

Change-Id: I3acfa1aa45fea56b1de74e9119ff5482f6eb3deb
Signed-off-by: AO55 <AO55@reden-emu.dev>
snx_cgltf is linked by tests that run under them; runtime_architecture
named it as built without them.

Change-Id: I42df926124a4c1c98b03f30c166dc05bfdea19e0
Signed-off-by: AO55 <AO55@reden-emu.dev>
Only the NVN path gave a draw its fixed point size; the 3D engine's draws drew every point
1 pixel wide, whatever SET_POINT_SIZE held.

Change-Id: I380b076f42b7e6e997fd87ecc5d7e928a0f86cbb
Signed-off-by: AO55 <AO55@reden-emu.dev>
Only the NVN path gave a draw its depth bounds; the 3D engine's draws drew whatever
SET_DEPTH_BOUNDS_TEST and its two bounds held.

Change-Id: I71ec8a5a82acc3e194af4b3686f0a41d376221ef
Signed-off-by: AO55 <AO55@reden-emu.dev>
Only NegativeY was applied, as the viewport's sign; a swap of x and y drew the picture as
it was. No viewport takes the others, so the stage that writes the position does, before
clipping as the console does; RADV has no VK_NV_viewport_swizzle.

Change-Id: Ib0a5b84edbd59385736f55e375944b7fa1c374ba
Signed-off-by: AO55 <AO55@reden-emu.dev>
VK_EXT_primitive_topology_list_restart restarts a list as the 3D engine does; without it
the index stays a vertex there, as before. An indirect list restarts at Vulkan's own.

Change-Id: Iab8d860da8f5f87e4cca9e28189f7bd9a343d0b1
Signed-off-by: AO55 <AO55@reden-emu.dev>
One file says which drivers break which extension or feature, and the log says why.
The bans the code had move there: dynamic vertex input, MoltenVK's stride, Qualcomm's FTZ.

Change-Id: I2332a7e160632e11dd05f9d303f561f9b9d831a3
Signed-off-by: AO55 <AO55@reden-emu.dev>
Each from Eden, yuzu, ANGLE, DXVK, vkd3d-proton, Dolphin or PPSSPP, with its source and
the case that tests it again; the ones not proven for this renderer only warn.

Change-Id: I5523c2b00c285b2c12a3bb4f928cb0f4886e1ce9
Signed-off-by: AO55 <AO55@reden-emu.dev>
To test a driver again: each key it names is logged with the ban it goes over,
and a key the table has not stops the game with the nearest ones it has.

Change-Id: Iaeb9d6d062fd0105067a060d55ad9d8b6d7f9859
Signed-off-by: AO55 <AO55@reden-emu.dev>
guest_format's ?: of an int32_t and a uint32_t is unsigned: -42 came out as 4294967254.
android_bionic checks the guest's printf through its HLE handler.

Change-Id: I4f005ad546dce0c64971159d01383005fe74679d
Signed-off-by: AO55 <AO55@reden-emu.dev>
scan_pointers read 24 arguments, up to 18 of them past the guest's stack pointer: a native
method called right below the end of its stack crashed the JVM in load64 (1 run in 17).

Change-Id: I7a72f221dd469f50332e95623f7281eabde873af
Signed-off-by: AO55 <AO55@reden-emu.dev>
strerror gave the host C library's words in the user's language, and EIO's for a number it
lacked. bionic's table and "Unknown error N" now give strerror, strerror_r, perror and %m.

Change-Id: I5cf9568eed12311b06f91cd743166ffcb363fe3d
Signed-off-by: AO55 <AO55@reden-emu.dev>
The NDK builds send(), recv() and readlink() of a sized buffer as __sendto_chk,
__recvfrom_chk and __readlink_chk, which returned 0: a native socket sent nothing.

Change-Id: I62f4a845008cf5bb5a743859cfead2107c55596e
Signed-off-by: AO55 <AO55@reden-emu.dev>
Without an HLE each returned its own argument, left in v0: cbrt(2.0) gave 2.0.

Change-Id: Ia1b36d2539fe02bc921f4815b57b8b185e2899e4
Signed-off-by: AO55 <AO55@reden-emu.dev>
They returned 0 without an HLE, so a loop over /proc/self/maps read no line. Windows' C
runtime has neither: one reader serves every host.

Change-Id: If43a3dd9b0518c893d3c68495ee184f839ae9419
Signed-off-by: AO55 <AO55@reden-emu.dev>
sigismember returned 0 without an HLE, so a signal sigpending reported looked absent.
sigset64_t is sigset_t on LP64: its forms are the same calls.

Change-Id: I20c3095d78b2c982706c2008e4693f5aa69d61cf
Signed-off-by: AO55 <AO55@reden-emu.dev>
They were the host's: a guest's setlocale(LC_ALL, "") set the whole process to the user's
locale. bionic's have the C locale alone; a name sets only MB_CUR_MAX (4 or 1).

Change-Id: I50b6cc38c361c18e94e456ad2f2593a603475fa6
Signed-off-by: AO55 <AO55@reden-emu.dev>
The host's locale is the user's, which the JVM sets: a guest's printf gave "3,14",
strftime "ter nov", strtod stopped at the point. A host call into guest code now takes
C (C.UTF-8 on Linux) for its thread until it returns, as bionic has no other.

Change-Id: Ia2f55a142f129204caab90dad34656d9beac4fcd
Signed-off-by: AO55 <AO55@reden-emu.dev>
They returned 0 without an HLE. Linux's run in the guest's C.UTF-8 locale; the
other hosts' take the bridge's own UTF-8, as the rest of the multibyte calls do.

Change-Id: I4424f37d6f9c23cdc9f68ec59604ba1797abad27
Signed-off-by: AO55 <AO55@reden-emu.dev>
getaddrinfo of another machine's name gave EAI_AGAIN (2) offline; Android gives
EAI_NODATA (7), "No address associated with hostname", for it and for .invalid.

Change-Id: I59deeaf3d8ca46988172af03e8f5f473d1e4a036
Signed-off-by: AO55 <AO55@reden-emu.dev>
The host's hosts file may list ::1 for localhost too, which getaddrinfo gave the guest
first, and glibc gave 127.0.0.1 twice for AF_INET. Android's has it once; ::1 is
ip6-localhost, and its lookup ignores the name's case.

Change-Id: I7674e541b27e7b786d12588b83af7d098f253aa6
Signed-off-by: AO55 <AO55@reden-emu.dev>
GetVersion was the host JVM's, JDK 25's JNI 24 (0x00180000); ART gives 0x00010006.
android_jni runs the guest's JNIEnv functions on the host's JVM.

Change-Id: I9eab89b3fee36916695900b8b2632abdecba4c0a
Signed-off-by: AO55 <AO55@reden-emu.dev>
FindClass fell back to the app's class loader on every thread. ART uses the
system class loader on a thread with no native method of the app (one the app
attached), and throws ClassNotFoundException for an app's class there.

Change-Id: I4573787072ebc392472db448dd8545c0120edd92
Signed-off-by: AO55 <AO55@reden-emu.dev>
HotSpot's is CESU-8: a supplementary character came out as 6 bytes, and NewStringUTF
ended a string at a 4-byte sequence. ART's has UTF-8's 4 bytes both ways.

Change-Id: I3a6bc28a93af1ac8189c2a0dc953018352f3d8f4
Signed-off-by: AO55 <AO55@reden-emu.dev>
A socket call before WSAStartup logged "host error 10093 has no translation" and
reported EIO. The stack is down, as net.c's start reports its own failure.

Change-Id: Ib880009bfe2e4314e552be409fc5efe2bcd9abb5
Signed-off-by: AO55 <AO55@reden-emu.dev>
android_bionic used socketpair, which Winsock lacks, and its send on that -1 came
before any WSAStartup (10093). The HLE's start now starts Winsock, and the test uses
a loopback TCP connection with a send on a file first, which is ENOTSOCK on every host.

Change-Id: I4bec828bc9cccf866c86fad102bfe10651496173
Signed-off-by: AO55 <AO55@reden-emu.dev>
hle_pass calls through a type of eight integers, which -fsanitize=function stops at
for hle_strerror_r. strlcpy, strerror_r, basename, strsep, strtok_r and Windows'
64-bit fseek and ftell, the bridge's own functions, get adapters of their own.

Change-Id: I5b3f72e473c54ac8991f40699db81eb5d3a406bf
Signed-off-by: AO55 <AO55@reden-emu.dev>
The exports keep their names, malloc's, in a mapped table that LeakSanitizer does not
search: android_bionic under ASan reported each name as a leak. bridge_init registers it.

Change-Id: Idbd0691b997e582090b079ac6e7216fa6a94c7ea
Signed-off-by: AO55 <AO55@reden-emu.dev>
android_framework checked localhost alone. The resolver also takes LocalHost as
Android's hosts file does, and offline refuses another machine's name.

Change-Id: I6c56c4cf3c248bd3b6f3622cb0f3d58804d4c9f2
Signed-off-by: AO55 <AO55@reden-emu.dev>
lavapipe draws 4, 5, 7, 3, 5, 6 all green with no restart, where RADV draws (3, 5, 6) red;
at 0 both draw the fallback's triangle red and the restart's quad green.

Change-Id: I66b4a0b7867277e4fb447210b334a6fe77807e95
Signed-off-by: AO55 <AO55@reden-emu.dev>
Android's game mode and the makers' game launchers (HyperOS Game Turbo) then list it,
close what runs behind it and offer their performance mode.

Change-Id: I4ba1328ec5a8e949e5441c1de38246c8761c802c
Signed-off-by: AO55 <AO55@reden-emu.dev>
Where the device's subgroups leave a vertex, evaluation or geometry stage out (an Adreno
830 lists fragment and compute), a program there that votes or shuffles was refused, its
draws skipped: it runs as a warp of lane 0 alone, as the console runs one vertex's batch.

Change-Id: If7c8affa7d3608db46ddb6d219d97f34a3209039
Signed-off-by: AO55 <AO55@reden-emu.dev>
Which stages' programs use subgroup operations, and what VOTE and SHFL do in the others,
were not in the log: a skipped draw's cause took reading the driver's properties apart.

Change-Id: I32f2d5fdd213f94584b3e53f14a45ae91ac7bfd4
Signed-off-by: AO55 <AO55@reden-emu.dev>
On a phone the blocks come out of the system's memory: a heap's blocks against what is
allocated in them tells how much room they hold that nothing uses.

Change-Id: Icf58f24924bd81b50c760b70c2643dc02f15b0b5
Signed-off-by: AO55 <AO55@reden-emu.dev>
Their features on, the 1.3 commands under the extensions' names, shaders in SPIR-V 1.5.
A 1.2 device missing one is refused by name; 1.3 devices take the path they took before.

Change-Id: I64dc32c5a66128a0d8832e1588382a54a61ef6b0
Rebased-by: AO55 <AO55@reden-emu.dev>
Signed-off-by: AO55 <AO55@reden-emu.dev>
1.2 runs the Vulkan 1.2 way on a 1.3 device, to test it there; the log says the way and
why, and any other value stops the game, naming it and the two it takes.

Change-Id: Ic486384bdff5357dc3ebb13cab32d4bf75b09846
Signed-off-by: AO55 <AO55@reden-emu.dev>
A game that reaches the keyboard with a non-inline mode (0) logged nothing,
so a log=1 run could not tell whether it got there. Every keyboard now
logs "am: library applet 0x11 (mode N)" when it is created.

Change-Id: I7f86eb4c68e330f876525ea75a87997de4dd3158
Signed-off-by: AO55 <AO55@reden-emu.dev>
A probe that knows machine= gets machine=scarletnx@<the runtime's commit>, so the
cases that end ScarletNX every time are skipped as banned, not relaunched.

Change-Id: I84c5d33de21d849166e3af707db6a200612eafba
Signed-off-by: AO55 <AO55@reden-emu.dev>
The checker's test sent the SubagentStop hook a report whose agent ID came
from $$ between two quotes inside $( ). Bash 3.2, which /bin/sh is on macOS,
expands that to nothing, so the hook saw no report and the test failed on a
Mac, where Linux passed. printf's %s now takes the ID as an argument, which
both shells keep.

Verified: claude_ste100 and claude_ste100_checker pass on macOS.
Mesa's KosmicKrisp runs Vulkan on Metal through the Vulkan loader, and a Mac
needs it to move off MoltenVK as the only driver. The support is new, so
MoltenVK stays the default.

A game's Graphics setting, vulkan_driver, takes auto, moltenvk or
kosmickrisp, and the driver takes --vulkan_driver=. It is listed on macOS
only, as the Android GPU driver setting is listed on Android only. The
runtime looks for the
driver beside the program, which is an app built with SNX_KOSMICKRISP or a
game's runtime copy, in Homebrew's mesa, or in a LunarG Vulkan SDK under
~/VulkanSDK, the newest when there is more than one. KosmicKrisp needs its
ICD JSON and the loader, so the runtime sets VK_DRIVER_FILES and has SDL load
the loader. The log says which driver was picked, then which driver runs on
the device. A driver that is not there is said, and the other driver plays
instead. A value that is no driver stops the run with the line that says so.

The 3DS and Vita frontends take the same three names, as ctr_vulkan_driver
and vita_vulkan_driver, and put the ICD in VK_DRIVER_FILES before their loader
makes the instance. On a Mac without VK_DRIVER_FILES the loader's own driver
is MoltenVK, so moltenvk there is what auto is. The Android GPU Drivers and
Freedreno Settings pages, and the game box's driver rows, are listed on
Android only.

SNX_KOSMICKRISP takes a LunarG Vulkan SDK's macOS folder. CPack puts its
driver, its loader and an ICD JSON with a relative library path in the app's
Frameworks, and the deploy puts the three beside each game's runtime, as the
MoltenVK library is. Homebrew's build links the prefix's libraries and is not
bundled. iOS keeps MoltenVK, as KosmicKrisp has no iOS driver.

A feature comes from what the device reports. A driver that has one uses it,
also where the other driver is missing it, and a missing one takes the path
the runtime already has for a device without it.

Verified on an M5 with macOS 27.2. The ctest suite passes, and with
VK_DRIVER_FILES set to KosmicKrisp's ICD the 15 Vulkan tests pass too,
including the 3DS draws against the CPU reference. The LunarG 1.4.363 SDK,
installed from its notarized installer, served a plain build's
VK_DRIVER_FILES run as KosmicKrisp vulkan-sdk-1.4.363 (729 frames in 20 s),
the app's three bundled files (1138 frames in 20 s), and a 3DS game. Another
3DS game ran on KosmicKrisp through VK_DRIVER_FILES. Three
Switch games and two 3DS games ran unattended on both drivers, with no crash.
The GBA driver presents through SDL, not Vulkan.

Rebased-by: AO55 <AO55@reden-emu.dev>
The MoltenVK pick used the SDK finder, which iOS does not build, so the iOS
app stopped at an undeclared sdk_library. The call is behind !SNX_IOS now.

The GUI test expects the Android driver rows in the add-ons tail, which only
Android builds have, so its assertion failed on Linux and Windows. The tail
follows the platform now.

The app's configure also picked up the Homebrew SDL3 that the shared-SDL test
step installs, so its build rpath no longer matched the binary that the app
packaged, and CPack's install_name_tool failed. The app configure refuses the
system SDL3 now and keeps the pinned static one.

Verified: the macOS GUI test passes the add-ons tail check and continues to
its known Folders check, and the macOS build is green.

Rebased-by: AO55 <AO55@reden-emu.dev>
The game box's rows are nine plus the platform's tail, and the tail has two
more rows on Android, the GPU driver and Freedreno Settings. The test's total
counted the Android tail on every platform, so it failed off Android.
The game box's tail has two more rows on Android, the GPU driver and Freedreno
Settings. The test checked the Android indices on every platform, so Save and
Play were two rows early off Android.
Save and Play sit two rows earlier without the Android rows, so the loops that
walk to them, and the indices they expect, follow the platform's row count.
snx_vulkan_driver_find takes the program, the package prefixes and the SDK folder, so the
new vulkan_driver_pick checks auto, moltenvk and kosmickrisp on every system.

Change-Id: I0b02b8a4d807c8c79a066a194398b4cd7a5b18f2
Signed-off-by: AO55 <AO55@reden-emu.dev>
The "was not found" reasons said ~/VulkanSDK, while the search reads $HOME/VulkanSDK: with
HOME set elsewhere they pointed at a folder it never looked in.

Change-Id: Id7038295ee6904fa58d99a83996bf353a2386dbd
Signed-off-by: AO55 <AO55@reden-emu.dev>
"The other driver plays instead" was wrong for a missing moltenvk, whose place auto's
driver takes, the system's loader on a checkout: the warning names it and its library.

Change-Id: If26c420427841c7373c1ec3f54d213c2e186f77a
Signed-off-by: AO55 <AO55@reden-emu.dev>
The 3DS and Vita frontends take no driver setting (no ctr_vulkan_driver, no
vita_vulkan_driver), so their stdlib.h and vk_common.h serve nothing, nor
vk_common.c's stdio.h.

Change-Id: Ic7613ee66006172e37eac2e8aee18e0ca9f33524
Signed-off-by: AO55 <AO55@reden-emu.dev>
The UI hides no row per platform, as main had it: the Android-only rows, their tests and
gpu_driver's platform ANDROID go, and with them gui_sdl.c's #ifdef inside the arguments
of assert(), which C99 leaves undefined (6.10.3p11).

Change-Id: Iadffa445dafe274c857d0d0f2dd276b11533f03c
Signed-off-by: AO55 <AO55@reden-emu.dev>
Every row shows on every system: platform MACOS, settingsgen's platform word and its flags
go. Off macOS, moltenvk and kosmickrisp warn that the system's driver plays, and a value
that is no driver stops the game naming vulkan_driver, as on a Mac.

Change-Id: I4efc9d2af0b33191299fd82da27f43d993ad0bb4
Signed-off-by: AO55 <AO55@reden-emu.dev>
auto takes KosmicKrisp (the app's, else Homebrew's or an SDK's) on Apple silicon with
macOS 26 or later, else the app's MoltenVK, else the system's loader, and leaves a driver
the environment names; the first vulkan: log line says which driver runs and why.

Change-Id: I78f918304687b6a542c825796956fcfc85d74f5f
Signed-off-by: AO55 <AO55@reden-emu.dev>
edenprobe's probes on a player's machine: a data folder of their own, launched again after
a crash, their counts in a box; Continue and Clear Crash List for a run left unfinished.

Change-Id: Ic637a605ced3ced481d2aa1b7b3520896f12d59d
Signed-off-by: AO55 <AO55@reden-emu.dev>
A draw's new pipeline waited for all of it to compile; it now binds the link of four
libraries, each made once for the pipelines that share it, and the pipeline made whole
replaces the link when a worker has made it.

Change-Id: I83172b18491e3e0d14da8ca8c0070e9c62c983de
Signed-off-by: AO55 <AO55@reden-emu.dev>
Every .ini an older version wrote holds vk_descriptors=0, its default before Automatic,
which reads as Sets picked: those games never took Automatic and said "Debug on" over
the picture.

Change-Id: I091b5c34c5aec608b9114de243b810e0ce7db7a1
Signed-off-by: AO55 <AO55@reden-emu.dev>
A pick of vk_descriptors in settings.ini would stop reaching runs once the runtime lists
vk_descriptors_mode in its place: it is read on that row, said once, and written so.

Change-Id: I7f4e2ec5b8e30838327edd3bbc1fe0244c6f23ff
Signed-off-by: AO55 <AO55@reden-emu.dev>
A game run with a gpu_driver package, then the system's driver, started its one cache over
each time: each driver keeps its files, the shared one of before copied to it once, and a
start over names what of the key changed.

Change-Id: Iafcff5f59c4d63b13ae1a33e5a82fa8b03b2a5ad
Signed-off-by: AO55 <AO55@reden-emu.dev>
Every row of DEPRECATIONS.md's table is a notice's, which the setup test checks; the
per-driver cache's row had none, and its column now names the commit and how it is told.

Change-Id: Ia4b7e140e10e4318bdf40c98594ea28270053204
Signed-off-by: AO55 <AO55@reden-emu.dev>
The two lines said "kept as it is" for the file every driver shared: they name it, say it
stays where it is, and the driver's file it is the start of.

Change-Id: I22317d321262990955eb25dd67595ca197704b9c
Signed-off-by: AO55 <AO55@reden-emu.dev>
The aarch64 runner's lavapipe takes 55 to 58 s for it, so a slow run times out at 60.

Change-Id: I31f77b0f9d9419ded09cbe447d3cb5376b58d444
Signed-off-by: AO55 <AO55@reden-emu.dev>
A pool kept room for the arrays' 512 samplers in all 1024 sets, and Qualcomm's driver
makes the whole pool at once: 470 MiB each, 3.7 GiB in the 8 a game made on a phone.
A frame's pool now holds them for 64 sets (98 MiB there), compute's for none (73 MiB).

Change-Id: Ia72c042fa812211a99db3b573fcbb44ab70cf411
Signed-off-by: AO55 <AO55@reden-emu.dev>
A banned case ends the same way in every run of one build, so a baseline written again
from runs keeps holding it to banned instead of dropping it.

Change-Id: I9f5dd849928a9b1c3a2e9c60f58793ec54ae1307
Signed-off-by: AO55 <AO55@reden-emu.dev>
v0.10.0 runs every case and skips SM4 and DAIF as banned on ScarletNX, so fatal asks for
nothing; its 23 new judge cases pass on lavapipe.

Change-Id: Idec1c9c2d15b548126d909c72afbb4a2a995174f
Signed-off-by: AO55 <AO55@reden-emu.dev>
A probe that knows machine= then skips as banned the cases that end ScarletNX every time,
as scripts/edenprobe.py has it, instead of each costing a launch.

Change-Id: I8493aabc9ee0efac4c817505f46c83824fdc5146
Signed-off-by: AO55 <AO55@reden-emu.dev>
It takes the REST API; the releases/download link answered 504 for hours on 2026-11-08.

Change-Id: I6ba35a09a706d4c1f79d6e841f9667c5945bb201
Signed-off-by: AO55 <AO55@reden-emu.dev>
On the FreeBSD build machine, libcurl's own CMake project does not build
unless CMAKE_INSTALL_MANDIR is set. The build now passes man, a folder
under the prefix that libcurl installs into, which the build never reads.

Tests: a configure and build of build/rel on FreeBSD finish with the
change, and libcurl.a installs into its prefix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The translator casts a value to the narrower class where the code uses
it, for the JVM's verifier. One game's Play Services library stores an
object in a static field of an interface type that its class no longer
implements: R8 took the interface off the class. ART does not check
that store, and the cast that the translator put before it threw
ClassCastException in the class's static initializer.

HotSpot's verifier takes any reference where an interface type is
wanted, as ART's does, so these casts are now left out. DEX's own
check-cast is emitted apart and keeps its cast.

Tests: the game's Games.<clinit> runs, and its activity goes on to
onCreate. android_framework_api and the other android tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The install extracted lib/arm64-v8a alone, so an app with only 32-bit
libraries got none, and its System.loadLibrary found no library. It now
takes the best ABI that the APK and its splits have, in a 64-bit ARM
phone's order: arm64-v8a, then armeabi-v7a, then armeabi. The 64-bit
ones go into the app's lib/arm64 as before, the 32-bit ones into
lib/arm. AndroidInstall keeps the ABI it took.

Tests: an APK with only lib/armeabi installs its libraries into lib/arm,
and an arm64-v8a app's go into lib/arm64 as before. android_inputs and
the other android tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An app with only armeabi or armeabi-v7a libraries could not load them:
the native bridge runs AArch64 code, where a guest pointer is a host
pointer. ILP32 code's pointers are 32 bits, so the 32-bit bridge gives
the guest a window of 4 GiB of its own (arm32.c):

- the libraries, the heap of bionic's malloc and mmap, the files the
  guest maps and each thread's stack are in the window
- the A32 and Thumb block compiler of the GNU ABI runtime runs the code,
  and a table for each library's code finds a compiled block without a
  lock
- an import is an address at the top of the window, which the dispatch
  loop gives to its host handler, with the arguments as AAPCS and the
  softfp ABI pass them. Linux's kernel helpers, which ARMv5 code calls
  for its atomics, are the bridge's too
- the loader applies the four relocation types of these libraries, runs
  DT_INIT and DT_INIT_ARRAY, and gives PT_ARM_EXIDX to the unwinder

arm32_libc.c has bionic's functions in ILP32's layouts, the guest's
printf and scanf, libm, liblog and libdl. GLES 1.1 is hle_gles.c's, its
calls' arguments put in an AArch64 CPU's registers and stack as AAPCS64
passes them. arm32_jni.c gives the guest 32-bit handles for the JVM's
references and IDs, with each method's signature for the calls with
variable arguments. jni.c sends a 32-bit ELF and its native methods
there. NATIVE.md tells how it works and what it lacks.

Tests: one game's 6 MB armeabi engine loads, runs its constructors and
JNI_OnLoad, and its native_start finds its 40 Java methods and reads its
assets. With the framework commits after this one, it draws its menus
and its game. The android tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A game made its sounds' pool in onCreate and stopped there with
NoClassDefFoundError. SoundPool and its Builder now load a sound at
once, tell the load listener on the looper of the thread that made the
pool, as Android does, and give each play a stream ID. Nothing plays:
the framework has no audio decoder, and MediaPlayer completes its clips
at once the same way.

Tests: the game makes its pool in onCreate and loads its sounds, and
onCreate goes on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A game's view is a GLSurfaceView, which the framework did not have. It
makes the EGL display, config, context and window surface on its GL
thread through EGLContext.getEGL(), the runtime's EGL that native GLES
calls see current too. It calls onSurfaceCreated for each new context,
onSurfaceChanged at each size, and onDrawFrame with a swap, continuously
or when asked. queueEvent's events run on the GL thread before the next
frame. onPause gives up the surface, and the context unless the app
keeps it.

The config chooser takes the first config with the colors asked and at
least the depth and stencil asked, as Android's does. The context's
client version is the one that setEGLContextClientVersion gives.

Tests: the game's renderer gets onSurfaceCreated and onSurfaceChanged
at 600 by 1066 on a GLES 1 context, and draws its frames, which
--shot saves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A game's main layout is a <merge>, and the inflater took the tag for a
class name and threw ClassNotFoundException. A merge's children now go
into the root, which it needs with attachToRoot, as Android requires.
An <include> inflates the layout it names into its parent: a merge's
children, or its root view. Before, the inflater left include out, and
also the children of the tags it skipped went into the parent. Now the
whole element is skipped.

Tests: the game's setContentView inflates its RelativeLayout with its
views into the content frame.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An ad SDK checks with it that an activity is in the app, and stopped a
game's onCreate with NoSuchMethodError. It gives the activity of the
intent's component from the package manager, or of the activity that
the package manager resolves with MATCH_DEFAULT_ONLY, else null, as
Android's does.

Tests: the SDK's start goes on past its check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Android gives org.apache.http.legacy to each app that targets API level
27 or older. A game that targets 25 has ad SDKs that make their clients
with DefaultHttpClient, SchemeRegistry and SSLSocketFactory, and stopped
with NoClassDefFoundError in onCreate.

The classes that those SDKs use are now in the framework, with the API
of Android's legacy library, as ScarletNX's own code: the messages,
headers, entities, parameters, contexts, cookies, credentials, schemes,
socket factories, hostname verifiers and the request classes.
AbstractHttpClient runs each request through the JDK's
HttpURLConnection, which keeps the connections and speaks TLS, with the
client's interceptors, retry handler, cookie store and timeouts around
it. A redirect is followed as the parameters ask. The connection
managers keep their scheme registry.

Tests: the ad SDKs make their clients and start, and onCreate goes on.
The network setting is off in these runs, so no request went out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A game's onCreate reads its settings with it and stopped there with
NoSuchMethodError. It gives the shared preferences named by the
activity's local class name, as Android's does.

Tests: the game's onCreate reads them and goes on to onResume.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The framework has no resources of the android package. On a phone the
base Theme sets android:attr/alertDialogTheme, and Play Services' error
dialog reads that style's name and android.R.string.ok. Without them a
game stopped with NotFoundException when Play Services failed to
connect, as it does on a device without Google Play.

AssetManager now has a small table of the framework's own: the base
Theme's alertDialogTheme, a style of type 0xff that no public framework
resource uses, named android:style/Theme.Dialog.Alert, and the English
text of android.R.string's cancel, copy, cut, no, ok, paste, selectAll,
unknownName, untitled and yes. The app's tables come first.

Tests: the error dialog shows with its OK button, and a tap on it
closes it. android_framework_api passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Android's installd makes /data/data/<package>/lib a link to the app's
native libraries, and apps open files there by path. A game reads its
assets from a libdata_*.so in it, which it never loads as a library,
and stopped with "Could not open" without the link.

The install now makes the data folder's lib a link to the app's
library folder. A link that an earlier install made is made again, as
the ABI can change. Anything else there is the app's and stays.

Tests: the game opens its libdata_1024.so through the link and reads
its 3065 images.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GL10 had no methods, so a game's renderer stopped at its Java
glLoadIdentity with NoSuchMethodError. GL10 and GL11 now declare the
GLES 1.0 and 1.1 calls that hle_gles.c has. Gl, the GL object of each
EGL context, calls each one by its name through one native, which puts
the arguments in an AArch64 CPU's registers and stack as AAPCS64 passes
them, as native code's calls come. A pointer is a direct buffer's
memory, or an array's, held while the call runs, from the buffer's
position. glGetString gives the current context's strings.

Tests: the game's onDrawFrame runs its glLoadIdentity and its native
frame, and the frames that --shot saves show its menu.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
--taps and --keys counted the frames of the app's views. A game that
draws on its own GLES or Vulkan surface makes few of those, so a tap at
frame 200 never came, while --shot-frame counts the surface's presents.
Once the app presents, a thread now follows the count of its presents
(hle_vulkan_presents, through Window.nativeAppPresents) and runs the
scripts at each, so both options count the same frames. An app with no
surface of its own keeps the frames of its views.

Tests: a game's scripted taps at its presents 200, 260 and 560 close
its error dialog, start the game and its first round, and the shots at
presents 330, 700 and 900 show the tutorial, the round and the score.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Android apps ship their sounds and music as MP3, Ogg Vorbis, FLAC, WAV
and AAC files, and the build's FFmpeg had none of their demuxers and
only the AAC and Opus decoders. With the Android driver, FFmpeg now also
has the MP3 (float), Vorbis, FLAC, PCM and ADPCM decoders, the MP3, Ogg,
WAV, FLAC and AAC demuxers and their parsers, for MediaPlayer and
SoundPool. All of them are LGPL, as the rest.

Tests: FFmpeg configures and builds on FreeBSD, and libavcodec.a and
libavformat.a define ff_mp3float_decoder, ff_vorbis_decoder,
ff_flac_decoder, ff_mp3_demuxer, ff_ogg_demuxer and ff_wav_demuxer. The
nvdec, vic, opus and android tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The framework had no audio out: MediaPlayer completed each clip at once
and SoundPool played nothing. runtime/audio.c is the runtime's audio,
and snx.android.media.Audio its Java side:

- a source is a file's bytes, which FFmpeg demuxes from memory and
  decodes, and libswresample makes 48 kHz stereo of 16-bit samples
- a sound is decoded whole when it loads, a stream as it plays
- a voice plays one of them with its volumes, loops, rate, pause and
  position, and one SDL audio stream asks the mixer for the sum of the
  voices as the device plays it
- a stream's voice stays paused at its end, for its player, and a
  thread on the Java side tells each watched voice's end

A run with --headless mixes on SDL's dummy driver, which takes the audio
at real time with no sound out, as does a machine whose audio device
does not open. libavformat's avformat.h has an anonymous union, so
audio.c is C11.

Tests: in a headless run of a game, the mixer took 27.7 s of audio in
about 28 s of its run. The game's 26 WAV sounds decode to the frames of
their headers at 48 kHz (within one frame), with their signal (peaks up
to full scale), and its 180 s MP3 music opens as a stream. The android
tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SoundPool loaded nothing and played nothing. A load now reads the
source (a resource, a path, an AssetFileDescriptor's range or a file
descriptor's) and decodes it on the pool's thread, then tells the
listener on the looper of the thread that made the pool, with status 0,
or 1 for a source with no audio that decodes. play gives a stream of
the runtime's audio with its volumes, loops and rate (0.5 to 2), and at
most maxStreams play at once, the oldest stopped for a new one, as
Android does. pause, resume, stop, autoPause, autoResume, setVolume,
setLoop, setRate, unload and release act on the streams.

Tests: in three headless runs of a game with the same scripted taps,
every play (19 in one run, 20 in the others) ended by itself, and its
frames are as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MediaPlayer completed each clip at once, with no sound. prepare now
reads the source (a resource, a path, a file:, android.resource: or
content: URI, a file descriptor's range) and opens a stream of the
runtime's audio, decoded as it plays. start, pause, stop, seekTo,
setLooping and setVolume act on it, getDuration and getCurrentPosition
give its length and place, and its end calls onCompletion on the
player's looper, as Android does. start after the end plays from the
start again. A path still opens when it is set, so a missing file is
FileNotFoundException there, and a network URI (http, rtsp) has no
audio: a clip of length 0. A source with no audio that decodes still prepares as a
clip of length 0, which completes at once, as before. INTERFACES.md
tells what plays.

Tests: a game's music, a 180 s MP3, prepares with that duration and
plays from the game's start in a headless run, and its frames are as
before. The android tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Unity 4 game's player stopped in its constructor at each of them with
NoClassDefFoundError:

- SurfaceTexture: Unity makes one for a camera's preview. Nothing gives
  it images yet: updateTexImage leaves the texture as it is, and the
  transform is the identity.
- XmlPullParserFactory: Unity reads its settings with it. Its parsers
  are the framework's text parser, with namespaces off unless asked, as
  Android's factory gives them.
- ApplicationErrorReport: Unity's crash handler asks the hidden
  getErrorReportReceiver which receiver of the installer takes reports.
  None does here.

Tests: the game's UnityPlayer is made, and its nativeFile runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Unity 4.7 game for armeabi-v7a imports 387 functions that the 32-bit
bridge did not have, and Mono generates and patches ARM code as it runs.
Its libraries now run:

- arm32_thread.c: pthread_create and the rest of the threads in bionic's
  32-bit layouts, mutexes, conditions, keys, onces, semaphores, the C++
  guards of static objects and the cleanup handlers. Every wait waits in
  slices and runs the thread's signals between them, as Linux interrupts
  a wait: Mono's collector stops each thread with a signal. A handler
  runs between two blocks, or in a wait, in Linux's ARM frame
  (siginfo_t, and a ucontext_t whose uc_mcontext the handler may
  change). sigaction, the masks, kill, tkill, pthread_kill, sigsuspend
  and sigaltstack are the guest's own. setjmp and longjmp are guest
  code. The system calls that guest code makes itself are the bridge's:
  cacheflush, futex, gettid, tkill, tgkill, clock_gettime.
- arm32.c: code outside the libraries compiles from where it is, kept
  by its page, and cacheflush drops the blocks of the range it names.
  A handler may set the pc instead of returning. A thread has the stack
  size its attributes ask for. mmap's MAP_FIXED takes the address.
- arm32_shim.c: the 64-bit bridge's EGL, GLES 1.1 and 2.0 and
  ANativeWindow handlers, and its handlers of files, descriptors,
  sockets and the process, called with an AArch64 CPU of the call's
  arguments. Host objects are 32-bit handles. glShaderSource,
  eglChooseConfig, glGetVertexAttribPointerv and a client array's
  pointer (an offset while a buffer is bound) are converted on their
  own. libandroid's looper, input queue, configuration and sensors (none)
  are the bridge's own. hle.c gives the handlers by name (hle_find).
- arm32_posix.c: the functions whose arguments have ILP32's layouts:
  directories, fcntl, poll, epoll_wait and select in slices, the memory
  maps, time, the process, strings, ctype's tables, wide characters, the
  environment, the names of the network, zlib with its z_stream, SHA-1.
- arm32_libc.c: the rest of stdio, fstat and lstat. The guest's errno
  is Linux's positive number (gnu_host_errno gives it negated).
- arm32_jni.c: a thread that the guest made is attached as a daemon and
  detached at its end. Class.forName(String) becomes Runtime.forName,
  which loads with the app's loader, as the 64-bit JNI gives it.
- dlsym of a library's handle searches that library first: Unity's
  libmain asks for libunity's JNI_OnLoad.

bionic's sem_wait gives EINTR only to apps that target API level 24 or
newer, so the wait goes on after a handler.

Tests: the game's Mono starts its collector and JIT, its C# code runs,
it makes its GLES 2 context through native EGL, and it draws its menus
and a level (with the framework commits after this one, for its input
and its audio buffers). A headless run reports no import or system call
that the bridge lacks. A 32-bit GLES 1.1 game draws its menu, tutorial
and game as before. The android tests pass, but for android_bionic's
two sscanf checks by position, which fail on origin/main on FreeBSD too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FMOD, which Unity plays its audio with, allocates a direct ByteBuffer in
Java and writes its samples into it from native code. A 32-bit library
reaches only its 4 GiB window, so GetDirectBufferAddress of the JDK's
buffer gave it nothing. The translator now sends
ByteBuffer.allocateDirect to snx.dalvik.Runtime, which gives a buffer
of the window's memory while a 32-bit library runs
(NativeBridge.allocateGuest) and frees it when the buffer is
unreachable (a Cleaner), and the JDK's own buffer otherwise. On Android
all of an app's memory is one address space, so either reaches its
native code.

Tests: a Unity 4.7 game's FMODAudioDevice makes its buffers, and the
"GetDirectBufferAddress of a buffer outside the guest" lines are gone.
The android tests pass, but for android_bionic's two sscanf checks by
position, which fail on origin/main too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Unity 4.7 game's activity is a NativeActivity with Unity's
ForwardNativeEventsToDalvik meta-data: its player ignores the touches
that reach its views, and reads them from the native input queue
instead. The framework loaded the activity's library and ran nothing
else, so no tap reached the game.

NativeActivity now calls the library's ANativeActivity_onCreate (or the
function of android.app.func_name) with an ANativeActivity in the
32-bit guest's window: its JavaVM, JNIEnv, activity, data paths and SDK
level. It runs the callbacks that the library sets at onStart,
onResume, onPause, onStop, onDestroy, onWindowFocusChanged,
onConfigurationChanged and onLowMemory. It takes its window's input
queue, as Android's does. The system's touches and keys then go to
that queue (ViewRootImpl), not to the views. The native code reads
them with AInputQueue_getEvent and the AInputEvent, AMotionEvent and
AKeyEvent getters, and the looper that the queue is attached to wakes
for them. Window.takeSurface keeps its callback: the window's surface
is its views', so no surface callback runs. The 64-bit bridge has no
glue yet: its NativeActivity loads the library as before.

Tests: in a headless run of the game, a scripted tap on its
Singleplayer button opens that menu, and a tap on Training starts the
level, which draws its gun, its HUD and an enemy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
NATIVE.md's 32-bit section said the bridge had no threads, signals,
sockets or native EGL. It now tells how the threads, the waits and the
signals' frames work, the JIT's code and cacheflush, the 64-bit
handlers that the shim calls (files, sockets, EGL, GLES 2), the direct
buffers in the window, Class.forName, and NativeActivity's glue and
input queue. The apps it was checked with are an armeabi GLES 1.1 game
and a Unity 4.7 game for armeabi-v7a.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Its files take bionic's ILP32 layouts from the host's POSIX ones (struct stat, struct tm,
the socket and resource limit headers), which MinGW lacks, and arm32_init refused Windows
at run time already. arm32_none.c gives jni.c that refusal, with the library's path.

Change-Id: I280786cdf6ee9fbeed2e1e5ff3942156fa27d488
Signed-off-by: AO55 <AO55@reden-emu.dev>
macOS's <sys/signal.h> defines SIGINFO, so the enum of the frame's sizes did not compile
there.

Change-Id: Ia0c2ea194cabbe040d1d447374863102b9381095
Signed-off-by: AO55 <AO55@reden-emu.dev>
An NDK r28 library for API level 26 has DT_GNU_HASH alone, and the loader read DT_HASH
only: its JNI_OnLoad and Java_* functions were not found, with no message. android_arm32
loads libraries the test writes with each table and calls their functions.

Change-Id: I3175ff5d09f55760092c688b63239449c6f5c2b6
Signed-off-by: AO55 <AO55@reden-emu.dev>
NDK builds use _FORTIFY_SOURCE=2: its libraries call 18 __*_chk and __open_2, which
returned 0 here. Each now checks as bionic's fortify.cpp does and aborts with the sizes in
its message; android_arm32 calls each within its buffer and past it.

Change-Id: I88dbacbef2288d46989a66dc44ae1951c6bb3025
Signed-off-by: AO55 <AO55@reden-emu.dev>
The shim swapped O_DIRECTORY, O_NOFOLLOW, O_DIRECT and O_LARGEFILE into asm-generic's
values, but arm64 keeps ARM's: O_DIRECTORY reached the host as O_DIRECT and O_NOFOLLOW as
O_LARGEFILE. android_arm32 opens a file with O_DIRECTORY and a link with O_NOFOLLOW.

Change-Id: Ie234835e8f480bbe5cf5695960262480e8ff2ae8
Signed-off-by: AO55 <AO55@reden-emu.dev>
open64, openat, creat, pwrite, pread64, pwrite64, faccessat, unlinkat, fchdir, chown,
fdatasync, ftruncate64, symlink, link, pipe2, umask, mkstemp, getpgrp, setsid, getpriority
and eventfd went to 64-bit handlers that do not exist and returned 0; now the host's.

Change-Id: I5043da9057dba43bfce7983bab8d3dc5dfb2f16a
Signed-off-by: AO55 <AO55@reden-emu.dev>
The shim returned 0 for a name the 64-bit bridge has no handler for: open64 gave fd 0. Now
its first call names it and every call fails with ENOSYS; android_arm32 checks that no
name the shim sends lacks a handler (arm32_shim_unresolved).

Change-Id: Ia574f6e8d3753758544e39512b09bcc8011434ea
Signed-off-by: AO55 <AO55@reden-emu.dev>
With nextafter and the float and long long forms: imports the bridge lacked, which
returned 0 (expm1 and log1p 4.4e18 ulps off, fma 0). android_arm32 checks each against
the host's.

Change-Id: I5a3ce8c41f7618ce7234abeb424682eca9c6a402
Signed-off-by: AO55 <AO55@reden-emu.dev>
sigemptyset, sigaddset, sigismember and sigpending were imports it lacked, which returned
0 and left the set as it was, so a blocked signal ran; sigfillset and sigdelset with them.
android_arm32 builds a set and keeps a blocked SIGUSR1 pending.

Change-Id: I86d9caa90d69dbde4fa8f52609abb112e2d41b03
Signed-off-by: AO55 <AO55@reden-emu.dev>
With getdelim: imports it lacked, which returned 0: remove said it removed what it left,
getpagesize gave 0. android_arm32 reads lines, removes a file, makes a folder and asks
the page size.

Change-Id: Iadae5f5d26cf9c88729c026d734f889d2f1eecfa
Signed-off-by: AO55 <AO55@reden-emu.dev>
Imports it lacked, which returned 0: an app read no wide characters and an MB_CUR_MAX of
0. bionic's C.UTF-8 gives 4. android_arm32 converts UTF-8 both ways and a stray byte.

Change-Id: I40cbac227e12d08d5bea4e7b19c6a897cae13ebd
Signed-off-by: AO55 <AO55@reden-emu.dev>
They were imports the bridge lacked, so a GLES 3 shader's uint uniform stayed 0. The
64-bit bridge has all eight; android_arm32 checks they are imports.

Change-Id: I2da672dc9b40a70f4b7e9b3d8c132baea1aaf34a
Signed-off-by: AO55 <AO55@reden-emu.dev>
The host's ERANGE never reached the guest, and strtoul clamped where bionic negates: "-2"
gave ULONG_MAX. android_arm32 converts past each range and checks the value and errno.

Change-Id: I0fc4437c694b7ed20c902f6d6a7ea7d60a1f8772
Signed-off-by: AO55 <AO55@reden-emu.dev>
Its imports called the host's C library in the user's locale, which the JVM sets: printf
gave "3,14" and strftime "ter nov" in pt_BR. android_arm32 checks both under a host locale
with a decimal comma.

Change-Id: I5e0d3358812c5fc9968795507a82793ffdccc409
Signed-off-by: AO55 <AO55@reden-emu.dev>
As ART and the 64-bit bridge do: elsewhere, as on a thread the app attached, FindClass
throws ClassNotFoundException. android_jni tests the 32-bit JNI too, on a library that the
test writes (android_arm32_elf.h, shared with android_arm32).

Change-Id: If11a045fecc43e7e426e38a30917165b4966256c
Signed-off-by: AO55 <AO55@reden-emu.dev>
They went through HotSpot's CESU-8: a supplementary character came out in 6 bytes, and
NewStringUTF cut the string at one. jni.c shares its encoder and decoder; android_jni
checks the 32-bit JNI's four string functions.

Change-Id: I1ffc2429a15c0d479f8f4206b661e279aa19d371
Signed-off-by: AO55 <AO55@reden-emu.dev>
free of an address no allocation gave said "ignored", and a failed growth of the free list
lost pages with no word. Both now say the address, the size and what happens.

Change-Id: I01b6e0f8835e02f044bde48d218e86213b1104ec
Signed-off-by: AO55 <AO55@reden-emu.dev>
A void function returned the void result of another, an enum held 0x80000000 past int,
and android_arm32 called imports with an empty array. c99check finds none of them now.

Change-Id: Icdafaec6b3590a56960cbf7672226ffb7755d17d
Signed-off-by: AO55 <AO55@reden-emu.dev>
Each of its 21 FORTIFY aborts dumped the child's 5.8 GiB address space: 50 s here with
cores on, 488 s on the CI, where it slowed the tests that ran beside it.

Change-Id: Ie12b05d9c27aed834c6c5e8d157f9b38a56dd1b8
Signed-off-by: AO55 <AO55@reden-emu.dev>
The check compared it with a * b - 1, which clang fuses at -O2 into the same value, so it
failed on every CI job and passed in -O0 trees.

Change-Id: Ide82d8344dfe595b97fa24fb90641f3616b1990c
Signed-off-by: AO55 <AO55@reden-emu.dev>
keep_invalidation_map kept only the wrapper of a function's first leader,
and snx_recompiled_invalidate cleared only the dispatch slots that point
at that wrapper. The entry table holds one function for each address, so
a leader address that two functions share has the wrapper of only one of
them. A slot that the clear misses can then still lead into a retired
function. Its stale check sets the pc to the same entry and returns, and
snx_recompiled_run calls it again, so the guest makes no progress.

Keep the entry of every leader of a function and clear all of their
slots when the function is retired.

Verified on Windows x86-64 with Clang and LLVM 23.1.5. The
scarletnx-recompiler archive builds and tests/recompiler_library.c
passes. An Android game whose mod library patches the game's code at
start-up, run through the library with dispatch hooks on, stopped at one
pc after the patch without this change. With it, the game reaches its
title screen, and 854 of 2800 invalidations cleared leader slots that
the old loop did not reach.
The flow walks that decide whether a definition reaches a use (direct_can_reach and direct_reaching_writes) took every KIL as the end of all lanes. A KIL under a predicate or a condition code demotes only the lanes that take it, as a conditional EXIT ends only those, which #864 handles. So every write before such a KIL looked unable to reach code after it, and a bindless handle loaded before it and used after a forward branch and a MOV was refused: "untracked texture handle R18 of TEX.B: MOV (reg)". In one game every battle drew its characters as black silhouettes.

A KIL now ends the walk only when flow_always says it takes every lane.

Verified: the cases the next commit adds to shader_direct_regressions fail without this change and pass with it. The refused program translates and passes spirv-val. Another game's 165 recorded programs translate byte for byte the same with and without it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Four cases beside the conditional EXIT ones: a predicated KIL and a condition-code KIL, each before a loop that samples the handle, and before a forward branch whose target moves the handle to another register and samples it. Each was refused as an untracked texture handle before the previous commit and translates with it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
libGDX draws through GLES20, Android's static Java calls of GLES 2.0,
which the framework did not have: a game stopped at its first
glGetIntegerv with NoClassDefFoundError. Each call of GLES20 is now the
runtime's GLES function of its name on the thread's current context
(snx.android.opengl.Gles.call). Its arguments are put in a CPU's
registers as native code passes them: integers, floats, pointers of
direct buffers or of arrays from their offsets (several in one call, as
glGetActiveAttrib's), and strings. hle_find picks the current context's
function for a name of both GLES 1.1 and 2. glShaderSource passes its
string as an array of one, and the info logs are read by their length.

The methods are those that libGDX's backend calls, and the constants
are gl2.h's.

Tests: a libGDX game makes its shaders, meshes and textures, and draws
its title screen and its game.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Apps read the system properties to tell Android from a desktop. libGDX
loads its natives with System.loadLibrary only when java.runtime.name
names the Android Runtime. With OpenJDK's name it took them for a
desktop's and loaded nothing, and the game stopped at its first native
method (Matrix4.prj) with UnsatisfiedLinkError. The boot now sets what
ART reports: java.runtime.name, java.vm.name and java.vm.version,
the vendors, os.name Linux, and os.arch of the app's libraries
(aarch64, or armv8l for a 32-bit app, as a 64-bit phone gives it). The
JDK's own version properties stay, as the JDK reads them.

Tests: the libGDX game loads libgdx.so, and its natives run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An Android app's class loader gives the APK's own files as resources,
as jar: URLs of their entries. libGDX reads its default font
(com/badlogic/gdx/utils/lsans-15.fnt) by Class.getResourceAsStream,
and the app's loader found nothing: the game stopped with "File not
found". AppClassLoader now finds a resource in the base APK and in its
splits.

Tests: the libGDX game reads its font, draws its title screen, and
plays: in a headless run, scripted taps start it, stack two slabs and
end it with its score.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Linux's open gives ELOOP when O_NOFOLLOW meets a symbolic link, and
bionic's callers check for it. FreeBSD and DragonFly give EMLINK there,
and NetBSD EFTYPE. The GNU ABI runtime does not meet this, as its
hostfs resolves the links itself and gives ELOOP. The Android bridge
opens with the host's open, so the guest got errno 31 (EMLINK).
open and __open_2 now give ELOOP for that error with O_NOFOLLOW.

Tests: android_arm32, whose open of a link with O_NOFOLLOW wanted ELOOP
and got EMLINK on FreeBSD, passes. The other android tests pass, but
for android_bionic's two sscanf checks by position, which fail on
origin/main too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dalvik lets any code call clone() through Object on an array or on an object
of another class, but the JVM's verifier refuses a protected Object.clone
call there ("Bad access to protected data"), so the whole class failed to
load. The translator now calls the array type's own clone for an array
receiver, and for an object it cannot prove to be a subclass of the caller
it calls snx.dalvik.Runtime.cloneObject, which clones arrays directly and
calls a public clone() by reflection.

Verified with an emulator app whose classes clone arrays this way: they
now load and run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An emulator app loads Vulkan through adrenotools, whose liblinkernsbypass
walks libdl's dlopen to its first BL to find the linker's __loader_dlopen,
opens ld-android.so and libdl_android.so with it, and looks up the
__loader_android_* namespace calls. Without them adrenotools gives no
Vulkan library and the app aborts with VK_ERROR_INITIALIZATION_FAILED.

- dlopen is guest code now (hle_code.c), whose first BL reaches a veneer to
  the HLE __loader_dlopen, as bionic's libdl calls the linker.
- ld-android.so and libdl_android.so are system handles, and the namespace
  calls (create, link, get_exported) exist: the process has one namespace,
  so a namespace is a name the app keeps and links always succeed.
- android_dlopen_ext loads as dlopen in any namespace. A library from a
  descriptor that is a copy of a system library's stub file is that system
  library.
- /system/lib64/<name> and /system/lib/<name> of a library the HLE is read
  as a small ELF whose .dynamic has the DT_SONAME, marked so that a copy
  (adrenotools copies libvulkan.so to a memfd and patches its soname) is
  recognised.
- memfd_create, as syscall(279) and bionic's function: an unlinked
  temporary file on hosts without Linux's call.

Verified: adrenotools_open_libvulkan now returns the HLE libvulkan and the
app's Vulkan instance is created.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A global command (vkCreateInstance, the instance extension, layer and
  version queries) is resolved by no instance: with one, the host loader
  gives NULL for it (Vulkan 1.2.193 on), and an app that makes a second
  instance while its first lives then failed to load its function pointers.
- Surface(SurfaceTexture) exists, and ANativeWindow_fromSurface gives such
  a surface a window of its own that shows nowhere (its size and buffer
  geometry its own). vkCreateAndroidSurfaceKHR makes a headless surface for
  it without taking the host window from the renderer, and that surface is
  presentable from a graphics queue family, as Android's are, also on a
  driver without headless presentation.

Verified with an emulator app that probes the GPU's driver through a
SurfaceTexture: its settings screen opens, where it aborted before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- @null (aapt writes a reference to 0) is no value, in a layout's
  attributes and in a style's, as Android's attribute resolution makes it.
- A reference the tables cannot resolve (to the framework's resources,
  which they lack, as @android:id/button1) stays the reference with its
  resource ID, as Android's ApplyStyle keeps it: a view's android:id of
  the framework's is no longer dropped. TypedArray resolves such a value
  through the resources, which know the framework colors and integers.
- The framework's colors darker_gray, white, black, transparent,
  background_dark and background_light, and the integers of
  config_shortAnimTime, mediumAnimTime and longAnimTime.

Verified with an emulator app: its alert dialogs find their buttons, its
navigation graph's @null arguments inflate, and its views that use the
framework's colors load.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The drawables of XML resources were made empty: every <shape>, <selector>,
<layer-list> and <vector> drew nothing, and <inset>, <ripple> and others
were refused. Each class reads its element now, through the theme so that
?attr references resolve (DrawableXml holds what they share):

- selector and animated-selector (AnimatedStateListDrawable, whose
  transitions are kept but not played): the items' state sets and drawables
- layer-list: each item's drawable, id, insets, size and gravity
- ripple: its color and radius, and its items; RippleDrawable is a
  LayerDrawable, as on Android, whose mask is the android:id/mask layer
- shape: solid, stroke, corners, padding, size and gradient
- inset, color, bitmap, nine-patch, adaptive-icon, and animated-vector (its
  vector, unanimated)
- vector: groups, paths (SVG path data with arcs, from Android's
  PathParser), clip paths, trimming, fills of colors, color state lists or
  <gradient> colors, strokes, and the tint

A drawable has a constant state now: one loaded from a resource loads it
again, and an inset, layer, ripple or shape drawable made in code copies
itself, as Material's navigation menu needs.

Verified with an emulator app: its icons, cards and dialog backgrounds
draw, and its menus inflate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What an emulator app's RecyclerView, ConstraintLayout and Material views
need of the framework's views, each as Android has it:

- Inflation: the activity's private factory (a FragmentActivity's
  FragmentContainerView), onFinishInflate after a view's children, and an
  <include>'s id, visibility and layout params (and its theme attribute)
  on the included root.
- The View constructor sets the id, tag and visibility into their fields,
  as a subclass's setter (ConstraintLayout's setId) runs before its own
  fields are set; setBackground calls setBackgroundDrawable, which applies
  the drawable's padding to the view.
- The layout params resolved for the layout direction before a subtree
  measures (resolveLayoutDirection): ConstraintLayout's start and end
  constraints become left and right, else a view of 0dp between them is 0
  wide.
- android:textAlignment, inherited, which TextView's layout follows.
- RecyclerView's attach and detach of children, removeDetachedView,
  offsetDescendantRectToMyCoords, suppressLayout, the drawing order calls;
  the view overlays (ViewOverlay, ViewGroupOverlay) drawn over the content,
  the animatable Property constants, getWindowId, setScrollContainer,
  bringToFront and the other members the app's libraries call.
- TextView's line count and bounds, minimum and maximum width and height
  in pixels and ems, letter spacing, line height; ImageView's
  adjustViewBounds and maximum size; Space; AbsListView's list padding.
- A window is laid out by its params, a wrapping one at most the display's
  size, and placed by its gravity (a dialog without one in the middle),
  its events in its own coordinates.
- A dialog's show, cancel and dismiss listeners run as messages of their
  own, as Android's ListenersHandler runs them; Dialog.getLayoutInflater.

Verified with an emulator app: its first-run setup, home screen, settings
and dialogs lay out and draw as on a device, and the earlier test apps
still run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The system's pickers (OPEN_DOCUMENT, OPEN_DOCUMENT_TREE, CREATE_DOCUMENT,
  GET_CONTENT, PICK), which every device has, no longer throw
  ActivityNotFoundException: the caller gets RESULT_CANCELED, as when the
  user backs out of DocumentsUI, or with --pick=PATH (a run without a user)
  the file, or a folder picker's tree of its folder.
- com.android.externalstorage.documents is the shared storage's documents
  provider (ExternalStorageProvider): the host's files by document IDs
  "primary:<path>", their children, opening, creating, renaming and
  deleting. android.provider.DocumentsProvider answers DocumentsContract's
  URIs (root, document, children, and the same under a tree), for this one
  and an app's own; getDocumentId reads a tree's document URI as Android's.
- A configuration change relaunches only the top activity at once; one
  below it is relaunched when it comes back on top, as Android relaunches
  an activity that is not visible when it is next shown. Before, the
  activity below was made again on top of the one that turned the display,
  hiding it, and a relaunch paused and stopped the activity below.

Verified with an emulator app: its folder picker gives it a games folder
of the host, which it scans and lists, and its landscape game screen stays
over the portrait home screen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The --taps, --keys and --shot-frame scripts count presents, and an app
whose window does not change presents nothing more, so a tap or a shot
after an app's first few frames never came. While a tap, a key or a shot
is still to come and the app has no GLES or Vulkan presents of its own,
the last frame is presented again at the display's rate, as a display
keeps showing it. The runtime passes the shot frames to the Java side
(snx.android.shot_frames) for this.

Verified with an emulator app whose screens are still between taps: its
taps and shots at frames in the hundreds now come.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
getFd returned the placeholder 3 and detachFd gave it to the app, so an
app's native code that read a document through its descriptor read
descriptor 3, which is the APK's zip, and then closed it: the app read the
APK's bytes as its file, and the runtime's later reads of the APK failed
("bad local header"), as did files that took the number afterwards (a
SharedPreferences file read back garbled).

A java.io.FileDescriptor's host descriptor is read and made through JNI
now (runtime/fds.c, snx.android.os.Fds):
- getFd gives the descriptor; detachFd gives a duplicate the caller owns
  and closes this object, so that no Java object or cleaner closes what
  the caller owns;
- fromFd duplicates a descriptor, adoptFd takes one over, dup duplicates;
- getStatSize of one made of a descriptor reads its size from the host.

Verified with an emulator app that scans a games folder through the
documents provider and reads each file in native code: it lists the game
with its icon and title, and the APK reads no longer fail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A member's read was a seek and a read of the zip's one stream, so two
threads reading members at once (an Android app's resources on one, its
assets on another) could read at each other's offset. Each seek and read
is one under the stream's lock now, and extracting a member reads its
pieces by their offsets the same way.

Verified with an Android app that reads its resources and assets on
several threads: the runs read every member, and the Android tests pass
(but android_bionic's two sscanf checks, failing before this too).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- VibratorManager (the vibrator_manager service and InputDevice's), with
  no vibrators and a default one without a motor, and CombinedVibration.
- NfcAdapter, Tag and NfcA: the device has no adapter, so
  getDefaultAdapter gives null, as on a device without NFC.
- InputDevice's motion ranges (the touchscreen's axes), controller number
  and vibrator.
- ActivityManager.MemoryInfo.advertisedMem, ShortcutInfo's excluded
  surfaces, Parcel.readStringArray and readTypedArray.

Verified with an emulator app: its game screen starts, where it failed
on each of these.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It drew the built-in look whatever controls_skin chose.

Change-Id: I8f62abc17be619b4c1b9f2b1df5d7631358312a1
Signed-off-by: AO55 <AO55@reden-emu.dev>
The D-pad has no button bit: shifting by its -1 was undefined, as UBSan said.

Change-Id: Ibeef73f54ed28d46f39349f2a1330e08f940c4d1
Signed-off-by: AO55 <AO55@reden-emu.dev>
Written before the encoder made its BC7 image, its work was dropped or its pieces encoded
where the game waits; one read unwritten a while is made BC7 again.

Change-Id: Ibdc473e53c474fece528371538bcca4a73923a01
Signed-off-by: AO55 <AO55@reden-emu.dev>
plat_cpus lists CPUs only on desktop Linux, which pins game threads to them: Auto gave
two workers everywhere else. plat_cpu_count takes the system's count there, for the
save state's and the shader file's workers too, which read the same zero.

Change-Id: I14740799425f4eaec4087205e4a95cdbf7870eb5
Signed-off-by: AO55 <AO55@reden-emu.dev>
The console's counter always runs: one game reports it around a depth pass and draws its
colour only where the two reports differ, never resetting it, and both held one count.

Change-Id: I840352e991492b0fe34730e4465021419608ce98
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
background_recompile=auto, the default, recompiles gently while the host runs on its
battery and at full speed on its charger. recompile_background's full, which every
app.ini wrote, is auto, its gentle gentle; app.ini is written again so, said once.

Change-Id: I5b84b1828d776f546817a78321225f9b58969705
Signed-off-by: AO55 <AO55@reden-emu.dev>
Play, or View Progress for a game the queue recompiles, Recompile, and Mods and Save
States for a made Switch game, so a phone reaches a compiling game's actions too.

Change-Id: Ie100467e12e6506c78efeb1a1947234582037efd
Signed-off-by: AO55 <AO55@reden-emu.dev>
Every row of DEPRECATIONS.md's table is a notice's, which the setup test checks; the
recompile_background row had none.

Change-Id: I827df1749be8d113369ebca1742bce28dce8dc3d
Signed-off-by: AO55 <AO55@reden-emu.dev>
A smaller header was taken as the target's corner whatever its layout: one game's 256x1
colour ramp, where a depth target had been, took its pixels and the sky stayed white.

Change-Id: I6bd83508886d537d2999ed527e8900bc4302fc1d
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
It lies past the 8 MiB the run maps at its start: the check stopped at its first write.

Change-Id: I4a3c1eeeab701d9b9dbe6199df0ff2ccc98e9b24
Signed-off-by: AO55 <AO55@reden-emu.dev>
A dispatch or a draw with an image slot whose header is empty was skipped whole: one
game's program that makes a texture's levels left them zero, a dark square under its kart.

Change-Id: Ic4893a262312d120a064ef57b8bbff28790deedd
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
Allocations past its 1 MiB wrote over the test's own data, its count of failures among
them: with more segments taken, a failed check still ended in ok.

Change-Id: I2264fb86906ca60f213c2d10f6a0bef0b822908a
Signed-off-by: AO55 <AO55@reden-emu.dev>
One game stopped after 5 minutes with all 4096 segments in use: a ring's old JUMPs kept
their pieces, and a slow ring's pieces sat in every segment.

Change-Id: I26d30a2219fbdc1faeda103d76b349dcdf2d71c4
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
Freeing what went unused for two presents took textures a game uses every few frames, each
loaded and encoded again at once: in one game's menus, 2,358 of the 3,000 it evicted.

Change-Id: Ib4e3e8abf8ba019f6f337d8349524a4f8e130032
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
Hashing it waited for the submit with the write and the work before it: one game's
exposure histogram, filled by one compute program for the next, held the GPU thread
20 ms of each frame.

Change-Id: I7b71090b693b9f360c67b19df7352f56e27c4aec
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
Reading them on the CPU waited for the pending write over them: one game's dispatches
bound 256 bytes of constants such a write covered; the GPU thread waited 18 ms a frame.

Change-Id: I2a3270259ad808c0adb33ae651db4204da90ed3a
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
No program writes headers, and a pending write over a dispatch's headers made the GPU
thread wait for it, about 20 ms a frame in one game.

Change-Id: I0b02fc72810b9e593697535e623928bba1502476
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
With write tracking by page protection a scan leaves the pages it found written protected,
and amdgpu refused them to the import (VK_ERROR_INVALID_EXTERNAL_HANDLE): copied instead.

Change-Id: I6fc65b7bfa4dfe2218d55bf844b3701bf7df884e
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
The check went in twice, and vulkan_headless.c did not build.

Change-Id: I28612bb4683e6d87bd4d35a3f557e60d1a794f74
Signed-off-by: AO55 <AO55@reden-emu.dev>
It builds texture.c, which now copies a texture over a pending write in place.

Change-Id: I3e9779e8caab29fd7fc375a7ad72e287df9fa0d9
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
A write the GPU finished during a check read as waited for: dispatch_constants failed
3 runs in 6 on RADV under the validation layer, with descriptor buffers.

Change-Id: Ib8adc5dacc3dea891a5e41fb29835197b33ca048
Signed-off-by: AO55 <AO55@reden-emu.dev>
CheckFriendListAvailability (10120) and GetPlayHistoryRegistrationKey (10700) went
unanswered: with no friends the list is there to read; with no network the key is zeros.

Change-Id: I1172cdb9085f561dbca95630d27fcb18f987e7d8
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
Auto's workers past the two every machine had now take only the CPU time the game leaves:
all of it in a first scene's burst, after the game's threads as it plays. nice +10 on
Linux, utility QoS on Apple, below normal on Windows, idle class where FreeBSD allows it.

Change-Id: Ia4cbaa60f58925057306b7e6591761a528681482
Signed-off-by: AO55 <AO55@reden-emu.dev>
macOS starts a thread at 21 beside a main thread at 17, so the check failed there.

Change-Id: I1e3ec304ada554c449b45f4eb82f28236b676a94
Signed-off-by: AO55 <AO55@reden-emu.dev>
The Ounce's SDK decodes Opus on the audio DSP through nn::codec::hwacod,
a client of IHardwareOpusDecoderManager's command 100 with a task queue
in shared memory, which the runtime doesn't have. One game creates two
managers at 48 kHz, with 128 mono and 72 stereo decoders, and waits on
their system events.

The 13 nn::codec functions it calls are hooked now (the codec family,
hle/hook/codec.c), and decode on the Opus service's FFmpeg decoder,
which audio.c exports outside the service's objects (hwopus_new,
hwopus_delete, hwopus_decode_packet). A request is decoded as it is
enqueued, ExecuteHardwareOpusDecoderDecoding completes the waiting ones
and signals the manager's event, and Dequeue hands the oldest completed
one's samples over. A packet the decoder refuses, or a decoder that
can't open, gives a frame of silence. The manager's event is attached
through the SDK's own nn::os::AttachReadableHandleToSystemEvent
(hook_attach_event), which runs in the game through hook_guest_call. The
state is the runtime's, and a save state doesn't hold it.

diag_abort, which links the hook table, has stubs of the new handlers.

Run on a Radeon 890M host: the game's managers and decoders initialize
and decode, and it runs on to its output stream, the next commit's. All
775 tests pass or are skipped (two of the 3DS), the Vulkan ones on RADV.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 00a80bed20dc4009bc0c34422f925c9fddd0c54f)
The Ounce's SDK plays nn::audio's output streams through the audio
device manager (auddmg:u) and the audio DSP, which the runtime doesn't
have. One game opens a stereo stream of floats at 48 kHz, 1920 frames
long, and writes its mix to it.

The 12 output stream functions it calls are hooked now (the audio_stream
family, hle/hook/audio_stream.c). A stream is a ring that
WriteOutputStream fills. The audio clock, every 5 ms, now calls
outstream_tick, which plays a started stream in guest time at its rate
onto the host's output, converted to signed 16 bit, and signals the
stream's system event for the room it freed. The state is the runtime's,
and a save state doesn't hold it.

audio_out and diag_abort have stubs of the new functions.

Run on a Radeon 890M host: the game's stream opens, its samples reach
the host's output (PipeWire), and the game runs on past the point where
it stopped before. All 775 tests pass or are skipped (two of the 3DS),
the Vulkan ones on RADV.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 7f863ff184bd592b9d093f3644548ba54d94c2e3)
The Ounce's SDK asks auddmg:u for its virtual input devices and opens
input streams on the console's microphone through it, and one game
crashed on the null list it got. Those functions now run here, as the
output streams' do: one virtual input device, VirtualAudioIn, whose
started streams fill at their rate in guest time up to their capacity,
as the DSP records. The host's microphone isn't read yet, so the frames
are silence.

GetVirtualOutputDeviceProperties answers stereo with a latency of 10 ms,
and the event variant of OpenOutputStream without flags and
GetOutputStreamFilledFrameCount are hooked too.

Run on a Radeon 890M host: that game opens two mono input streams at 48
kHz and goes on. On the last commit of this series all 776 tests pass,
the 28 Vulkan ones on RADV and on lavapipe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 3092afd22e2082b8c9ed854ad3dcd4c5fb910037)
The full encoder tries every mode on each block: a sparse texture of seven 8192x8192
layers took it 14 s on an RTX 2080. From 2048x2048 a level keeps mode 6 where its error
is 256 or less, from 8192x8192 it takes mode 6 alone, by its size however it loads.

Change-Id: I372fdab4119430f6773f35bb80e43afafdf37e7c
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
The full build took most of a game's textures, the ones under 2048x2048, and a batch of
them held a frame for seconds; the fast one keeps mode 6 on the blocks it holds closely.

Change-Id: I44e441a997d87717f5cc8aced2da41f82c8c167f
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
Random blocks have every block mode and many partitions, where a game's textures are
mostly void extents and one partition, and the BC7 encoder's time depends on its input.

Change-Id: Ie25933667abb372c26baaae85b1fa85ac25d2e59
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
pipeline_file.c cut its file in a static helper of its own, which the BC7 cache needs too.

Change-Id: I27488458b9273cf01086e3851a35955055b294b7
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
The same ASTC bytes always become the same blocks, and a texture the trim evicted came
back through the encoder each time: one game encoded 6,000 to 14,000 levels in 150 s.

Change-Id: I1e28bdacb1ae67aa6ef82604cbd93da5e6cc1203
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
A level the trim evicted came back through the decoder and the encoder each time: a hit
copies its cached blocks into the image, straight or between frames, with no encode.

Change-Id: I5d4136adf0d99c1b5fbbea77f92b6423a13929cf
Co-authored-by: fuddlesworth <39394314+fuddlesworth@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
ctest runs the four astc_vulkan entries at once in one directory, and one run's remove or
lock of the shared file made another's cache miss: astc_vulkan_pieces failed beside it.

Change-Id: Ib69d0506354a3b3fe113c80df9ab4f5fce9bd795
Signed-off-by: AO55 <AO55@reden-emu.dev>
An Ounce's SDK numbers the same applets from 0x01000000. One game's controller applet came as 0x0100000C, which the service did not know, so it had no output and the game took it as cancelled. The ids at 0x01010000 take the same number here, which no run has shown to be right.

Ran that game on a Radeon 890M. The service gives that applet's result. The demo needed the next commit too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit a1c78b7c5bdac17e8126500edd5a7e28cc4bd19b)
An Ounce game's SDK sends the software keyboard a KbdConfigForGen2 of 0x530 bytes
(nn::swkbd::keyboardConfig2kbdConfig), with its texts, limits and password where they were but its UTF-8 flag at 0x3aa
and the initial text's offset and length at 0x3bc and 0x3c0. Read at the old places, one game that asks for UTF-8 got
UTF-16 and took the name a player typed for its first letter. The storage's size tells the layouts apart, so older
games read theirs as before.

That game then kept a whole name, checked on screen. The initial text wasn't seen in a run, and no older game was run
on this.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit dfbcbfe76579a05f8cfbe2f9276686eaccfda76c)
SDK 22's audio renderer asks for revision 16 (REV@ and REv@), which the
renderer refused as an invalid revision, and one game stopped there. It
is taken as revision 15.

Run on a Radeon 890M host: that game opens its renderer and plays sound.
On the last commit of this series all 776 tests pass, the 28 Vulkan ones
on RADV and on lavapipe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 5be3a75bc4c5b101f00e37db0f2a0e57ffd302f9)
nn::socket::Initialize of SDK 22 registers its client with command 36 in
place of RegisterClient: the pid and its configuration's version
(0x1000c), and no transfer memory. The library refuses to start (0x81b)
unless the reply's errno is 0, which one game aborted on. It is
registered as RegisterClient registers.

Run on a Radeon 890M host: that game's sockets start. On the last commit
of this series all 776 tests pass, the 28 Vulkan ones on RADV and on
lavapipe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit e9dc4683b33265b4aef5992c675b3e2247019e54)
StartLibraryApplet of SDK 20 and 22 calls command 90, then waits on
command 170's event beside the state changed event. With 170 unanswered
the wait was given handle 0, and one game aborted with InvalidHandle
when it showed its controller applet. 90 is a stub, and 170 returns an
event of the applet's own that is never signaled. What either is for
isn't known.

Run on a Radeon 890M host: that game gets through its controller applet.
On the last commit of this series all 776 tests pass, the 28 Vulkan ones
on RADV and on lavapipe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit f151d9316e08e55cf0da2f7677d1101ef4f1bba5)
An Ounce game's title screen uploaded 28 to 32 textures (about 11 MB) from
guest memory each frame. They were its reflection cubes. One compute dispatch
writes each mip level of a cube through a base-level view of that level, as a
storage image, and publishes each view over guest memory. The layers of a view
are a whole mip chain apart, so the span of each view holds the other views'
levels and faces. Three things made each view and each cube load all of its
memory again every frame:

- A publish put its buffer over its whole span and stamped all of it written.
  The bytes between its layers kept their values (staged as the GPU saw them),
  but every other view found its own texels in that span written.
- A texture's span took the size of level 0 of the chain for each of its
  levels, not the size of its base level. A view of the 64x64 level reached
  over the levels after it, and a 2x2 view took 64 KiB of each layer.
- The GPU's write records are of pages. The views of the last levels share a
  page, so each publish marked the others' texels written.

The readback in the hypothesis does not occur. The hash reads the owners'
serials and the uploads copy the owners' bytes on the GPU. Nothing landed on
the CPU, but each frame staged and deswizzled about 11 MB again.

Now a publish takes the image's own bytes, each layer from where it starts,
and the spans of the targets it copied in (rt_retire_over). The rest of the
span keeps its owners. A texture's span takes the size of its base level. A
texture's change check leaves out the bytes between its layers (pieces_own),
and the bytes that its own last publish still owns, unwritten since
(vk_guest_owned_by, Surf.pub_serial).

What remains each frame are the three full mip chains, which the views really
change, loaded from the views' published bytes on the GPU.

Verified on the title screen of the game, 110 s runs with --vk_gpu_profile=1,
one warm-up run of each build and 3 measured runs:
- Texture uploads a frame (median of the frames over 50 ms after 25 s): 31,
  32, 28 before (10.9 MB), 4, 4, 4 after (1.8 MB).
- Frame rate over 40 s to 110 s: 10.1, 7.8, 11.2 before, 13.2, 14.0, 11.5
  after. The scene changes every few seconds and the rate is noisy.
- No GPU hang in the measured runs. Two of the debug runs hung with Xid 109,
  the known mesh_draws issue, and one baseline warm-up run hung too.
- ctest: all 737 tests pass. With SNX_TEST_VULKAN=ON, vulkan_headless_uma and
  vulkan_headless_descriptor_buffers_uma fail at vulkan_headless:675 and :5370
  (check_uma_placed_view), as before the change. The other 31 pass.
- Validation with VK_KHRONOS_VALIDATION_VALIDATE_SYNC=true: the game run gives
  84 messages before and after, the same ones. snx-test-vulkan -H gives the
  same 16 messages before and after and stops at check_storage_image_keep in
  both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit ffd6815b107926cb6be6f2bd4a4a539eaea26268)
One game's compute writes its frame through an RGBA8 UNORM descriptor,
and its draw samples it as sRGB. The texture cache kept the two apart,
and loaded the sRGB one again on every frame from the storage image's
owner, 15 MB each time. A sampled lookup now takes the twin when it is
current, with its view format following the descriptor, as render
targets do. Storage and raw lookups still match exactly.

Run on a Radeon 890M host: that game's uploads go from 15 MB to 184 KB a
frame. On the last commit of this series all 776 tests pass, the 28
Vulkan ones on RADV and on lavapipe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 5f59b9db0f22e8b051ff712b471e6395f893a3ee)
The USSE translator matched words against a table of letter strings and handed
its handlers the fields by position (f[12], f[23 - i]), and the PICA
interpreter and decompiler each switched on their own copy of the opcodes. Both
instruction sets are now .decode files, as A32 and A64 are, and tools/decodetree
makes their decoders:

- src/vita/gpu/usse.decode (-w 64): Vita3K's 35 patterns with their fields
  named, the overlapping ones in { } groups in Vita3K's order. usse.c defines a
  trans_ function for each, its handlers read arg->field, and usse_survey runs
  through the same decoder.
- src/3ds/gpu/pica.decode: nihstro's opcodes and formats. shader.c has a trans_
  function for each instruction; vsgen.c's trans_ functions give the step that
  its flow analysis reads and compile the instruction when asked.
- The bit operations the decoders call are in common/utilities/decodetree.h,
  which the ARM decoders include too.

A differential harness ran 600k random USSE and PICA programs through the old
and the new code: the same survey names, SPIR-V bytes and errors, and the same
interpreter state but for the sign of a NaN that both addends of an add were
(which one x86 gives back is the register allocation's). vsgen still makes the
unused temporary that CMP's and MOVA's destination bits named, to keep the
module the same. ctest: 815/818, the failures main has (3ds_memory_adopt,
android_bionic, android_arm32).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A console's update ExHeader gives the game's program ID, not the update's: refused.

Change-Id: I41898f4c5fedf7220b669390f412a9462b58c61d
Signed-off-by: AO55 <AO55@reden-emu.dev>
The Vita loader kept a static copy of snx_library_open, _symbol and _close
from common.c, and the AGB recompiler its own dlopen/LoadLibraryA calls.
LoadLibraryA took the module's path in the ANSI code page, so a game folder
whose path was not ASCII could not load its module on Windows. Both now use
the one implementation in common/utilities, which converts the path to UTF-16.

Verified: the full build, and ctest -R 'agb|vita' (34 tests, the jsmolka
gba-tests among them recompile with -r and load the module).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
composite_line asked window_mask for every pixel, which tested both
windows' horizontal ranges and the OBJ window again each time, and it ranked
the four backgrounds by a key it computed per pixel. text_bg read the screen
entry and recomputed the tile row address for every pixel, although eight
pixels in a row share them.

The window masks are now filled once per line as spans (the outside, then the
OBJ window, then WIN1 and WIN0 over it, so the precedence is unchanged), the
backgrounds are sorted by priority once per line, and the sprite is merged into
the two front layers by its key, which never equals a background's. The
backdrop colour and the blend weights are read once per line. text_bg reads a
map entry once per tile. The scanline buffers move from a file static into
AgbPpu (one global per file).

Measured with a scratch harness that calls the old and new static functions
on a fixed scene of four text backgrounds and WIN0, minimum of 15 runs on a
host with load average 11 to 14: text_bg 574 ns per line against 964,
composite_line 2.0 us per line against 2.26 (the composite figure is noisy,
single runs ranged 2.0 to 5 us on both).

Verified pixel-exact: the same harness rendered 5000 frames of random VRAM,
palette, OAM and PPU registers (all six modes, windows, mosaic, blending)
with the old and new ppu.c, and every framebuffer was identical. agb_ppu gains
a check of WIN0 over WIN1 over the OBJ window with a WIN1 span that wraps
around the screen edge, which passes on the old and the new code. All agb_*
tests pass, the jsmolka ppu_hello, ppu_shades and ppu_stripes among them. No
GBA game was run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each internal compute shader of the Switch, 3DS and Vita renderers filled the
same VkShaderModuleCreateInfo and VkComputePipelineCreateInfo by hand, and the
present quad kept its own module() wrapper. vk_common now has
snx_vk_shader_module, snx_vk_module_pipeline (a module's "main", with optional
specialization constants) and snx_vk_compute_pipeline (SPIR-V to pipeline, the
module freed again). The sites keep their own logging: the ones that said
"cannot load" and "cannot create" separately (texconv, block linear, ASTC, BC7,
VIC, MSAA) still make the module and the pipeline in two calls. The depth pack
timing now includes the module creation, which it did not before.

Verified with a RelWithDebInfo build and ctest on FreeBSD: the 3DS Vulkan tests
(validation layer included) pass, and the failures are the known
3ds_memory_adopt, android_bionic and android_arm32. The Switch compute sites
are built but not run here (no Switch game on this host). Windows not built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebased-by: AO55 <AO55@reden-emu.dev>
snx_ctr_dispatch fetches the instruction at the pc before every block, and
each fetch, read and write went through physical(), which scanned the model's
physical regions to find the host memory of the page's frame. snx_ctr_map
already finds that region (a mapping lies in one), so the page now keeps its
index plus 1 in place of the present flag, in the byte of padding the flag
used: 0 still means unmapped, and an access goes straight to the region's
backing.

The fetch on a static block hit stays. It runs touch_virtual, which lands a
GPU-tracked page before its code is executed, and skipping it would need a
proof that the side effect is kept elsewhere.

Measured with a scratch program that fetches 4 bytes at 20 million spread
addresses of a FCRAM mapping through snx_ctr_fetch, minimum of 9 rounds, three
runs each on a loaded host: 11.6 to 12.4 ns per fetch before, 7.6 to 8.9 ns
after.

All 3ds_* tests pass except 3ds_memory_adopt, a known failure of the
branch base. No 3DS game was run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PMutex and the pm_* calls lived in common/filesystem/host.c, and the
condition variables, the waits on a word, plat_yield and plat_tid in the
NX platform layer, where no other driver could link them. They are now
common/platform/thread.{h,c}, in a new target scarletnx-platform that
links only the system's threads. scarletnx-filesystem links it, and
filesystem/host.h and plat.h include its header, so the callers are
unchanged.

pm_tid and plat_tid were two ids for one thread, each with its own TLS
cache. plat_tid is now the only one: gettid on Linux,
pthread_threadid_np on Apple systems and pthread_getthreadid_np on
FreeBSD (pthread_self before), kept in the TLS slot of the lock
bookkeeping. The Windows timer-period request is now plat_timer_1ms, as
the condition variables need it.

Verified: the full build on FreeBSD and ctest (815 of 818, the same three
failures as main: 3ds_memory_adopt, android_bionic, android_arm32). The
Windows half is moved text, but no Windows build was run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
About fifty files had their own copy of a helper that common/utilities
already has: little- and big-endian loads and stores (and one-line wrappers
around snx_ld_le32 and the like), clamps and min/max, a mask align_up, FNV-1a
loops, hex digit tests, path-leaf loops and separator tests, and eight sign
extensions. They now call endian.h, bits.h, ascii.h and snx_path_leaf.

bits.h gets what was missing: snx_sext32 and snx_sext64 (the low bits as a
signed number, with no implementation-defined conversion), snx_fnv1a32 and
snx_fnv32_step, and snx_clamp_s16 for the three 3DS clamp16 copies. The
FNV-1a users hash the same bytes in the same order, so the corpus file names
of the Vita shaders and the recompiler library's cache keys stay the same.
gnuabi's gnu_vfs_put16/32/64 are replaced by snx_st_le16/32/64. mcp.c formats
its title IDs with %016llX instead of a digit loop, a pad loop and toupper.
audio.c's align_up took only powers of two, which all its callers pass, so
snx_align_up gives the same sizes.

Not changed: pipeline_file.c's pf_get32 and pf_get64 read the cache in the
host's order (as it is written), not little-endian, and glslc keeps its own
FNV and hex digit test, because tests/architecture.py keeps src/glslc free of
common/.

Verified with a RelWithDebInfo build (-Werror=missing-prototypes) and ctest on
FreeBSD. The failures are the known 3ds_memory_adopt, android_bionic and
android_arm32 (an O_NOFOLLOW errno check, not the loader), and xdg_layout,
which passed when run again alone. A unit check of snx_sext32 and snx_sext64
against a reference over all bit widths, under UBSan, passed. Windows not
built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
wake_waiters_nl scanned all 256 KThread slots under g_klock on every signal of
an object that has waiters. A KThread is several kilobytes (the CPU state, the
32-bit CPU, 64 waits, the sleep registers), so the scan touched 256 cold cache
lines to find, on average, one thread.

HostKernel now keeps a 256-bit mask of the thread slots whose nwaits is not
zero, set in waiter_add and cleared in waiter_del when the last wait goes,
both under g_klock, and the wake walks only its set bits. The checks of type,
nwaits and wait_kind stay, so a bit left on a freed slot is harmless. The mask
is derived data and lives in g_host, which a save state never holds: the
state load rebuilds it from the threads' waits right after g_hle is put in
place (kernel_waiters_rebuild). The state format and its version do not
change.

Measured in a game with a temporary build that timed wake_waiters_nl with
rdtsc and could run the old loop instead, 90 s headless from boot, same route:
17408 wakes of objects with waiters in both runs, 8562 cycles a wake with the
old scan against 1370 with the mask, with 1.00 threads in object waits on
average. A second, lighter game made too few such wakes to measure.

kernel_mutex, kernel_wait, kernel_cores and state_file pass. A save state
round trip (--state_check) could not be checked on this FreeBSD host: the load
stops in load_memory, before g_hle is installed, because guest memory views
here are copies with no alias pool.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
plat_thread, plat_thread_exit, plat_cpus and plat_thread_cpus move from
the NX platform layer to common/platform/thread_spawn.c. A file of its
own, so the tests that stub them still link the rest of thread.c.

What NX does on each thread is now a hook table (plat_thread_hooks):
- the touch of the fault handlers' TLS before the thread can fault
- the end of SDL's per-thread state
- on Windows, the sampling profiler's handle.
plat_posix.c and plat_win32.c register it from a constructor, so the
runtime and each test that compiles them have it before any thread.

plat_thread_cpus now returns -1 with errno, and the kernel's core_pin
says the warning that plat_posix.c used to say.

The network threads (snx_net_thread) and the gnuabi guest threads
(gnu_thread_spawn) had their own pthread_create and CreateThread code.
They now use plat_thread with the same stack sizes, except that a
network thread on Windows gets the default stack in place of 64 KiB, as
on POSIX. With a stack of 256 KiB or more, a gnuabi guest thread now
also gets the alternate signal stack for a crash report.

Verified: the full build on FreeBSD, and ctest with the same three
failures as main. plat_cpus.c (a Linux-only test) and the Windows code
were not built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebased-by: AO55 <AO55@reden-emu.dev>
docs/ was one flat folder of 55 documents with capitalized names, where a
player's guide sat next to a GPU audit. They now go in user/, dev/,
platforms/<system>/, layers/<part>/, hosts/ and history/, with lower-case
names. docs/README.md lists them in that order and keeps its place as the
index, and docs/CREDITS.md stays beside it.

A script moved each file with git mv and rewrote each reference by its exact
path: Markdown links by where they resolve from the file's old and new place,
and the docs/ paths in comments, CMake, presets, CI paths and CODEOWNERS,
the messages the programs print, the po msgids with their translations, the
links the setup and users files write, and the test inputs (setup.c's
deprecations table, gui_theme.c's themes, cpu_plan.py's plan and status).
check-docs.py now finds the settings table at docs/user/settings.md, and
the fixtures of docs_test.py and architecture_test.py use the new paths.

build.yml said ARCHITECTURE.md was a test input. It is not, and the CPU plan
is, so the paths filter now names the plan.

Verified with scripts/check-docs.py, a link check of every tracked Markdown
file, the ste100 checker, docs_test.py, architecture_test.py and
nightly_notes_test.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebased-by: AO55 <AO55@reden-emu.dev>
Six drivers wrote a P6 header and then their pixels one by one: the Switch
renderer, the 3DS frame dumps (rotated to landscape), the Vita, the GBA
runner, and the Android renderer and Vulkan bridge. common.c now has
snx_ppm_write, which takes a FILE, the size, the first pixel, a pixel step and
a row step (negative for the 3DS's rotated read), and the byte order (RGBA,
BGRA, or the GBA's host-order words). It writes a row at a time and returns -1
on a failed write. Each caller keeps its own file handling: the 3DS's staged
rename, the Switch's warning and the Android format checks.

Verified the bytes: a check that ran each old loop and snx_ppm_write on the
same pixels (the 3DS rotation, RGBA, BGRA, a Vita pitch wider than the
picture, GBA words) under ASan and UBSan gave identical files. The build and
ctest pass but for the known 3ds_memory_adopt, android_bionic and
android_arm32. Windows not built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The setup and users files that older versions wrote link to
docs/USAGE.md#setup and #users, older nightly notes link to USAGE.md and
ANDROID.md, and the messages of older versions name docs/DEPRECATIONS.md.
Each of these paths now holds a short page that points to the new one, and
the USAGE.md page keeps the Setup and Users headings so that the old anchors
still land. docs/README.md lists them under Moved pages, which check-docs.py
requires of every document in docs/.

Verified with scripts/check-docs.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Switch loader, the Android bridge's 32-bit loader and the Vita image
loader defined their own PT_, PF_, DT_, R_ARM_ and R_AARCH64_ numbers (the
32-bit one with a trailing underscore on each). They now include
common/cpu/recompiler/llvm/elf_defs.h, which gets the names it lacked
(DT_RELAENT, DT_SYMENT, DT_REL, DT_RELSZ, DT_RELENT, DT_RELRENT, PT_ARM_EXIDX
and the five R_ARM_ relocations). The Switch loader keeps only DT_COUNT, its
own bound.

The SysV and GNU symbol hashes were written three times (the bridge's linker,
its 32-bit loader, and the recompiler's ELF linker, which kept an unsigned
long). They are now snx_elf_sysv_hash and snx_elf_gnu_hash in a new
elf_hash.h beside elf_defs.h, apart from it so that link_elf.c, which has the
system's <elf.h>, can include it too. The SysV value stays below 2^28 at each
step, so the unsigned long version gave the same hashes.

Verified with the build and ctest on FreeBSD: loader_native, the llvm link
tests and the Android tests pass. android_arm32 still fails only on its known
O_NOFOLLOW errno check, after the loader and relocation checks pass, and
android_bionic fails as before. Windows not built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Four pages only made sense next to another one, and each was half
duplicated there:

- the shared fonts' Noto stand-ins go under Shared fonts in
  platforms/nx/filesystem.md, which already said most of their first part
- ldr:ro goes into platforms/nx/nro.md as the run-time half of NRO loading
- guest buffers on unified memory go under the UMA section of
  layers/gpu/ownership.md, which it pointed to for the in-place path
- the first SIMD milestone goes into layers/cpu/guide.md, which sent each
  new contributor there first

Their headings move down one level, links to them now land on the merged
section, and the comments and the plan's status file that named them name
the merged file.

Verified with scripts/check-docs.py and a link check of every tracked
Markdown file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Switch runtime, the 3DS driver and the Vita driver each cut the key of a
--key=value argument into a 64-byte buffer with the same length check and
memcpy. ini.c now has ini_arg, which gives the value and fills the key, or
NULL for another argument or a key that does not fit. Each driver keeps its
own tables and aliases (the 3DS's shared Switch settings and gamepad_map, the
Vita's vita_script and the rest), and the Switch runtime still skips --game=
and --fullscreen= there. The behavior is the same.

The common switches (-x, -r, --output, --outdir, --data, --game=) are left in
each driver: the 3DS has "--" and positional handling, the Vita a --patch
folder and the GBA runner other names and messages, so one parser would need
more flags than it saves lines.

Verified with tests/ini.c's new ini_arg checks, and with ctest on the 3DS,
Vita and ini tests (only the known 3ds_memory_adopt fails). Windows not built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The development guide opened with three sections on GPU benchmarks, the
NVN reference mixed the current design with the replay that it replaced,
and the 3DS page still carried the staged plan that the parity roadmap
superseded. A reader could not tell which text described the code as it
is.

- development.md's NVN storage ordering, descriptor submission and GPU
  settings search go to the GPU benchmark pages in history/, and its
  Profiling section points to them
- nvn.md's abandoned replay, the verify mode's first runs and the fixes
  that the investigation left go to history/nvn-investigation.md
- the 3DS stages 2 to 6 go to history/3ds-staged-roadmap.md, and the
  local wireless section that sat under them becomes a section of the
  3DS page
- the descriptor measurements' current text on vk_descriptors_mode moves
  into its row in settings.md

Each page in history/ now opens with a line that says it is a snapshot
and is not kept up to date.

Verified with scripts/check-docs.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The 3DS and Vita input files each opened and closed SDL gamepads on the added
and removed events, read the same WASD and IJKL sticks and nearly the same
keys, and scaled their sticks past a round dead zone, which the Switch
gamepad backend also did. Now:

- pad_sdl.c has snx_pads_event and snx_pads_close (the 3DS still turns on a
  new pad's motion sensors through its callback), snx_pad_axis, and
  snx_pad_keys and snx_pad_key_sticks for a Switch game's keyboard layout.
  Each driver maps those buttons to its own bits and adds Space itself (A on
  the 3DS, Cross on the Vita, as before).
- pad_map.c has snx_pad_dead_zone, snx_pad_map_sent (the button in its place,
  the player's map over it, A and B swapped) and snx_pad_map_setting (the
  gamepad_map text with its warnings, which was the 3DS's).
- The Vita reads its gamepads through pad_map as the 3DS does, so
  --gamepad_map= now works there. The GBA runner reads its pads through
  snx_pad_held. Both now link snx_pad_sdl.

Behavior changes: on the Vita, gamepad_map is honored, and Enter with Alt held
no longer presses Start (Alt+Enter is the window's fullscreen, as on the 3DS).
On the GBA, a trigger is held past SNX_PAD_TRIGGER (8000 of 32767) as on the
Switch and the 3DS, not past 16384. The 3DS and Vita dead zone is now computed
in double, so a scaled stick can differ in the last float bit. The Switch
backend's dead zone does the same operations in the same order as before.

Verified with the build and ctest on FreeBSD: 3ds_input, pad_map, the Vita and
GBA tests and runtime_architecture pass. In one full run 3ds_input hung in
SDL_Quit (libusb_exit, while another worktree's tests ran) and passed when run
again. No gamepad was connected, so the pad paths ran only against SDL's
virtual controller in 3ds_input. Windows not built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
d0af29a3 brought back a Maxwell front end for programs that write their
own GPU command buffers: gpu.c pulls the GPFIFO that SUBMIT_GPFIFO queues,
and src/nx/gpu/maxwell/ has the engines, the macro interpreter, the draw
state from the 3D registers (once tests/support/mx_state.c) and
write_pages.c. The roadmap, architecture, NVN and edenprobe pages, CLAUDE.md
and a CI comment still said that NVN was the only GPU path and that
SUBMIT_GPFIFO drew nothing. They now describe both front ends, and the
architecture's ownership table has a gpu/maxwell row. CREDITS lists the
Eden files that the front end ports.

Other names that the code no longer has:

- gpu/writes.c (the page writes are in maxwell3d.c and write_pages.c),
  in nvn.md, settings.md and the gpu_page_check help
- SNX_CHUNK_INSTRUCTIONS (library.c's CHUNK_INSTRUCTIONS) and snx_simd
  in architecture.md
- SNX_3DS_AOT in the 3DS page (the offline compiler is part of the
  driver)
- FS_NOTFOUND (SNX_RC_FS_PATH_NOT_FOUND) and fs_tree.c (the tree is
  src/common/filesystem/tree.c) in filesystem.md and CLAUDE.md
- brx_far_ldc (shader_brx_targets now) in the NVN investigation
- tests/a64_audit.py, which this repository never had

hooks.md now says that src/nx/patches/ does not exist yet, though the
build still collects it. CLAUDE.md's Platform row names
src/common/platform/, the host layer that the drivers share, and
architecture.md says the same in one paragraph.

Verified with scripts/check-docs.py and the ste100 checker (--all).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
unattended.c had its own parser for the Switch game's --script (ms:hex and
Nf:hex presses, 64-bit masks), beside common/utilities/script.c, which the
3DS, Vita and GBA drivers use for ms:hex. SnxPress now holds a 64-bit mask and
a frame flag, and snx_script_read takes the buttons a console allows, whether
Nf: presses are allowed, and gives where it stopped instead of printing.
snx_script_parse keeps the drivers' stderr line on top of it. unattended.c
reads through snx_script_read and copies the presses into its own ScriptPress,
which keeps the run state (held_since, done), and keeps its own log warning.

Behavior changes: the drivers' parser now wants a digit at the start of a press
and a hex digit after its colon, as the Switch's did, so a press with a space
or a sign before its number now ends the script. The Switch's "too long"
warning is now its out of memory one. snx_script_held skips Nf: presses, which
only the Switch runtime times.

Verified with tests/script.c (new checks for Nf:, a 64-bit mask, the stop
position and the stricter start), unattended_script, 3ds_input and the Vita and
GBA tests under ctest on FreeBSD. Windows not built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The docs named the games that the investigations used, and the usage
guide gave one game's title ID as the example of a game folder. The rule
is that docs describe what a game did and never name it.

The NVN page and the NVN investigation now call their four games game A
to game D, which keeps the comparisons between two SDKs readable. The
other pages say "one game" or "a cave scene in one game", the folder
example uses <title ID>, and run_game.py's default is the input sequence
of the game it was written for.

Verified with scripts/check-docs.py and a search of docs/ for the titles
and title IDs that were there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
y2r.c kept a 64-entry table of the PICA's 8x8 Morton order, which
snx_ctr_morton_offset in transfer.c already computes from its x and y tables.
A tile's pixel k is at row k / 8 and column k % 8, so the offset of that pixel
with one byte per pixel is the table's entry.

Verified with 3ds_vk_y2r and its copy and in-place variants, which compare the
Vulkan shader with this CPU reference over every format, rotation and both
block layouts. Windows not built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each driver had its own monotonic clock, wall clock and sleep: plat_sdl.c went through SDL, the GNU ABI, the Vita,
the network stack and snx_seconds each read clock_gettime or QueryPerformanceCounter, and the 3DS and the Vita each
had a copy of the high-resolution waitable timer sleep. Now time.c has plat_ns, plat_monotonic_ns, plat_unix_ns,
plat_unix_time and plat_tz_offset without SDL, and sleep.c has plat_sleep_ns and plat_yield, a file of its own so the
tests that stub the sleep still link the clocks.

plat_ns reads the clock SDL_GetTicksNS read on each system (CLOCK_MONOTONIC_RAW on Linux, CLOCK_MONOTONIC on Android
and the BSDs, mach_absolute_time on Apple systems, QueryPerformanceCounter on Windows), so intervals keep their
pace. Its origin is now the system's start, not SDL's first call. The gamepads' arrivals and leavings were told in
SDL_GetTicksNS while the overlay's notices compare with plat_ns, so they now take plat_ns too. The Windows sleep waits
on a timer of each thread's own, which an FLS slot closes when the thread ends: the 3DS and Vita copies shared one
static timer between threads.

On top of the shared clocks: gnu_monotonic_ns and gnu_realtime_ns are thin wrappers (the guest's CLOCK_MONOTONIC
stays the host's, which the condition variables wait on), snx_net_now_us and snx_net_sleep_us are inline wrappers in
microseconds, snx_seconds is plat_ns in seconds, the 3DS's 1900 wall clock is plat_unix_ns plus plat_tz_offset, and
the Vita's RTC and gettimeofday read plat_unix_ns. vita_now_ns is gone for plat_ns. The recompiler library's default
counter reads plat_ns, and its archive takes the platform's objects with common's. The AGB host keeps
SDL_DelayPrecise, whose spin at the end plat_sleep_ns does not have.

Verified on FreeBSD 15: the RelWithDebInfo build and ctest, where only the known 3ds_memory_adopt, android_bionic and
android_arm32 fail. The Windows code was not built (no cross toolchain here), and Linux and Apple were not run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Switch runtime crashed at startup on FreeBSD: the window's Vulkan driver lookup calls snx_executable(NULL), and
with no /proc/self/exe (FreeBSD mounts no /proc by default) it went on to snx_find_tool(NULL), which reads the name
it is given. FreeBSD now asks the kernel with the KERN_PROC_PATHNAME sysctl, and a NULL argv0 returns NULL where the
system does not say the path, instead of searching PATH for nothing.

Verified on FreeBSD 15: a game that crashed at its first frame with the branch's base now runs headless for 60
seconds to its title screen (3121 frames), and the build and the common tests pass. Windows, Linux and Apple keep
their branches unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The new tree sorts the documents by platform and by layer, but a reader
on a platform's page still had to know which layer documents applied to
it. Each platforms/<system>/README.md now starts with a table of the
loader, CPU, kernel and HLE, GPU, audio, input and platform layers: the
code of each and the documents that describe it. The Switch had no page
of its own in platforms/nx/, so it gets one that holds only that table,
and docs/README.md links it.

The Android app's host page and the Android apps' guest page now each say
which one they are, and point to the other.

Verified with scripts/check-docs.py, which checks each link and anchor of
the tables.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CLAUDE.md, the skills and the agents name docs by path, and the move of
docs/ showed that nothing checked them: a broken link there would go
unseen until a session followed it. check-docs.py now checks their links
and anchors as it checks those of docs/. It asks no ## Index of them, and
it skips .claude/worktrees/, where other sessions keep their checkouts.

Verified with tests/docs_test.py, which has two new cases (a broken link
in each kind of Claude file, and a long Claude file without an index), and
scripts/check-docs.py on the checkout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Many links read [USAGE], [NATIVE] or [GNUABI], the capitalized file
names that the documents no longer have. They now read as the titles
(Usage, Native bridge, GNU ABI). Only the link text changes.

Verified with scripts/check-docs.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each driver parsed --update, --data, --seconds and the rest by hand, with
different forms (only --opt=VALUE here, only --opt VALUE there), different
messages and different help text. common/utilities/cli.{h,c} holds one table
of the common options: long name, short letter, older name (--recomp,
--repo, --patch), value, and help line. snx_cli_match takes both value forms,
says an older name once through snx_option_renamed, and refuses a common
option a driver does not take in one wording. SnxCli collects a run's
options (--update repeats), snx_cli_help prints the lines in one column, and
snx_cli_joined joins --opt VALUE into --opt=VALUE for a reader of the = form.

Verified with the new cli ctest (forms, letters, older names said once,
refusals, repeated --update, joined arguments, help lines the same for each
mask). No Windows toolchain here, so the Windows build is not checked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scarletnx-agb parsed -r, --frames=, --script=, --shot=, --game= and
--fullscreen=0|1 only in the = form, and --data and --outdir only with the
value apart. It now matches them through snx_cli_take first and keeps only
--press_len= and --registers. Each value option takes both forms, -f and
--fullscreen work, and --output DIR names the game's folder itself, as it
does for the 3DS and the Vita (snx_mkdirs, then snx_absolute, in place of
snx_game_folder). --frames is checked as a whole number. A common option the
AGB cannot do (--update, --keys, --seconds, -x, -H) is refused, and usage
goes to stderr on a mistake.

Verified with the 24 agb ctests, the jsmolka gba-tests among them, and a run
of arm.gba with --frames 60 --shot FILE --output DIR, which made the folder
and the shot. No Windows toolchain here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scarletnx-android's --keys=TEXT was the text to type, where every other
driver's --keys names a key file. The text is --type=TEXT now (the Java
side's property snx.android.type). An Android app has no key file, so
--keys and --keys=... stop with a message that names --type, rather than
type a key file's path. --headless (now also -H), --shot (both forms) and
-h are matched through snx_cli_match. --shot keeps its Android meaning: each
frame --shot-frame names, %ld in the path its number. --help shows the
common lines in the shared column, then the Android options.

Verified with runs of scarletnx-android: --help, --keys=x and --data d (both
refused, status 2), and -H --shot DIR/g%ld.ppm --shot-frame=60,200 on a
32-bit app, which wrote both frames. No Windows toolchain here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scarletnx-gnuabi has no game folder, keys, update or timed run, so of the
common options only two fit. -h/--help now goes through snx_cli_match and
prints the shared lines first. --data DIR (or --data=DIR) is new: the data
folder whose linux/ is the guest's default root, which before was always
the one snx_data_dir picks. A --data run leaves the deprecated
SNX_LINUX_SYSROOT out, as the command line goes first. The other common
options are refused in the shared wording. Its own QEMU-like options (-L,
-E, -U, -0, --sysroot=, --jit-*) are unchanged.

Verified with the 9 gnuabi ctests and runs of --help, --data with no
folder, --keys (refused) and --data DIR with an ELF. No Windows toolchain
here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
usage.md gets a "Common options" section: the table of the options every
driver reads from common/utilities/cli.c, both forms of a value, the shared
refusal, and which driver takes each. Each platform's README links it and
says which of them its driver takes, and the pages that named the old forms
(the Vita's --patch DIR, the AGB's --fullscreen=1 and --script=, Android's
--keys=TEXT and --headless) give the names now. deprecations.md's "Now"
table records the Vita's --patch (still taken, said once a run) and
Android's --keys=TEXT (refused with a message that names --type), under the
row the "[cli] the options' names" notice already covers.

Verified with scripts/check-docs.py and the setup, docs and claude_ste100
ctests (setup holds each row of "Now" to a notice).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The rebase onto main brought in NfcAdapter.java, which names
docs/android/INTERFACES.md. That page is now
docs/platforms/android-apps/interfaces.md.

Verified: scripts/check-docs.py, and a grep for the old docs paths
outside the stub pages and the docs test fixtures finds none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The zip reader took the stream's lock around a seek and a read, so that
threads could read members of one zip at once. plat_pread reads at an
offset and leaves the stream's position alone, so the lock and the two
host-specific lock calls are not needed.

Verified: the full build on FreeBSD, and the full ctest (816 of 819). The
failures are 3ds_memory_adopt and android_bionic, which also fail on main,
and 3ds_hid, which timed out under load and passed three runs alone.
Windows was not built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The file calls were in four places: plat_pread, the read-only maps and plat_replace_file in plat_posix.c,
plat_win32.c and plat_sdl.c, the shared files and plat_mkdir in common/filesystem/host.c, the Android bridge's
host_pread and common.c's snx_replace. Now file.c has plat_pread_fd (the descriptor form), plat_pread on a FILE*,
plat_is_dir, plat_mkdir and snx_host_wpath, file_map.c the PFileMap maps, file_share.c the shared files and
file_replace.c plat_replace_file. Each group is an object file of its own, as the tests stub them by group.
common/filesystem/host.{c,h} are gone, and their includers include file.h, or thread.h for PMutex alone.

plat_pread_fd keeps host_pread's errno (EBADF and EIO on Windows, pread's elsewhere), and sets EINVAL for a range
past INT64_MAX, where plat_pread returned -1 with no reason. plat_is_dir and plat_replace_file no longer go through
SDL: stat or GetFileAttributesW, and rename or MoveFileExW.

snx_replace and plat_replace_file differed in two ways. snx_replace asked MoveFileExW for MOVEFILE_WRITE_THROUGH,
and plat_replace_file did not: the merged one keeps it, as each caller replaces a file or folder that must be whole
on the disk before the call returns (saves, settings, caches, compiled modules). plat_replace_file deleted its
source on failure, and snx_replace kept it: the merged one keeps it, because the 3DS driver moves whole folders of
saves with it, which a failed move must not delete. The NX callers that relied on the deletion (the pipeline cache
and the save state writer) now remove their temporary file themselves, as the settings, the hints and the shader
files already did.

Verified on FreeBSD 15: the RelWithDebInfo build and ctest, where only the known 3ds_memory_adopt, android_bionic and
android_arm32 fail. The Windows code was moved, not built (no cross toolchain here), and Linux and Apple were not
run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Six places made address space on their own: common.c's snx_vm_* (the JIT's code arena and the Vita), the 3DS and
AGB's snx_host_* on POSIX, the Android bridge's host_reserve, host_commit, host_lazy, host_protect and host_unmap,
gnu_memory_init's aligned reserve and its protects, the Vita's direct mmap decommit, and the NX runtime's
plat_vm_reserve and commit. Now vm.c has plat_mem_page, plat_mem_reserve (aligned to a power of two, with the trim of
the NX reserve), plat_mem_reserve_at (Linux's MAP_FIXED_NOREPLACE, FreeBSD's MAP_FIXED with MAP_EXCL, else a hint
that is checked), plat_mem_commit (fresh zero pages over whatever is there), plat_mem_alloc, plat_mem_decommit,
plat_mem_protect and plat_mem_release.

Two kinds of commit stay apart on purpose. plat_mem_commit maps fresh pages, which the 3DS views and the Android
bridge need. A commit that keeps the mapping (the NX runtime, whose userfaultfd registration a new mapping would
drop, the code arena's data pages and the Vita) is plat_mem_protect, which on Windows commits the reserved pages
first as snx_vm_protect did. The NX runtime keeps its write-tracking wrappers, the Windows write watch reservation,
the Linux MADV_DONTNEED decommit and the alias pool on top. The 3DS's Windows placeholders and views stay in
memory/host.c.

Behaviour changes: the Android bridge's reservations on FreeBSD are PROT_NONE mappings with MAP_EXCL, not MAP_GUARD
guards, so plat_mem_protect works on them as on the other hosts. Its Windows commit decommits first, so a commit
always gives zero pages. The GNU ABI's reservation now has MAP_NORESERVE. A failed reserve_at on Windows says EEXIST.

Verified on FreeBSD 15: the RelWithDebInfo build and ctest, where only the known 3ds_memory_adopt, android_bionic and
android_arm32 fail. The Windows code was not built (no cross toolchain here), and Linux, Android and Apple were not
run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There were two library loaders: the NX runtime's plat_dl_* through SDL in plat_sdl.c (with plat_dl_loaded in
plat_posix.c and plat_win32.c), and common.c's snx_library_*, which the 3DS, AGB, Vita and Android drivers used.
Now dl.c has plat_dl_open, plat_dl_sym, plat_dl_close, plat_dl_error and plat_dl_loaded, with dlopen and RTLD_NOW |
RTLD_LOCAL, or LoadLibraryW of the UTF-8 path, as both did. plat_dl_error keeps the calling thread's last reason,
dlerror's or the system's message for GetLastError. snx_library_* is gone, and its callers say "cannot load PATH:
reason" from plat_dl_error as snx_library_open did.

Android's shared storage is mounted noexec, so the NX runtime loaded a module from a copy in SDL's cache folder when
the system refused it. That copy needs SDL, which the platform target does not link: plat_dl_fallback takes it as a
hook, which plat_sdl.c registers on Android with a constructor, as plat_posix.c registers the thread hooks.

Verified on FreeBSD 15: the RelWithDebInfo build and ctest, where only the known 3ds_memory_adopt, android_bionic and
android_arm32 fail, and two games run headless for 60 seconds with input, one to its title screen and through its
intro, the other into play (their modules load through plat_dl_open). The Windows code and the Android hook were not
built (no cross toolchains here), and Linux and Apple were not run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
src/nx/runtime/platform/plat.c holds the log and the fatal error, and nothing of the platform layer: log.h already
declared what it defines. It is now log.c, and the build, the test that includes it, the comments that named it,
CLAUDE.md's Platform row and the two reviewer agents that list it follow. The Platform row and docs/ARCHITECTURE.md
also name common/platform, the host layer every driver now shares, in a few words.

Verified on FreeBSD 15: the RelWithDebInfo build and ctest (claude_ste100 and platform_log among them), where only
the known 3ds_memory_adopt, android_bionic and android_arm32 fail. Windows was not built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The bridge's host_tid was a second copy of plat_tid (thread.h): Linux's gettid, FreeBSD's pthread_getthreadid_np,
the low half of macOS's thread id and Windows' GetCurrentThreadId, each the same. bionic's thread id slot and the
signal calls now take plat_tid, which keeps the id per thread after its first call. The bridge forks no process
(fork is refused), so a kept id never belongs to another process.

Verified on FreeBSD 15: the build, and the android tests, where only the known android_bionic and android_arm32
fail. Windows and Apple were not built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scarletnx-3ds parsed -x, -r, --extract-container, --game=, --update, --data,
--outdir, --output, --keys and --seconds by hand. It now matches them through
snx_cli_take first and parses only its own options (--model, --board-info,
--max-blocks, --ipc-stubs, --KEY=VALUE) after. Each value option now takes
both --opt VALUE and --opt=VALUE (--game DIR, --keys=FILE, --data=DIR were
refused before). --script and -f/--fullscreen are the common names of the
settings ctr_script and fullscreen, so --script SPEC and -f work too. A
common option the 3DS cannot do (--headless, --frames, --shot) is refused
as "scarletnx-3ds does not take --headless". --help shows the common lines,
then the 3DS options, aligned in one column, with no semicolons.

Verified with ctest 3ds_driver (new checks for the forms, the refusal and the
help), 3ds_update, 3ds_dlc, 3ds_addons, 3ds_extract, 3ds_container, 3ds_cci,
3ds_fs and 3ds_decrypt. No Windows toolchain here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scarletnx-vita parsed -x, -r, --game=, --shot=, --seconds, --data, --outdir,
--output and --patch by hand, --game and --shot only in the = form. It now
matches them through snx_cli_take first and keeps only its --KEY=VALUE
settings. The dumped game's update folder is --update DIR, as the other
drivers name an update, and --patch stays as its older name, said once.
--game, --shot and the rest take both --opt VALUE and --opt=VALUE, and
--script is the common name of the setting vita_script. The local
parse_seconds, a copy of snx_parse_seconds, is gone. A second --update, or a
common option the Vita cannot do (--keys, --frames, -f, -H), is refused.

Verified with the vita ctests, and runs of scarletnx-vita --help, --patch,
--patch=DIR with --shot S --seconds 2, two --update, --keys and --seconds 0,
each giving the expected message and status. No Vita game is on this
machine, so no game was played. No Windows toolchain here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The driver matched -x, -r, -H, -f, --extract-container, --data, --update,
--outdir, --keys and --game by hand, in the forms each stage happened to
take. snx_driver now runs each argument through snx_cli_match first and puts
the option into rest in the form the stages after it read: --update,
--outdir and --keys as the option and its value, --data into the data
folder, the flags into the SNX_* bits. Combined letters (-rx, -Hs), -S, -s,
--tracy, --build-dir, --program and the rest stay local. snx_cli_flag
(nx/runtime/cli.h), which the game runtime's startup.c shares, takes its
long names and single letters from the table too.

--game, --seconds, --frames, --shot and --script given as --opt VALUE are
joined into --opt=VALUE (snx_cli_joined) in the driver and in snx_main, so
the runtime's settings take both forms. --mcp takes --data=DIR too, and its
message names --data, not --repo. --output, which the Switch has no use for
(--out names the dump's extraction), is refused in the shared wording.
--help shows the common lines, then the Switch options, then a paragraph
for what is the Switch's own (dumps, prod.keys, the data folder's default).
--fullscreen=invalid now says "--fullscreen takes 0 or 1", which
driver_workflow now checks.

Verified with ctest driver_workflow, runtime_unknown_option and the extract,
setup and mcp tests. A recompiled game ran through its own copy with
--keys=FILE --seconds 30 --shot PATH, and through build/rel/scarletnx with
--keys FILE --game DIR --seconds 20 --shot PATH. Both ended at the time
limit with exit 0 and wrote the screenshot. No Windows toolchain here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main added the comment after the documents moved into docs/layers.

Change-Id: Iacd9a7bd1e3833fde15ccb95e861cb3db423412b
Signed-off-by: AO55 <AO55@reden-emu.dev>
astc.c, blocklinear.c and texconv.c make their pipelines through snx_vk_common now.

Change-Id: I91ec4ed84226c2c151158ee0cb7cd69e2f31cd57
Signed-off-by: AO55 <AO55@reden-emu.dev>
The rebase dropped the leaf the copy's messages print.

Change-Id: Iff03713566f569d8225099a10d17ce4a38b9186d
Signed-off-by: AO55 <AO55@reden-emu.dev>
The header that brought it moved into common/platform.

Change-Id: If3584dcc3c814d1bea9b8a11051f3a8dc6051c44
Signed-off-by: AO55 <AO55@reden-emu.dev>
fgetc, __fgets_chk, __memchr_chk, __strncpy_chk, mkdtemp, nextafter, fmax and fmin, with
their float forms: edenprobe's arm64 library imports them, and they returned 0 (30 cases).
android_bionic calls each, and checks the FORTIFY aborts with their sizes off Windows.

Change-Id: I31ef610589377641bde85d9a459509dba701ee2c
Signed-off-by: AO55 <AO55@reden-emu.dev>
open64, openat, creat, pwrite, pipe2, eventfd, memfd_create, umask, faccessat, unlinkat,
link, symlink, mkstemp, getpriority, setsid, fma, lround, __strncat_chk and more had none.
android_bionic calls each; Windows and macOS say ENOSYS and the name where they lack one.

Change-Id: Id7add2d31e45cdf0c581bf310d6e57c5a5ab9607
Signed-off-by: AS55 <AS55@reden-emu.dev>
setsid is ENOSYS by name: a session of its own would take the emulator off its terminal.
openat is called with the guest's O_DIRECTORY and O_NOFOLLOW (AArch64's values).

Change-Id: I4df274258efb092bdae9120f81d847a6abcdfcfe
Signed-off-by: AS55 <AS55@reden-emu.dev>
macOS' C library makes such a template's file as it is named, where bionic's OpenBSD code
gives EINVAL.

Change-Id: I581bf3062beacccae4f0487460f61ca20497915a
Signed-off-by: AO55 <AO55@reden-emu.dev>
Its kernel call made the thread's kernel state before bridge_init, which wiped its table:
a leak under ASan and a crash on Windows.

Change-Id: Ie97bac1b14109a019acf6007ef2fa9a12de72845
Signed-off-by: AO55 <AO55@reden-emu.dev>
It makes an unlinked temporary file where the host has none, so the ENOSYS one goes.

Change-Id: I541cc50b8f4e78f10ac459cfaf5e1e7dd985f360
Signed-off-by: AO55 <AO55@reden-emu.dev>
The main thread's SetThreadStackGuarantee lost it in the move to common/platform.

Change-Id: I7ebf0366263c499b1322455ec77e6ffc72c382fd
Signed-off-by: AO55 <AO55@reden-emu.dev>
runtime_architecture found the platform code linked into sanitized tests without them.

Change-Id: Iaf37c973e7aee1b2f90e83ea01f778de8beb03b7
Signed-off-by: AO55 <AO55@reden-emu.dev>
plat_wait_word's WaitOnAddress moved there, and the 3DS tests that link it failed to.

Change-Id: Icc3657beb95486c73ec995860624124f452f3bf6
Signed-off-by: AO55 <AO55@reden-emu.dev>
A 3DS emulator app's library has R_AARCH64_TLSDESC relocations, which the
linker refused ("unknown relocation type 1031"). It also had already put
the library in the global group, so the app's later lookups found the
symbols of a library whose code the JIT did not have and whose
constructors never ran: the first call of one jumped to "no code".

- Each library's PT_TLS is a module of dynamic TLS, as bionic gives a
  dlopen'd library's. Each thread gets the module's block (its .tdata,
  then zeros) the first time it reaches it.
- TLSDESC descriptors point at an HLE resolver that gives the variable's
  offset from the thread pointer in x0 alone, as the ABI asks.
  DTPMOD64/DTPREL64 and __tls_get_addr give the general dynamic model.
- A library whose relocations fail leaves the global group again.

Verified: the app's library loads and its constructors run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
They had no HLE, so each returned 0: an emulator app's reallocarray gave
no memory, its strnlen empty strings, and its fortified preads read
nothing, so it saw its game file as the wrong type.

- reallocarray: realloc of count times size, ENOMEM for a product past
  SIZE_MAX.
- strnlen: the host's.
- __pread_chk and __pread64_chk: pread through host_pread, failing as
  fortify does for a count past the buffer.

Verified with the app: it reads its 3DS game file's header and lists the
game with its title.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An app that probes the GPU's GLES renderer through EGL14 (a pbuffer
context and glGetString) failed with NoClassDefFoundError. EGL14 and its
EGLDisplay, EGLConfig, EGLContext and EGLSurface call the runtime's EGL
through Egl10's natives, as JSR 239's EGL10 does: one Java object for each
handle, the arrays read and written at their offsets, OpenGL ES the only
client API.

Verified with an emulator app: it reads the GLES renderer string at
start.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An app's theme inherits from the framework's themes on a device, which
the tables lack, so a framework attribute that the app's own styles never
set had no value: Material's BottomNavigationView, whose styles leave
android:textAppearance to the theme, refused to inflate ("This component
requires that you specify a valid TextAppearance attribute").

When the app's theme lacks textAppearance or textAppearanceSmall, Medium
or Large, the theme gives the framework's TextAppearance style IDs, as
Theme.DeviceDefault's do.

Verified with an emulator app: its main screen with a bottom navigation
bar inflates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The first GLES surface brings the GLES-over-Vulkan device up, which it
chooses by a surface of the window, and making that surface takes the
window from ScarletNX's renderer (its frames then go into the layer that
an app's presents blend). An app that only made a pbuffer to read the GLES
renderer string so took the window for good: no view frame showed again,
and no shot came.

A pbuffer's first surface is a probe now (hle_vulkan_probe_surface), of
the same kind but without the renderer giving the window up; the device is
chosen by it as before.

Verified with an emulator app that probes GLES at start: its welcome
screen draws and the shots come.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A command is resolved through the guest's last instance, else another
  that lives. The loader gives an extension's command for an instance
  that enabled it, and an app that makes a surface-less instance after its
  main one got no surface commands (ExtensionNotPresent on
  vkGetPhysicalDeviceSurfaceFormatsKHR). When the last instance goes, the
  one before is the last.
- Without a display, vkEnumeratePhysicalDevices lists the devices that
  present to a headless surface first: a driver without headless
  presentation has no present queue or surface formats for the app's
  surface, and an app that takes the first device then takes one that
  shows its frames. No device is left out, and with a window the host's
  order stays.

Verified with an emulator app on a host with an NVIDIA GPU and llvmpipe,
without a display: its renderer starts on the presenting device and the
game boots.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- An android.settings.* intent opens a screen of the system's Settings,
  which every device has: the caller gets RESULT_CANCELED, as when the
  user backs out, instead of ActivityNotFoundException.
- Environment.isExternalStorageManager is true for an app that asks for
  MANAGE_EXTERNAL_STORAGE, as every permission it asks for is granted
  here.

Verified with an emulator app whose setup asks for all-files access: the
step completes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- DocumentsContract's createDocument, renameDocument, deleteDocument,
  removeDocument, copyDocument and moveDocument call the document's
  provider through the content resolver, and DocumentsProvider answers
  them, as Android's do: an app's DocumentFile.createDirectory made
  nothing before.
- The shared storage's documents ("primary:<path>") are the files under
  Environment.getExternalStorageDirectory(), as Android's: an app that
  turns a tree into a path (the primary volume's folder, then the path)
  finds the same files. A folder --pick gives that is elsewhere on the host
  is linked into the shared storage by its name, as if the user had picked
  it there.
- The external storage provider copies, moves and removes documents, and
  deletes a folder with what it holds.

Verified with an emulator app that keeps its user folder in a picked
tree: it makes its folders there, reads its keys from it and lists the
game in it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An emulator app shows its second screen in a Presentation, and without a
second display it puts that on a virtual display of its own that nothing
shows; the class was missing (NoClassDefFoundError).

- Display has an ID, flags and size: the default one is the host window;
  DisplayManager.createVirtualDisplay makes others (presentation and
  private flags as Android sets them), lists them, and tells its display
  listeners when one is added or released.
- createDisplayContext gives a context of the display, with its metrics,
  whose window manager puts windows on that display.
- A window on a display other than the host window's lays its views out
  and draws for no screen: it is not part of the host's frames. A
  SurfaceView there gets a surface that shows nowhere, which
  ANativeWindow_fromSurface gives a window of its own (as a SurfaceTexture's
  surface), so the app's renderer draws its screen into nothing instead of
  the host window.
- Presentation is a dialog on its display; WindowManager has
  InvalidDisplayException for a display that was released.

Verified with the app: its game screen starts, with the presentation on
the hidden display and the game drawn on the host window.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A drawable turned by its level, from fromDegrees at level 0 to toDegrees at
10000, about its pivot (a fraction of the bounds or a dimension), as
Android's. An emulator app's navigation menu icon is a <rotate>, which
failed to inflate ("invalid drawable tag rotate").

Verified with the app: its menu inflates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Members an emulator app's classes call:
- Bundle.getParcelableArray(String, Class) and
  getSparseParcelableArray(String, Class), API 33's typed getters;
- Os.dup, a second descriptor of the host's open file, and Os.lseek
  through the descriptor's channel, which shares the host's offset;
- View.requestUnbufferedDispatch, a request for events as they come,
  which they always are here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An invoke-super of a default method of an interface that the class
implements only through another interface (a lifecycle observer that
inherits DefaultLifecycleObserver.onCreate from an interface of its own)
went to the superclass, as the JVM allows invokespecial only of the
superclass and a direct superinterface. Resolution from the superclass
does not see the default method, so the call failed with
NoSuchMethodError 'void java.lang.Object.onCreate(LifecycleOwner)'.

The call now goes to the direct superinterface that is the interface or
extends it through interfaces of the program, as an InterfaceMethodref,
whose resolution finds the default method among its superinterfaces.
Calls with no such interface still go to the superclass.

Verified with a browser app, whose boot got past its lifecycle observers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An app that sets its own default uncaught exception handler can swallow
the exception that ends the boot: a browser app's handler records it and
returns, so the process exited with 0 and no trace of what failed.
Android's RuntimeInit logs every uncaught exception with a pre-handler
before the default handler runs, so the boot's exception is now logged
as "FATAL EXCEPTION" first when the default handler is the app's (the
runtime's own logs it already).

Verified with a browser app: its boot failures show in the log.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
JobScheduler.forNamespace (API 34) gives a scheduler of a namespace's
own jobs: the same job ID in two namespaces is two jobs, and cancel,
getAllPendingJobs and getPendingJob see only the namespace's. The
pending jobs keep their namespace, and a finished job is removed by
itself instead of by its ID, which another namespace may share.

A browser app's work manager schedules its jobs in a namespace and
failed with NoSuchMethodError on forNamespace. Verified with the app:
its workers are scheduled and run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The device has no speech recognition service: isRecognitionAvailable and
isOnDeviceRecognitionAvailable are false, startListening reports
ERROR_CLIENT to the listener, and checkRecognitionSupport reports
ERROR_CANNOT_CHECK_SUPPORT, as Android does without a recognizer. A
browser app's voice search checks for one at startup and failed with
NoClassDefFoundError.

Verified with the app: its boot gets past the check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
WebView stays without a web engine; a browser app also builds against
the parts of android.webkit around it, which failed to link. Added, all
inert or giving what a WebView that loads nothing has:
- WebView: an empty back-forward list, find-in-page, web messages, the
  certificate, scale, the WebView looper and class loader, printing,
  and typed download and find listeners. getCurrentWebViewPackage
  returns a PackageInfo (null: no provider), as Android's does;
- the clients' onReceivedHttpAuthRequest (cancelled) and
  doUpdateVisitedHistory, and onReceivedTouchIconUrl;
- DownloadListener, WebHistoryItem, WebBackForwardList, WebMessage,
  WebMessagePort, HttpAuthHandler, GeolocationPermissions, WebStorage,
  WebViewDatabase (HTTP auth credentials kept in memory), and the
  service worker controller, client and settings;
- URLUtil, Android's URL checks and guessFileName;
- android.net.http.SslCertificate, with its distinguished names.

Verified with the app: its classes link and its boot gets past them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TaskStackBuilder builds an activity's back stack from the manifest's
parent activities (addNextIntentWithParentStack, addParentStack) and
starts it, or makes a PendingIntent of it, with the first intent
starting a new task cleared over home (NEW_TASK, CLEAR_TASK and the
new FLAG_ACTIVITY_TASK_ON_HOME), as Android's does. The manifest's
android:parentActivityName is now read into ActivityInfo.

A browser app builds its notifications' and widgets' intents with it
and failed with NoClassDefFoundError. Verified with the app: its boot
gets past it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There is no home screen to host widgets, so they are never shown, but an
app's widget classes still link and run their callbacks:
- AppWidgetProvider, a receiver that sends the widget broadcasts
  (update, options changed, deleted, enabled, disabled, restored) to its
  callbacks, as Android's onReceive does;
- AppWidgetManager's actions and extras, empty widget options, pinning
  that is not supported, and notifyAppWidgetViewDataChanged;
- RemoteViewsService and its RemoteViewsFactory;
- RemoteViews' collection members (setRemoteAdapter, RemoteCollectionItems,
  setEmptyView, the click templates and fill-ins), recorded nowhere.

A browser app's search and favorites widgets failed with
NoClassDefFoundError at startup. Verified with the app: its boot gets
past them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- DnsResolver resolves a name through the host's resolver on a thread of
  its own and answers on the caller's executor, with DnsException for a
  name that does not resolve;
- InetAddresses.isNumericAddress and parseNumericAddress, a numeric
  IPv4 or IPv6 address without a lookup;
- VpnService: prepare says the app may start one (null), protect is a
  no-op, and the Builder keeps its settings but establish gives no
  interface (null), as when the system refuses the VPN.

A browser app's tracker blocking and DNS code linked against them and
failed with NoClassDefFoundError. Verified with the app: its boot gets
past them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The device's autofill framework never binds an app's autofill service
(the app is not the user's chosen one), but a password manager's
service class and the types it builds still link:
- AutofillService, with its fill, save and saved-datasets callbacks;
  onBind gives no binder, and a saved-datasets request reports
  ERROR_UNSUPPORTED;
- FillRequest, SaveRequest, FillContext, FillEventHistory, and the
  responses' Dataset, Field, Presentations, InlinePresentation and
  FillResponse with their builders;
- AssistStructure with its window and view nodes, ViewStructure.HtmlInfo,
  InlinePresentationSpec and InlineSuggestionsRequest, which they carry.

A browser app's autofill service failed with NoClassDefFoundError at
startup. Verified with the app: its boot gets past it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Members a browser app's classes call:
- Process.getStartRequestedUptimeMillis and
  getStartRequestedElapsedRealtime (API 33), 0 as the start times are;
- Parcel.readLongArray and writeSparseArray;
- Point.CREATOR and readFromParcel, and Bitmap.CREATOR, which reads the
  bitmap that writeToParcel puts in the parcel's object table.

Its startup timing failed with NoSuchMethodError on
getStartRequestedUptimeMillis. Verified with the app: its boot gets past
it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A rectangle of the color that a ColorStateList gives for the drawable's
state, stateful when the list is, with its own alpha and color filter,
as Android's. A browser app's tab layout makes its background one and
failed to inflate with NoClassDefFoundError.

Verified with the app: its onboarding screen inflates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- All of View's protected state sets (the combinations of pressed,
  enabled, focused, selected and window focused), which a subclass's
  onCreateDrawableState reads; only three were there, and a browser
  app's tab layout failed with NoSuchFieldError SELECTED_STATE_SET;
- setTouchDelegate and getTouchDelegate, the delegate given the touches
  first in onTouchEvent, as Android's;
- setRequestedFrameRate and getRequestedFrameRate, kept;
  isShowingLayoutBounds (false) and postInvalidateDelayed of a rectangle.

Verified with the app: its onboarding screen inflates and draws.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ObjectAnimator.ofObject and PropertyValuesHolder.ofObject of a Path and
a TypeConverter from PointF: the value is the path's point at the
animation's fraction of its length, its contours joined with no length
between them, as Android's path keyframes are, converted to the
property's type. ofFloat of an x and a y property along a path sets
each coordinate. Also ofObject of a Property with an evaluator and a
converter, and the converter's use when values are set.

Added TypeConverter, FloatEvaluator, IntEvaluator, PointFEvaluator and
RectEvaluator, and LayoutTransition's setAnimateParentHierarchy and
isChangingLayout.

A browser app's onboarding uses a ChangeBounds transition, which moves
its views along a path, and failed with NoSuchMethodError on
ObjectAnimator.ofObject. Verified with the app: its onboarding moves to
the next step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The device has the default apps' roles (browser, dialer, SMS, home,
assistant and the others) and the app holds none: isRoleAvailable is
true for them, isRoleHeld false, and createRequestRoleIntent gives
Android's REQUEST_ROLE intent for the permission controller. Starting it
answers RESULT_CANCELED, as the system's Settings screens do here, as if
the user backed out of the dialog. The service is Context.ROLE_SERVICE.

A browser app's onboarding asks to be the default browser and failed
with NoClassDefFoundError. Verified with the app: the request returns
and the onboarding moves to its next step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Layout styled each run of text with every span that getSpans gave for
it. getSpans also gives, as Android's does, the empty spans at the
run's ends and the spans that only touch it, which Android's text
drawing (SpanSet) leaves out. A typing animation that moves a
transparent color span along the text leaves it empty at the end, and
that hid the whole last line: a browser app's onboarding titles showed
only their first line, or nothing for a one-line title.

The paint and replacement spans of a run are now those over some of its
text.

Verified with the app: its titles show in full once typed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The renderer clamped a round rectangle's x radius to half its width and
its y radius to half its height each on its own, so a pill drawn with a
huge radius (a Material button's fully rounded shape) became an ellipse.
Radii too big for the sides are now scaled down by one factor, as
Skia's SkRRect does, which keeps the pill.

Verified with a browser app: its onboarding buttons are pills.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- setHeight and setWidth, an exact size in pixels (the minimum and the
  maximum), and setMaxHeight, which caps the measured height before
  the minimum as Android's onMeasure does;
- setImeActionLabel, setPrivateImeOptions and their getters, kept for
  the input method;
- setSelectAllOnFocus, which selects the text when the view gains focus.

A browser app's pill label sets its height and failed with
NoSuchMethodError on setHeight as its first screen inflated. Verified
with the app: the screen inflates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AnimatorInflater.loadStateListAnimator reads a <selector> of items, each
with its state attributes (negated when false, as a drawable selector's)
and the animator inside it, into a StateListAnimator. A Material app bar
sets its elevation animator from one, and a browser app links against
it. The views' state changes still apply at once here.

Verified by building and with the app, whose browser screen shows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Intent.getSerializableExtra(String, Class) (API 33) and the chooser
  with an IntentSender for the chosen app (none is chosen here);
- IntentFilter.countDataAuthorities and countDataPaths, which now count
  what addDataAuthority and addDataPath add;
- TextUtils.expandTemplate, ^1 to ^9 and ^^ as Android's;
- OsConstants' address families AF_UNSPEC, AF_UNIX, AF_INET and
  AF_INET6, Linux's values as Android's are;
- Window's enter, exit, return and reenter transitions, kept (the
  return and reenter ones default to the enter and exit ones).

Verified by building; the app links against them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A layout element named view takes its class from its class attribute,
as Android's createViewFromTag does. Material's snackbar layout is one,
and it failed with ClassNotFoundException: view when a browser app
showed a snackbar on its first screen.

Verified with the app: its browser screen shows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Visibility, Fade, Slide, ChangeBounds and AutoTransition (fade out,
move, fade in), with their modes, edges and options, and Scene, a
layout or enter action for a scene root, one per layout. A scene
change shows at once here, as every transition does:
TransitionManager.go and transitionTo enter the scene and tell the
transition's listeners of a start and an end.

A browser app's screens build ChangeBounds transitions and failed with
ClassNotFoundException. Verified with the app: its browser screen shows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every Android WebView provider has AndroidX WebKit's support library
glue (org.chromium.support_lib_glue), which AndroidX finds through
WebView.getWebViewClassLoader. For a feature of API 33 and later, such
as ALGORITHMIC_DARKENING, AndroidX reports the feature as supported by
the framework but sets it through the glue, and checks that the
provider's package is version 105 or later. A browser app sets it on
its first screen and failed with UnsupportedOperationException.

WebView keeps no engine, so the glue is as inert. Its factory supports
only ALGORITHMIC_DARKENING, and its settings go to WebSettings' methods
of the same name, or are kept and read back. Every other call gets a
default value: an inert handler for an object, an empty array or
collection, false or 0. getCurrentWebViewPackage now gives AOSP's
provider package, version 136.

Verified with the app: its browser screen shows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A failed job already decides the run; the jobs still going only cost runner time.

Change-Id: Iea1598c65c0a25b44b792400161bdd540008b457
Signed-off-by: AO55 <AO55@reden-emu.dev>
host_pread became plat_pread_fd in the platform move, so main no longer built the bridge.

Change-Id: I1dc5325a134c43cca856a49317a909316806a402
Signed-off-by: AO55 <AO55@reden-emu.dev>
A job that cancelled its own run ended cancelled, so the run showed no failure at all.

Change-Id: Ib9f1529e7d80917f56a0a2ff970258ba5aca0caf
Signed-off-by: AO55 <AO55@reden-emu.dev>
Every Windows platform file linked file.c for it, against filesystem_service's own plat_*.

Change-Id: I71d684fd464bd58e8a6c537b1e0e141ce9418218
Signed-off-by: AO55 <AO55@reden-emu.dev>
android_bionic wants one on every host, and Windows answered ENOSYS.

Change-Id: I3904db7c5d51a668324f4d24b6a72754b742b27b
Signed-off-by: AO55 <AO55@reden-emu.dev>
llvm-rc took src/common/platform as an include path, where time.h hides the system's.

Change-Id: I99b7beaec7c3143a352087f0c5c351625bfebec9
Signed-off-by: AO55 <AO55@reden-emu.dev>
The resources moved there, and platform/ itself hides the system's time.h.

Change-Id: I1a493416764daa9c908072226f9e1e9c95d6b6d5
Signed-off-by: AO55 <AO55@reden-emu.dev>
Joins these commits of fuddlesworth's feat/ounce, rebased on main:
- 83d85a5d4 [nvn] Bring up an Ounce game on the NVN loader, with an SM70+ shader frontend
- f3793dfa2 [nvn] Draw an Ounce game's title screen right
- d662b1391 [gpu] Translate an Ounce game's shipped programs before it starts
- 2c9a3f723 [test] gpu_park links blocklinear.c, where g_gob_native is
- 48d614c0f [gpu] Read an Ounce program's root tables as banks 24 to 31
- 771d1d425 [gpu] Make the SM70+ program dump a setting, and pass main's new doc checks
- 0049e8066 [docs] Call the second console Ounce, its name in the game files
- 36a8d2761 [gpu] Call the Ounce's shader frontend SM86, its GPU's, not SM70

With main's SNX_RC_* result names, audin only in audio.c, and blocklinear.c linked where the
tests reach it. mem_layout_large_heap moves the kernel region with the stack where it follows
the stack, as main lays out its reservations past 128 GiB as well (memory_accounting checks
512, 256 and 128 GiB, and 32 and 48).

Rebased-by: AO55 <AO55@reden-emu.dev>
Joins these commits of fuddlesworth's feat/ounce, rebased on main:
- c8567f0f0 [nx] Give an Ounce game its 31.25 MHz tick, and tell one by its NPDM
- bce9db473 [nx] Make the NPDM the one Ounce flag, for the CPU, memory and GPU
- 7f5825866 [nce] Count an Ounce game's 31.25 MHz tick in the counter's stubs

Rebased-by: AO55 <AO55@reden-emu.dev>
Joins these commits of fuddlesworth's feat/ounce, rebased on main:
- 6c14e4ced [hle] Answer an Ounce game's IApplicationProxy GetPerformanceFunctions
- 5dc34f260 [hle] Answer the five service commands an Ounce game's boot left undeclared

Rebased-by: AO55 <AO55@reden-emu.dev>
Joins these commits of fuddlesworth's feat/ounce, rebased on main:
- 43f335924 [tools] Let nvn_missing.py run again without nvn_verify_kinds

Rebased-by: AO55 <AO55@reden-emu.dev>
Joins these commits of fuddlesworth's feat/ounce, rebased on main:
- 9e4d0c05a [hook] Read the SDK version of an Ounce module's label

Rebased-by: AO55 <AO55@reden-emu.dev>
The SM86 translator declared each global buffer a storage buffer of its
own, so the GPU's compiler took them for different memory and could keep
a value it had read. One game binds a range and a part of it to the same
compute program, writes through one and waits for the value through the
other: the program never finished, the runs froze with the GPU's
submissions undone, and the driver timed out its context (Xid 109, CTX
SWITCH TIMEOUT), which the runtime saw as a lost device. On the console
global memory aliases freely and another invocation's store is seen:
the buffers are now Aliased and Coherent.

Verified: breadcrumbs around each dispatch named the program that never
finished (one workgroup, three buffers, two of them overlapping). With
the decorations, no run lost the device in seven, against most of them
before; shader_sm86 passes.

(cherry picked from commit c7535df6055d8dac42cf99634e3f0ff517f045df)
The SM86 translator refused every TEX and TLD4 with a texel offset, and
TLD with one: 107 of one game's fragment programs, whose draws were
skipped (a menu draw every frame among them).

- The offset follows the LOD in the second operand list, before the
  depth reference, as Mesa's NAK lays it out: four bits a component for
  TEX and TLD, eight for TLD4, and TLD4's own offset for each texel in
  two registers.
- Vulkan takes a sample's offset as a constant only. Where every path
  to the TEX sets its register with one unpredicated MOV of the same
  immediate, and nothing else that may write it comes after, the sample
  takes it as ConstOffset (the game's programs all do). Otherwise the
  coordinates move by the offset over the size of the level sampled.
- TLD adds its offset to the integer coordinates. TLD4 passes it as a
  gather's Offset; an offset for each texel takes four gathers, each
  texel from the one with its offset, as SPIR-V's ConstOffsets does.

Verified: shader_sm86 checks the ConstOffset of a MOV before the TEX,
of two paths setting the same value, and none for paths setting
different values, a guarded MOV or a path without one (the coordinates
move instead); TLD4's four gathers and TLD's fetch; spirv-val passes on
each. Taking the first MOV found on any path, or not sign extending the
offset, fails it. The game's 111 programs with offsets translate, and no
draw is skipped in the menus. All tests pass but the two forced-UMA ones
that fail on main too.

(cherry picked from commit f21914678d07ceb722ba1a204ff8aa6d56bf66b0)
The GPU hangs that ended most runs of one game (Xid 109, CTX SWITCH
TIMEOUT, then a lost device) were one compute program's, run once at
boot: checkpoints in the command stream named its dispatch as the last
begun and never done. It has no loop, but its translation had: both of
its BRX went to the wrong instructions.

- BRX's offset is bits 34 to 81 in 4-byte units, as BRA's. Read from
  bit 33, each of the program's two BRX added its own index plus one
  less than the table's targets, and two of the cases went back to the
  program's start. ptxas writes minus the next instruction's address,
  which bit 34 gives for both.
- A jump table is as long as ptxas's bound on the index says (an
  unsigned IMNMX with an immediate, then an IMAD by 4), no longer read
  up to the first word that names no instruction: the program's two
  tables lie one after the other in c[1], and the first BRX took the
  second's targets as its own.
- The base of each global address follows the flow: a block starts with
  the bases its reached predecessors end with where they agree, until
  none changes. In program order the jump table's cases wrote over the
  address register that the code after them had from before them on
  every path; once the targets were right, that code was reached and
  the program refused.

Verified: shader_sm86 checks a BRX's cases are the instructions its
table names (reading the offset from bit 33 fails it), that a bounded
table's word past its entries isn't a case and makes no loop (ignoring
the bound fails it), and that an address's base on the path to its LDG
wins over one written on a path that exits (in program order, fails
it), with the program refused where the paths disagree. In the game the
program translates with the table's targets; four runs to the menu had
no lost device, where 9 of 11 runs before did. All tests pass but the
two forced-UMA ones that fail on main too.

(cherry picked from commit 171b167a16e39e0cc70858b78e97e734b182a4c7)
A game's menus drew without four fragment programs at draw time, and
twenty more failed in the pass over the shipped programs, all with
"not translated: FSWZADD". The compiler reads a neighbour with
SHFL.BFLY and then takes the difference across the quad with FSWZADD,
as Maxwell programs do for their derivatives.

FSWZADD has a at 24, b at 64 and the swizzle at 32-39. Each lane of a
quad does the mode in its two bits, lane 0 in the top two: a + b,
b - a, a - b or b. This is the semantics of the Maxwell translator
(emit_float.c, nouveau's QUADOP). CuAssembler's sm_86 names agree:
0xcc is ZPPPZPPP, b alone in lanes 0 and 2. Bit 77 is NDV. The
translation refuses the other modifier bits, which no program sets.

The test runs the translated program on the CPU, with a new SPIR-V
evaluator in tests/support (spv_eval.c), at each lane of a quad.

Verified: shader_sm86 checks the four lanes of swizzle 0x1b. It fails
when the lanes take their bits from the bottom, when modes 1 and 2
swap, and when a and b swap. ctest -j1 passes (647 tests).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit d51259ee5be1035862b4cddbf4b2a7130d7edb9e)
Three refusals stopped about 140 of a game's shipped programs:

- "S2R in stage 4/0": the translation took every S2R other than LANEID
  as a compute program's. Only the thread and block ids (0x21-0x27)
  are. The game's fragment programs read SR_LTMASK with a VOTE ballot
  for their warp-wide atomics, which every stage can do.
- "BREAK": BREAK takes its lanes out of a convergence barrier and goes
  on to the next instruction. The BRA after it leaves the loop, as
  "!P1 BREAK B2; !P1 BREAK B1; !P1 BRA" in the programs shows. The
  structured translation keeps no barriers, so BREAK does nothing, as
  BSSY and BSYNC do.
- "LDC of type 0": LDC of NAK's MemType U8, I8, U16 and I16 now takes
  the byte or halfword at the address, zero or sign extended, as
  mem_load does from memory.

Verified: shader_sm86 runs each form on the CPU. It fails when S2R
outside compute takes LTMASK as a compute register, when BREAK is
refused again, when the byte index ignores the register, when the
signed types extend with zeros, and when bytes take 16 bits.
ctest -j1 passes (647 tests).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit d94618734636c164afc3418190fa1f6494c37119)

Rebased-by: AO55 <AO55@reden-emu.dev>
22 of a game's shipped programs stopped with "STL (no uniform)": they
keep arrays in local memory, with STL to fill them and LDL with a
register index to read them. The translation had no local memory.

- LDL (0x983) and STL (0x387, 0x987) now read and write a Function
  array of words, with the address in the register at 24, the signed
  offset at 40-63 and NAK's MemType at 73. Its size is the SPH's local
  memory (words 1 and 2, bits 0-23, the 0x100 to 0x200 bytes the
  programs ask for) as a power of two, and an address wraps in it, as
  spirv_translate.c does for Maxwell's LDL and STL. A byte or halfword
  store changes its bits of the word alone.
- The memory instructions take a uniform register only with bit 91,
  at 32 for a load and at 64 for a store. CuAssembler's sm_86
  encodings show it: LDS R, [R + imm] has 0 at 32 and bit 91 clear,
  and LDS R, [R + UR + imm] sets bit 91. The translation read UR0 into
  every LDS without it, and added UR0 to its address.

Verified: shader_sm86 runs STL.64, a byte STL and LDL.S8 back on the
CPU, and an STS and LDS pair in a compute program with UR0 at 0x40.
They fail when the byte store keeps the old bits, when LDL and STL use
shared memory, and when LDS adds the register at 32 without bit 91.
ctest -j1 passes (647 tests).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit f6ba2d75837da7423b9b4e2abdf02e92a8585483)
The pass over a game's shipped programs refused 295 of them with "BRX
with no jump table in c[1][0x0] (no word, unread 0x0)". Their draws
translated them with the constants that the draw binds, so the game
translated them during play instead of at startup. The pass gave an
Ounce program no constants at all, because an Ounce program has no
wrapper that names its control section.

An Ounce program's constants (bank 1, with the jump tables of BRX) are
in its code area, at its code's bytes rounded up to 256. The control
section's 0x40 gives that offset, as stage_of reads it at draw time.
The code's bytes (the section's 0x38) run from the header to the end
of the NOPs after the program's branch to itself. Every code record of
the game's BNSH containers agrees (12788 records), and the SHARCB and
sead containers lay their programs out the same way. The pass now
hands each program the bytes from there, at most 64 KiB, because only
the control section knows their size. A draw takes the pass's
translation only where the words that it read hold, so bytes past the
constants cost a translation, never a wrong one.

Verified: shipped_shaders checks the constants' offset of a program
with NOPs past a 256-byte boundary and of one without. It fails
without the NOP walk and without the rounding. In the game, the pass
refused 44 programs in place of 525, with no BRX refusal, and the 290
BRX programs of its agl archive read jump tables whose entries all
name instructions. ctest -j1 passes (647 tests).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 0033cdc25556cc87e3cc580fda3a4a861a212fcf)

Rebased-by: AO55 <AO55@reden-emu.dev>
Four forms stopped 10 of a game's shipped programs:

- "unknown opcode 0x634": HSETP2 with b in a constant buffer. HSETP2
  takes the forms of the 16-bit ALU, which CuAssembler's sm_86
  encodings give: b a register (0x234), two halves (0x434), a constant
  buffer (0x634). The decoder took the forms of the 32-bit ALU, and
  the translation had no HSETP2. Each pair of halves is compared as
  FSETP compares, with the swizzles of HADD2, the set operation at
  69-70 and the predicates at 81 and 84.
- "unknown opcode 0x958": BRXU, BRX with its index in a uniform
  register, as CuAssembler names 0x958. Its table is read as BRX's,
  through the ULDC.IDX that writes the register, with the bound that
  ptxas puts on the uniform datapath (UISETP.LT.U32, USEL, USHF.L by
  2).
- "unknown opcode 0x526": IPA with a uniform register in its address
  (bit 91, the register at 24). The register is the same in every
  lane, and the input is the one of the header's inputs at the sum.
- "TLD of a multisample texture": TLD with bit 78 reads a sample of a
  multisampled 2D texture, its index after the level and the offset as
  in Maxwell's TLD. Its slot takes a multisampled view (ShTex.flags
  bit 1, which the renderer binds already), and a TXQ of the same
  handle earlier in the program shares the slot and asks for its size
  without a level.

Verified: shader_sm86 runs HSETP2 of forms 2 and 3, BRXU and the
indexed IPA on the CPU (the evaluator now unpacks halves and takes
inputs), and checks the multisampled fetch's SPIR-V. They fail when
the halves write the other predicates, when the set operation comes
from FSETP's bits, when BRXU reads an R register or loses its bound,
when IPA leaves out the uniform register, when TXQ makes its own slot,
when the sample comes from another register, and when the size takes
a level. snx-sm86 translates the game's dumped programs of these
forms but the BRXU one, which needs its constants, and spirv-val
passes them. ctest -j1 passes (647 tests).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 0459b4d7125bcaeba5b478a2b7cf9313a4af0695)

Rebased-by: AO55 <AO55@reden-emu.dev>
The NVN driver's own programs that a game ships in its SDK module
draw a full-screen triangle: the vertex program writes the first
texture coordinate (a[0x300]) and the fragment program reads it.
Eight lines of the pass over the shipped programs refused them with
"attribute store 0x300", "IPA of attribute 0x300" and "BMOV (to
register)".

- The fixed function's varyings (the colors, the fog, the ten texture
  coordinates) now move to generics 17-31, as spirv_translate.c moves
  Maxwell's: each group to generic 17 plus its index, in every stage,
  so that the stages of either ISA agree. A fragment program's moved
  input takes the interpolation of the header's color or texture
  coordinate map. A program that also uses the generic itself is
  refused. The declarations move from translate.h to translator.h,
  so that both translators share forms.c's one copy.
- BMOV.32.CLEAR RZ, B0 before the vertex program's BSSY B0 reads a
  convergence barrier into RZ. The structured translation keeps no
  barriers, so into RZ it changes nothing. Into a register it stays
  refused.

Verified: shader_sm86 runs both stages on the CPU. AST a[0x304] writes
output 22's y, and IPA a[0x300] reads input 22's x with the constant
interpolation of the header's map, not the FragCoord.w of a
perspective input. It fails when the store keeps 0x304, when the
input takes the generic's map, and when BMOV into RZ is refused.
ctest -j1 passes (647 tests).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 3a6dc1516223210a5f78f2e8ecb2746090b57556)

Rebased-by: AO55 <AO55@reden-emu.dev>
Bit 79 of an SM86 texture fetch asks for half precision results. The
hardware then packs the selected components two to a register: the
first two into the destination (the first in the low half), the next
two into the second destination. NAK notes the bit on TLD. The
translator ignored it and wrote each component as a 32-bit float in a
register of its own.

One game's text programs fetch only the alpha of the glyph cache with
the bit set, then widen it with HADD2.F32 R8, -RZ, R4.H0_H0. They read
the low 16 bits of a float, which is 0 for a full alpha. So the glyph
interiors failed the program's alpha test and its 0.54 fill threshold,
and the menus showed dark text with a ragged outline. In the programs
it drew its text with, each fetch with bit 79 set feeds a HADD2. Of
about 46,000 fetches in its shader archives, none without the bit feeds
a half precision instruction. A fetch of four components into R4 and
R6 is read back as R4.H0, R4.H1, R6.H0, R6.H1.

The SPIR-V evaluator of the tests now samples images (a texel for each
binding) and runs PackHalf2x16.

Verified: shader_sm86 runs a TEX.F16 of one component and one of four
components through the evaluator. It fails with the bit ignored (R0
reads 0) and with the second register taken as dst + 1. The full ctest
passes (648 tests). The game's main menu, character select and cup
select now show white and yellow text with dark outlines, in place of
dark text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 80f1767daf514539eac45e3a092638dd9725f48c)
The console gives (0, 0, 0, 1) to the components of the position and
of each generic output that a vertex program does not write.
spirv_translate.c stores that default at the start of every Maxwell
vertex program. The SM86 translator stored nothing, so a component
that the program left alone was undefined in Vulkan.

One game's full screen passes write only the position's x and y
(AST a[0x70] of two components) and a generic's x and y. With an
undefined w, their triangles drew nothing. The first of them reads
the 3D scene and its depth, and writes the target that the later
passes tone map and lay under the menus. So the title screen, the
menus and the character and vehicle select showed black where the 3D
scene goes, while the scene itself was drawn: a dump of the targets
after each draw showed the character in the scene's target, and the
pass's target stayed all zero.

The translator now makes each output that an AST of the program
names before the code, and stores the default into it there. The
SPIR-V evaluator of the tests now keeps the Position output.

Verified: shader_sm86 runs a vertex program that writes the
position's x and y and a generic's x. The position and the generic
end with z 0 and w 1. Without the stores, w is 0 and the test fails.
The full ctest passes (648 tests). The game now shows the 3D scene
behind the title screen and the main menu, the character on the
right of the character select, the character on the kart in the
vehicle select, and the map behind the cup select. Four of five runs
through the menus with this change reached their last frame (760 or
1000). One stopped at 387 frames with the game's threads waiting and
the GPU idle. A run with the .F16 fix alone stopped the same way at
490 frames, so that stop is not this change's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 9adeec4027b56ade57649d7ff6a3e5f1e97b87a0)

Rebased-by: AO55 <AO55@reden-emu.dev>
Four programs of the Ounce driver's code (two vertex, two fragment) were
refused for opcode 0x956. Each is the debug variant of a full-screen
program in the same data: the normal program's instructions after a
prologue of 20. The prologue tests UR2, and when it is zero writes
BMOV.32 B0, 0xffffffff, BMOV.32 B1, B0 to BMOV.32 B15, B14 (0xf55) and
BMOV.32 B15, 0x0, then sets UR2 to 1. One debug vertex program also
zeroes R0 with HFMA2.MMA R0, -RZ, RZ, 0, 0 where the normal one has
MOV R0, RZ.

The encodings come from public tables made with nvdisasm:
- 0x956 is BMOV.32 B, imm, the barrier at 24-27 and the immediate at
  32-63 (the SM89 tables of nv_isa_solver). With 28-29 set the same code
  writes a state register.
- 0xf55 is BMOV.32 B, B or a state register, the barrier written at
  16-23 (CuAssembler's sm_86 record "BMOV.32 B15, MACTIVE", 0x1a0f7f55).
- 0x435 is HFMA2.MMA in HFMA2's form 2 (CuAssembler's sm_86 records,
  "HFMA2.MMA R4, -RZ, RZ, 0, 0").

The BMOVs write only convergence barriers. The structured translation
keeps no barrier value (BSSY's writes neither), and no translated
instruction reads one, so they change nothing. A write of a state
register is refused. HFMA2.MMA is taken only with RZ in the product: the
product is a signed zero and the sum with c in floats is exact. Other
forms are refused.

Verified: snx-sm86 translates the four programs of the sdk module, and
spirv-val passes them. The new test_debug_prologue in shader_sm86 runs
the prologue and two HFMA2.MMA loads on the CPU evaluator. A sign of the
zero product that is always negative, and a state register limit of 32,
each make it fail. Full ctest -j1 passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 229516f8fbf6cca98ee65b3389a513f899d9c81b)

Rebased-by: AO55 <AO55@reden-emu.dev>
One game's vertex program was refused with "global address whose base no
constant buffer holds". It loads a 64-bit pointer from a table that
c[0][0x110] holds, one for each vertex, and stores {0, 1, 0, 0, 0}
through it: the 20 bytes of an indexed indirect draw, which it resets.
No constant buffer word holds the pointer, so track_globals gives the
access no buffer.

The Maxwell translator takes such an access as Eden's SPIR-V backend
does (shader_global_dynamic): it compares the 64-bit address with each
buffer that the program binds, and accesses the first that holds it. A
load from none reads 0, and a store there is dropped. global_dynamic does
the same for an SM86 LDG or STG whose address register an LDG, LDS or LDL
wrote. Each buffer is the 16 MiB that the renderer binds from its
address, and the comparison takes the whole 64-bit address. A compute
program's store logs its bytes for the buffer that takes it, as the
tracked path does. An address that the flow loses on other paths is still
refused.

Verified: snx-sm86 translates the game's program, and spirv-val passes
it. The new test_global_pointer in shader_sm86 runs three pointers from a
buffer on the CPU evaluator: one inside it, one below it and one 4 GiB
past it with the same low word of the difference. The first takes the
store and the load, the others neither. A comparison of only the low
words, and a load from none that keeps the register, each make it fail.
Full ctest -j1 passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 45062622095f9d0b5f2eab071cf8d715d3be587a)
The SPH cannot tell a task program, or a mesh program without one, from a
vertex program (all three have word 0 0x000c0481), nor a mesh program
after a task program from a tessellation evaluation program (0x020c0c81):
NVIDIA's hardware runs them in those slots. stage11 took the stage from
the SPH, so a mesh program replaced the vertex or tessellation stage of
its program. The control section names the stage in its halfword at
0x56: 6 is a task program and 7 a mesh program, which the order of one
game's programs, their sizes and the per-primitive header after each
mesh program's code show.

- nvn.h: NVN_SHADER_STAGE_TASK and NVN_SHADER_STAGE_MESH.
- NvnProgram and NvnPBindProgram keep the two stages (NVN_STAGES); the
  Ounce compute program's c[0] record moves from 0x78 to 0x98 of the
  guest's program.
- nvn_section.h reads the stage and a mesh or task program's fields:
  invocations, payload, task or not, vertices of a primitive, most
  vertices and primitives, and the per-primitive SPH's offset.
- SetShaders logs each mesh and task program with them, and keeps its
  bytes with the sm86_dump setting. The skipped mesh draws log their
  group counts. stage11 logs a section whose stage differs from the SPH
  of a program that is no mesh or task program.

Verified: two runs of one game logged 7 task and 12 mesh programs, all of
them at stage 6 or 7, and no other program whose section and SPH differ.
Its mesh draws are DrawMeshTasks (0, 1), (0, 6) and (0, 30), about 14 a
frame. The new test nvn_section checks the fields; each of five changed
offsets in nvn_section.h makes it fail. Full ctest -j1 passes.

(cherry picked from commit 2ee94630955e17e2fccf9fc3872e650d3e31f9a3)
Rebased-by: AO55 <AO55@reden-emu.dev>
docs/OUNCE.md gets a section on mesh shaders: the stages that the
control sections and the SPH give, the section's mesh fields, the ISBE
reads and writes of the game's programs (workgroup index, payload, launch
count, skewed per-vertex and per-primitive outputs, indices, primitive
count) with disassembly, what the driver's DrawMeshTasks* and
SetGeometryProcessingMode write (Turing macro calls 0x51, 0x64, 0x31,
0x13), a design for the NVN layer, the translator and the Vulkan
pipeline, and the open questions. The ISBE layout agrees with Mesa's NAK
(nak_nir_lower_mesh_intrinsics.c) at every offset checked.

Verified: scripts/check-docs.py passes, and the docs_check test.
(cherry picked from commit 3b04c4ea6fa677ec554746cf2212feab1c6a82b5)
Six programs of the Ounce driver's code were refused as "tessellation
control ... stage 1". Five are an EXIT, and one is the debug variant of
it. Their header asks for 0 threads for each input primitive (word 2),
has 6 TessFactor words and no outputs, the header that Mesa's nouveau
writes for a tessellation control program (nvc0_tcp_gen_header). Such a
program runs no invocation. It is the driver's stand-in for no
tessellation control stage. Nouveau binds its own (tcp_empty) with the
stage off (nvc0_tctlprog_validate): the control points go on as the
vertex stage wrote them, and the tessellator takes its levels from the
state. That is the renderer's passthrough (vk_tess_passthrough), which
the Maxwell path makes for a draw with an evaluation program and no
control program.

- sm86.h: sm86_tcs_empty reads that word.
- render.c: a draw whose SM86 control program runs no invocation takes
  the passthrough in its place.
- pipeline.c: the pass over the shipped programs skips them, as it skips
  the stages whose key holds the draw's state.
- sm86_translate.c: the translator refuses one with that reason. A
  control program with threads is still refused: no Ounce program found
  so far has one.

Verified: test_tcs_empty in shader_sm86 checks the driver's header, and a
limit of 3 threads in sm86_tcs_empty makes it fail. Full ctest -j1
passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 5eaad6e240aa437d3c939a2efb9394e5d5427de2)
Rebased-by: AO55 <AO55@reden-emu.dev>
An Ounce game draws part of its frames with task and mesh programs. Their
SPH is that of a vertex or a tessellation evaluation program, so only the
NVN control section can give their stage, and the translator needs stage
values of their own. ST_TS and ST_MS come after ST_CS, with the TaskEXT and
MeshEXT execution models in the SPIR-V emitter.

A mesh pipeline has no vertex and no tessellation stage, so shader_vk_set
gives a mesh program the vertex stage's set 0 and a task program the
tessellation control stage's set 2. The five sets of the pipeline layouts
stay as they are, and the fragment program keeps set 1. The tables that a
stage indexes and that can now see the new values get their entries: the
Vulkan stage bits and the Tracy names in pipeline.c, the shipped stage
names and the names of snx-sm86. The corpus and the Maxwell translator
still refuse the new stages, as only the SM86 translator takes them.

Verified: shader_sm86 checks the sets of the new stages. The full ctest
-j1 passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 524da2f2e2d3a02400e3d063b2fe862c747f26ee)
The game's task and mesh programs do all their I/O through ISBERD and
ISBEWR (docs/OUNCE.md, "Mesh shaders"): the workgroup index, the task
payload and its launch count, the skewed per-vertex and per-primitive
outputs, the primitive indices and the primitive count. sm86_to_spirv now
takes ST_TS and ST_MS, with the fields of the NVN control section and the
per-primitive SPH in ShaderInfo.mesh, as a draw knows them. sm86.h gives
the interface for the draw and the pipeline.

The ISBE becomes arrays of words: a mesh program's attribute area and map
(Workgroup), and a task program's payload (TaskPayloadWorkgroupEXT), which a
mesh program after a task program reads too. ISBEWR and ISBERD are stores
and loads at their byte offsets, so the program's own addressing needs no
decode. The program body is a function of its own, and EXIT returns from
it. main zeroes the count, calls the body, waits at a workgroup barrier,
and then either launches the mesh groups (OpEmitMeshTasksEXT(count, 1, 1))
or sets the mesh outputs: Position with the depth fix, the generic outputs
at their locations, the per-primitive ones PerPrimitiveEXT, and the
triangles' indices. The skew offsets come from the SPH output maps at
translation. A form, an output map bit or a key that the game's programs do
not show is refused with its reason.

The test evaluator now runs calls, barriers and the two mesh instructions,
and gives push constants, the payload and the Output arrays. snx-sm86 gets
--task and --mesh to translate a dumped program with its section fields.

Verified: new shader_sm86 tests run a mesh program alone, a task program
and a mesh program after a task program on the evaluator, and check the
refused forms. spirv-val passes their modules. Each of 17 wrong changes to
the translator (the first group, the skew group size, the primitive area,
the zeroed count, the byte mask of the indices, the count clamp, the depth
fix, the skew rule and others) makes the test fail. The 7 task and 12 mesh
programs that one game run dumped translate and pass spirv-val with
snx-sm86. The full ctest -j1 passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit a1759ecc3c4fabcca13b4da043e84f371fb699a3)
Rebased-by: AO55 <AO55@reden-emu.dev>
A mesh program writes some generics per primitive. A fragment program reads
them as plain inputs, but its module must declare them PerPrimitiveEXT, or
the mesh pipeline does not link them. ShaderInfo.prim_mask of a fragment
program's key now names those inputs: the draw takes it from the mesh
program's prim_mask, which its translation sets (sm86_mesh_primitive_mask
gives it from the key alone).

Verified: a shader_sm86 test translates a fragment program with and
without the mask, and checks the decoration and the MeshShadingEXT
capability. spirv-val passes the module with the mask. The test fails when
the decoration is taken out. The full ctest -j1 passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit cdb6799d97280ee6159d5f556c4793f77170ad90)

Rebased-by: AO55 <AO55@reden-emu.dev>
The pass over the programs that a game ships finds a task program and a
mesh program by their SPH, as a vertex or a tessellation evaluation
program. Its translation needs the control section of its draw, which the
pass does not have, so it is no program that the pass can make. ship_program
now skips an Ounce vertex or evaluation program that has an ISBERD or an
ISBEWR (sm86_uses_isbe), and the log no longer counts it as a program that
did not translate.

Verified: a shader_sm86 test finds the ISBE accesses of a mesh program and
none in a vertex program. It fails when sm86_uses_isbe finds nothing. The
full ctest -j1 passes. No game ran: the draws of these programs are the
next step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 7e33a55dcd01518dadb5ba2ae2abbbd6350b61bc)
SetShaders kept the driver's record of an Ounce compute program's c[0]
at bytes 0x98 to 0xab of the program object, and cleared them for every
program. The Ounce's program object is 0xa0 bytes: the driver's
nvnProgramInitialize zeroes that many, and uses offsets up to 0x98. So
each SetShaders wrote 12 bytes of the game's memory after the object,
and the game could change bytes 8 to 19 of the record before a bind
read them.

The record now goes in a table by the program's serial, as the
tessellation declarations and the capture layouts do, and the replay of
a bind reads it from there. The bind record no longer carries it. The
three tables share one insertion function.

Verified: nvn_names checks that SetShaders leaves the bytes after the
program object as they were, and that a replayed bind takes the record
after the control section is cleared. Mutation checks: the old clear
past the object fails the first check, and a lookup that returns zeros
fails the other two. A 760-frame run through the menus of an Ounce game
showed 747 frames, with no "not translated" line. The full ctest -j1
passes. 3ds_static_pipeline passed with TMPDIR on disk, as the tmpfs
/tmp had no room for its copies. The SNX_TEST_VULKAN tests are off in
this build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit a7330280c836f9fd836abc60f10fa4b24d507211)
Rebased-by: AO55 <AO55@reden-emu.dev>
The Ounce's push constants and mesh draws are the 65th and 66th op.

Change-Id: I1b0d364a8e5f3d737e44df54a6107a458925c2f3
Signed-off-by: AO55 <AO55@reden-emu.dev>
The game draws part of its 3D scenes with DrawMeshTasks, which NVN
logged and dropped. The commands now record OP_DRAW_MESH: first and
count, a 3D draw as its x y z workgroups in a row, and an indirect one
with its buffer, count and stride. The replay gives the renderer a
DrawCall with mesh set, of the bound task and mesh programs, whose
fields the draw state keeps (DsPrograms task, mesh and mesh_key).

SetShaders keeps the task and mesh programs' fields of their control
sections by the program's serial, beside the c[0] record. The offset of
the per-primitive SPH counts from the end of the program's own SPH: a
code area of 0xe00 bytes has it at 0x80 + 0xd00.

The game's driver binds the task and mesh stages apart from the others:
uniform buffer groups 9 and 0xb, handle banks 5 and 6, storage buffers
at c[0][0x670] and c[0][0x770], and BindProgram bits 0x40 and 0x80. So
the draw state has two stages more (DS_TASK, DS_MESH), and bank 0 is
0x870 bytes. The renderer counts the mesh draws in its stats line and
skips them for now.

Verified: nvn_draw_banks checks the task and mesh stages' buffers,
storage tables and constants, the fields from a bind, and the replay of
direct, empty and indirect mesh draws. nvn_names checks SetShaders,
BindProgram(0xff) and DrawMeshTasks and DrawMeshTasks3D through to the
renderer, and nvn_section the fields. Mutation checks: the mesh stage
bound as the vertex stage, the per-primitive SPH offset without its
size check, and a 3D draw of x workgroups each fail a check. A 760-frame
run through the menus showed 736 frames, with no "not translated" line
and no GPU fault, and its stats line counted 5380 mesh draws, all
skipped. The full ctest -j1 passes, but
vulkan_headless_uma and vulkan_headless_descriptor_buffers_uma, which
fail on this machine.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 6f5bd38c64d9cc7129a8095e5490dc982de568a5)
Rebased-by: AO55 <AO55@reden-emu.dev>
A mesh draw (DrawCall.mesh) is now drawn with a pipeline of the task,
mesh and fragment programs, where the device has VK_EXT_mesh_shader
with a required subgroup size of 32 in its mesh and task stages. The
translator's programs use their warp's lanes, so the stages require a
subgroup of 32, and whole subgroups for a workgroup of 32 invocations.
The mesh program takes the vertex stage's set and push constants and
the task program the tessellation control stage's set, each with the
bindings of its own stage. A mesh pipeline has no vertex input, input
assembly or tessellation state, and no topology, restart or vertex
input dynamic state. vkCmdDrawMeshTasksEXT draws count workgroups, with
the first workgroup in push constant x. The fragment program's key
takes the generics that the mesh program writes per primitive. Storage
writes of the task and mesh stages join the barriers before their
results land. The indirect forms are skipped, as their records are not
Vulkan's.

The mesh draws are behind the experimental mesh_draws setting, off by
default. With them on, most runs on this machine's RTX 2080 ended in a
GPU fault: Xid 31 (MMU faults of GPCCLIENT_GCC) or Xid 109, then
VK_ERROR_DEVICE_LOST, in 6 of 7 runs. Runs without mesh draws had
none. The mechanism is not found yet (docs/OUNCE.md).

Verified: vulkan_headless_mesh draws a mesh program alone and a task
program that launches as many mesh groups as its workgroup index, on
the GPU, and reads the depths back: no group from workgroup 0, one from
workgroup 1. Mutation checks: a first workgroup of 0 in the push
constant, and a pipeline without its task stage, each fail it. It
passes under the validation layer with synchronization validation.
Two 760-frame runs through the menus of the game: by default, 749
frames, its 6910 mesh draws skipped, with one log line, and no GPU
fault. With --mesh_draws=1, 1195 mesh draws drawn and none skipped, no
"not translated" line, then Xid 109 and Xid 31 and
VK_ERROR_DEVICE_LOST at 757 frames. A run under --vk_validation=1 with
the mesh draws on had no message about them. The full ctest -j1
passes, but vulkan_headless_uma and
vulkan_headless_descriptor_buffers_uma, which fail on this machine.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 13f663e9f81276e63c8d1ee01726c20ae3b8dff4)
Rebased-by: AO55 <AO55@reden-emu.dev>
The mesh shader section of docs/OUNCE.md now gives the driver's binding
tables of the task and mesh stages (their BindProgram bits, uniform
buffer groups, storage tables and handle banks), the offset of the
per-primitive SPH, the size of the program object and why its records
moved out of it, the two words of DrawMeshTasksIndirect, what the NVN
and Vulkan parts of the design now do, and the GPU faults with the
mesh_draws setting on, with the checks that did not remove them.

Verified: docs_check passes, and the facts are those of the commits
before and of the driver's code at the sdk offsets the section names.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit d42fde18d65663cf8fd9a0af9dfab70c4d810473)
The control section's word at 0x64 gives the offset of the per-primitive
SPH from the start of the program's code area, its own SPH included. The
renderer read it 0x80 bytes later, where the code area holds zeros. It
thus found no per-primitive SPH in any mesh program, and it dropped every
per-primitive output, also from the ISBE layout of the program.

The dumps of the 11 mesh programs of one game show the SPH word 010c1081
(or 010d1081) at the offset itself in each program whose offset is not 0,
and zeros at 0x80 past it. The section header and docs/OUNCE.md now say
so.

Verified: a menu run with mesh_draws=1 logs the per-primitive generics of
each mesh program (0x1 for the programs of 32 and 128 vertices, 0xf for
the program of 256 vertices), where it logged none before.
vulkan_headless_mesh has a new check: a mesh program with its
per-primitive SPH at 0x200 of its code area gets generic 0 per primitive.
With the old offset the check fails. The full ctest passes but for the
two UMA tests that fail on feat/ounce.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 1c6d9f543fb46bf9262ece360a14f751e18ab9ff)
Rebased-by: AO55 <AO55@reden-emu.dev>
A mesh pipeline must not declare more outputs than the device's
maxMeshOutputMemorySize. The Vulkan spec ("Mesh Shader Output") counts
four scalars for each output location, per vertex in granules of
meshOutputPerVertexGranularity and per primitive in granules of
meshOutputPerPrimitiveGranularity, and not the triangle indices.
sm86_mesh_output_bytes counts the locations that the translation
declares. The renderer logs the count of each mesh program, and a
program past the limit fails with the reason, so its draws are skipped
with a log line.

Verified: in one game's menu, no mesh program goes past the limit of an
RTX 2080 (32768 bytes). The largest, of 256 vertices and 192 primitives,
needs 24576 bytes, the others 1536 to 5120. shader_sm86 compares the
count with the Output variables of a translated program, and
vulkan_headless_mesh checks that a program of 256 vertices with all 32
generics fails. A count of 3 scalars for each location makes the first
test fail. The full ctest passes but for the two UMA tests that fail on
feat/ounce.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 1d81338e5f4ffda35495fdeec0451209480f104f)
With mesh_draws on, an RTX 2080 faulted in each menu run of one game:
Xid 31 (GPCCLIENT_GCC, reads of addresses that no memory backs), or Xid
109 (CTX SWITCH TIMEOUT) and a hang or a lost device. A mesh
program takes the vertex stage's descriptor set and a task program the
tessellation control stage's, and each set was visible to its own mesh
stage only.

NV diagnostic checkpoints put each of these hangs in a draw with a task
program. The device fault data put the faulting instruction in a task
program, at the same address in each run, also when the program read no
constant buffer. A task program with its body taken out gave no Xid 31.
Each program's outputs are within maxMeshOutputMemorySize, and the
required subgroup size, the order of the stages and the payload reads
made no difference. With every set visible to every stage the faults
stopped, and also when only the two mesh stages see both sets, which is
this change. Eden gives each binding the stage of its program, in one
set. The mechanism inside the driver is not known.

Verified: before, 8 of 8 menu runs with mesh_draws=1 had Xid 31 or 109,
and 6 of them hung. After, 0 of 13 runs (7 of this change, 6 of the two
experiments) had Xid 31, and 11 drew all 760 frames. 2 of the 7 still hung
with Xid 109 alone, a failure that also came once with the task programs
emptied, so it has another cause. vulkan_headless_mesh checks the stages
of the sets, and fails when each mesh stage sees only its own set. The
full ctest passes but for the two UMA tests that fail on feat/ounce.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit c7e36d4371d83b3cc18ade3fc2b764877837e644)
Rebased-by: AO55 <AO55@reden-emu.dev>
After the change to the descriptor set stages, no menu run had Xid 31,
but 2 of 7 runs still hung with Xid 109 alone. The same hang came once
with the task programs emptied, and its checkpoints put it in a draw
without a mesh program, so it has another cause. The section says so,
so that the experimental setting is not taken as safe.

It also records where the mesh draws go. None of 184,239 mesh draws in
16 menu runs went to a cascade of the shadow map, a depth-only target of
3072 by 3072. Each had one color target. So the mesh draws do not cast
the missing shadows.

Verified: the counts come from a log line in the runs, which this commit
does not keep. Seven runs with mesh_draws off had no Xid. The full ctest
passes but for the two UMA tests that fail on feat/ounce.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit b120d88b21668c29dc4831fefe87dc5f5e3f27fc)
(cherry picked from commit 6318c8de8bc6d6b60615e9377b562d4f2896926d)
A primitive index at or past the vertex count reads a vertex the program
never wrote, which some drivers hang on (the Ounce's Xid 109). Clamp each
index to the last vertex, as the vertex count itself isn't written.

(cherry picked from commit ca3e1ff5b8f3907b21d640d62571e5802351bc44)
A shader record of the cache file was refused as not a shader when its
stage came after the fragment stage. The Ounce's task and mesh stages
do (6 and 7), so the first task or mesh shader a game saved ended the
file's reading, and every record after it was dropped. In one game's
file that was its third unit of records, at 988,200 of 4,962,912 bytes:
each run loaded 43 shaders and 7 pipelines and made the rest again,
about 480 pipelines, some of them 5 to 9 s of the driver's compiler.

A record now holds any graphics stage, the task and mesh stages too.
Compute pipelines keep their own records.

A script that walked the file's units with the loader's checks found
the record. With the change, a run after a cold one loaded 634 shaders
and 473 pipelines, with nothing dropped, and the game started its
title in 1.8 s against 16.8 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 0d7e7b145b8ead42ab96c8d99d0199ccaa5f2cd5)
A fragment program's key names the inputs that no output of the stage
before writes (in_unfed_mask), and the Maxwell translator reads them as
0, 0, 0, 1 with no Input variable. The SM86 translator ignored the key
and declared them. The validation layer reported it for an Ounce game's
mesh pipelines, whose mesh programs write fewer generics than their
fragment programs read: VUID-RuntimeSpirv-OpEntryPoint-08743, at
locations 0 to 3. Such an input is now 0, 0, 0, 1, as the Maxwell
translator makes it.

Verified: shader_sm86 checks that an unfed input has no Input variable
and reads 0, and that a fed one reads its value. Mutation check: with
the unfed branch off, both checks fail. A 760-frame run of the Ounce
game under --vk_validation=1 with the mesh draws of the later commits
had no 08743 message, where the run before this change had 9. The full
ctest -j1 passes, but vulkan_headless_uma and
vulkan_headless_descriptor_buffers_uma, which fail on this machine.
3ds_static_pipeline needs TMPDIR on disk here, as /tmp is a full tmpfs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 326812bf4d75abf87b4f2c04d1fab4ee968e3c26)
Rebased-by: AO55 <AO55@reden-emu.dev>
The translator stopped at the first it did not know, so each one hid the next: F2F to F16, F2I from F16, MUFU.F16, F2FP.MERGE_C, HMUL2, HMNMX2 and HFMA2. The forms that dumps of one game's programs do not use fail with a message.

Ran that game on a Radeon 890M. Its 319 programs give 0 failed, and its scenes draw. Only the forms in those dumps ran.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit afafc059239b47d0cbe8c8531da7f4ab44033c92)
Rebased-by: AO55 <AO55@reden-emu.dev>
Colour draws of one game's characters were skipped, because their fragment programs use TEX.B, and they stayed black shapes on the screen. Each handle comes from an LDC whose address is x * stride + base, with x from a FLO on a mask of lights, so the texture is chosen for each pixel from an array. The strides are 0xc0 and 0x130, which the shift of the indexed path can't give, so a slot now has a stride and a count. The count is 32 for an index from FLO, so the data after the table is not read as handles.

Ran that game on a Radeon 890M through a scene with a crowd. The person who ran it saw the characters in their colours, and the log gives 0 draws skipped. Refused with a message: TEX.B of 5 or more operands in the scalar form, and an index that no IMAD with constants makes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 19dda128775f8e1e85a7d49f25a54ee635094faa)
Rebased-by: AO55 <AO55@reden-emu.dev>
A draw whose writable storage shares a page with another of its buffers binds them all as an atlas of pages, and SNX_VKB_SMAP gives each buffer's pages. The Maxwell translator reads that table and this one did not, so an SM86 program read other memory. In one game a culling program's input and counters share a page in every other frame.

This comes from reading the code and captures. A run on a Radeon 890M with it alone still showed the flicker that the next commit fixes, so no visible fault is shown to go with this one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 8dfb223837b71a92d9a0b0838dc222ce2ef31679)
Rebased-by: AO55 <AO55@reden-emu.dev>
A warp has 32 lanes, and a program compares its LANEID with a bit of a ballot. The raw lane went to the program. This device reports a subgroup size of 64 and offers no required size for the vertex stage, so lanes above 31 can occur there, and they never match. One game culls in vertex programs: the highest lane of a ballot adds to a counter and the others take its result. Those lanes would not count, and their instances would go over the first slots of the list, which fits whole objects that came and went or jumped.

Ran that game on a Radeon 890M. The person who ran it saw the flicker and the jumps stop in the scene that had them. The lane count of a vertex program was not measured, and no device with 32 lanes ran this.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 8bcba9a2908f19fceda33e83afce63082f3bfd63)
Rebased-by: AO55 <AO55@reden-emu.dev>
One game's fragment programs use them, and their draws were skipped. Both meanings come from another emulator's lowering, not from the hardware. RELU turns a result at or below zero into zero where the predicate at 87 holds, and H0_NH1 swaps b's halves and negates the new low one, as the second term of a complex product needs. That game's programs agree as far as they can: their RELUs have PT at 87, and the others have 0 there.

The programs pass spirv-val, and their draws were on screen in that game with nothing wrong seen. Nothing compares their results with a console's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 0653ca2ee31cc8fa8c85b72e1d188f655ee77483)
Rebased-by: AO55 <AO55@reden-emu.dev>
One game's fragment programs use it. Its registers are in the order of Maxwell's TXD and not of TEX: from a the coordinates and then the layer, from b each coordinate's change along x and along y. A texel offset is refused.

The one program dumped has an array of 2D textures, and passes spirv-val. Other dimensions weren't run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 28673e192d8c7cb65d0fb12d069123a592164b5d)
One game's compute programs use ATOMS and ATOMS.POPC.INC, opcode 0xf8c, which the table didn't have. POPC.INC adds the lanes that run it and returns nothing, which here is one for each invocation. LDS, STS and ATOMS now share how they address, and ATOMG and ATOMS their table of operations.

That game's exposure program builds a histogram of 64 bins with them, and in a capture its bins add up to exactly 1920x1080, each pixel once. The form with a uniform register, 0x98c, wasn't run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit b54b0687d1f64520ec2a31072fb025d2b250d038)
Rebased-by: AO55 <AO55@reden-emu.dev>
ptxas scales a switch's index with an IMAD by 4 or a SHF.L by 2, and only the first was read as the table's bound. Without one, a table is read up to the first word that is no target. One game has two tables of 3 entries side by side in c[1], so the first BRX took the second's targets as its own and jumped into the second's loop, which made the graph irreducible and refused three of its fragment programs.

That game then translated all of them, with 0 of 408868 draws skipped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit a7d0311e88d088017457239ba6dfae57db1b7e11)
An SM86 instruction with a directed rounding (FADD, FMUL, FFMA and I2F
with RZ, RM or RP) is emulated: its exact result as a double, rounded
to nearest as a float, moves a step when the double lies on the other
side of that float, which the float widened back to a double tells.
Where the two conversions may be inexact, NIR may take the round trip
for the double itself, and on lavapipe and on RADV, which both compile
through NIR, the comparison never found a side: shader_sm86_gpu's float
case came out rounded to nearest, 1 ULP off the reference in 24 of its
results, in FADD with RZ, RM and RP, FMUL.RZ, FFMA.RP, I2F.U32.RZ and
I2F.S32.RP.

The two conversions are now exact (NoContraction), and NIR leaves their
round trip alone.

Run on a Radeon 890M host: shader_sm86_gpu passes all five of its cases
on lavapipe, the device it picks, and on RADV picked through
VK_DRIVER_FILES, both with the Khronos validation layer loaded and no
message from it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 401f9aa920826a94fc638a040a04ed603a7bfcb8)
One game's fragment programs use SUATOM with the surface's handle in a
constant buffer, opcode 0x593, which no source names. It is the bindless
0x394 plus 0x1ff, as SURED's 0x59f is to 0x3a0, with the bindless one's
fields as NAK has them and SURED's handle at bits 40 to 58. The
translator refused it.

It translates as SURED does, with its operation 4 bits wide, where 8 is
an exchange, and the value before the operation written to its
destination. may_write counts the destination's registers as SURED's.

Run on a Radeon 890M host: the game's fragment programs with it, refused
before, translate. No test runs one. All 775 tests pass or are skipped
(two of the 3DS), the Vulkan ones on RADV.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit fee1755407d362ce03967003636744b1c5466869)
One game upscales with its own network, compute programs whose matrix
products use the warp's matrix instructions, HMMA, LDSM and MOVM, in
CuAssembler's sm_86 encodings. The translator refused them, and the
network's dispatches didn't run.

Each now runs on the lanes of the invocation's own 32 in a subgroup of
32 or 64, lane l of NVIDIA's warp being the local invocation index's l %
32, with each register spread over the lanes as PTX's mma.sync, ldmatrix
and movmatrix lay them out. A lane reads another's register with
OpGroupNonUniformShuffle. HMMA is m16n8k16 or m16n8k8 with f16 A and B
and f16 or f32 C and D, summed in f32. LDSM loads 1, 2 or 4 8x8 matrices
of 16 bit elements from shared memory, transposed or not, and MOVM
transposes one.

shader_sm86_gpu has a new program, tensor, that runs each of them over a
warp and checks every lane's registers against the layouts computed on
the CPU.

Run on a Radeon 890M host: tensor passes on RADV in subgroups of 32 and
of 64, and lavapipe, whose subgroups are 8 lanes, skips it. The game's
network dispatches run. All 775 tests pass or are skipped (two of the
3DS), the Vulkan ones on RADV.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 93898e0f108fe36021ef1d5d4e74732e04607c92)
Rebased-by: AO55 <AO55@reden-emu.dev>
A fragment program's outputs are the colours of the render targets its
SPH enables, four registers a target, then the sample mask's register,
then the depth's. The depth is the last colour register plus two whether
the program writes a sample mask or not, as emit_flow.c reads it and as
nouveau's nvc0_fp_assign_output_slots places it from Kepler on. The
epilogue took the depth from the sample mask's register when no sample
mask was written, and one game's lighting was black.

The epilogue now reads the depth from the register after the sample
mask's in every case.

test_fragment_depth in shader_sm86 checks the depth's register, R1 with
no colour target, R5 after one target, and R5 with a sample mask
written. It fails without the fix.

Run on a Radeon 890M host: the game's lighting shows. All 775 tests pass
or are skipped (two of the 3DS), the Vulkan ones on RADV.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 628e00a441d9afa76d510f23c931b7f8d1983902)
Rebased-by: AO55 <AO55@reden-emu.dev>
A program of a stage the SM86 translator doesn't have, a geometry
program say, was refused with its stage as the first thing unsupported,
and nothing of it was kept. It is now dumped as a program refused for an
instruction is (sm86_debug_dump), when dumps are on.

Run on a Radeon 890M host: one game's geometry programs are dumped. All
775 tests pass or are skipped (two of the 3DS), the Vulkan ones on RADV.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 1a98167816ed041d8d3fde06fd6db031f4f48f21)
An IPA at the centroid of a fragment input that no earlier stage writes
(in_unfed_mask) emitted OpDecorate %0 Centroid: such an input is a
constant and has no variable, so the decoration named id 0. spirv-val
and the validation layer refuse the module ("Id is 0"), and the driver
got it anyway. One menu run under the layer made 1343 modules, 10 of
them with that decoration, and the layer logged 9 such errors. The
decoration now goes only to an input that has a variable.

Verified: shader_sm86 translates an unfed input read at the centroid
and at the default place, finds no decoration of id 0, and passes
spirv-val. A 110 s menu run under the validation layer logged no
"Id is 0" error. The full ctest passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 2b9fbe81bf2bf9d57a2b1acb8e0326f4423e22fe)
Rebased-by: AO55 <AO55@reden-emu.dev>
An SM86 program whose first access to shared memory is an LDSM was
translated to invalid SPIR-V, an id defined twice, as LDSM bounded its
address by the shared variable's size before the variable was made. It
is made first, as LDS makes it.

Run on a Radeon 890M host: one game's programs translate and pass
spirv-val. On the last commit of this series all 776 tests pass, the 28
Vulkan ones on RADV and on lavapipe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 7007b74ace445516a134da5c7a98af93809fa8ae)
The driver reader did not recognize retab as a return, so it read on into the next function. The API version came out as 4.30 and the items above 0x68 as 0, and a pool of size 0 aborted. These items are also in a second switch, in the first helper that the first one calls.

Ran one game on a Radeon 890M. The log gives API 231.30 with 151 items, and the abort is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 3460ac1f1b0a0e107233c603683d844ef71c45c0)
Rebased-by: AO55 <AO55@reden-emu.dev>
(cherry picked from commit 6d526436ac766966c9ba279b805c189e3db4c803)
Push constants go to the root tables, which come after the inline banks. inl_wrote only knew the banks, so its stage came out past the end and it wrote over the dirty span of the vertex stage's bank 0. Storage binds then did not reach the renderer, and one game's draws read another object's instances, and its vertices flew off. The tables themselves were never copied either, so the renderer read them as zeros. They now have a dirty span of their own.

Ran that game on a Radeon 890M with a temporary check on each indirect draw. Over 600,000 draws, the renderer's copy of the binding differed in none, against 97% of them before. The person who ran it saw the vertices stop flying off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit e1557cae958f8d4c67733675f9366653ba37534d)
The Ounce's NVN has a DLSS network, which one game builds and
initializes through functions the runtime didn't hook: the builder's
GetTexturePool, GetTextureIDs, GetOptimalSettings and GetStorageSize,
the network's Initialize, Finalize and Resize, and the command buffer's
EvaluateDlss. The game asks for 2560x1440 with method 0 and preset 5.

They are hooked now, and no network runs. GetOptimalSettings answers
render sizes from the method as NGX's quality modes scale the output.
The network keeps the fields the driver's Initialize and Resize write
(NvnDlssNetwork, 0x258 bytes). An evaluation copies the input color's
subrectangle onto the output's with a linear filter, as
CopyTextureToTexture scales.

The stand-in answers that DLSS is available, and with that the game's 3D
is black: on the path it then takes, its own upscaling network reads a
texture that nothing writes, and the evaluation of DLSS on that path is
dead code in its main module, so the copy has not run in a game. With a
temporary switch, not in this commit, that made the stand-in answer that
DLSS isn't available, the game took its own temporal pass and its 3D
showed. Which answer the stand-in gives is not decided yet: two other
Ounce games have live calls to the evaluation.

Run on a Radeon 890M host: the game creates its network and renders at
1280x720, its 3D black as above. All 775 tests pass or are skipped (two
of the 3DS), the Vulkan ones on RADV.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit aae430c6701ff3b4d3bbdfff25254d886602b049)
One game creates its NVN device with flags 0x10400, and the Ounce's
driver hands its texture setup !(flags & 0x10000). The game's textures
are laid out as the older console lays them out, and read garbled with
the Ounce's GOB.

An Ounce game's device with that flag (NVN_DEVICE_FLAG_MAXWELL_GOB) now
clears g_gob_native at its initialization, before any surface, so the
game's surfaces take the Maxwell GOB. Two other Ounce games create their
devices with flags 0 and 0x600, and keep the Ounce's.

nvn_names and nvn_nvrm_sync, which link nvn_object.c, have stubs of
g_ounce and g_gob_native.

Run on a Radeon 890M host: the game's loading screen, garbled before,
reads right. All 775 tests pass or are skipped (two of the 3DS), the
Vulkan ones on RADV.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 3ee00cf944c673ab6e00b0e59aacd9534ee18e2c)
The compute path read a program in a window of 64 KiB. An Ounce program
has no NVN header with its size before its code, and one game's compute
program of 256,160 bytes had no end in that window. Each of its
dispatches (one workgroup of 32, about one a frame on the title screen)
was skipped as not translated: 476 in a run of 50 seconds.

The window now takes 512 KiB of code, as a graphics program's does
(SH_CODE). An Ounce program's read stops at its constants' offset, the
code's bytes rounded up to 256, which SetShaders keeps from its control
section (DispatchState.code_bytes). A Switch program keeps its header's
size, or 64 KiB. A read clears only what an earlier, longer program left
past the new one, and the fast path hashes the bytes it read, not the
whole window.

Verified on the game's title screen: the program translates (block 32,
4 global buffers) and no dispatch is skipped as not translated. ctest
passes but for vulkan_headless_uma and
vulkan_headless_descriptor_buffers_uma, which fail without the change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 75f8dc66af7e37e45d4929467c129ceb8ebc9592)
Rebased-by: AO55 <AO55@reden-emu.dev>
An Ounce control section gives a compute program's shared memory bytes
at 0x64, after its workgroup size at 0x58 to 0x60. The runtime read the
workgroup size but not this word, so every Ounce compute program came to
the translator with a size of 0, and the SM86 translator gave it 16 KiB.
On one game's title screen most programs have 0 there, and the others
have 0x800 to 0xc000, so the programs of 48 KiB reached past their
shared array.

Found by logging the section words 0x40 to 0xa8 of each compute program
over one run: the word at 0x64 is 0 or a size that fits the workgroup
(0x1000 for 128 threads, 0x900 for 4x4x4, 0xc000 for 64).

Ran the game for 110 s to the title screen and on: no compute program
failed to translate, no GPU fault, and the scene draws as before. The nvn
and Ounce tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit d1452a304a0dc499dab6689184d12c1cd62e1d5f)
NVN's API 231 sets a priority for the compute work recorded after it,
which the console's driver turns into limits on the SMs that compute may
take. One game calls it with 0x20 and 0x21 and stopped on it. The Vulkan
renderer has nothing to limit, and it records nothing.

Run on a Radeon 890M host: that game goes on past the call. On the last
commit of this series all 776 tests pass, the 28 Vulkan ones on RADV and
on lavapipe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 9f62cdad984a2dacdc0ff413109a5abbde5b2161)
An Ounce game aborted in its menus with result 2010-0221: its stage
loads a WebM ad board movie, and nn::gsv::UserSession 901 was unknown.
The SDK's nn::codec::video::detail::ipc::Initialize sends 901, then 902
(or 905 with the unlimited resolution flag), then 1001 and 1002, and it
aborts when any of them fails.

native_video.c serves the decoder and encoder contexts, their codec
sessions (TIPC) and the video image pools. 991 sizes a pool, 911 makes
it in a native memory that 114 binds to the game's CPU pages, 961
describes an image's NV12 planes for ReadUserImageNv12, and 426 to 428
map and describe it for the GPU. A codec takes its work memory (200 or
210), its MIME type and size (101), registers images (311) and gives a
fence for each. FFmpeg decodes the submitted packets (109) into the
image with the earliest fence, the codec's syncpoint reaches that
fence, and 213 gives the output's properties with the timestamp in
nanoseconds. native_video_core.c holds the layouts, the descriptors
and a codec's queues without state, so a test can check them.

The decoded picture goes to its image on the GPU, as NVDEC's pictures
do: nvdec_write takes pitch-linear NV12 surfaces now. FFmpeg's planar
rows are staged, the GPU interleaves the chroma, and the image is
published over guest memory.

What the SDK expects (its disassembly):

- 905 takes a u8 flag. 115 answers a u64 whose bit 1 makes the SDK
  mark the pages uncached and send flags 2 with 114. 115 answered no
  word, so the SDK read old TLS bytes. It answers 0 now.
- MapNativeImage checks that the low bytes of descriptor words 0 and 4
  are 1 and that the high word of word 5 (the size) is not 0.
- The fences are u32 values, with the counter id as the syncpoint's id
  inverted. 109 sends microseconds, 213 answers nanoseconds.
- 109's "input full" result (module 111, 3603) is retried. The game
  aborts on any other failure of 109 and of 213.

The preference words, 911's and 991's layouts, the 426 checks and the
fence encoding follow closed PR #1009, checked against this game's SDK.

Verified: the new native_video test checks the MIME types, the layouts
and requirements (also a refused layout past 32 bits), the CPU and GPU
descriptors, the pools' image numbers, the image queue across a fence
wrap, the output and input rings and the properties. Each of 20
mutations of native_video_core.c failed it. vulkan_headless checks two
pitch-linear NVDEC pictures against nvdec_ref.c, with padding kept, and
fails when the luma or chroma copy goes wrong. ctest -j1: only
vulkan_headless_uma and vulkan_headless_descriptor_buffers_uma fail,
as before (a placed view, not NVDEC). A game run comes after the merge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 88369d3c58324d44573f0359d54d3641b4bd0930)
Rebased-by: AO55 <AO55@reden-emu.dev>
A cup's opening movie stopped after its first image: the screen stayed
black, and the codec never started. After RegisterImage (311), the
game's decoder loop makes a syncpoint event for the image (SyncptSession
22) and arms it on the image's fence. To arm it, the SDK's
CancelSyncPointEvent first sends 202 and then waits on the slot's event
(nn::os::WaitSystemEvent), also for a new slot that was never armed.
DestroySyncPointEvent does the same. 202 only disarmed the slot, so the
thread waited for ever before its first ArmWait (201).

202 now signals the slot's event, and the next ArmWait clears it again.
The SDK's wait after 202 shows that the console signals it. The
movie's per-wait lines (ArmWait, a syncpoint reached) go to the verbose
log now: a movie arms one wait per frame. The video codec logs its
images, its start and stop, and its end.

Verified: runs of an Ounce game through its menus with presses to a
grand prix played two movies without an abort and without an unknown
gsv command. A 640x360 ad board movie (4 images) gave 382 outputs, was
stopped and finalized. The 2560x1440 opening (2 images) gave 1201
outputs over 20 s of its timeline. A debug read of the middle luma row
of the images after the GPU wrote them matched FFmpeg's picture in
all 11 samples. The game reads each output with 961
(ReadDecoderOutputImageNv12), one for each 213, but the screen stays
black during the opening: its display is still open. ctest -j1: only
vulkan_headless_uma and vulkan_headless_descriptor_buffers_uma fail, as
before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

(cherry picked from commit 4abe37ab59228fb697029cbdddb7ec2bf3684d17)
One game plays its opening movie through command 201, and the buffer of its Configure is the stream's SPS and PPS, not a MIME type. Its images have four bytes a pixel, which the NV12 writer dropped. Each picture now goes through NVDEC into the first bytes of the image, then through VIC into its pixels, with the matrix of the picture's colour space.

Ran that game on a Radeon 890M. The person who ran it saw the movie play correctly. Its frame pacing is a little irregular.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit ebe2d12a309d7b98762a3921b1dd75f79eb97284)
One game calls these as it starts. A pool made from a native handle is that native memory, and a game's video images on it are written pitch linear, so textures on such a pool read as linear. Ray tracing is not implemented: its calls log and do nothing, and the sizes returned are made up so that the game can allocate.

Ran that game on a Radeon 890M. It no longer stops at these calls, and the video reads without the woven pattern of a block linear read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit bc6605f54a480306bafd51da34498dbe659db4cc)
TryWaitSyncPoint on a fence not yet passed asks for the value again: it makes a bit of the request page differ from the acknowledge page, signals the request event and waits for the completed event until they agree. The service gave an end of that event that the kernel refused to signal, so the SDK aborted with 0xe401. One game's quiz demo did this as it polled the fences of a video in a loop. The value page is kept as syncpoints change, so answering is acknowledging.

The page layout comes from the header the service already writes and the SDK's reads, not from the code that sets it up. Built and booted on a Radeon 890M. The demo has not run since this change, so the fix of the abort is not verified.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 26b2dfc9ff349b20816467445a411955a7928b56)
Rebased-by: AO55 <AO55@reden-emu.dev>
SDK 22's BootWithRemoteMemory (version 7) sends command 126 right after
the boot, with no request, and only sends command 120 next when the
answer is 1. What the mode means isn't known, and it is answered 0, with
which the SDK boots on.

nn::codec::video::detail::InitializeServerContext opens the video
decoder's context with command 906 in place of 902. It takes 902's flag
and, in the next word, the decoder library's version (one game sends
0x3'00030000), and returns the same session.

Run on a Radeon 890M host: that game boots and reaches its intro movie.
On the last commit of this series all 776 tests pass, the 28 Vulkan ones
on RADV and on lavapipe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 3e3d75f1bf90a07b1f01e062c95919331be46072)
The SDK's CreateIndividualDisplays opens a display and an endpoint at boot for each guest a game asks for, named player1 to player3, whether anyone joins or not. vi2 knew only the console's display, and one game aborted on its 0xe09. Each display now keeps its own references and endpoint.

OpenEndpoint's first word is the display and its second the endpoint's name, which the console's display, with both "default", didn't show. The SDK opens a guest's display with flags 4, so flags 1 is only asked of the console's.

A present to a guest's display isn't told apart, and would show in the one window. That game got through its boot, with its log showing the guest's display and endpoint opened.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 25ef41a6a3c112d154e51dd686bf3c850549421f)
Rebased-by: AO55 <AO55@reden-emu.dev>
One game aborted in its first seconds at commands of its graphics supervisor that nothing served: 1501 and 1502, 204 with a request shorter than the one declared, the camera, chat and graphics frame contexts, and chat:u. The camera session answers RC(452, 6), which the game tolerates as it opens its camera.

Ran that game on a Radeon 890M. It boots to its first menus without those aborts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 2e8de8f5c118f3816fd1f5f1b96678f810b1904c)

Rebased-by: AO55 <AO55@reden-emu.dev>
One game asks stpl:u at boot how much memory GameShare would take, whether it shares or not. The stand-in for a missing service answers with no object, and the SDK's next call went through null. Command 0 now gives the object, commands 1 and 9 answer sizes, and command 300 gives a shared memory, which the SDK maps as its HidApplicationResourceHolder.

The console asks its video encoder for these sizes, so the ones here are made up. They only agree with each other, as the SDK divides the memory it is given by what a guest takes. No session ever starts to use them.

Ran that game past the crash and played it for 11 minutes. GameShare itself was never run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 6ad92f17354fae0dd9adde33bd064fa4940ae655)
An Ounce NRR's header is 0x180 bytes longer, with its fields that much further on. One game loads each of its demos from an NRO that such an NRR registers.

Ran that game on a Radeon 890M. Its NROs map and run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit bc000c81d079df17bc99c28883ad972d36f405d2)

Rebased-by: AO55 <AO55@reden-emu.dev>
(cherry picked from commit 9eb81e5b8eae2d454fcfa28cd20d58f5a597a04f)
The Ounce's SDK takes the regions of its virtual address memory
(nn::os::AllocateAddressRegion) from the alias region, which GetInfo 2
and 3 give less GetInfo 28. One game reserves 60 GiB there twice, at its
startup and again in its main, and frees neither. The 64 GiB of the
39-bit layout can't hold both, and the game didn't boot past them.

An Ounce program's alias region is now 256 GiB, with its heap, stack and
kernel regions moved up past it, all within the 512 GiB the runtime
reserves (mem_layout_ounce_alias, after mem_layout_large_heap). A Switch
1 program on the Ounce reports the 64 GiB, so an Ounce program's layout
differs from it, but by how much is not known, and the code is marked an
experiment until it is. The runtime logs the regions it gives.

Run on a Radeon 890M host: the game's two reservations succeed and it
boots. Two other Ounce programs were not run again with it. All 775
tests pass or are skipped (two of the 3DS), the Vulkan ones on RADV.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit dc845e339a33bccfc54cc2c0fb2f03645e0912f5)
Two Ounce games store their NSO segments as ZBIC where the segment's
compressed flag means LZ4. ZBIC is zstd with its own frame magic
(0x4349425A, "ZBIC") and with the headers of the FSE tables coded by
binary interpolative coding in place of zstd's normalized counts. The
loaders took those segments for LZ4 and refused them as corrupt.

common/utilities/zbic.c builds zstd's decoder from the zstd sources the
build already fetches, its symbols local or renamed (zbic_names.h), with
that magic, and a reader of the BIC headers in place of FSE_readNCount.
The reader was written after reading kinnay's zbic (GPL-2.0), and none
of that code is here. The recompiler's loader, the runtime's, and
hactool's NSO extraction now take a segment that starts with the magic
as ZBIC, and every other as before. snx_zbic links where snx_lz4 does. A
build with the sanitizers (SNX_TEST_SANITIZERS) builds it with ASan and
UBSan, as it does snx_lz4.

The new zbic test decodes a 5541 byte frame of synthetic text that
kinnay's compressor made at level 19, and checks a destination one byte
short, truncated frames, and that zstd itself, given the frame with its
own magic, refuses it.

Run on a Radeon 890M host: the reader gives the same bytes as kinnay's
decoder on six segments of the two games, about 116 MB, and scarletnx
--dump-modules extracts one game's modules. All 775 tests pass or are
skipped (two of the 3DS), the Vulkan ones on RADV. In a build with the
sanitizers, runtime_architecture's check of them passes, and the zbic
test and the six segments decode with no report.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit aa21619a15be400349e6400efebb86e3c4aa9fd3)

Rebased-by: AO55 <AO55@reden-emu.dev>
One game's intro movie is AV1, and the native video service refused it,
after which the game aborted. FFmpeg's own AV1 decoder only parses a
stream for a hardware decoder, so a software decode needs dav1d.

dav1d 1.5.4 (BSD-2-Clause) is built from its release with meson and
ninja, static, at 8 and 16 bits a sample and with its assembly, before
FFmpeg, which takes it as its libdav1d decoder. pkg-config looks for it
only in its install folder. It is built on Linux and the BSDs and not
yet in a cross build, which would need a meson cross file.

The service decodes AV1 through it with a frame delay of 1, as its loop
expects each packet's picture at once. A build without it plays an AV1
movie black instead of refusing it: each input comes out as a black
picture with its timestamp, painted into an image once, so the game
plays the movie through and goes on.

Run on a Radeon 890M host: that game's movie decodes with no errors. On
the last commit of this series all 776 tests pass, the 28 Vulkan ones on
RADV and on lavapipe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit eaf2c094bf2871939ed1a6d43142c0c5e05d1e71)

Rebased-by: AO55 <AO55@reden-emu.dev>
One game's mouse demos read Jcms and Nmouse states from memories they give the service, and ask for bit 12 of the Npad styles alone, which the mask of known styles cut to no style at all. The layouts are the SDK's reads, as the wiki has none. Bit 12 acts as a Joy-Con pair and bit 13 as a left one, because the game tests them with those. The host's mouse is the right Joy-Con and the merged mouse, with its clicks also on R and ZR, as most games expect in this mode. The mouse is held in relative mode while a game takes only these styles, and Ctrl+G lets it go.

Ran that game's mouse demos on a Radeon 890M. The person who ran them says they work. Not known: the flags at 0x18, which are set to 3. Not served: gyro and angle, RestrictNmousePointer and the button configs, and any motion of the left Joy-Con.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit bfb42cc41d5986c85bcb056fc368cfdedfd0dc5f)

Rebased-by: AO55 <AO55@reden-emu.dev>
The SDK's reader of two states or more retries until the numbers at 8 of neighbouring states differ by 1, and a game looks for new states by that field too. The runtime kept the time there and the number at 0. A game that asks for one state never runs that test, so one game's mouse demos worked, and another that asks for 16 spun in the reader forever with its frame waiting for it.

That game then ran 11 minutes with no stall. The demos weren't played again on this.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit eec07c46a6d2683fd53c155b762ed4779cef38f4)
nvn_commands: a command buffer now cuts from segments that hold only its
own pieces (ef5159be0). The test used 1.13 MiB of its 1 MiB of guest
memory, and the stub of kmem_alloc wrote past its end. The memory is now
2 MiB, and the stub stops when an allocation goes past it.

misc_service: the supported styles now include the Joy-Con 2 pair and
left styles (bfb42cc41), 0x307F.

shader_sm86: a store logs no bytes in a mask now (eace5d491). A global
buffer of a vertex program reads the page table of its draw (SNX_VKB_SMAP,
8dfb22383), which the test now gives, so the evaluator takes 128
bindings. On Windows, the spirv-val command has extra quotes, because
cmd.exe removes the first and the last quote of a command.

Verified: the three tests pass in the macOS ctest. The Windows change runs
only in CI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 7e0cd6f1b24e7aeb184d64ff27d061670efa2822)

Rebased-by: AO55 <AO55@reden-emu.dev>
A guest thread that touches memory the GPU holds waits in a userfaultfd
fault while the trap thread lands the page, and a landing can wait for
the GPU for seconds. That thread kept its emulated core all the time. In
the menus of an Ounce game, the audio threads (priorities 31 and 32)
waited for core 5 behind a priority 44 worker in such a fault, up to
3.7 s at a time. On the console the access takes no time, and the
better thread would run at once. A fault that came during another
landing kept its core until the trap thread read it.

The trap's reader now takes each fault from the userfaultfd as it comes,
tells the kernel (plat_trap_waiting), and queues the fault for a landing
thread of its own. kthread_fault_lend lets the faulting thread's core
go to the core's next thread and sets its poll. Back in game code, the
thread takes a core again at its next poll (core_preempt) or SVC. The
signal-based traps tell the kernel when the trap thread takes the fault.

The thread dump now prints each core's holder, its poll flag and its
waiters, and how long a running thread has been out of an SVC. The
host wait list groups the waits that many threads share, so it no
longer drops the others after 64 entries. A line in the log tells of a
holder that keeps its core 250 ms after a waiter of better priority
came, with the host thread's state. The report at exit counts the late
hand-offs for each core.

Verified: kernel_cores has a test where a priority 31 waiter gets the
core of a priority 44 holder in a fault, and the holder gets a core
again at its next poll. It fails when kthread_fault_lend does nothing,
and when the poll does not take a core back. In 5 menu runs without the
change, 16 log lines told of a core that a thread in a trap fault kept
for 250 ms or more. In 32 menu runs with it there were none. The late
hand-offs that remain are threads in host disk reads (page faults on
files) and threads in game code. The full ctest passes, except
vulkan_headless_uma and vulkan_headless_descriptor_buffers_uma, which
fail on feat/ounce too. The Windows cross-build was not run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit c3609d321d294876db4019a396d9600e611db402)

Rebased-by: AO55 <AO55@reden-emu.dev>
A program built with the Ounce's SDK 22 reads its thread's own handle
from its TLS at 0x110, where the console's kernel stores it. Without it
one game aborted as its first thread started. The handle is now written
there for the main thread and for every thread svcCreateThread makes, in
an Ounce program only.

The kernel cores test, which builds thread.c with stubs of its own,
defines the g_ounce it now reads.

Run on a Radeon 890M host: that game runs past the abort. On the last
commit of this series all 776 tests pass, the 28 Vulkan ones on RADV and
on lavapipe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 8dd351970c7a60aac781f8716e8e7d8083c85843)

Rebased-by: AO55 <AO55@reden-emu.dev>
An Ounce program's storage buffer is all of the memory mapped from its
address, up to 16 MiB: the programs don't keep to the size the game binds.
Each result was compared with its original bytes whole, after every
dispatch and wherever a draw asked whether it was still copyable.

- Where write tracking saw a page written since a result's snapshot,
  out_copyable and copyable_span compare the pages it saw written
  (org_holds), not every byte of the span.
- The SM86 translator marks the 4 KiB window of every store and atomic of
  a compute program (ShaderInfo.gbuf_marks): a plain store of 1 into
  SNX_VKB_WPAGES, which no compute program used. A result whose every
  writer marked its windows compares and lands only those
  (vk_buf_writable_marks, land_marked); one written by any other writer, a
  draw or a Switch program, is compared whole as before. The compute
  queue's results do the same (cs_write_back).

Verified: in one Ounce game memcmp went from 19% of the profile to 1%.
shader_sm86_gpu checks on the GPU that the stores of four programs marked
every window of their output and no other, nor any of their input; a
window of 2 KiB in place of 4 KiB failed it. shader_sm86 checks the bit.
All tests pass but the two forced-UMA ones that fail on main too.

(cherry picked from commit a372ee0fee9210a90df74977cb5fa3c5509fe626)

Rebased-by: AO55 <AO55@reden-emu.dev>
An Ounce program's storage buffer is all of the memory mapped from its
address, up to 16 MiB. Each writing dispatch copied the 16 MiB of every
range it wrote as its original bytes, compared the result with them
after the dispatch to find what changed, and on the graphics queue first
copied the whole result back from the GPU for that. With the window
marks of a372ee0fe the copy of the original bytes was still a quarter of
one game's CPU time, for about 260 bytes a result the shader changed.

- The SM86 translator has every store and atomic of a compute program
  log the bytes it writes (mark_written): an atomic OR of a bit for each
  byte into its window's mask, and the window's flag, which indexes the
  masks (SH_WLOG_*, ShaderInfo.gbuf_mark, nmarks).
- A result whose writers log lands the bytes they logged, every one and
  no other, read where the shader wrote them (land_logged, cs_write_back,
  vk_write_runs). It keeps no original bytes and is not copied back
  whole. Its writers' logs are attached at vk_buf_writable_commit, so an
  abandoned setup leaves none behind.
- The logs are host memory from a pool (writelog.c), cleared when they go
  back where their flags say they were written, and freed after 600
  presents unused.
- A writer that logs nothing (a draw, a Switch program, a buffer image)
  makes a result that compares as before. One joining a logged result
  being set up takes its original bytes then; one writing a pending
  logged result composes a result of its own over it.

A byte the CPU writes while a logged result is pending, which the shader
writes too, now takes the shader's value; the comparison took the CPU's.
Over 80 s of the game, 14,000 results landed with no such byte.

Verified: shader_sm86_gpu checks on the GPU that five programs log
exactly the bytes the reference interpreter stored (a new one stores 16,
8, 4, 2 and 1 bytes and leaves one byte unwritten); a wrong bit position
and every store logged as 4 bytes each fail it. vulkan_storage_logged
checks the landing, the CPU's writes beside it, two writers in two
submits, writers that log nothing joining, and the pool coming back
clear; landing more than was logged, a pool that doesn't clear, and an
in-place reuse by a writer that logs nothing each fail it. All tests pass
but the two forced-UMA ones that fail on main too. In six alternating
runs of 90 s against the commit before, the runs that didn't hang showed
350, 542 and 749 frames against 357, 388 and 451. Both builds hang in
some runs (3 of 6 and 2 of 6), as before this change.

(cherry picked from commit 53624c65b985a51f3243d20df5a9498bab1df217)

Rebased-by: AO55 <AO55@reden-emu.dev>
Each storage buffer of an Ounce compute program is all of the memory
mapped from its address, up to 16 MiB. Made anew for each writing
dispatch, it took a 16 MiB buffer and a 16 MiB readback slot each time:
about 1,500 every 10 s in one game, 15 to 25 GB handed out by the rings,
and GPU copies of whole results to compose them.

- vk/mirror.c: one sparse buffer as big as the guest's address space, at
  the same offsets, memory bound in 2 MiB granules where bindings are,
  and a mask beside it, a bit a byte. A host shadow keeps the guest bytes
  each page was given; binding a buffer copies in only the bytes the CPU
  changed since (write tracking, then a compare with the shadow), so the
  bytes programs wrote that haven't landed stay. Programs read and write
  it in place, one after another on the graphics queue.
- At each submit mirror_harvest.comp copies the pages written in it with
  their masks into a host ring and clears the masks; they land in guest
  memory and the shadow once the submit is done. The ring's room follows
  the pages recent submits wrote; pages past it take a pass of their own.
- The translator logs each store at its buffer's base in the mask, the
  bases and lengths in a uniform (SNX_VKB_MBASE, the fragment stage's
  binding, which no compute program has). A store past its buffer's
  length logs nothing. Without the mirror (no sparse residency of
  buffers, unified memory, no write tracking) a dispatch's own log takes
  the same layout, a mask for each buffer's 16 MiB.
- A read of guest memory under pending writes lands them first; a draw
  reading them binds the mirror (buf_get).

Verified: vulkan_mirror checks the sync (a CPU byte goes in, the GPU's
beside it stays; uploading changed pages whole fails it), the landing
(the logged bytes and no others; landing whole pages fails it) and a
harvest past its room. shader_sm86_gpu checks five programs log exactly
the bytes the reference stored, and that a store past its buffer's
length logs nothing (removing the clip fails it). All tests pass but the
two forced-UMA ones that fail on main too. In three alternating runs of
120 s against the commit before, the mirror's showed 440 and 678 frames
(the other lost the device to the GPU hang both builds still show)
against 333, 356 and 521. Host and GPU memory peaked about the same in
both: what is left of the rings is the other paths'.

(cherry picked from commit 44aaa4832c46b3c4c9795adc4c7de1ca952525ae)

Rebased-by: AO55 <AO55@reden-emu.dev>
A draw that read bytes an Ounce compute program had written in the GPU
mirror, not yet landed, bound the mirror there. At an offset its use
can't bind at (a draw's constants or vertices, a few bytes at any
address, where a uniform buffer binds at 64) the bytes landed first:
a submit, a wait for the GPU and a landing of everything pending. In
one game's menus that was 150 times a second, nearly every vk_finish,
each a stall of the GPU thread.

Now the bytes are copied on the GPU from the mirror into device memory
the use binds at, after the programs' writes, and the draw reads that
copy. The mirror is brought up to date over the range first, as when it
is bound itself.

Verified: vulkan_mirror reads 20 bytes of constants at an unaligned
address over a program's pending write: the copy is at an offset the
use binds at, holds the program's bytes, and no finish happened (taking
the landing instead fails it). In the game, finishes fell from about
150 a second to a handful, and the menus' slow phase ran at 5 to 14
frames a second instead of 3 to 4. All tests pass but the two forced-UMA
ones that fail on main too.

(cherry picked from commit 9dfc3433df534bfafe96a85b1765c13a0d99c16f)

Rebased-by: AO55 <AO55@reden-emu.dev>
At each submit the mirror copied every page its programs had written,
bytes and mask, into host memory, and once the submit was done landed
the logged bytes into guest memory and the shadow. With a submit after
each such dispatch, harvesting and landing took most of the GPU
thread's time per dispatch in one game's menus, for pages the CPU
mostly never read again.

Where the host traps guest memory:
- The harvest lists the written pages with their masks only, a fifth
  of an entry.
- Once the submit is done, each page's changes by the CPU since it was
  brought up to date, the bytes its programs didn't log, are copied into
  the mirror (a byte both wrote keeps the program's, as before; a page
  landed since takes all its unlogged bytes from guest memory), and
  then the runs of pages are published over guest memory with the
  mirror as their owner, a borrowed resource (vk_own_res_borrow).
- The CPU's first touch of a page lands it whole, which is exact as
  none of its bytes can change in between; the landing lets go of the
  page's shadow (vk_mirror_landed), so its next binding takes it whole.
  A CPU write after the submit is done now comes after the program's.
- Binding skips the pages the mirror owns, and copies other owners' in
  sixteen at a time, however many there are.
- Landing inside the landing of a batch (a published page writing a
  render target back can finish the commands) takes nothing: a batch
  leaves the list first.
Without traps the pass copies the bytes and they land as before.

Verified: vulkan_mirror checks that after the submit a written page is
owned by the mirror and not landed, that binding it again keeps the
program's bytes in the mirror, and that the CPU's touch lands the
program's bytes with the byte the CPU wrote beside them meanwhile
(skipping that copy into the mirror fails it). A self-copy of the
mirror's own pages is not caught by a test (it changes no byte). In the
game the menus' slow phase runs at 7 to 8 frames a second instead of 3
to 5, the work after each dispatch fell from about 600 to 105 us, and
the screens render as before. All tests pass but the two forced-UMA
ones that fail on main too.

(cherry picked from commit f26cb868c4040cc013b4a60abf23595264432fb9)

Rebased-by: AO55 <AO55@reden-emu.dev>
Reverts f26cb868c, which kept the pages the mirror's programs wrote
GPU-owned until the CPU touched them. With it, two of three runs through
one game's menus crashed in the driver, binding a draw's descriptor
sets, and one runtime path wrote a page the mirror owned without
landing it first (gmem_ptr acquired before it landed what was pending,
which could publish the page again). It comes back once the crash is
understood.

(cherry picked from commit 99673e9e01f9d686dfea7944a5050ed6cc76545d)

Rebased-by: AO55 <AO55@reden-emu.dev>
At each submit the mirror copied every page its programs had written,
bytes and mask, into host memory, and once the submit was done landed
the logged bytes into guest memory and the shadow. With a submit after
each such dispatch, harvesting and landing took most of the GPU
thread's time per dispatch in one game's menus, for pages the CPU
mostly never read again.

Where the host traps guest memory:
- The harvest lists the written pages with their masks only, a ninth
  of an entry. Once the submit is done they are queued, still pending.
- At the next point where nothing is being recorded (vk_mirror_publish:
  before the releases those submits gate are performed, at the end of a
  GPU job, before a CPU read of them) each page's changes by the CPU
  since it was brought up to date, the bytes its programs didn't log,
  are copied into the mirror (a byte both wrote keeps the program's),
  that copy is submitted, and the runs of pages are published over
  guest memory with the mirror as their owner, a borrowed resource.
- The CPU's first touch of a page lands it whole, which is exact as
  none of its bytes can change in between; the landing lets go of the
  page's shadow (vk_mirror_landed). A CPU write after publishing now
  comes after the program's.
- Binding skips the pages the mirror owns, and copies other owners' in
  sixteen at a time, however many there are.
- gmem_ptr lands pending results before it takes the bytes from their
  owners: landing could publish them again, and the CPU then wrote a
  GPU-owned page.
Without traps the pass copies the bytes and they land as before.

The first version (f26cb868c, reverted) took the pages in and
published them where results land. That runs inside a frame's
recycling, which begins a command buffer: the copies began it again
there, the recycling then reset its pool and descriptor pools and began
it once more, and draws crashed in the driver binding descriptor sets
("vkBeginCommandBuffer while still recording" under validation).
Nothing is recorded or submitted inside a landing, a recycling or a
submission now (vk_rec_unsafe). Publishing only at the end of GPU jobs
left the game reading stale untrapped pages after a release, and
stalled it 15 seconds in two of three menu runs.

Verified: vulkan_mirror checks that after the submit a written page
is pending and not yet owned (publishing inside the landing fails it),
that once published it is owned by the mirror and not landed, that
binding it again keeps the program's bytes, and that the CPU's touch
lands them with the byte the CPU wrote beside them meanwhile (skipping
that copy fails it). vulkan_release checks that no release is
performed between a landing and the publishing (removing it fails it).
Under the validation layer the game's menus report no new message over
225 seconds; three menu runs had no crash and no stall. All tests pass
but the two forced-UMA ones that fail on main too.

(cherry picked from commit 6072680150841b1901b8e1636fe160fc95f1d956)

Rebased-by: AO55 <AO55@reden-emu.dev>
The menus of an Ounce game froze about one run in twenty, with no new
frame and 0 GPU submissions. A host backtrace of the frozen process
showed the GPU thread on a CPU, with vk_lock held, in guest_runs at GPU
address 0x489dae32e000, far past the 40-bit GPU address space:

  vk_buf_frame_done > land_logged > vk_write_runs > gpu_mem_written
  > guest_runs

A landing of storage results read guest memory that the GPU mirror
held (vk_write_runs > gmem_ptr > gmem_need > vk_mirror_mem_need), and
that read finished the GPU's work with vk_finish. Its land_through then
landed the next submissions' results inside the first landing. The inner
landing reset and refilled buffer.c's g_chg, the runs that the outer
vk_write_runs was writing from. A run that then ended before it began
gave gpu_mem_written a size near 2^64, and guest_runs walked that page
by page for minutes. The trap thread's landings waited for vk_lock, the
game's workers waited in their faults on GPU-owned results, and the
main thread waited for the workers.

The nested landing was also wrong when it did not hang: it landed newer
results before the older ones that the outer landing still wrote.
land_through now returns at once inside a landing. The landing in
progress lands the rest in order, or the next one does. vk_write_runs
also stops with a message when its runs are out of order, so a later
change of them is a report and not a hang.

Verified: a probe build logged the nested landing in 17 of 17 menu
runs without this change, and 0 of 15 with it. In the same session,
2 of 41 menu runs without the change froze with the same backtrace, and
0 of 15 with it froze this way. One of those 15 froze in another way
(4 graphics submissions that never completed, the GPU thread waiting in
vk_finish), which this change does not touch. The full ctest passes,
except vulkan_headless_uma and vulkan_headless_descriptor_buffers_uma,
which fail on feat/ounce too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 11e97aac12bb96572310928cbe2438bb6828867d)
The SM86 translator's mark_written still emitted SNX_VKB_WPAGES/MBASE and
an atomic OR into the mask, but the renderer's compute dispatch no longer
binds those two descriptors (its write log and GPU-mirror mask were dropped
for whole-owner publishing), so every store read the unwritten descriptors
and faulted the GPU (Xid 13, an MMU fault at a stale address). GPU-assisted
validation named it: Binding 106/108 never updated. Drop the logging; the
mask can come back with the mirror that uses it.

(cherry picked from commit eace5d491f1eb7bbd893d4dbc1a5ca10342ee204)

Rebased-by: AO55 <AO55@reden-emu.dev>
An Ounce program's storage buffer is all of the memory mapped from its
address, up to 16 MiB, but its dispatches write only a few hundred bytes of
it (0.04% of the compared bytes in one game). The whole-owner publishing
that replaced the write log only keeps buffers the CPU never reads; a
buffer the CPU reads back must land, and without the log the renderer
snapshotted its 16 MiB before the dispatch and memcmp'd the result after it
to find the few changed bytes -- most of one game's GPU thread.

Bring the write log back, beside the whole-owner path. The SM86 translator
has every store and atomic of a compute program record the bytes it writes
(mark_written, ShaderInfo.gbuf_mark/nmarks, SNX_VKB_WPAGES): a plain store
of 1 into its 4 KiB window's flag, and an atomic OR of a bit for each byte
into that window's mask. The flags index the masks, so reading and clearing
a log costs the windows written, not the windows bound. A deferred
dispatch's written buffers bind with vk_buf_copy_writable_logged and land
only the bytes the log gives (land_logged); the resident path still
publishes its owners whole, and only binds the log so the stores' atomic OR
reads a written descriptor (Xid 13).

The log is host memory from a pool (writelog.c), its flags first, cleared
where they say it was written when it goes back. In one game the writeback
comparison fell from 1.3 GB/s to a few MB/s.

(cherry picked from commit 4100f10b6f0f3c2d9e6f600fd0463c0dc851812a)
(cherry picked from commit 8f839457b5325354e50015044f8838f1d46157c4)

Rebased-by: AO55 <AO55@reden-emu.dev>
The write log covered the deferred (graphics-queue) dispatches, but a
dispatch on the compute queue whose buffers the CPU reads still snapshotted
its originals and compared the whole result after it landed (cs_write_back).
Its results now carry the log reference and part they wrote, and land the
bytes the log gives with vk_write_runs, dropping the reference after. In
one game this took the GPU thread from 73% CPU to about 15%.

(cherry picked from commit d7399b9c7c5366726b80601e1d09ac5cd0d9c6ba)

Rebased-by: AO55 <AO55@reden-emu.dev>
shader_sm86 checked that its compute program's store logged no bytes,
as no store did while the write log was off. 4100f10b turned it on
again, and the store now marks its buffer's part of the log, so the
check failed on origin/feat/ounce as well.

The check now asks for the store logged in the log's first part:
gbuf_marks of 1, one part, and buffer 0's mark of 1.

Run on a Radeon 890M host: shader_sm86 passes, where it failed on
origin/feat/ounce built alone. Of the other tests that aren't
Vulkan's, 746 with this one, all pass or are skipped (two of the 3DS).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 270903edf7429956c8c96424367176332a5a40c5)

Rebased-by: AO55 <AO55@reden-emu.dev>
A compute dispatch writing a storage buffer the program never reads (no
LDG or ATOMG, tracked in ShaderInfo.gbuf_rmask and mark_read) doesn't need
its input copied into staging. Skip the copy and mark the result no_input,
so a later reader composes over guest memory instead of reading the staging
in place (gfx_gpu_src).

The staging must still hold a valid value: the buffer's stores are partial,
and the GPU's read-modify-write of the surrounding cache line reads the
bytes the input copy would have written over. Zero them, or the shader
hangs the GPU on the ring's reused, uninitialized memory.

(cherry picked from commit f24651c69e48c9d2f57f74a8862bab6c744d3eac)
(cherry picked from commit dbfd99be96faca092721a96d9d29d171be6caa13)

Rebased-by: AO55 <AO55@reden-emu.dev>
The merge of main in c74cd575f dropped the dispatch side of the GPU mirror
(mirror_plan in compute.c), and the translator had moved to main's write
log. So each dispatch of an Ounce compute program made its storage buffers
anew, each one all of the memory mapped from its address, up to 16 MiB:
its input copied from guest memory on the CPU and composed on the GPU over
the results before it. In one game's race a frame had about 300 of these
bindings at addresses a few KiB apart, 2.9 GB of compositions and 230 MB of
CPU copies, and the game ran at about one frame a second.

- compute.c binds such a program's buffers in the mirror again, and a
  program whose buffers can't all be bound there takes the copies.
- The stores still set bits in the dispatch's write log. A pass after the
  dispatch ORs them into the mirror's mask at each buffer's place
  (mirror_fold.comp, vk_mirror_fold), the bits past a buffer's length
  dropped, so the submit's harvest lands the bytes the program wrote.
- A draw reads a range part of which the mirror owns from the mirror
  (vk_mirror_holds). It staged the CPU's bytes between the owned pages
  again for each draw, 16 MiB a binding: 48% of a profile's samples once
  the dispatches were in the mirror.
- vk_mirror_harvest: two written ranges that overlap gave their pages a
  count each, and the batch took one away for each joined range, so those
  pages stayed pending for good. The joined ranges take their own count
  first, then the written ones lose theirs.
- harvest_left took its descriptor sets from the frame (vk_desc_alloc),
  which starts the frame's command buffer, inside a landing. After a
  present's submission that command buffer stayed open, and when its slot
  came round again the draws recorded into it past the recording thread,
  with sets only that thread resolves: a crash in vkCmdBindDescriptorSets
  in 5 of 9 runs. The pass takes its sets from a pool of its own now.

Verified: the frames shown from 55 s to 110 s of a 110 s run of the
game, three runs each: the baseline 1.0, 3.9 and 2.9 frames a second, this change 9.9, 10.1 and
11.8. Six runs of the final code did not crash. A run of each under the
validation layer gave the same kinds of messages, none new.
vulkan_headless checks the fold: the bits of two overlapping buffers, the
first at bit 5 of a mask word, a window not flagged and bits past the
length. ctest passes but vulkan_headless_uma,
vulkan_headless_descriptor_buffers_uma, astc_vulkan and
astc_vulkan_pieces, which fail before this change too.
vulkan_headless_libraries and vulkan_headless_libraries_off fail now and
then on the driver's "NVVM compilation failed" after their checks pass,
the baseline 1 time in 10.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 78f7d94a4f0ce900939f9c06fe7ce9f4fcb32f57)

Rebased-by: AO55 <AO55@reden-emu.dev>
Two costs on the GPU thread came from the number of compute programs
an Ounce game dispatches, a few hundred a frame on one game's title.

The fast cache in front of cs_pipe had 64 entries by program address.
The programs put each other out, and almost every dispatch read its
program again, hashed it and walked it twice (shader_absolute_flow,
vk_shader_hash). With 1024 entries those walks went from about 5.9% of
the samples of a profile of the title screen to 0.8%.

A dispatch on the graphics queue was submitted at once, so that a
reader of its results waits for that submit alone. The GPU mirror puts
each Ounce program with a write log there, so the game made about 180
submissions a present, each with a harvest of the mirror, and the GPU
idled between them. A dispatch in the mirror is no longer submitted at
once: its results land where the CPU first touches them, and that read
submits what is open (vk_mirror_mem_need). The submissions went down to
70 to 86 a present.

Ran the game to its title screen and on, about 120 s a run: eight runs
with the submit change, five of them with the larger cache too. None
crashed or had a GPU fault.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit cfe9fbfe094cb5cc693f1ab168a50af2eddf888a)

Rebased-by: AO55 <AO55@reden-emu.dev>
On a device with unified memory, a dispatch's logged storage result that
couldn't be written in place stayed pending, and the next binding that
read its range landed it with a finish. In one game a 16 MiB binding
whose end overlaps a movie frame the GPU owns, and which no import can
hold, did that on every frame: about 137 ms a frame of finishes.

Such a result is now written back on the GPU right after its dispatch,
part by part: in place where an import holds a part, into the owner that
holds it, and for whole pages that neither holds into a new import or a
new owner, published GPU owned. A merge shader copies only the bytes the
write log marks, the bytes the CPU's landing writes, so the CPU's writes
to the others survive. A CPU access to an owned part still traps and
lands after the submission, and parts written in place reach the CPU
when their submission completes. A read across an import's edge with
writes in place pending is copied on the GPU part by part, without
waiting for the submission.

Run on a Radeon 890M host: that game's movie has no finishes left, and
goes from 2.4 to about 3 frames a second. A new check of the write back
runs in vulkan_headless and vulkan_headless_uma. On the last commit of
this series all 776 tests pass, the 28 Vulkan ones on RADV and on
lavapipe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 173cc00009bdc6dd3a7d05c7684369d6d19cad75)

Rebased-by: AO55 <AO55@reden-emu.dev>
The mirror is one buffer as big as the guest's address space: RADV makes none
past 4 GiB (maxBufferSize), and the validation layer refused the 512 GiB one.

Change-Id: I4208beb60e881ec583305aa3324d4221fd4fad4e
Signed-off-by: AO55 <AO55@reden-emu.dev>
A program whose lanes are a warp's needs 32 of them in one subgroup, whole; RADV
runs compute in wave64 otherwise.

Change-Id: I4e95e2dc86153433f5d28aad2b3b9f642ce6e944
Signed-off-by: AO55 <AO55@reden-emu.dev>
HMMA was translated into 32 subgroup shuffles, 32 unpacks of half pairs
and 32 dot products a lane. One game's video upscaler runs seven
programs of 46 to 768 HMMAs, which took 270 ms of a frame on a Radeon
890M.

A's pairs come from the lane's own quad, and they are read with quad
broadcasts where the stage has quad operations. Where the device has
VK_VALVE_shader_mixed_float_dot_product, each pair of products goes into
the f32 accumulator with one mixed dot, v_dot2_f32_f16 on AMD. Elsewhere
the previous paths stay.

Most of the cost was spilled registers. The driver merged identical B
gathers of many HMMAs, which then stayed live, and the programs needed
420 to 1430 registers a lane. B is now combined with a zero that changes
every 8 HMMAs, NumWorkgroups.x == 0, which no invocation that runs sees
as anything else, so the gathers aren't merged. A compiler that proves
it zero only merges them again.

Compute modules that read other lanes now require subgroups of 32 where
the device allows it. RADV ran them in wave64.

Run on a Radeon 890M host: that game's movie goes from 3.2 to 12.6
frames a second, its frame from 325 to 81 ms of GPU time.
shader_sm86_gpu chose lavapipe, whose subgroups of 8 skipped HMMA
without a word: it now chooses a device with subgroups of 32 or more,
and has new k8, accumulate and subnormal cases. The fallbacks without
quads and without the mixed dot were run in 12 configurations. On the
last commit of this series all 776 tests pass, the 28 Vulkan ones on
RADV and on lavapipe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 2a9393579b62e24bbc18d10a419d1116880d1226)

Rebased-by: AO55 <AO55@reden-emu.dev>
With VK_KHR_cooperative_matrix's 16x16x16 shape of f16 to f32, an HMMA
stages its fragments in a slot of shared memory for its subgroup, after
the program's own, multiplies them as cooperative matrices and reads D
back, with C added in f32. A k8 HMMA zeroes the rest of A and B, so no
stale value reaches the sums. It is used for compute programs with HMMA
where the device has the shape, the Vulkan memory model and subgroups of
32, and where the program's shared memory and the slots fit. Elsewhere
the previous path stays.

The extension requires the Vulkan memory model, which bans Coherent. In
the modules that take the path, global words are read and written with
relaxed atomic loads and stores at device scope, shared accesses take
NonPrivatePointer, and acquire and release semantics make their writes
available and visible. Mesa compiles them as before.

Run on a Radeon 890M host: one game's movie goes from 81 to 72 ms of GPU
time a frame, from 12.6 to about 14 frames a second. New cases cover the
path, its fallbacks and the memory model's barriers and atomics through
spirv-val, and every HMMA form against the reference on the GPU at 32
and 64 lanes. On the last commit of this series all 776 tests pass, the
28 Vulkan ones on RADV and on lavapipe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 09f635a7ca07e8ff46fe3c07aefa0dd06e393b50)

Rebased-by: AO55 <AO55@reden-emu.dev>
A game's add-on download menu waited forever on our success; NIM gives 0xC8A0D027.

Change-Id: I52392e0155d31f9722655dad7d57c636fb8ce521
Signed-off-by: AO55 <AO55@reden-emu.dev>
The sanitizer job counted the process and its memory as leaked.

Change-Id: I79d5b497f67278afb5e2d21fc6884c628fdc997f
Signed-off-by: AO55 <AO55@reden-emu.dev>
vk_gpu_profile timed rendering passes and the gaps between them, but most
of one Ounce game's submissions hold no pass (a dispatch on the graphics
queue is submitted at once), so 530 ms of its 550 ms of busy time a
present went unexplained.

- Each submission's busy time goes by what it holds: rendering passes,
  else dispatches, else copies, else nothing.
- Every dispatch and copy recorded into the frame's command buffer is
  timed (record.c's rec_CmdDispatch and copy recorders): dispatches by
  tag, a compute program's key or the ASTC decode and BC7 encode, copies
  by where they were recorded (an offset from vk_gpuprof_base, for
  addr2line), with their bytes. The report lists the 16 that took the
  most.

Off, it costs a comparison a dispatch or copy. It found the game's GPU
time in composing storage results: GPU copies of whole 16 MiB results,
194 MB a frame across PCIe.

Verified: all tests pass but the two forced-UMA ones that fail on main
too.

(cherry picked from commit 203d748ffb78d335785fab61b8de19be19a6a708)

Rebased-by: AO55 <AO55@reden-emu.dev>
The mirror copied in each run of bytes the CPU changed as a region of
its own. A page the CPU had rewritten in scattered bytes made one copy
command of 194,545 regions, 4.6 MB, bigger than the recording ring:
rec_push waited for room forever with vk_lock held, and the game froze
while loading a race, its memory thread's GPU mapping and the trap
handler behind the lock.

- A page with no program's write pending on it is copied whole when
  anything on it changed: nothing of the GPU's is there to keep. Only a
  page with pending writes takes the bytes the CPU changed.
- The copies go in commands of at most 1,024 regions.
- rec_push stops with an error for a command the ring could never take,
  instead of waiting for room that never comes.

Verified: vulkan_mirror now writes a program's bytes pending on one page
and a CPU byte on another: the first keeps the program's bytes, the
second is copied whole; copying every changed page whole fails it. The
game got through the race loading it froze in. All tests pass but the
two forced-UMA ones that fail on main too.

(cherry picked from commit f20121fe64b0a9bb3ea4be53e9f68216630badc3)

Rebased-by: AO55 <AO55@reden-emu.dev>
The SM86 translator flushed the operands and result of each FTZ
FADD, FMUL and FFMA by hand, four instructions each, on every device.
One game's large vertex programs were 3.8 MB of SPIR-V that way, and
the driver took 10 s to make a pipeline of one, while the game's
threads waited. The Maxwell translator already picks the device's way
(g_vk_ftz): nothing where the GPU flushes by itself, the
DenormFlushToZero execution mode where every such instruction flushes,
and the flush by hand only where neither holds.
sm86_to_spirv_ftz takes that mode, and the renderer passes g_vk_ftz.
sm86_to_spirv stays the flush by hand, for the tools and the tests.

A pipeline that takes a second or more to make is now logged with its
stages' program hashes and SPIR-V sizes, so that the shader corpus
finds the programs. A table from each module to its shader serves
that line, as the workers that make pipelines don't read the GPU
thread's tables.

Verified: shader_sm86's new test checks the mode, the flush by hand
and neither, for an FTZ FMUL under each device mode, and a program
that mixes FTZ and not takes no mode. With the flush by hand always,
with the mode in a mixed program, and with no mode, it fails. In the
game, on this GPU (which flushes by itself), vertex programs of the
same size are 1.7 MB of SPIR-V now and their pipelines take 6.3 to
6.6 s, against 3.8 MB and 10 s. All tests pass but the two forced-UMA
ones.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 5eca764104e642750b72a275fae7c11067d0c62f)

[AO55: the slow pipeline log stays out: main makes its pipelines through pipeline libraries now]

Rebased-by: AO55 <AO55@reden-emu.dev>
In one game's menus, its memory thread spent 59 s of a 130 s capture in
MapPhysicalMemory and UnmapPhysicalMemory, all of it waiting for vk_lock,
up to 7.9 s at a time. The lock's holders were waiting for the GPU or for
a pipeline. The changes themselves needed nothing of the renderer: no
result was pending on those pages and no GPU mapping showed them.

mem.c now tells the renderer which changes land or drop GPU-owned memory
on their own pages only (map, unmap, MapPhysicalMemory and
UnmapPhysicalMemory: GPU_MAPPING_GUEST_ONLY). For those, the renderer
looks under a new leaf lock, pend_lock, for a pending result on the
range, an owner on its host pages or a GPU mapping of it. The renderer
reads and writes guest memory only through a GPU mapping (or an owner),
with vk_lock held. When nothing is there, the change takes no vk_lock.
Every change of the pending tables takes pend_lock, own_begin runs under
it, and every mapping bracket holds it from its begin to its end, so
nothing that would cover the range comes while the change runs. The lock
order is vk_lock, pend_lock, then mem.c's lock.

vkr_mem_pending, which the game's threads ask on their reads through the
GPU's address space, now reads the tables under pend_lock, not vk_lock.
A change of guest memory that takes vk_lock no longer performs every
queued release and lands every storage image: releases only when a
pending result covers its pages (their payloads count there too), and
storage images only when their bytes are on the range.

Verified: the full ctest with -j1 (only vulkan_headless_uma and
vulkan_headless_descriptor_buffers_uma fail, in check_uma_placed_view at
the same line as on feat/ounce). New check_mapping_lock: with vk_lock held
on another thread, a map and an unmap of guest memory with nothing of the
renderer's go on, and an unmap under a GPU mapping or under GPU-owned
memory waits. Mutations: always taking vk_lock, skipping the GPU mapping
check and skipping the owner check each fail it. memory_accounting checks
the kind of each mem.c change, and fails when UnmapPhysicalMemory names
GPU_MAPPING_GUEST. The game's menus ran to 746 frames with this and the
next commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 1fdcb03bd4b6d2a445f7e6b9c5dd3c1586d28449)

Rebased-by: AO55 <AO55@reden-emu.dev>
In one game's menus, the longest stall (7.9 s) was a chain: a pipeline
worker made one pipeline for 7.9 s, the recording thread waited for it
at a draw, the trap thread's landing held vk_lock and waited for the
recording thread to drain (own_land, vk_rec_sync), and the GPU thread
and the game's memory thread waited for vk_lock. The GPU thread also
held vk_lock while it waited for the GPU to finish a frame slot's last
use (frame_recycle, up to 3.1 s at a time), and every thread that landed
results or performed releases waited behind it.

A landing now first waits, with no lock held, for the submission its
entries' writes are in (OwnHooks' writer and wait, own_wait in owned.c).
It takes vk_lock only to hand the commands being recorded to the GPU when
the writes may be among them. Under vk_lock, own_land then finds the
writes done: its copy waits on that submission's signal, which is there,
and takes the queue's lock, not the recording thread's drain. A landing
on a thread that holds vk_lock already lands as before.

When a frame slot becomes the current one, cmd.c keeps the submission its
recycling waits for. The GPU thread waits for it before each call and
job, with no lock held (the renderer's new ready hook,
vk_frame_ready), so frame_recycle finds the work done. The waits
themselves stay: a draw still waits for its pipeline.

Verified: the full ctest with -j1 (only vulkan_headless_uma and
vulkan_headless_descriptor_buffers_uma fail, as on feat/ounce). New
check_landing_wait: with a result's submission held back by a semaphore,
a landing on another thread waits while vk_lock stays free, then lands
the bytes. New check_frame_ready: the same for the wait for the next
frame slot. Mutations: no landing wait, the landing wait under vk_lock,
no kept recycle value, and the frame wait under vk_lock each fail them.
The game's menus ran to 746 frames with the menu script, with no stall
report.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit a20c87ead6cf9e881931c5c8d501af59e787a720)

[AO55: own.c lands once, as main does since its landings stopped looping: the wait for the GPU comes before the producer's lock, and the entries are read again after it]

Rebased-by: AO55 <AO55@reden-emu.dev>
The first commit held pend_lock from a mapping change's begin, through
the landings that wait for the GPU with vk_lock held. A capture of the
game's menus with the first two commits showed UnmapPhysicalMemory of
memory the renderer held nothing of waiting 2.2 s with no zone: a
guest thread's mapping change held pend_lock in vk_finish.

pend_lock only has to keep out a change of guest memory that skips
vk_lock while the page tables change, from the end of the begin to the
end, and each change of the tables takes it on its own. So the begin now
takes it after vk_lock and after its landings.

Verified: the full ctest with -j1 (only the two UMA headless tests fail,
in check_uma_placed_view as on feat/ounce). New check_mapping_landing: an
unmap of memory with a pending storage result, whose submission a
semaphore holds back, waits for the GPU in its landing, and a map of
other memory on another thread goes on meanwhile. With pend_lock taken
right after vk_lock again, it fails.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 92df965c903493adbe7151472ca096bc5c180a13)
With vk_validation=1 the layer now also instruments the shaders to report
out-of-bounds and unwritten-descriptor accesses (VK_EXT_validation_features),
which the plain layer can't see. That is what pinned the SM86 mask fault to
an unwritten descriptor.

(cherry picked from commit e24ae895831e795c475beabb67fb3d81c194a115)

Rebased-by: AO55 <AO55@reden-emu.dev>
The buffer report (vk_buffer_stats) now also logs, each 600 presents, how
many bytes the storage writeback compared against how many it actually
changed, and why keep_new turned a writable binding away (traps off, unified
memory, unaligned, not contiguous, or the CPU read it lately). The change
ratio shows whether the write log is landing sparse writes; the keep_new
reasons show what keeps buffers from staying on the GPU.

(cherry picked from commit e3e13ba40bb940c8d58f9605072da63d2e341385)

Rebased-by: AO55 <AO55@reden-emu.dev>
e24ae8958 turned on GPU-assisted validation each time the validation layer
was on. The layer then logs the settings that it changes ("validation is
adjusting settings"), and vulkan_headless_vic_validation fails on each
"vulkan validation:" line. That test also took 2.86 s in place of 0.33 s.
GPU-assisted validation is now the value 2 of vk_validation, and 1 is the
layer alone, as on main.

Verified: the macOS build and its ctest pass. The Linux validation test
runs only in CI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 10e8ea676e609273dc86d987d855ee2dad7a11f9)

Rebased-by: AO55 <AO55@reden-emu.dev>
A game stopped presenting about 600 frames in, before its title screen,
in every run. Its memory thread sat in svcMapPhysicalMemory or
svcUnmapPhysicalMemory, the loaders waited behind it, and the GPU made no
more submissions.

The host stacks showed a cycle of two locks. The GPU thread hashed a
sparse texture with tex_hash, which hashed each run inside gmmu_pieces,
under the index lock of the GPU page table. mem_hash then took pend_lock
(gmem_need, vkr_mem_pending). The memory thread held pend_lock from the
start of vkr_mapping_begin and asked for the index lock in guest_covered.
The GPU thread also held vk_lock, so everything else that needed the
renderer stopped too. The callbacks of gmmu_pieces must take no lock
(nvdrv.h), and 26f732bb9 put the hash in one.

tex_hash now takes the runs 64 at a time under the lock and hashes them
after it is free. The hash is the same as before: each run's offset and
the hash of its bytes, in order.

Ran the game under gdb until the stall and read the stacks of all host
threads (the cycle above). With the fix, ran it 3 times for 150 s with
mesh_draws on: no stall in any run, and each got past the frame where the
earlier runs stopped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit de315408ff9bf17015201ac80df8e9e9cbe51917)

Rebased-by: AO55 <AO55@reden-emu.dev>
vk_gpu_profile summed all of a game's dispatches under one key, the
renderer's own. The game's dispatches now give their program's key,
which they already carried for faults, so the profile names the programs
the GPU's time goes to.

Run on a Radeon 890M host, with one game and vk_gpu_profile=1. On the
last commit of this series all 776 tests pass, the 28 Vulkan ones on
RADV and on lavapipe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 0631442004d405ba4047691580ffb38c691c1133)

[AO55: main dispatches through rec_CmdDispatch with a checkpoint (vk_ck), so compute.c tags each dispatch with its program's key before it]

Rebased-by: AO55 <AO55@reden-emu.dev>
The renderer keys images by img_int_mask; SM86 read rt_int_mask's bit 8 + slot,
so every Ounce float image was unsigned, its dispatch skipped, a scene black.

Change-Id: Ifc58f83e2e5091de5032621234a808bc9b2c5d44
Signed-off-by: AO55 <AO55@reden-emu.dev>
A game's 8192x8192x68 ASTC 8x8 array, 7 layers mapped, was made whole: 23 GB, not made.
Device blocks lower than its GOB blocks now bind in stacks, and holed ASTC is held as BC7.

Change-Id: Ie8e3b4ebd586b3b0585caef301e17c275e3092d0
Signed-off-by: AO55 <AO55@reden-emu.dev>
The renderer tests depth ahead of a program it reads as keeping its pixels
(has_discard 0), which the SM86 translation never set.

Change-Id: I0721bfd210b94d3609a5ea271c4084db99d3c0c0
Signed-off-by: AO55 <AO55@reden-emu.dev>
tex_upload_rows held it made whole; now the 85 bricks and the 2x2 blocks a tile binds.

Change-Id: I48c2305c49bb5836780febbbf3d18a9cb3da6e33
Signed-off-by: AO55 <AO55@reden-emu.dev>
BC7 with no RGBA8 image before it, as feat/ounce holds them: a temporary mode to compare
an Ounce game on main with that branch.

Change-Id: Ic266d2ab2f5504b9898296922a870d68cba8ee30
Signed-off-by: AO55 <AO55@reden-emu.dev>
Its end is found by decoding it: each doubled prefix decoded it again, and the hash
once more, a sixth of the GPU thread in an Ounce game.

Change-Id: I46467a8f313ee973c24d105123c42123f521bded
Signed-off-by: AO55 <AO55@reden-emu.dev>
leaves_add looked each page's leaf up twice: a tenth of the GPU thread in an Ounce game.

Change-Id: Ib533010e54d293905629ba9d5aa315e6f7a8abfc
Signed-off-by: AO55 <AO55@reden-emu.dev>
As feat/ounce holds them: Exact on a GPU of 8 GB or more filled the GPU and evicted
every frame, and BC7 between frames made each texture RGBA8 first.

Change-Id: I3103669842076006e4f579702a1a0e732531cf76
Signed-off-by: AO55 <AO55@reden-emu.dev>
RADV (maxBufferSize 4 GiB) makes and runs it, as feat/ounce does; without it an Ounce
game's storage results landed through the CPU, 1.6 fps against 11. Temporary, on.

Change-Id: I49e6645ae77f99adaf5476b375ccebe6e1f054cb
Signed-off-by: AO55 <AO55@reden-emu.dev>
A draw or dispatch that reads guest memory the GPU mirror holds binds
the mirror in place (buf_get). Each such binding ended the rendering
pass and recorded a barrier from the compute stage's writes to every
later read, also when no program had written the mirror since the last
one. In one game's race the main color target was drawn in about 470
passes a frame, three draws each, and the GPU idled about 31 ms a frame
in gaps that held only barriers.

A count of the programs' writes of the mirror (vk_mirror_fold, after
each dispatch that writes it) now tells when one is due: the first read
after a write takes the barrier, and the reads after it don't. The
mirror's own copies of the CPU's bytes keep their barrier.

Measured in a race with --vk_gpu_profile: the main target went from
about 470 passes a frame to 190 to 210, and the gaps with barriers alone
from about 31 ms to 22 to 23 ms a frame. Five races of 450 s ran with
it. One of them stopped at the known GPU hang (Xid 109), in a draw that
hangs without this change too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 4f57ba0c2f4b89fd5faf8f92012363fc1ec043b2)
vk_mirror_slice brings the mirror up to date before a binding reads it:
it copies in the bytes the CPU changed and those of their owners, and
binds the granules it lacks. Then it ended the rendering pass and
recorded a barrier from those copies to every later read, also when it
had recorded no copy at all. Each draw that reads the mirror takes this
path, so on one user's RX 9070 (RADV) two thirds of all rendering
passes of a run ended there, 84,892 of 538,393.

The barrier now comes only after a copy, an owner's copy (up_owned
tells it now) or a new granule's cleared mask. Where nothing was
recorded, the barrier after the last copies covers the read.

Measured in a race on an RTX 2080 with --vk_gpu_profile, against the
build before this and the change to buf_get's barrier: the gaps with
barriers alone went from about 31 ms and 570 gaps a frame to 12 to 15 ms
and about 100. The main color target had 160 to 210 passes a frame,
from about 470. The race's median rate over 200 to 440 s was 11.4
frames a second, from 6.6 to 8.6 in four races of the build before. The
full ctest passes but for vulkan_headless_uma and
vulkan_headless_descriptor_buffers_uma, which fail without the change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 9691df118717cb7697879eefa25e57540017e509)
cmake/dav1d.cmake left Windows out with the cross builds, so a Windows
runtime played an Ounce game's AV1 movie black. MSYS2's CLANG64
environment, which upstream's CI builds in, has meson, ninja and NASM,
and dav1d builds there as on Linux. A native Windows build now builds it
too. Cross builds stay out, as meson would need a cross file of its own.
On Windows dav1d's threads are the system's own, so it links no pthread,
libm or libdl there.

Run on a Windows 11 host with an RTX 5080, built in MSYS2 CLANG64:
FFmpeg is configured with its libdav1d decoder, and one game's intro
movie decodes and shows as it does on Linux. The Linux build is
unchanged by this.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit fa8315b07ff5f0004c25c50783e93504f7de87b7)
A dispatch's read-only storage binding never tried the import that holds
its range on a device with unified memory: vk_buf_get_strict asked
buf_get with IN_NO, so the bytes were copied from the import into device
staging for every dispatch (owned.c's guest_read). One game's video
upscaler binds 16 MiB tensors that the dispatch before it wrote in
place, and copied 538 MB a frame that way, 14.5 ms of GPU time.

On unified memory vk_buf_get_strict now asks with IN_TRY, which binds
the import at the range's offset. It still copies, landing first, where
an unpublished storage image result or a queued release covers the
range, the guards copy_writable takes for writes in place. The binding
is ordered after the writer's dispatch by the barrier order() records
for writes in place, note_read covers a later write, and no trap is
involved, as nothing in the range is owned (range_owned is checked
first). A release waits for the submission that reads (vk_uma_bound).

Run on a Radeon 890M host: that game's movie goes from 21 to 30 frames a
second (its cap), its copies from the import from 14.5 to 0.8 ms a
frame, and the pictures are the same. check_uma_writes checks that a
range with a write pending binds the import at the write's offset, and
fails without the change. The full suite passes, the 28 Vulkan tests on
RADV and on lavapipe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 50bdc2cec671caae2fbddec9c5488485a663ac4f)
An Ounce compute program's dispatch writes a log of what its stores
wrote: mark_written adds a store and an atomicOr for every global store,
and vk_mirror_fold reads the log after the dispatch. The log was host
memory, so on a discrete GPU each of those crossed the bus. On an RTX
5080 one game's video upscaler program took 47 ms a dispatch for
0.13 ms, and each fold 14 ms for 0.3 ms.

A dispatch in the GPU mirror now takes a log in the GPU's memory
(vk_wlog_get_gpu). Only the GPU reads it, so vk_wlog_clear clears it on
the GPU after the fold, between two barriers in the same command
buffer, and the CPU never maps it. A dispatch whose mirror falls
through takes a host log as before, and so do unified memory and the
paths without the mirror. The log is the renderer's own, so who owns
guest memory doesn't change.

The mirror's landing also finds the runs of a page's mask a word at a
time (run_end) instead of a bit at a time. Without memory traps the
mirror lands every page its programs write, about 23,000 a frame in
that movie, and the landing went from 51 to 21 ms a frame.

Each of the renderer's own compute pipelines now has a profile tag of
its own (VK_PROF_*), which gpuprof.c names. They were counted as one,
which hid the folds behind an average of 6.4 ms a dispatch.

Run on a Windows 11 host with an RTX 5080: that game's intro movie goes
from 3.3 to 17.3 frames a second, the folds from 154 to 3.2 ms a frame,
and the picture is the same. On a Radeon 890M host, whose unified
memory path changes only by the tags, the movie runs at 27 to 28 frames
a second unprofiled, against about 30 before in another session.
check_mirror_fold also runs with a GPU log now, and checks that every
word of it is zero after vk_wlog_clear. All 776 tests pass, the 28
Vulkan ones on RADV and on lavapipe, and the Vulkan test passes with
the mirror on (--vk_memory=1), with validation giving no message.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit c1d1aef052e06b73ca4e66c3f500cad167059852)

Rebased-by: AO55 <AO55@reden-emu.dev>
Windows had no memory traps, so every GPU result landed in guest memory
at its fence, a readback per result. On a discrete GPU that is every
page the GPU mirror's programs write and every storage image a dispatch
publishes: one game's intro movie landed 47.7 GB in 600 presents.

Windows now traps by page protection, as Linux's memory_traps=1 does.
plat_trap_arm marks the pages in a bitmap and makes them PAGE_NOACCESS.
A vectored exception handler, first in the chain, posts a fault on an
armed page to the trap thread through the same ring as Linux's signal
handler, waits on WaitOnAddress until a trap lets pages go, and then
retries the access. A fault that repeats with no page opened since, or
4096 times in a row, goes on to the crash handlers. memory_traps 0 and 1
both mean these traps on Windows, and 2 none.

Windows has no alias pool, so there is no mirror to land through. Guest
memory is one reservation with the write watch, and owned memory stays
its own pages. own.c lands into a staging copy while the pages stay
trapped, then plat_trap_fill opens and fills them a page at a time, and
every entry on a page it opens lands with it. An edge page keeps a copy
of its CPU bytes from when it was armed, which own_stage reads. That
copy and the landed page compare in buffer.c read with ReadProcessMemory
(plat_vm_read), so nothing faults with a lock of ours held. mem.c lands
what it copies under its own lock first, and the write watch's scan
leaves armed pages out.

One difference from the mirror's landing remains: a thread that reaches
a page while its bytes go in, without faulting, can read old bytes. The
stress test in memory_own finds about 25 of 320,000 reads there, each
the owner's byte once the landing ends. Opening a page is a system
call, 512 of them for a landing of 2 MiB.

Run on a Windows 11 host with an RTX 5080: that movie goes from 16.7 to
54 or 55 frames a second, the GPU's frame from 56 to 16.1 ms, and the
mirror lands 40 MB in the same 600 presents. What still lands is the
movie's decoded pictures, which the game reads on the CPU. The
screenshots match the run without traps. One run in about 33 stopped
during loading, two guest threads waiting in a trap whose message the
trap thread never took, and no later run repeated it, so its cause is
not found. memory_own now builds and runs on Windows, with checks for
ReadFile and WriteFile over an owned page, copy views and the busy
thread report, and a test of uncovered bytes runs on Linux too. On
Windows 642 of 646 tests pass, the same four failing as before (two
LDN, HTTPS and a GUI language script). On a Radeon 890M host all 776
pass, and the movie runs at 28.5 frames a second with the same
pictures.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 9d0de4577c095d303c56a84334e98dabc184c1a2)

Rebased-by: AO55 <AO55@reden-emu.dev>
An SM86 BRA or EXIT can carry a second predicate besides its guard, in
bits 87 to 89 with bit 90 negating it, which the assembler writes after
the mnemonic: @P0 EXIT P1, @!P1 BRA !P2. The instruction takes effect
only where both hold. The translation read the guard alone, and
make_bra named the operand's bits but nothing read them.

One game's interface programs exit the lanes their KILL took that way:
P0 is the alpha kill's switch from a constant buffer, P1 the alpha
test, and @P0 EXIT P1 comes before the MOVs to the colour's registers.
Taken as @P0 EXIT, every lane of a draw with the switch on exited with
its colour unwritten, (0, 0, 0, 0), and with a SrcAlpha blend the whole
title screen drew nothing over the movie.

guard() now gives a BRA's branch condition and an EXIT's condition as
the guard and the operand together. sm86_always and sm86_never in
sm86.h judge an instruction by both, where the flow analysis, the
program's end in sm86_decode.c and the inliner judged it by the guard
alone. make_bra keeps a BRA's operand when it rewrites it.

Run on a Radeon 890M host: pressing A during that game's title movie
now shows its logo and menu over the movie, where nothing appeared
before. A RenderDoc capture had shown the interface draws' pixel shader
writing 0 with no discard, and the target unchanged by them. The movie
runs at the same 22 to 23 frames a second, within the runs' noise.
test_flow_operand runs nine EXIT and BRA cases, with and without a
guard and with a negated operand, four of which fail without the
change. All 776 tests pass, the 28 Vulkan ones on RADV and on lavapipe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 5add120726760e35b4bedd554520b8e0d0965dc3)

Rebased-by: AO55 <AO55@reden-emu.dev>
own.c calls plat_trap_fill and plat_vm_read since the Windows traps; the fixture lands
through its mirror, as Linux does.

Change-Id: Ia96479a4e45510893df7f5b562a22e1cf0b9527e
Signed-off-by: AO55 <AO55@reden-emu.dev>
host.c went into common/platform/file*.c (73350c1d3); the same files as the Linux test.

Change-Id: Id72d9294daef12ce0979909f72f828dbc3a38d77
Signed-off-by: AO55 <AO55@reden-emu.dev>
The resolved plat_win32.c stopped at plat_trap_waiting: plat_trap_init, arm, fill,
continue, disarm and plat_vm_read were gone; the -Werror test refused their helpers.

Change-Id: I9335ba1933d913857dce13f1cde7e114312e3e9f
Signed-off-by: AO55 <AO55@reden-emu.dev>
256 thousand blocks, a GT 1030's second, held an RX 6700 XT 5 s in one frame: Auto gives
256 thousand a 2 GB of the GPU's own memory, from 256 thousand to 4 million.

Change-Id: Id9623df859d78c2e0bf354f5a929e2cc31ec8ed5
Signed-off-by: AO55 <AO55@reden-emu.dev>
The ASTC partition hash's p -= p << 17, p += p << 7, p += p << 4 are one multiply by
4007528593; equal on all 2^32 inputs, astc_vulkan's GPU decode matches the CPU's.

Change-Id: I8ba483c4c2fc587f6a270fff3a48587d76f8b53b
Co-authored-by: Maty <maty@scarletnx.org>
Signed-off-by: AO55 <AO55@reden-emu.dev>
tex_check asks the tracking there, and hashes only what the CPU wrote: 8 GB hashed in
600 frames of an Ounce game went into nothing.

Change-Id: I971b976aaffe1c960795fc85e825a19412e02814
Signed-off-by: AO55 <AO55@reden-emu.dev>
Its report named the 512 GiB buffer on every run, failing vulkan_headless's validated
cases on RADV.

Change-Id: I310183a7d1faa14657e5b90f7dffa6677f2e5685
Signed-off-by: AO55 <AO55@reden-emu.dev>
One Ounce game's demo alone holds 3.3 GB of BC7: 4 GiB went over and started the file
over, every level encoded again.

Change-Id: Ie7ce1e050b92e2cf8b102ce512da92a3c3b6280f
Signed-off-by: AO55 <AO55@reden-emu.dev>
With the network on, an Ounce game's menus open it, and a stand-in gave command 0's object
back empty: the game crashed on it. Its task is done as it starts, the time the host's.

Change-Id: If7d12741f9e9bab0de464de617814aceb452b578
Signed-off-by: AO55 <AO55@reden-emu.dev>
The Ounce's task and mesh stages made Initialize and SetShaders zero 0x98 bytes of every
program object; one game keeps its code area's GPU address at 0x80, and its programs read
as zeros. Those stages now go last, written only in an Ounce game's object.

Change-Id: I98bc4015abab3266f73737bfc16741d0d4cc96a2
Signed-off-by: AO55 <AO55@reden-emu.dev>
A GPU context is announced once for the client's lifetime and replayed at every connection, so after a disconnect and reconnect snx_tracy_gpu_context returns 0 and the old client state re-armed nothing: the graphics and compute tracks stopped sending calibration events for the rest of the run, while the server kept the replayed context's original pair and drifted from the CPU.

Keep the announcement's clock pair in one SnxTracyGpuCal per track. On a new connection reset the delta's previous point to that pair instead of zeroing it, and leave the calibrated flag alone; an uncalibrated context and a clock that does not advance send no delta. The next calibration is then measured from the same pair ProcessGpuCalibration uses.

The test announces a context, checks that a changed connection id does not re-announce it, and checks the anchor across a reconnect, an uncalibrated context, and a non-advancing clock. Built with the tracy preset and ran snx-test-tracy-state.

Signed-off-by: Jucan Andrei Daniel <setrofex@gmail.com>
vk_gpu_profile is off by default, and with only --tracy the gap and idle sums were accumulated every frame and then returned on: gp_report's first line checked g_on, which the setting latches, so the numbers the runtime already had reached neither the trace nor the log. guest_stats had the same shape, with its counters only in a 600-present log line.

Send those sums as plots: the pass gaps by cause and the queue's idle categories from gpuprof's window, the guest and process CPU shares, the SVC and NCE rates, and the busiest thread from guest_stats' window. The host's heap, footprint and available memory join them, once a second, from snx_heap_used (jemalloc's mallctl, in a file of its own so a build without it takes no reference) and the platform's own two. The GPU thread's job-queue idle plot is named gpu thread idle, so it is not read for the graphics queue's execution idle, and every plot now has a format entry on the connect.

Verified with ctest on the tracy and the default presets: 743 and 742 tests, and a --tracy run's log and trace checked for the new plot names.

Signed-off-by: Jucan Andrei Daniel <setrofex@gmail.com>
main took most of feat/ounce as picks. This is the rest, the tree of
feat/ounce 20927d495 (main merged up to fe895b024) as one commit, as the
branch's history doesn't rebase onto main.

- Graphics pipeline libraries: feat/ounce's design (pipeline_parts.c)
  replaces main's pipeline_library.c. A pipeline is the link of four
  parts made once each, a draw waits for the link only, and a worker
  makes the optimized pipeline after it. main's "linked" headless run
  stays, with gpl_hold kept on the link.
- The write log for Switch compute programs: the Maxwell translators
  log their stores and atomics through one helper with the SM86
  translator (shader/write_log.c), and their results land from the log
  in place of the comparison of whole buffers. In one Switch game's
  street, props missing in every run before draw in every run now. Its
  programs stay out of the GPU mirror, where those props flickered.
- The GPU mirror: a read of it in place takes the barrier once after
  the programs' writes, and bringing it up to date takes none when it
  copied nothing. One Ounce game's race went from about 470 rendering
  passes a frame on its main target to 160 to 210, and from 6.6 to 8.6
  frames a second to 11.4. The pages the CPU touched lately land at
  each submit in place of a trap and a GPU wait at each touch, about 10
  times fewer landings.
- Parts that main's picks lost: the mark_written call in
  global_dynamic (788ad258b), land_pages' second look after the GPU
  wait (f1a5185de), and the kept owner's release in out_free
  (3197732d6).
- A GPU that stops ends the run with its checkpoints and the GPU's own
  fault report (VK_EXT_device_fault), where the game froze with no
  message, and a hanging draw's checkpoint names its programs.
- Others: a task program's mesh group count within the device's limit,
  the validation layers' clip distance sum of a tessellation stage's
  input and output passed (fixed in their 99fd2cb576, in no release
  yet), BC7 encodes on their way dropped when a cache file is opened,
  and the texture gradients check's NVIDIA skip for any driver version.

Tested on an RTX 2080 with driver 620.70: the full ctest passes on
e820a1dd3, the 15 headless runs under the validation layers too. One
Ounce game raced 450 s on the merged tree, and one Switch game ran 150 s
in its street with the props drawn. A GPU hang in a few rare draws of
the Ounce game is still open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The weights by one multiply, Widen without its branch and mask, Quant from two candidates, the texel
blend in one multiply, Fit's sums in Solve's pass and PAllowed read once a subset: found with ucas,
each an exhaustive equivalence. bc7_glsl's block digests stay as they are.

Rebased-by: AF52 <AF52@reden-emu.dev>
A cleanup of a game's data folder would go through a RomFS bind-mounted there and delete
the original files: snx_remove_tree refuses a tree holding a mount point, naming it.

Change-Id: I37e7eb3f39904acf6d3d008a31226e6acecaab9a
Signed-off-by: AO55 <AO55@reden-emu.dev>
A folder with exefs/ and romfs/ is read in place, source= naming it, on any disk; Extract
dump and tmpfs copy it with -x. Before, -r copied its RomFS, or with --tmpfs lost it.

Change-Id: If5ad0d596962b5acc1a51bef4a4f3ba3c2071797
Signed-off-by: AO55 <AO55@reden-emu.dev>
A library lists an extracted game's folder with the dumps, by its nacp name or title ID;
the Open screen's P (Folder on a touch screen, a pad's Y) opens the folder picker.

Change-Id: Ia6ddc415a08ee4bc8f281c74f16754779e5c3449
Signed-off-by: AO55 <AO55@reden-emu.dev>
Off Linux the sink was an unused function, which -Werror stopped on macOS.

Change-Id: Ie966ce855c28af66545678acecb2b536dfcdf0e3
Signed-off-by: AO55 <AO55@reden-emu.dev>
vk_wait_semaphore ended the run as "GPU stopped" when the graphics
timeline did not move for 15 s. A value is handed to the recording
thread before that thread submits it, and the recording thread waits at
each bind for a pipeline that a worker still makes. In one race of an
Ounce game on a loaded host, the recording thread waited in
vk_pipeline_resolve for more than 15 s. The GPU had done submission
3215, the last one on its queue, 2 MB of commands were not recorded,
and the wait was for 3268. No Xid came. The run ended with a hang
report that named a draw the GPU had finished.

The recording thread now keeps the timeline value of the last
submission that vkQueueSubmit2 took. While the GPU has done that value,
the wait does not count toward a stopped GPU. It logs once that it
waits for the recording thread, and the 15 s clock starts again when
the queue has work.

This does not fix the Xid 109 hangs of the same race. In those, the GPU
did not finish the submission of the hung draw, and every command was
recorded.

Verified: ctest, 821 of 821 pass. Six races under CPU load with the
diagnostic build gave this stall one time and two Xid 109 hangs. No
race with this change hit the stall, so the new path ran only in review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The CPU work of the GPU thread for each draw sets the frame rate of the
games we profile, about 23 us a draw in the last profile. A static
recompiler of one Ounce game (MIT) spends about 3.3 us. The plan takes
its general methods and adds ideas of our own: every buffer binding from
the GPU mirror, uniform blocks copied once a submission, generations for
each address in the memos, a program key made once, the NVN pool flags,
skipped descriptor builds, and bindless textures last. It also lists the
VRAM work. Its patches of one game's code are out of scope.

A new profile on this branch comes first and sets the order.

docs_check passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An Ounce game's dispatches leave an address with nothing mapped in one
of their storage buffer slots. mirror_plan refused the GPU mirror for any
dispatch whose buffers didn't map whole, so each such dispatch took the
copy path: copy_writable copied each of its logged written buffers from
guest memory into staging on the CPU (own_stage, with a lock for each
run), and the GPU then copied the owned parts over most of those bytes.
In a 230 s run of a race that was 3,819 dispatches and 12,002 copies,
52,673 MB, and 23% of the GPU thread with the lock.

vk_gbuf_desc now gives such an address as 0, for draws and dispatches.
Every path treats address 0 as no buffer: it reads zeros and drops the
writes, which is what the copies of guest memory gave an unmapped
address. The program can't access it, or it would fault on the console.

Tested on an RTX 2080: in the race, no dispatch is refused the mirror
now and no logged buffer is copied. vk_dispatch went from 46% of the GPU
thread to 27%, and the race from 8.4 and 10.0 frames a second to 13.4
(the mean from 200 s to 262 s, one run each, without perf). A Switch
game ran 150 s in its city street with its props drawn. ctest passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tex_resolve kept what a handle resolved to while two global counts held:
the stream's write-watch epoch, which moves at each submission and each
wait that ends, and g_pend_any.adds, which moves at each result any
dispatch or draw adds anywhere. In a Switch game's city street the epoch
alone dropped 39% of the lookups, and the count then took the same ones.

When the epoch moved, the lookup now asks whether the CPU wrote its two
headers since it was kept (vk_written_since), and when the count moved,
whether a pending result covers its headers or its texture's memory
(pend_hit). Those are what it read: the rest is checked at every hit as
tex_from_tic checks it (vk_tex_recheck for a texture's texels, the read
check and the defined contents for a render target).

Tested on an RTX 2080: the street's lookups hit 74% of the time, from
36%, and an Ounce game's race 89%, from 80%. The gain on the GPU thread
is small, as a hit's own checks cost most of tex_resolve: the full
resolves in the street went from 2.3% of the thread to 1.0%, and the
frame rates stayed within the runs' spread. The street ran 150 s with
its props drawn, the race 260 s, both with screenshots. ctest passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vk_mirror_slice walked every page of a binding three times at each
binding: for the oldest page brought up to date, to stamp them all, and
for the pages not given yet. An Ounce game's draws bind the same 16 MiB
ranges as the draws before them, 4096 pages each, and the walks were 8%
of the GPU thread in its race, with vk_mirror_slice at 13% in all.

A granule now keeps the page range it brought up to date whole in the
stream's epoch (vk_ww_epoch). A binding inside it skips the walks: the
CPU's writes since are a later submission's to see, as for every cache
that trusts a check for its epoch. A range keeps a page the mirror owns
out of it, as that page is given only once its result lands, and
vk_mirror_landed empties it when a page loses its shadow.

Tested on an RTX 2080: vk_mirror_slice went from 13.3% of the race's
GPU thread to 3.7%. The frame rate couldn't be measured, as other builds
loaded the host through every run. The race ran 260 s with screenshots
and drew as before, and a Switch game ran its city street. ctest passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tex_resolve kept a handle's resolution in one of 4096 slots by the
handle. A handle that shared its slot with another one the draws used
put it out each time, and a miss that found nothing to keep emptied the
slot anyway. 9% of an Ounce game's lookups in a race and 22% of a Switch
game's in its city street resolved a handle again that way, reading both
headers and finding the texture by them.

The memo is now 2048 sets of 4 ways by the handle's Fibonacci hash, the
way used longest ago making room, and a miss takes a way only when what
it found is kept.

Tested on an RTX 2080: the lookups that found no entry went to 8% of the
race's and 13% of the street's, from 10% and 22%. Both ran with
screenshots and drew as before. ctest passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
At each submit, vk_buf_host_barrier copies the frame's storage results
into host-cached memory (vk_stage_back), where the CPU lands them. It
left the logged ones out, to be read where their shader wrote them: the
output ring, which is device memory behind the BAR when the budget
allows. Since the Maxwell programs log their stores, a Switch game's
city street lands about 728 such results a frame, 3.8 KB each on
average, and the CPU's uncached reads of their logged runs across PCIe
were 19% of its GPU thread.

They are copied whole on the GPU now, as the others are, and their runs
read from the copy. The reason they were left out, an Ounce program's
bindings of up to 16 MiB copied whole at every dispatch, no longer holds:
those dispatches bind the GPU mirror.

Tested on an RTX 2080: the street's landing at each submit went from 30%
of its GPU thread to 9%, and vk_write_runs from 21% to 1.8%. The street
ran at 28 to 30 frames a second through a 150 s run, from 21. An Ounce
game's race drew as before in its screenshots, until the GPU hang that
is still open stopped it at 255 s. ctest passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
patch_own and patch_dirty copy the runs of a big own buffer the CPU or a
GPU-side write changed into its device copy. Past 64 runs, they joined
them into one copy from the first to the end of the last. A Switch
game's city street writes pages all over a 64 MiB window of indices for
its indirect draws (vk_buf_get_window_input), so nearly the whole window
was staged and copied at each patch: 33 GB over 600 presents, about
1 GB a second, and patch_own was 27% of its GPU thread.

The runs are now copied as they are, however many, in one copy command:
the first 256 in a static table, more in memory of its own. Only when
that memory can't be had are they joined as before.

Tested on an RTX 2080: the street's patch copies went to 1.1 to 1.8 GB
over 600 presents, from 14 to 33 GB, and with perf attached it ran at
29.3 frames a second, from 17.3 (one run each). The street and an Ounce
game's race ran with screenshots and drew as before. ctest passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #1521: the patch's run table and the texture memo's use count
were loose globals. The patch runs are a member of g_buffer now, with
the size of their fixed table a constant (PATCH_RUNS0) and the grown
table a member of its own, picked by patch_runs, in place of a pointer
into the struct. The memo's ways and its use count are one struct,
g_tex_memo.

ctest passes. A Switch game's street and an Ounce game's race ran with
screenshots and drew as before, the street's patch copies at 1.3 GB
over 600 presents as with 25e6d355a.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#1168 carries both behind its HDR and presented-effects work. This takes the two pieces that do not
need it: the key and the game menu's row that cycle the console's TV mode, and the quit key's second
press.

The cycle is On -> Off -> Auto -> On, from hotkey_tv_mode (Ctrl+D) and from a TV mode row on the
first page of the game menu. It changes only the choice in effect, so the .ini keeps its docked
value, and Auto starts the host's power watcher once. The menu's pads call the step under the
input's lock, which hid_update takes for the new mode's Npad, so the display-mode events go to the
frontend's next tick instead of being signalled there. A held Left or Right steps the row once, not
at the key repeat rate.

The quit key warns on its first press and quits on a second within three seconds, with the Switch's
own toast and log line. The 3DS, Vita and GBA print the warning, and ignore the key with Ctrl, Alt
or the system key held, as the Switch's exact match does.

Verified with ctest, 809 of 809. A Switch 2 title, after the runtime was rebuilt and its shaders
regenerated: the scripted menu walked to the TV mode row and pressed A three times (Off, Auto, On),
the log named each mode and Auto's pick, and the run ended with exit 0 during the title's asset
load, so the mode changes did not crash it. A run with no input and a menu-only run were the
controls. The host's MoltenVK budget was marginal in that load: the cycle run and the menu-only
control both logged allocations out of memory, and the no-input run did not, so that fault is not
this change and needs a quieter host to measure.
This reverts commit e169bbfe05.
Layer 0 records the baseline kernels and counters. Layer 1 adds the
abi_contract recompile setting, default off, with the PROMOTE model, the
QEMU differential switch and the calls-saved kernel. Layer 2 is reverted. Layer 3 follows bounded jump
tables during discovery, reads their entries from the module image and
marks the cases as leaders.

The callees_first ordering bug from Layer 1 is deliberately left unfixed:
current main's llvm_module_stats asserts that splitting a module into
units does not change promotion totals, and per-unit summaries break that
invariant. Cross-unit summaries are Layer 5's job.

Verified on b89571050: snx_codegen_test passes, the LLVM suite has no
failures (55 pass, the AVX-512 variant skips on this host), all five QEMU
differential variants pass, and the switch kernel runs at 7.29 ns per
iteration with x1 = 124000000.
FRINT32Z/X, FRINT64Z/X and BFCVTN called a helper once per lane. The
FRINT forms now use the host's rounding behind a guard for NaNs,
flushed denormals and the signed range, with the helper as the
fallback; BFCVTN is exact whole-vector integer arithmetic including
FPCR's rounding, DN, FZ, NaN payloads and all five FPSR flags.

The lane test compares every lane and the whole FPSR against
snx_fp_round_int and snx_fp_bfcvt: 3,747,456 checks, 0 failed. The
no-helper-call probe covers the ten new forms. BFDOT/BFMMLA and the
non-AVX2 estimates stay on their helpers; the lane and no-helper-call tests say why.
callees_first() checked `if (snx_codegen_word(...)) continue;`, but
snx_codegen_word() returns 1 on success, so every decodable branch was
skipped and no callee was ever emitted before its caller. With the check
inverted, a unit that holds both ends of a direct guest call emits the
leaf first and the caller keeps the leaf's untouched guest registers in
host registers across the BL instead of storing and reloading them.

The layer 5 pre-pass (whole-program summaries exported across unit
boundaries) was implemented, measured and reverted: on a split build the
cross-unit call kernels are 0-5.5% slower, and the whole-module win
reproduces with the pre-pass disabled.

tests/llvm_module.c now records the hand counts of a whole unit and of
one function per unit separately; the old single row was invariant only
because no summary was ever applied. tests/llvm_bench.c gains the
calls-leaf and calls-live kernels and --unit-instructions.

Verified: snx-test-llvm-module (QEMU differential x9=3bb4, stale and
hook variants, hand counts), snx_codegen_test, and the LLVM suite at 55
passed with the AVX-512 variant skipped on this host.
A game runs as a native program of the user, so the page says which limits are the
console's behaviour and which a player can rely on, for the security policy's scope.

Change-Id: I2f207e74a4456e1cc32f82b0166399fdaf77a0de
Signed-off-by: AF52 <AF52@reden-emu.dev>
23.1.3 was the default; CI's Android, macOS and iOS jobs take it and rebuild their LLVM.
The Linux jobs pass the container's LLVM_VERSION and do not change; no checksum is read.

Change-Id: Ia7367c850f2d56de736a87e0e847296e002e0de7
Signed-off-by: AF52 <AF52@reden-emu.dev>
The check asked for an artifact the failed build never uploaded and ended red on
its download: it now names that job and its result in a notice and runs nothing more.

Change-Id: I7b85a04258d92b030850f49031b412661b7c38c7
Signed-off-by: AF52 <AF52@reden-emu.dev>
A second-class architecture from here: still supported and built by its
linux-loongarch64-cross preset, with no job, no package and no notes row of its own.

Change-Id: If01e1830a6db06358fe4dc90463c57f168d1da41
Signed-off-by: AF52 <AF52@reden-emu.dev>
The log's times count from the run's start, and the file's date is lost once the log is
shared: only the launcher could say how old the build was. The four runtimes write
"run: started <day> <time> UTC" after the build line, and logscan counts from it.

Change-Id: I5c2f1b7ed1de9d6da53d6bbd0143e96b0b83bdb0
Signed-off-by: AF52 <AF52@reden-emu.dev>
Auto holds an Ounce game's ASTC textures as BC7 at load, every level
in the encoder's fast build, which costs about 25 ns a texel on a
Radeon 890M. So the two 1365x1365x90 arrays of one game's first 3D
scene stopped it for 10 s at the scene's start, every run: they are
bigger than the BC7 cache's capture limit of 32 MiB, so no run keeps
them. And vk_bc7_build counts one layer, so the choice of encoder build
misses how big they are.

A level held as BC7 at load of astc_quick_mtexels or more, 8 Mi texels
by default with all its layers and slices counted, now takes a quick
encode: a fourth encoder build that tries mode 6 from its first line
only, 0.46 s for both arrays. While it runs, each strip's ASTC blocks
are copied into a host snapshot. The fast build's encode of that
snapshot is made in the background and stored in the BC7 cache in
pieces of up to 256 KiB of blocks, each under a key of its own, so the
cache takes a level of any size and a run that stops keeps the pieces
it finished. texture.c keys such a level (vk_astc_quick) as it keys one
the cache takes whole. Each piece is also copied into the live image as
it is done, until the level is uploaded again or freed. The next run
loads the pieces from the cache, at most 100 ms of reads in the frame
that uploads the level and the rest over the following presents. Main
already makes an upload wait for the GPU once 256 thousand blocks are
queued (bc7_queued_limit), which keeps each submission of these strips
far from the driver's job timeout, so the submissions this was split
into on feat/ounce are not needed here.

astc_background picks where the background encode runs. 2, the
default, is the GPU: a piece after each present, in a submission of its
own (VK_SUB_BACKGROUND in the GPU profile). 1 is worker threads at the
system's idle priority (plat_thread_idle, new in common/platform), as
many as astc_background_threads says. The CPU path runs the ASTC
decoder and the encoder the tests had, moved into src/nx/gpu/texture
(astc_cpu.c, glsl.hpp and bc7_encode_cpu.cpp), and its blocks are the
GPU's byte for byte. On that game it took about 45 times the GPU's
time, at 0.7 Mtexel a second a core, which is why the GPU is the
default.

Run on a Radeon 890M host before the port to main, from a save of that
game: the frame at the scene's start went from 10.1 s to 0.42 s, and to
under 0.25 s in the next run, which read the pieces from the cache. The
background made 1890 pieces in 133 s, at 2 to 10 ms of GPU time a frame,
with the frame rate within the runs' spread, and the cache file grew by
450 MB. On main with the whole series, from the same save: the first
run, with no shader cache, encoded the 13 very large levels quickly, and
the frame at the scene's start took 3.7 s, 1.2 s of it waiting for
pipelines. The second run finished their 1604 pieces in the background
and the third took all 13 from the cache, with no frame past 125 ms in
either. The scene ran at 8.6 to 9.4 frames a second, where feat/ounce's
runtime gave 8.4 to 8.8 on the same replay.

astc_vulkan has background cases on the CPU and on the GPU (blocks of
4x4 and 6x6, layers, the copies into a live image, the load from the
cache, stopping and going on), and on main their pieces are main's fast
build byte for byte. bc7_glsl checks the quick build's PSNR. On main the
36 ASTC, BC7, texture upload, settings, docs and platform tests pass
with this change alone, astc_vulkan on RADV. With the whole series on
main the full suite passes but nvn_game_benchmark, which fails on main
alone too: its script needs Python 3.12, and this host has 3.11. The 38
Vulkan tests pass on RADV and on lavapipe, vulkan_headless on lavapipe
at a rerun: its first run there failed the check that a descriptor heap
transition stays in one command buffer, which a periodic submit can
split, and five runs after it passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 1a788264f9db28ff675640bb87284c9efd14eb0d)
Where the device can't sample ASTC, the renderer decodes it on the GPU
and encodes it as BC7, in strips that fit its 16 MiB scratch buffer.
Every strip went into the frame's one command buffer, so a big texture
put all its work in a single submission. One game's first 3D scene
uploads two 1365x1365 ASTC 4x4 arrays of 90 layers: 110 encodes of
about 90 ms each, 10 s of GPU work in one submission, and amdgpu
resets the ring after 2 s.

vk_astc_upload now submits before a strip that would take the ASTC
texels recorded in the submission past 4 Mi, through vk_submit_split.
That submits without landing results and keeps the frame slot, as
vk_submit_open does, and gpuprof counts it as a reason of its own,
"split". The upload takes the new command buffer itself, as a rows
callback only hands one back after a submission of its own.

Run on a Radeon 890M host: that scene hung the GPU with the previous
runtime, and a RADV hang dump showed the GPU in the BC7 encoder's
dispatch with no page fault. With the change the game goes on into the
scene, with about 110 split submissions. astc_vulkan's BC7 cache case
now goes through the split path. All 776 tests pass, the 28 Vulkan ones
on RADV and on lavapipe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

(cherry picked from commit 2bb30889eac568caf06270b749cf49a3ff881f46)
Rebased-by: AO55 <AO55@reden-emu.dev>
The Android NDK's libc++ (before LLVM 19) has no std::atomic_ref, and the
CPU encoder now builds there.

Change-Id: I942612ef1603416b22eeaa5c0f384a534006b90b
Signed-off-by: AO55 <AO55@reden-emu.dev>
One game's first 3D scene had 119 of its programs refused. Most of the
global accesses among them have a base that is no constant buffer's
word: the program loads a 64-bit pointer with LDG from a table that a
constant buffer's word addresses, and adds to it. 202 of the 215 such
pointers point outside every window the program binds, so comparing
the address with those windows (global_dynamic) can't find their
memory.

A new kind of global buffer key, SH_GBUF_INDIRECT, names the pointer
stored at a cell of a parent buffer. The tracker takes an LDG.64 or
.128 at an exact constant buffer base plus a constant for one, keeps a
loaded pointer dynamic through IADD3, IMAD.WIDE, LEA, SEL, LOP3 and
SHF, and makes a predicated write or a merge of paths between such a
key and another a dynamic access with both as candidates. The program
loads the buffer's base from the parent's cell (gbuf_base), and the
renderer reads the pointer from guest memory as it binds the draw or
dispatch and binds a window of up to 16 MiB there (gbuf_pointer), which
the windows, ownership and write log treat as any other. A pointer the
GPU writes earlier in the same stream would be read too early. Buffer
device addresses would need every page a pointer can reach imported
and tracked, which the import limit and the ownership model don't
allow.

RED and ATOMG F32 ADD are now an OpAtomicFAddEXT where the device has
shaderBufferFloat32AtomicAdd, else a compare and exchange loop. F2IP's
U8 and S8 forms with RELU, ULDC and ULDC.IDX of bytes and halfwords,
SHFL with its c operand in a register, and S2R 0x84, the shading rate,
which a fragment program reads as the full rate, are translated too.
TEX, TLD, TLD4 and TXQ with the handle in a uniform register (0xf60,
0xf66, 0xf63 and 0xf6f) are decoded, and refused naming where the
handle comes from. spv_eval's OpAtomicCompareExchange read its value
and comparator from the wrong words.

Run on a Radeon 890M host before the port to main, from a save of that
game: 75 programs were refused instead of 119, and 1,381 dispatches
skipped instead of 56,863 in the same replay. Of the 641 programs of the
scene, translated offline, 568 translate instead of 520, none of the 520
changes its SPIR-V, and all pass spirv-val. The frame rate went from
about 18 to 14 frames a second, as work that was skipped now runs. New
tests cover each form, among them the float add with 64 invocations
racing on RADV and on lavapipe. On main, vk_dispatch reads a buffer's
address from any constant buffer bank already, which reads an indirect
buffer's parent as it is. On main the 56 shader, SM86, compute and
pipeline tests pass with this change alone, the Vulkan ones on RADV.
With the whole series on main the full suite passes but
nvn_game_benchmark, which fails on main alone too: its script needs
Python 3.12, and this host has 3.11. The 38 Vulkan tests pass on RADV
and on lavapipe, vulkan_headless on lavapipe at a rerun: its first run
there failed the check that a descriptor heap transition stays in one
command buffer, which a periodic submit can split, and five runs after
it passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 498c5cf6e5c211a73f453369f06aaa1396cdfbdd)
DrawMeshTasksIndirect's draws were skipped. One game draws about 30 a
frame that way in its first 3D scene. Its record is taken as {count,
first}, as NV_mesh_shader lays out its own: the GPU writes it, so the
CPU can't check it. The renderer copies the record on the GPU into a
staging {count, 1, 1} for vkCmdDrawMeshTasksIndirectEXT, and its first
into a uniform buffer bound at SNX_VKB_RS. A task program, or a mesh
program without one, reads its first workgroup from there when the
push flag SH_PUSH_GPU_MESH_FIRST is set. The copy ends the render pass
of each indirect draw.

docs/platforms/nx/ounce.md records that on a Radeon 890M the mesh draws
run without a fault, and that RADV_DEBUG=hang, which waits for each
draw, stalls the task programs' submissions and times out a ring by
itself.

Run on a Radeon 890M host before the port to main, with mesh_draws=1,
from a save of that game: about 12 runs without a fault, the scene's
indirect draws drawn, and a validation run with no message from mesh
draws. test_mesh and test_task check a first workgroup read from the
uniform buffer. On main the 77 shader, Vulkan, mesh, settings and docs
tests pass with this change and the ones before it, the Vulkan ones on
RADV. With the whole series on main the full suite passes but
nvn_game_benchmark, which fails on main alone too: its script needs
Python 3.12, and this host has 3.11. The 38 Vulkan tests pass on RADV
and on lavapipe, vulkan_headless on lavapipe at a rerun: its first run
there failed the check that a descriptor heap transition stays in one
command buffer, which a periodic submit can split, and five runs after
it passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit acef4c060bc3b39512070b9fc402559350f0a6cd)
One game's material programs load each texture's handle with LDG.64
from a table whose address a constant buffer holds, move it to a
uniform register, and sample with TEX, TLD, TLD4 or TXQ taking the
handle from that register, or with TEX.B. Those programs were refused
and their draws skipped, about 400 a frame in its first 3D scene,
which showed white.

memory_handles keeps the instructions that compute each handle in
ShaderInfo.memh when every value they read is the same for a whole
draw: a constant buffer's, an immediate, or a global load at such an
address, with one unguarded writer of each on every path and no other
write between. The renderer runs them on the CPU for each draw and
dispatch, on the constant buffers and guest memory it binds
(sm86_eval.c, memh_handle in render.c), and binds the texture as it
binds one whose handle a constant buffer holds. A handle that differs
by invocation, such as one from a grid of lights in world space or
from a texture's value, binds no texture, which samples zeros, and the
log names its program once. In that scene about 45 draws a frame take
it. A table the GPU writes earlier in the same frame would be read too
early, as gbuf_pointer's pointers would.

ISETP's .EX bit was read as a negation of its a operand, so its 64-bit
compares were wrong. That changes the translation of SM86 programs that
compare 64-bit values. ShaderInfo grows by about 1.1 KB, so the shader
caches are made again on a first run.

Run on a Radeon 890M host before the port to main, from a save of that
game, with mesh_draws=1: the scene shows its room textured and lit where
it was white, and with the change after this one no draw is skipped,
against 400K of 1.96M before. test_uniform_handle checks the CPU's run
with constant buffers and memory of its own, TEX.B and the fallback.
test_memory_eval compares the CPU's run with the translated program for
IADD3's carries, LEA, SHF, IMAD.WIDE, PRMT, ISETP and its .EX, SEL,
IMNMX, PLOP3 and LOP3, and fails without the ISETP fix. On main the 77
shader, compute, pipeline and Vulkan tests pass with this change and the
ones before it, the Vulkan ones on RADV. On main with the whole series
and mesh_draws=1, from the same save, the scene draws textured and lit
with no draw skipped. With the whole series on main the full suite
passes but nvn_game_benchmark, which fails on main alone too: its script
needs Python 3.12, and this host has 3.11. The 38 Vulkan tests pass on
RADV and on lavapipe, vulkan_headless on lavapipe at a rerun: its first
run there failed the check that a descriptor heap transition stays in
one command buffer, which a periodic submit can split, and five runs
after it passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 1379320530a8728148be4ba10062107ad94eaead)
track_step took every ULDC and LDC for a 64-bit load, so a 32-bit ULDC
into UR6 dropped the base key UR7 held, a constant buffer's word plus
0x30, about a thousand instructions before the global load that used
it. The program was then refused as a global address whose base no
constant buffer holds. In one game that program draws a room's floor,
and its holes showed the lighting pass's white. A ULDC or LDC now
takes the register after its own only when it loads 64 bits, type 5.

Run on a Radeon 890M host before the port to main, from a save of that
game: the floor's program translates, the floor has no holes, and no
draw of the scene is skipped. test_uldc_word_key fails without the
change. On main the 33 shader tests pass with this change. On main with
the whole series and mesh_draws=1, from the same save, the scene draws
textured and lit with no draw skipped. With the whole series on main the
full suite passes but nvn_game_benchmark, which fails on main alone too:
its script needs Python 3.12, and this host has 3.11. The 38 Vulkan
tests pass on RADV and on lavapipe, vulkan_headless on lavapipe at a
rerun: its first run there failed the check that a descriptor heap
transition stays in one command buffer, which a periodic submit can
split, and five runs after it passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit c175f16610442ff5526d9947906cc9a283d7a5bf)
Pipeline libraries took the polygon mode, depth clamp, provoking vertex, conservative
rasterization and patch control points as dynamic state wherever the device had the
member: the table's bans on them (RADV before 23.1, PowerVR) were said and not applied.

Change-Id: I6e1c06486f523e7dce4fb72e704479c95def4179
Signed-off-by: AF52 <AF52@reden-emu.dev>
With VK_EXT_depth_clip_control and the range as dynamic state of pipeline libraries, the
device clips depth from -w and the last stage's z = (z + w) / 2 is off. Elsewhere, and on
a driver the table bans from the state, the last stage makes the range as before.

Change-Id: I449c3672840880a6c550cd9c9a945b98603447d7
Signed-off-by: AF52 <AF52@reden-emu.dev>
near and far are empty macros in Windows' headers: with them as member names
vulkan_headless did not compile for Windows.

Change-Id: I2de77dbfb10cedb02cfdbb078a848d12808d143f
Signed-off-by: AF52 <AF52@reden-emu.dev>
riscv64's openssl is 4 while its libldap still needs OpenSSL 3, so the cross AppImage's
pacman -Syu refused its transaction three times on every branch.

Change-Id: I78f8fb3f64150db45436a532b794a612104472a7
Signed-off-by: AO55 <AO55@reden-emu.dev>
Turnip lists the geometry stage in supportedStages and gives wrong ballot and shuffle
results there (Eden PR 4344). A ban table line takes the stage out, so its programs take
the path of a device that does not list it, as Qualcomm's own driver has them.

Change-Id: Ia3dd38b0e04e33f2353af7f85e05a0fd6c1f9695
Signed-off-by: AF52 <AF52@reden-emu.dev>
MoltenVK gives each timestamp a Metal encoder of its own, which ran a scene about 10
times slower, and its timestamps are unreliable. The warning says the value asked for,
the one in effect, and points at MTL_HUD_ENABLED=1 and Instruments' Metal System Trace.

Change-Id: I586167852f5880d42b7fe96b5613e46b484f3b45
Signed-off-by: AF52 <AF52@reden-emu.dev>
A thread stopped inside one of the SDK's spinning locks lost its core to a better waiter,
which then spun on that lock for good (NCE stops code anywhere). It keeps the core now,
its interrupt flag set, until svcSynchronizePreemptionState, as the console's kernel does.

Change-Id: Ia2bb263221629e99d4a4c1a94c6068ba52f99ad2
Signed-off-by: AF52 <AF52@reden-emu.dev>
nvnSamplerInitialize wrote a serial into each sampler object, which nothing reads. A game
whose sampler cache compares the objects' bytes then never found one it had, and filled
its sampler pool. Found and patched by datatan-eu in #1194.

Change-Id: I76cd06d251f7382a3f7f4842ab15b4f5181bf740
Co-authored-by: datatan-eu <262989309+datatan-eu@users.noreply.github.com>
Signed-off-by: AF52 <AF52@reden-emu.dev>
The descriptor was written while the replay could still have draws ahead that read the old
one. It now waits for every live queue's work and is recorded, unless the entry holds it
already. Found and patched by datatan-eu in #1194, whose patch waited on every write.

Change-Id: Ie7b11deb064984c0be7594b019fb89a6c385629c
Co-authored-by: datatan-eu <262989309+datatan-eu@users.noreply.github.com>
Signed-off-by: AF52 <AF52@reden-emu.dev>
The stub answered 2010 with success and no data: the SDK left the caller's font
unset and the game read it as a font. Both commands answer from the shared fonts.

Change-Id: I6cb701fa7df01f2fc6e4272b20a0df934e56b791
Co-authored-by: ClosetPie107 <159765986+ClosetPie107@users.noreply.github.com>
Signed-off-by: AF52 <AF52@reden-emu.dev>
A program encodes a BC5 texture through an RGBA32UI view; the target took the
texture's size in texels, 16 times its bytes, and the blocks landed elsewhere.

Change-Id: I4ec046c8e9a6be71afdda9d7434d0d35e57225d1
Co-authored-by: ClosetPie107 <159765986+ClosetPie107@users.noreply.github.com>
Signed-off-by: AF52 <AF52@reden-emu.dev>
The compile thread a game thread waits on ran at nice 10, behind all else on a busy host.
A thread can't raise its priority back, so one more thread never lowers it and takes only
the misses a thread waits for. Each thread's priority is logged once.

Change-Id: Idb83a00af20d74dd6a1fafd0ab275f059aac7754
Signed-off-by: AF52 <AF52@reden-emu.dev>
At a resolution other than 1 a compute program's fetch read texel p of a render target at
pixel p of its scaled image, and its size query the scaled size: its textures are now
copies of the guest's size, as its storage images are.

Change-Id: I7b81e4e9e6f11fe13bc2ad4232fa422e82a829ee
Signed-off-by: AF52 <AF52@reden-emu.dev>
A fragment's position stayed in its scaled target's pixels: at resolution 2 a fetch of a
guest-sized texture at it filled the frame's top-left quarter (#1571). It is FragCoord
over the scale now, with TLD and TXQ of a scaled target scaled as Eden's rescaling does.

Change-Id: I3eb35b43a63a1b2160194b98673d39a528927a43
Signed-off-by: AF52 <AF52@reden-emu.dev>
Run edenprobe's ESC check ends the launch when it sees the count, which the fake probe
wrote before the report: an ESC between the two left no run to go on with, and the check
failed (Windows CI, "drivers_continue == 5"). The count now follows the report.

Change-Id: I026db44e671fba6bf5de0c6b46e478bad67c715f
Signed-off-by: AF52 <AF52@reden-emu.dev>
FINDING SHADERS showed only a percentage and "files checked", so a slow file looked stuck.
Its row reads "N of M files, <name>" until done. Every step's detail is now cut before its
progress, as the launcher's clip_row does; the rows move to prepare_screen.c for a test.

Change-Id: I0bc1e0a419cb3536d48ddd3207bea3c71030602b
Signed-off-by: AO55 <AO55@reden-emu.dev>
The size rule (a depth-only pass unlike the last color target drawn) also took depth
prepasses and changed with the draws' order. A shadow map is now a depth target a draw
sampled with a compare in the last 60 presents; only the passes into one are skipped.

Change-Id: I7b20ada601b090d54a61aae5a6c38d8bc0dfd32e
Signed-off-by: AF52 <AF52@reden-emu.dev>
With VK_EXT_transform_feedback the position was captured after the last stage's fix for
the rasterizer (in a depth range of -1 to 1 its z was (z + w) / 2), and only whole. The
capture is now a copy made before the fix, at an output location the program leaves free.

Change-Id: I71f68f83eb5987ceeba845646586de64d2c7c007
Signed-off-by: AF52 <AF52@reden-emu.dev>
They draw at a fixed clock of 50 s, but the last box had closed on the real one: a test
that took longer to get there kept that box's shade on every frame, and the Exit? box's
check read it as the settled colour.

Change-Id: Icbbd7ce89783d6b1e3d28ad9250487b79cd04a26
Signed-off-by: AF52 <AF52@reden-emu.dev>
A render enable over two reports of one counter, both still queued, read
both counts and waited for the GPU. They differ when a segment between
the two counted a sample: a predicate, as a count against zero has.

Change-Id: Ie3ddf01481973f9c712642412d95be578a6b9dc5
Signed-off-by: AF52 <AF52@reden-emu.dev>
A game's title and title ID may not be written, so a doc that says "a Switch game, open
world" leaves no way to find it again. The tag is game- and 8 hex digits of an HMAC of the
ID under a key in the user's config folder; which resolves one, scan checks a text.

Change-Id: I52133b130b85176d3c09a1169ce63e587482288c
Signed-off-by: AF52 <AF52@reden-emu.dev>
The rule against game names and title IDs now says what to write when a reader has to
find the same game again, and the skill says how to make, resolve and check a tag.

Change-Id: Ia1b00ad4b6b970b736a61e11829f24f4e561cc5c
Signed-off-by: AF52 <AF52@reden-emu.dev>
The fake driver's played game now ends only when the test makes its .go file, which it
takes, so a game the queue starts can no longer end inside the pump that started it. One
the test never lets end says so and exits with status 98.

Change-Id: I387ee9c81c654a5f69da1ec509b09bfc8663b0fc
Signed-off-by: AF52 <AF52@reden-emu.dev>
On a picture twice the size each of its quads is twice as big, from the first draw there.

Change-Id: I2aa2e39a43572c3819683b6966a84cafe63bf0bf
Signed-off-by: AF52 <AF52@reden-emu.dev>
On a display scaled 2x (Wayland, a Mac) the window had half as many pixels each way and
the display server stretched it: the game and all drawn over it came out blurred.

Change-Id: Icd3d76ef90cea9fce372921fc9a19b65222a28b4
Signed-off-by: AF52 <AF52@reden-emu.dev>
The first file's compile shows the Compile tab, where a drop opens
nothing, so the drag's other files (a game's DLCs) were lost unsaid.
They now join the queue, on the load the drag was dropped on.

Change-Id: I3992a576df26202459a5d0cb7fe79e2c48d827d3
Signed-off-by: AF52 <AF52@reden-emu.dev>
A changed row was told apart only by its missing [default]. The * follows the value where
Del has something to put back; a page's row and an All carry it for their rows.

Change-Id: I12c9b3c5a60d22d1a6348e7a559d7acdd46fc5b5
Signed-off-by: AF52 <AF52@reden-emu.dev>
Choosing IPC client functions to hook needs the requests a game makes,
how many and what they cost. The renderer's stats cadence logs the window's
sum and the 8 commands that took the most time; another log level pays one load.

Change-Id: Ie290a1f0d92f51a2f2c9e4cd948c6c4cbebe5dde
Signed-off-by: AF52 <AF52@reden-emu.dev>
A game that leaves the offset unset (0xCD in every byte) had every buffer played as
silence. Such a buffer now plays from its start, as Eden and yuzu play every buffer: they
never read the field.

Change-Id: Iadaa62436a30b63eb08dd8a59d98bcd4bf495878
Signed-off-by: AF52 <AF52@reden-emu.dev>
Asked for six channels, a stereo system mixes them its own way: a phone's left the voices'
centre far under the rest. One or two channels now get the console's default downmix, the
one audren's device sink uses, saturating: SDL's own mix scales the fronts to 0.29.

Change-Id: I9d73dea3a6087478a87a37e4d3ec0745ca614821
Signed-off-by: AF52 <AF52@reden-emu.dev>
Android's and the AppImage's were saved at the job's end, if it succeeded: a failed test
or a cancelled run lost 17 builds in a week, 325 runner minutes.

Change-Id: I10c34be36cf5d9178ddb6a1eba2795b166da003d
Signed-off-by: AF52 <AF52@reden-emu.dev>
Pull requests saved 700 GB of them in a week into the 10 GB all caches share, so main's
LLVM builds and system roots were evicted within the hour and built again: 3700 runner
minutes. 36 of 45 Linux jobs read main's anyway, and built as fast (70 s against 69).

Change-Id: I46e1c48c3291d4b71dfc5e410967606711eaf4fb
Signed-off-by: AF52 <AF52@reden-emu.dev>
The hint named memory_gb=6 for an Ounce game too, whose memory that key does not change,
and nothing of Auto having told the game less than the console's. It says the amount
told, what gave it, and the key that tells this game more, with the amount it gives.

Change-Id: I67913c16801fe94bcd33f6b30ba98db6c55ed27a
Signed-off-by: AF52 <AF52@reden-emu.dev>
An Ounce game is told its own pool whatever memory_gb says, and a run with the key given
said nothing of it. The log says so once as the game starts, with the amount told.

Change-Id: I5358a2673c461d7a7332a5b55f56932ddcc731ff
Signed-off-by: AF52 <AF52@reden-emu.dev>
The configure named neither cache, so a developer who wanted sccache passed both launcher
variables by hand and a developer who wanted ccache did the same. It now uses ccache for the C
and C++ compiles when it is found, and sccache when ccache is not. ccache is faster for local C
and C++, and sccache suits a shared or remote cache. Neither is required. SNX_COMPILER_CACHE=off
or an explicit CMAKE_C_COMPILER_LAUNCHER or CMAKE_CXX_COMPILER_LAUNCHER still decides.

Verified with a configure of this tree for ccache, sccache, off and an explicit launcher, and a
snx-shaderc build. A small project including the module compiled through sccache, missed once and
hit on the second clean build. scripts/check-docs.py passes.

Signed-off-by: Vigo <77800979+VIGO-VI@users.noreply.github.com>
AMD, Intel and Arm GPUs interpolate a clipped primitive's inputs less precisely than its
position: the position over w missed its pixel by 25 on a plane clipped at the eye (RADV).
Eden PR 4575's position pass (John, Amicuchu), keyed by draw with the draw's own viewport.

Change-Id: Icaf32cbc69568fbd11cae0313eb99fc5c82515df
Rebased-by: AO55 <AO55@reden-emu.dev>
Signed-off-by: AF52 <AF52@reden-emu.dev>
The position pass leaves a huge clipped quad's other inputs to the host: a sea of clouds
read the depth pixels away from its fragments. Their vertices' values now, weighed by the
fragment's place (VK_KHR_fragment_shader_barycentric), under Eden PR 4575's draw rule.

Change-Id: I7fe7d635817366cbfe4b74c798b42d1761f4637c
Rebased-by: AO55 <AO55@reden-emu.dev>
Signed-off-by: AF52 <AF52@reden-emu.dev>
Without VK_KHR_fragment_shader_barycentric (RDNA1, lavapipe) the per-vertex pass had no
way in: a generated geometry program writes each vertex's values flat, as Eden PR 4575's.

Change-Id: Ic147266fe786c312da143e5a9cf0eeaf481d6a4a
Rebased-by: AO55 <AO55@reden-emu.dev>
Signed-off-by: AF52 <AF52@reden-emu.dev>
Liz wants it in the nightlies with ppc64le and riscv64: its job and notes come back.

Change-Id: I9a205b7022fdbc2995e31e84bd0955bbc0a701a6
Signed-off-by: AO55 <AO55@reden-emu.dev>
A pull request builds big-endian ppc64's alone: emulated jobs held the runners for hours.

Change-Id: I36862716194df19f7dd408b80e0794fe2759788f
Signed-off-by: AO55 <AO55@reden-emu.dev>
Merges cancel main's push runs, none ended since 16:00; a scheduled run is not cancelled.

Change-Id: I71d884e777e542b1d4c8b2bef9bc5df3130280e5
Signed-off-by: AO55 <AO55@reden-emu.dev>
So a nightly can be had at once, without waiting for the schedule.

Change-Id: I743b1535a184cb8b8635ab049cc00358a4d8eac0
Signed-off-by: AO55 <AO55@reden-emu.dev>
maxwell_opcodes.def becomes sm53.decode: the same 16-bit patterns, read by
tools/decodetree (-w 16 on the word's top 16 bits). The rows that overlap
go in { } groups, the narrower first, and decodetree refuses any other
overlap, as shaderdec did. CCTL's second encoding is the CCTLT pattern.

The opcode list (enum order, display names) is SM53_OPS in translator.h,
and decode.c makes a trans_ function of each entry. Every word's top 16
bits, with 40 sets of low bits each, decode to the same opcode and name as
before. shader_decode now checks that every opcode has an encoding and that
the groups pick the narrower pattern.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
meson's pkgconfig module installs dav1d.pc in libdata/pkgconfig on FreeBSD,
whatever --libdir says. FFmpeg's configure looked only in lib/pkgconfig, so
it found no dav1d and the build stopped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nothing runs shaderdec since sm53.decode replaced maxwell_opcodes.def. The
docs, CREDITS and CODEOWNERS name decodetree and sm53.decode instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A format of no fields uses none of ctx, a and insn, and most formats use no
ctx: the decoder failed to compile under -Wall -Wextra -Werror, which the
tests that build sm86_decode.c on its own use.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sm86_opcodes.def becomes sm86.decode, read by tools/decodetree on the low
16 bits of the instruction (-w 16). An opcode of 12 bits is one pattern, and
an ALU opcode has a pattern for each form it takes, so decodetree checks
that no two codes collide, which shader_sm86 checked by hand.

The opcode list (enum order, kind, display name) is SM86_OPS in sm86.h, and
sm86_decode.c makes a trans_ function of each entry. Every value of the low
16 bits, with 24 sets of the other bits each, decodes to the same Sm86Insn as
before. shader_sm86's table test now checks the patterns against the kinds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main takes c from a register for the IR and RR forms; this checks the four forms, four
modes and four values of c at each of the 32 lanes against shfl.sync's rule.

Change-Id: Ie6515eb4436bae444dbd1441d85b6b6bbb390fa7
Rebased-by: AO55 <AO55@reden-emu.dev>
Signed-off-by: AF52 <AF52@reden-emu.dev>
The /dev/kgsl-3d0 condition was ours: libadrenotools' hook takes the place of whichever
driver the Vulkan loader asks for. A render node whose kernel driver DRM names amdgpu, the
one RADV opens, loads packages too; asked on Android alone, as opening one wakes a GPU.

Change-Id: I4c3147d453dbf3ba6fe9363496019c87003f48ab
Signed-off-by: AF52 <AF52@reden-emu.dev>
A package for another GPU (Turnip on an Xclipse, RADV on an Adreno) loads and lists no
device: the run said "No Vulkan device: ScarletNX needs Vulkan 1.3", with no word of the
package. It now names the package and the GPU it does not drive.

Change-Id: If623c473534c983b2ef68f7ef9ad9cf53ff09378
Signed-off-by: AF52 <AF52@reden-emu.dev>
GPU Drivers offered a package, Download Driver and Add Driver on every system, where a
pick does nothing. They are greyed there, each row saying what the device lacks and Enter
the whole line; Download Driver too on an Xclipse: its repositories hold Adreno's drivers.

Change-Id: Idb5227756d4cf2075b451c76a914a6d5d25d851d
Signed-off-by: AF52 <AF52@reden-emu.dev>
With all 1024 handles open, the commands that hand the game a handle answered success with
handle 0. They answer OutOfHandles now, and a reply whose object gets no session drops the
handles and sessions it had made.

Change-Id: I918d050745f6ed823b3d29ede20251d78f1ebee1
Signed-off-by: AF52 <AF52@reden-emu.dev>
A full pool ended the game on an assert. For the objects the console runs out of too
(threads, events, transfer and code memories, domains) the request answers OutOfResource
or OutOfDomains and logs the pool; the runtime's own bounds still end the game.

Change-Id: I374c85746db593c74ebed1a49ef738cbd45e54de
Signed-off-by: AF52 <AF52@reden-emu.dev>
kernel.h promised LimitReached to a thread past THREAD_MAX, and CreateThread made it with
a warning. It is refused now, counted under the kernel lock; an Ounce program, whose limit
is not known, keeps the warning.

Change-Id: I0e5b6944b371e63d3645a3fb5d87efb66c8befe5
Signed-off-by: AF52 <AF52@reden-emu.dev>
StartThread read the thread's state, let go of the lock, then started it: two calls on one
handle both made a host thread. The state is read and set in one hold of the lock, and the
second call gets InvalidState.

Change-Id: Iabd1c03cfa5b7cc04451f01e15df8886ab4d2f28
Signed-off-by: AF52 <AF52@reden-emu.dev>
The counters' test sends command 10 as one the test service doesn't have. It answered a
handle and two objects here, which nobody closed, and failed_command found the event.

Change-Id: I801cabb065b43ce3978d778f4993a03ff5113249
Signed-off-by: AF52 <AF52@reden-emu.dev>
GetBuiltInFontSharedMemory gives the same handle as command 4 and answered success with
handle 0. The test's handle table gives a handle now, and 0 where a check asks for it.

Change-Id: I606ea0a2d6836a270a51995afad6b417e6c28e96
Signed-off-by: AF52 <AF52@reden-emu.dev>
SNX_TEST_GPL=whole clears g_vk.has_gpl after the device chose its dynamic state, which the
whole pipelines keep: the check read the flag and took the device for one with no range.

Change-Id: If2a8e1965a1bd19393cdba821e6e88fe7ddce11d
Signed-off-by: AF52 <AF52@reden-emu.dev>
The job ran the plain vulkan_headless alone, so the depth range check that broke
vulkan_headless_pipeline_library_whole merged green. Eight variants join it, each with
the plain run's timeout: about seven minutes more a Linux job, by this machine's times.

Change-Id: I4dabbc95938bc224084387ce184cbc0729c6a532
Signed-off-by: AF52 <AF52@reden-emu.dev>
The SDK reads the font's 12 bytes at 4 of the reply (a u64, then a u32 at 12). They were
at 8, so it took offset 0 and the font's offset as its size.

Change-Id: Iefbc69b164f8f5738d521a782c7e534a4bea8e59
Signed-off-by: AF52 <AF52@reden-emu.dev>
Auto's read of the host and the services' change are functions of their own, so the start
reads the host itself instead of through two flags. snx_tv_mode reads the mode atomically,
as Auto stores it from the frontend's thread while the game's threads read it.

Change-Id: Ia7c341a7d2d233e4370496d8f22250c62fa20980
Signed-off-by: AO55 <AO55@reden-emu.dev>
hotkey_tv_mode (Ctrl+D) and the game's menu's TV mode row step it round On, Off and Auto
for the run; docked keeps the .ini's. The services hear of it on the frontend's next tick,
out of the input's lock the pads step under, and a held direction steps the row once.

Change-Id: I7c8418210309ce5820c503c2002e2967545a6987
Co-authored-by: GreenStar <77800979+VIGO-VI@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
A first press warns, the Switch's in a toast and its log, and a second within 3 seconds
quits, so a stray press cannot end the game. The 3DS, the Vita and the GBA take Esc the
same way, warning on the terminal, by one rule in common/utilities/quit_key.h.

Change-Id: I4131286e433230cfed63a1c32b158fc40121dba7
Co-authored-by: GreenStar <77800979+VIGO-VI@users.noreply.github.com>
Signed-off-by: AO55 <AO55@reden-emu.dev>
The parser wrote the names of an assignment's, a unary operand's and a
declaration's types into buffers before it knew of any error: 56,000
snprintf calls for the 25 test shaders, every one of which compiles.
type_text makes a name in the context's few buffers, and only glslc_fail's
arguments call it, which C evaluates only when the message is made. The
messages are the same; parsing takes 18% less time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each row of the keywords, built-in types, functions, variables and
extensions is ROW(name, ...), which makes the name a string and its length
sizeof less the NUL. The keyword search and the built-in function and
variable scans compare that length before any byte, and no lookup calls
strlen: 2.6 million calls for the test shaders before. glslc_view_is is
inline, so a literal's length is the compiler's. Parsing takes 41% less
time, lexing 15% less.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every identifier with the same text has one name (g->names, by hash), which
its tokens carry. A name holds the macro it names, so a macro is found
without hashing its text again, and its keyword row, looked up once a name
instead of once a token; the version and extensions still decide each
token's kind. #undef clears the name's macro. Lexing takes 15% less time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
glslc_open cleared the emitter's hash (160 KB) and its ids by type and
symbol (72 KB) for every shader, a sixth of a test shader's time. The hash
says which slots are taken with a sparse set (Briggs and Torczon's), which
whatever the workspace held cannot fake, so it starts empty with a count;
glslc_emit clears the ids of the types and symbols the shader has. A
workspace filled with any pattern still gives the same words, as
emit_test checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A kind is 32 bits: a punctuator's characters, packed from the first in
the low byte (TK_LPAREN is '(', TK_ADD_ASSIGN '+' | '=' << 8, made from the
bytes one at a time, so the same number on a big-endian host); keywords
from 0x80, the built-in types from 0x100; a name the preprocessor let
through is GLSLC_TK_NAME | its index, so two tokens name the same thing
when their kinds are equal, and the token carries no name of its own. The
lexer scans a copy of the source with zero bytes after it, which lets it
read ahead without a bound check, and classifies bytes with a table.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A name's innermost symbol in scope is its g->names entry's sym, and each
symbol's next the one of its name it hides: finding one is a load, and
leaving a scope gives each name back what it had; the symbol hash goes.
Symbols, members and parameters keep their name's index, and compare it
in place of their text. A name's first rows of the built-in functions and
variables are looked up once, and a call scans that name's rows alone, as
they follow one another. The keyword search decides most steps on the
first byte, and the hash takes 8 bytes a step, each made from its bytes,
so the same on a big-endian host. Parsing takes 20% less time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The source's copy has zero bytes after its end, and the synthesized text the
workspace's next array, so the last bytes of a name are read as 8 and the
ones past it masked off: the same hash as byte by byte.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
known() compared a type or constant with every one made before, so a
module's types and constants cost the square of their count; an index on
a power of two (known_slots, at the end of SpvEmitter) finds one in a slot
or two. The NonUniform ids are a set on a power of two the same way. The
same words, in the same order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each instruction took a call to reserve, and each word a test and store of
the section's count. reserve's test is inline now, its growing out of line,
from 512 words (a small shader's section grows once or never, where it was
reallocated about 11 times). EMIT writes a whole instruction after one test,
for the 120 whose words call no function (an initializer's are evaluated in
no set order), and put_n an array of words at once. On a corpus of 195
programs from two games, the emitter's own work is 40% less, the words the
same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
known_slots, the 32-bit constants' tables and the NonUniform set are kept
at most half full on a power of two and grow only as an entry joins them,
so each one's size follows from its count (table_size); known doubles from
128 entries the same way. Their capacity fields go. known_slots grows by
realloc and is placed again from known, which keeps every entry's hash:
doubling moves an entry's slot, so its old half cannot be kept as it is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The writing of words (spv_words_reserve, spv_emit_words, SPV_EMIT,
spv_emit_id, spv_binary) and the 54 instruction functions that are only an
id and their words are static inline in spirv_emit.h, so each user can
inline them; a section grows out of line (spv_words_grow), and a load's
NonUniform follows only where the module has any (spv_emit_nonuniform_from).
On the corpus of 195 programs the time is the same, with the calls inlined
or not (always_inline too): the emitter's calls cost little next to the
translator's work. The same words.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This reverts commit d719d593133ab44d77c15b4f9756c0eb634fb4a8.
The 32 functions that each wrote one opcode with a result type and one, two
or three operands (spv_emit_fadd, spv_emit_bitcast, spv_emit_select...) are
spv_emit_unary, spv_emit_binary and spv_emit_ternary, which take the op and
assert it is one of their own. Their 1,360 calls pass it, laid out by git
clang-format over the lines changed only; spv_emit_convert_f_to_f, which
nothing called, goes. The same words.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A table's size still follows from its count, which decides when it grows;
known_slots, the constants' tables and the NonUniform set keep their mask
(the size less one, what a lookup takes), set as they grow, so a hit reads
it in place of computing the size again. In a Release build that is 7
instructions a constant made again: the emitter's work on the corpus of 195
programs is 11% less than before these changes, where computing the size
had taken most of it back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The 32 functions that are another with some arguments given (the scalar and
vector types, the pointer types, the capabilities, spv_emit_sample_image
and spv_emit_sample_grad...) are static inline: declared where they were,
with their comments, and defined together at the header's end, after every
function they call. The same words.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A // comment's end is the line feed memchr finds, the carriage returns
before it looked at only there (one with no line feed after it ends the
line); from 3.00 a backslash before it continues the comment. A block
comment's end is a star memchr finds with a slash after it. 3,000 shaders
with comments of every line end, continuation and unclosed comment in them
compile as before, to the word and the error's place.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tools/glslc_kwgen hashes builtins.c's keyword table as glslc is built: hash
and displace, the keywords in buckets by their hash's low bits, each bucket
the displacement that gives each of its keywords a slot of its own
(glslc_keywords.inc, 512 slots, 8 buckets now). A lookup is one slot, then
the length and the bytes; intern makes it with the hash it has, once a name
as the name is made. A cross build builds the tool for the machine doing
it, as decodetree. glslc_hash is inline in internal.h for the tool. Lexing
takes 17% less time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each compilation defined GL_ES, __VERSION__, __LINE__, __FILE__,
GL_FRAGMENT_PRECISION_HIGH and every extension's name before reading the
source: twenty names written into the synthesized text, interned and made
macros. Every macro lookup interns its name now, so a new name that starts
GL_ or __ is looked for in a short table there, and made the macro then,
its value the synthesized "0" or "1" defined already has. A predefined
macro is GLSLC_MF_PREDEFINED, which #define and #undef refuse. The 511
macros a shader may define count the predefined ones it reads only.
Lexing takes 7% less time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tokens the preprocessor lets through are two arrays: their kinds
(g->kinds, then 16 TK_EOF kinds past the last, so kind_at reads a look past
the end without a bound) and the rest, 8 bytes (GlslcPlace: text, site,
flags). put takes the lexer's token by pointer and writes the two in place
of copying 12 bytes twice. Parsing takes 3% less time, lexing 6%.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
shader_u32 keeps each constant under 64 in DirectCtx once the emitter has
made it, so the translator's 0, 1, cbuf element and component indices and
the like stop looking up the emitter's constant table on every use. The
modules are the same; the corpus bench runs 0.8% fewer instructions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The reaching-definition and dominance searches ask direct_flow_targets of
every instruction in the program, many times a program: a fragment's
screen-uv check alone was a third of the corpus's translation time, most
of it decoding. Every flow instruction it looks for has 0xE2 as its top
byte, so an inline check of that byte answers the rest, and the decode
stays out of line. The modules are the same; the corpus bench runs 29%
fewer instructions (125.1M to 88.6M), 64.6 to 49.7 us a shader.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
shader_direct_screen_out asked direct_output_def of up to 99 output words,
and each one went over the whole program decoding every instruction for
its last AST. direct_output_stores now finds each word's last store once,
decoding only the words with AST's top 13 bits. The modules are the same;
the corpus bench runs 8% fewer instructions (88.6M to 81.5M).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every reaching-definition, dominance and reachability search went over
the whole program asking each word for its flow targets, decoding it
again each time: a block start alone was a scan of the program, and a
fragment's screen-uv check asked thousands of them.

ShFlow holds what they ask, made once when to_spirv starts: each word's
decode, the flow instructions with their targets (a jump table's read
once), the first word decode doesn't know, and each instruction's block
start, with how far that holds past a jump table that isn't found. The
searches take it in place of (insn, n): a block start is a lookup, the
dominance and forward-only scans go over the flow instructions alone,
and nothing in dataflow.c decodes a word the table has. to_spirv's own
passes read their decodes from it too.

The modules are the same for the 195-program corpus; it runs 10% fewer
instructions (81.5M to 73.3M), 48.1 to 45.9 us a shader.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebased-by: AO55 <AO55@reden-emu.dev>
The passes came from main after the emitter's fadd, fmul, fdiv and fnegate went away.

Change-Id: Id7b4f85b5fa7a11a775e9636303eb973c404a007
Signed-off-by: AO55 <AO55@reden-emu.dev>
Seven of the Switch's compute passes and the Vita's deswizzle each filled the same
VkWriteDescriptorSet per storage buffer by hand. snx_vk_storage_buffers writes a set's
bindings 0 on from the buffer infos, as each of them did.

Change-Id: If6ee08195059f3951d626f4935742ff84ef2d68f
Rebased-by: AO55 <AO55@reden-emu.dev>
Signed-off-by: AF52 <AF52@reden-emu.dev>
The same passes each made a set layout of storage buffers and a pipeline layout with one
push constant range by hand, as the 3DS's snx_ctr_vk_compute does for its own. A pair that
fails leaves neither layout now, and the four fatal ones say both in one message.

Change-Id: Ia3349a6f1e3b403e1611c3861a0cbf93e34c97df
Rebased-by: AO55 <AO55@reden-emu.dev>
Signed-off-by: AF52 <AF52@reden-emu.dev>
The GBA and 3DS drivers refuse the option, so each recompile of theirs failed while the
queue went gently (Gentle, Auto on battery, a game playing). They keep the low priority.

Change-Id: Id3279a8b82587496317cfb095a11233ea7ddca81
Rebased-by: AO55 <AO55@reden-emu.dev>
Signed-off-by: AF52 <AF52@reden-emu.dev>
Reverts 2e45bd1ca: each driver is to take the option (review of #1596), not the launcher
to hold it back from the 3DS, Vita and GBA ones.

Change-Id: I6dff9f5208ff8f649dcb20a2ac23d93bd4c0be11
Rebased-by: AO55 <AO55@reden-emu.dev>
Signed-off-by: AF52 <AF52@reden-emu.dev>
The launcher's Gentle queue gives it to every driver and these refused it. The 3DS and
Vita compiles run on that many threads, as the Switch's; a GBA ROM is one module on one
thread, which its recompile says with the value.

Change-Id: I70ae4f1f907fee84d82562599ad13eb33b54c21e
Rebased-by: AO55 <AO55@reden-emu.dev>
Signed-off-by: AF52 <AF52@reden-emu.dev>
d4e47d63 reads a compute program's shared memory bytes from the word at
0x64 of its section. The console's driver puts that word in the QMD's
SHARED_MEMORY_SIZE rounded up to 256 bytes, and the translation took it
as it is. One game's video upscaler declares 0x5460 bytes and addresses
exactly 0x1e60 + 128 * 0x6c = 0x5460, and its programs that declare 0
have no shared instruction.

nvn_section.h now gives the compute section's fields (the workgroup size
at 0x58 to 0x60, the shared size at 0x64, the barriers at 0x74) and
nvn_section_shared, which stage_of reads the size with. cs_make rounds
the size up to 256 as the driver does. A program that declares 0 and
still addresses shared memory keeps the translation's 16 KiB, and a log
line says so, but not for a pipeline of an earlier run made again from
the pipeline file, whose key may have been made without the size.

Run on a Radeon 890M host before the port to main: that game's movie
plays with no corruption at about 20 frames a second. The nvn_section
test checks the size of a compute section. On main, with this change
alone, the nvn and compute tests pass but nvn_game_benchmark. With the
whole series on main the full suite passes but nvn_game_benchmark, which
fails on main alone too: its script needs Python 3.12, and this host has
3.11. The 38 Vulkan tests pass on RADV and on lavapipe, vulkan_headless
on lavapipe at a rerun: its first run there failed the check that a
descriptor heap transition stays in one command buffer, which a periodic
submit can split, and five runs after it passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Loading a save of one game ended the process on Windows every time, in
the first frames of its outdoor scene, with exit code 0xC0000005, no
crash report and no Windows Error Reporting event. Under lldb the fault
is in the game's module, at the start of guest function 81e8ac8, whose
host frame takes 74712 bytes (sub $0x123d8, %rsp). Its stores near the
top of the frame went to committed stack, and the first store near the
bottom faulted on a write to reserved memory. The thread had used
little of its 32 MiB stack, and the frame stepped over the guard page
below the part in use.

Windows commits a thread's stack as it grows, through that guard page,
so a prologue whose frame is a page or more must touch each page on its
way down. LLVM calls __chkstk to do that, but guest functions carried
"no-stack-arg-probe" because a module links no compiler runtime. Linux
maps a thread's whole stack, so the same code runs there. 267 of the
game's 296767 functions have a frame of a page or more, the largest
this one.

The process ended silently because the system writes an exception's
record below the stack pointer, which was in that reserved memory. It
could not deliver the fault, so no handler ran (code_fault, the crash
filter, Windows Error Reporting) and only a debugger saw it.
plat_win32.c says so beside code_fault.

The runtime library now defines snx_stack_probe for Windows x86-64, a
probe with the contract of __chkstk: the size in rax, every register
kept but the flags, one read in each page from the caller's stack
pointer down to the new one. Generated guest functions for Windows
x86-64 name it in "probe-stack", so LLVM calls it from a prologue of a
page or more. Every AOT module and the code arena of the JIT link the
library, which keeps -mno-stack-arg-probe: its own frames are 632 bytes
at most.

A Windows module built before keeps its unprobed frames and must be
recompiled. The keys of the unit cache change with the IR of the
functions, and the JIT cache with the hash of the runtime library.
SNX_ABI stays: the runtime runs a module of either kind.

stack_probe emits a guest function with a 256 KiB frame for
x86_64-w64-windows-gnu and checks that its object needs the probe to
link. On a Windows host it also links it with the AOT runtime library
and runs it from the JIT loader on a new thread whose stack is mostly
reserved. Without the attribute the first check fails, and the run
ends the test with an access violation.

Run on the Windows host with an RTX 5080: two runs under lldb of the
input recording that loads the save showed the fault above. With the
game recompiled by this change (no unit of the cache reused), three
runs of the same recording loaded the save and played the outdoor
scene to the end of their 120 and 150 seconds at about 20 frames a
second, with no crash and the save unchanged. The PC's ctest passes
722 of 728 tests with this change and the next one. The six that fail
failed before them: ldn_lan, ldn_service, https, gui_languages_script,
and nvn_contracts and nvn_game_benchmark, which need symbolic links
that this account may not make. On Linux the 67 recompiler, linker,
JIT and LLVM tests pass, stack_probe among them. The code of a Linux
module does not change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The device enabled VK_NV_device_diagnostic_checkpoints wherever the
driver had it, and then marked every draw and dispatch with a
checkpoint, so that a lost device could name the work that hung. A
RenderDoc capture records the extensions its device enabled and
replays only where the driver has each of them: a capture made on an
NVIDIA GPU could not be opened on a Radeon, whose driver has no such
extension.

The extension is now enabled only when vk_checkpoints=1 asks for
checkpoints. With it on, record.c's draw and dispatch markers and
checkpoints.c's work markers go on as before. With it off, a lost
device still logs the GPU's own fault report (VK_EXT_device_fault).

Run on the Windows host with an RTX 5080: with RenderDoc 1.47 in the
game, the input recording that loads a save of one game captured
present 60 and went on into the outdoor scene, the save unchanged. The
vkCreateDevice of that capture enables 34 extensions, none of them
NVIDIA's, and the driver of a Radeon 890M has each one. Its qrenderdoc
1.46 still refuses to replay the capture, now for two features that
driver lacks, primitiveTopologyPatchListRestart and
extendedDynamicState3ExtraPrimitiveOverestimationSize, which the
device enables because the RTX 5080 has them. The PC's ctest passes
722 of 728 tests, the six that fail as before. On Linux docs_check,
settingsgen, gui_settings, vk_renderdoc_setting, runtime_architecture
and vulkan_headless pass. vulkan_headless_pipeline_library_linked
failed once on its check that a descriptor heap transition stays in
one command buffer, as an earlier commit saw on lavapipe, and passed
the three runs after it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vk_gpu_profile=1 splits the graphics queue's idle time between
submissions by what the CPU did, which needs the GPU's timestamps on
the CPU's clock. That pair came from VK_EXT_calibrated_timestamps with
CLOCK_MONOTONIC, and the CPU's time of each submit from
plat_monotonic_ns. Windows has no CLOCK_MONOTONIC: the extension was
not even enabled there, plat_monotonic_ns returns 0, and the profile
on Windows left out the idle report, the GPU thread's waits and the
submissions by why.

Where the device calibrates against QueryPerformanceCounter, the
extension is now enabled for it too (has_calibrated_qpc), the CPU's
times are plat_ns, which reads that counter on Windows, and the
counter's ticks of the pair are turned into plat_ns's nanoseconds
(plat_qpc_ns, 0 on the other systems). Elsewhere nothing changes.

Run on the Windows host with an RTX 5080, the input recording that
loads a save of one game, 120 s with vk_gpu_profile=1: the log now
says the graphics queue was busy 9.80 ms of each 46.20 ms present
(21%), idle 36.40 ms, 28.29 ms of it while the GPU thread was still
recording the next submission, with 76.5 submissions a present. The
GPU thread is what holds that scene's frame rate, not the GPU. The
save stayed unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Windows profiler (profile=1) took the program counter of every
runtime thread each millisecond, waiting or not, and wrote the top 200
addresses. In a 150 s run of one game, 94% of its samples were one
address in ntdll, the system's wait function where a hundred threads
sleep, and the GPU thread's work hid under it.

A thread whose cycle count (QueryThreadCycleTime) moved less than
100000 cycles since the last tick is now taken as waiting and gives no
sample. Each sample is kept by its thread, whose name
(GetThreadDescription) heads its lines, and a line gives each busy
thread's share of the ticks. An address outside the runtime and the
game is written as its module's name and offset, and is kept with the
first address into the runtime's code found in the 64 words above the
stack pointer, most often the return address of the runtime function
that called into the module: a scan, as an unwind could take a lock
the stopped thread holds. Every bucket is written, so a runtime
function's samples, spread over its 16-byte runs, can be summed by its
symbols afterwards.

Run on the Windows host with an RTX 5080, the input recording that
loads a save of one game, 150 s, the samples between 65 s and the end
summed by function with llvm-symbolizer: the GPU thread ran in every
tick in the game's forest, and 13.8% of its samples were in
NtGetWriteWatch under plat_ww_scan, 7.3% in vk_mirror_slice, about 7%
in landed_order and the qsort around it, and 6.5% in the memset and
memcpy of copy_writable. The recording thread ran in 97% of the ticks
but waits in 86% of its samples. The save stayed unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A finish submits what was recorded, waits for the GPU to run all of it
and lands every result: a round trip that leaves the GPU idle while the
GPU thread records again. The stats said how many there were and how
long they waited, not who asked for them. vk_finish now counts its
callers by file and line, as vk_render_end counts the passes it ends,
and the stats every 600 presents name the eight sites with the most,
with their share and their time.

Run on the Windows host with an RTX 5080, the input recording that
loads a save of one game, 150 s with vk_gpu_profile=1: in its forest
the game makes 9 finishes a present, 8 of them (89%, 1283 ms over 600
presents) in flush_wait at surface.c, a render target's pixels read
back for the CPU, and 1 at buffer.c. The GPU profile puts 2.20 ms of
the GPU thread's wait and 3.29 ms of the GPU's idle time a present on
them. The save stayed unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each draw counted by a samples-passed counter runs inside an occlusion
query, and a report of the count copies the results of the queries
ended so far into host memory, then resets them, in the submit the
report waits for. Copies and resets can't be recorded inside a
rendering pass, so each report ended the pass. One game reports after
almost every draw of its scene's main pass: that pass became about
1850 passes a frame, one a draw, each end a drain of the GPU with a
barrier and a new pass after it.

A report now only ends its counter's open query, which is legal inside
a pass, and the pass goes on. The copies are recorded where the
command buffer ends, before the submit the report is gated on, as
cmd.c's submit did already for the segments ended without a report.
They come sooner where a shader reads the counts: the render enable's
predicates and the counts a draw reads are dispatches, which end the
pass anyway, and now record the copies first. When half the ring of
4096 queries waits for its copy, a report, a reset or a counter turned
off records it there, so a pass never runs out of reset queries. What
the game reads and when is unchanged: a report is still performed once
its submit is done, with the same segments summed.

Run on the Windows host with an RTX 5080, the input recording that
loads a save of one game, 150 s with vk_gpu_profile=1, in the game's
forest, before and after: the target of the main pass took 386098
passes for 424360 draws over 205 frames, and now 7917 for 452514 over
219; the GPU's time in passes went from 11.98 to 2.26 ms a frame and
the gaps with barriers only from 14.28 ms (405497 of them) to 13.33 ms
(19189). The graphics queue was busy 30.49 ms of each 48.89 ms present
(62%) and is busy 9.92 ms of 45.81 (22%); nvidia-smi read 43% and
21%. The frame rate went from 20.7 to 21.9 a second, the median of
the 5 s rates: the GPU thread holds it, as the idle report shows
(27.8 ms a present idle while it still records), and the GPU thread's
1.57 ms a present of waits for reports' submits are gone. The pictures
show the same scene and the save stayed unchanged.

vulkan_pass_breaks has a case of draws with a report after each: they
keep one pass (12 passes for 12 draws before), their reports hold the
samples since the reset, a render enable on a queued report is made on
the GPU from counts copied by the predicate's batch, and 2100 resets
with draws and no report end the pass once at most. It passes on RADV
and lavapipe. On Linux the Vulkan tests pass on RADV, 38 of 38, and on
lavapipe but vulkan_uma_hot, which fails the same way at the parent
commit. The other tests pass but nvn_game_benchmark, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A landing of GPU results into guest memory notes each page it wrote
with a hash of its bytes (vk_ww_landed), so that the next write scan
that reports the page counts it only if those bytes changed. The list
is kept sorted by page, the newest entry of a page alone, for the
scan's ranges to find their entries. Every take of new scan results
sorted the whole list again with the C library's qsort when a landing
had added entries since, and compacted the whole list after, though
entries stay until a scan reports their pages and the list grows to a
quarter of a million of them.

The list now keeps the length of its sorted part. A take sorts only
the entries added since, merges them in from the end with a copy of
them, and drops a page's older entries from where the merge began. The
compaction after the marks starts at the first entry a mark removed,
and does nothing when none was. vk_ww_landed_check and
vk_ww_landed_hash give the tests the list's order and a page's kept
hash.

Run on the Windows host with an RTX 5080, the input recording that
loads a save of one game, 150 s with the CPU profiler, together with
the next change: in the game's forest, landed_order, the compaction in
ww_take_scanned and the qsort around them were 9.4% of the GPU
thread's samples, and are 0.8% now. The two changes took the frame
rate from 20.7 to 24.8 a second (the median of the 5 s rates, with the
profiler on). The save stayed unchanged.

vulkan_write_tracking has a case of landings over pages below, among
and above the kept ones, some of them again, several between two takes
and one alone: one entry a page, in order, with the newest landing's
hash. It passes on RADV and lavapipe, with the write tracking's other
cases, and the Vulkan tests pass on both, 38 of 38.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A slice of the GPU mirror is a storage binding's granules, up to 16 MiB
of them for each writable storage buffer of each draw and dispatch of
the programs that log their writes. For each granule it looked at
every page of the binding's span three times, one bit at a time: for
the oldest time a valid page was brought up to date, to set that time,
and for the pages not given their bytes yet. The second loop is a
fill the compiler vectorizes; the other two were a branch per page.

The first and the last now take the valid mask 64 pages at a time: a
word with no valid page is skipped, a whole valid word's times are
reduced with a loop the compiler vectorizes, by their age before now
(every time taken is now or before it), and the pages not given yet
are the set bits of the inverted word. What they find is the same.

Run on the Windows host with an RTX 5080, the input recording that
loads a save of one game, 150 s with the CPU profiler, together with
the change before: in the game's forest vk_mirror_slice was 7.3% of
the GPU thread's samples, and is 1.7% now. The two changes took the
frame rate from 20.7 to 24.8 a second (the median of the 5 s rates,
with the profiler on). The pictures show the same scene and the save
stayed unchanged. The Vulkan tests pass on RADV and lavapipe, 38 of
38, the mirror's checks among them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Write tracking finds the pages the CPU wrote with the write watch of the
system, a scan of a 4 MiB leaf of guest memory at a time, once in each
epoch for each leaf a check needs: an epoch starts when the CPU may have
written what a stream reads next. The scanner thread scans the leaves
the last epochs needed as soon as an epoch starts, and a check scans
what it finds unscanned. Nothing said how many epochs a frame had, nor
how many leaves each thread scanned.

The stats every 600 presents now give the epochs a present, and the
leaves the scanner and the checks scanned with their time. A check whose
range spans several leaves claimed them all and scanned the whole span
from the first unscanned leaf to the last, again over leaves between
them that the scanner had scanned in the epoch already. It now scans
each run of unscanned leaves alone and lets the others go, as it did
with those at either end.

Run on the Windows host with an RTX 5080, the input recording that loads
a save of one game, 150 s with the CPU profiler: in the game's forest
there were 31 epochs a present, the scanner scanned 2634 leaves a
present (10.9 ms) and the checks 707 (7.4 ms of the GPU thread), and the
checks let go of about 10 leaves a present that the scanner had scanned.
The save stayed unchanged. The Vulkan tests pass on RADV and lavapipe,
38 of 38.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Write tracking scans the game's memory again in each epoch: an epoch
starts when the CPU may have written what a stream reads next, at each
submission and, in NVN's replay, at each wait of a stream for an event
or a sync that is met. One game waits on events between its queues
about 25 times a frame. Each met wait started an epoch on the GPU
thread, which went on at once and found the leaves its next checks
needed unscanned: 31 epochs a present, 2634 leaves of 4 MiB scanned a
present by the scanner thread and 707 by the GPU thread itself, 7.4 ms
of its time.

What releases such a wait came after the CPU's writes that the wait
covers. A stream's signal comes after its submission, or after its own
wait, which started or took in an epoch then. A CPU signal now starts
an epoch before it (gpu_cpu_signal): nvn_EventSignal, and a syncpoint
increment through nvhost-ctrl. So the epochs started so far hold every
write the work after a met wait may read, and the stream takes in the
newest of them (renderer.h mem_seen, vk_ww_seen) instead of starting
another. A memory write of the CPU straight over an event's word, not
through nvnEventSignal, is not seen as a signal. The GPFIFO path's
semaphore waits, which the CPU writes, still start one.

Run on the Windows host with an RTX 5080, the input recording that
loads a save of one game, 150 s with the CPU profiler, together with
the next change: in the game's forest there are 8 epochs a present
now, the scanner scans 966 leaves a present (3.8 ms) and the GPU
thread 37 (1.5 ms). NtGetWriteWatch under plat_ww_scan went from 16.8%
of the GPU thread's samples to 3.8%. The frame rate went from 24.8 to
30.4 a second (the median of the 5 s rates, with the profiler on). The
pictures show the same scene and the save stayed unchanged.

On Linux the Vulkan tests pass on RADV and lavapipe, 38 of 38, and the
other tests pass but nvn_game_benchmark, as before; nvn_nvrm_sync,
nvn_names and nvdrv_service, whose stand-ins now have gpu_cpu_signal,
among them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A release the game can observe (a semaphore, a report, a syncpoint
increment) waits in a queue for the submit before it, and the stream
holds its releases until it stops or waits: the release thread then
performs them. Each release queued woke that thread with a broadcast,
though the release just queued is held and the thread has nothing new
to do until the hold ends. One game queues a samples-passed report
after almost every draw, about 1900 a frame: the GPU thread woke the
release thread that often, a system call each (NtAlertThreadByThreadId,
3.4% of the GPU thread's samples), and the release thread woke, found
nothing and slept again.

The broadcast now comes only when the queue was full and its hold
ended there. Whatever else ends the hold, vk_release_submit,
release_match and read_queued, wakes the thread as before.

Run on the Windows host with an RTX 5080, the input recording that
loads a save of one game, 150 s with the CPU profiler, together with
the change before: the wake-ups under release() are gone from the GPU
thread's samples, the release thread ran in 39% of the profiler's
ticks where it ran in 58%, and the frame rate of the two changes went
from 24.8 to 30.4 a second (the median of the 5 s rates, with the
profiler on). The save stayed unchanged. On Linux the Vulkan tests
pass on RADV and lavapipe, 38 of 38, vulkan_release among them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A draw or dispatch that writes a storage buffer it never reads, and
logs its writes, gets staging that no guest bytes are copied into: its
results land from its write log. Its stores are partial, and the GPU's
read-modify-write of the surrounding cache line reads what the staging
held, so the staging is given zeros rather than whatever the ring held,
which can hang the GPU. The CPU wrote those zeros with a memset of the
whole binding, up to 16 MiB, for each such binding of each draw.

The GPU writes them now: a fill in the upload command buffer, which
runs first in the submission. Nothing before it there uses the new
staging, and nothing on the CPU writes it after, so the fill comes
before the program's stores as the memset did. The staging is taken in
whole words for the fill, and the barrier after the upload command
buffer covers fills as well as copies.

Run on the Windows host with an RTX 5080, the input recording that
loads a save of one game, 150 s with the CPU profiler: in the game's
forest the memset in copy_writable was 4.4% of the GPU thread's
samples and is gone, and the frame rate went from 30.4 to 32.1 a
second (the median of the 5 s rates, with the profiler on). The
pictures show the same scene and the save stayed unchanged. On Linux
the Vulkan tests pass on RADV, 38 of 38. On lavapipe three variants of
vulkan_headless failed once on the check that a descriptor heap
transition stays in one command buffer, as earlier commits saw, and
passed three runs each after it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
F2IP was translated with the nearest even rounding only, and refused
any other value in bits 78 and 79. Three of one game's mesh programs
have 3 there: "F2IP.U8 R223, RZ, R22, RZ" right after R22 is
multiplied by 255, as a shader's uint() of a colour truncates. F2I
keeps its rounding in the same two bits (nearest even, down, up,
toward zero), and F2FP keeps .RZ as 3 too, one bit higher. CuAssembler
records only the nearest even form of F2IP, so the order is taken from
F2I's and the program's use.

The two bytes now round as those bits say before they saturate. The
test packs four pairs with each other rounding, .U8 and .S8, and a
flag outside the known ones is still refused.

Run on the Windows host with an RTX 5080, the input recording that
loads a save of one game, with mesh draws on: the three programs that
were refused with "F2IP with flags 0xc4" translate, and no program is
refused for F2IP. They draw about once a run, at the scene's start, and
no change was seen on screen. The run kept 32 frames a second in the
game's forest, no fault, and the save stayed unchanged. shader_sm86
passes on the host.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Four of one game's compute programs were refused, "global address
whose base no constant buffer holds (from LDC)": they load 64-bit
pointers with LDC.64 from cbuf 4 at an offset they compute, then load,
store, ATOMG and RED through them. They cull the forest's vegetation
and fill the lists, counts and indirect draw records that its task
programs read. Refused, those records said no task groups, and the
trees were drawn as bare trunks and branches.

A compute program's LDC.64 with a register now gives a pointer from
the bank's table (SH_GBUF_TABLE): the tracker follows it as it follows
a pointer loaded from memory, through moves and arithmetic, and once
the flow settles gives each table the buffer slots the program's other
buffers leave. Each such slot is a window of the table: the renderer
reads the bank as it binds the dispatch, takes the 64-bit words that
map as its pointers, and binds the run of memory mapped from the
lowest of them, the next from the lowest past its end, and so on. With
more runs than windows the two closest runs are bound as one. The
program reads each window's base from the uniform buffer at
SNX_VKB_MBASE, which no compute program used. The game's table holds
20 pointers in 11 runs, and the program with the most buffers of its
own has 9 slots left.

global_dynamic compares an address with each buffer's bound length
(OpArrayLength) rather than 16 MiB, so an address past a shorter
buffer goes on to the next, and it now takes ATOMG and RED too. RED
adds the uniform register at bits 64-69 only with bit 91: the culling
programs' RED of a register pair have 0 there without it, where an
unused uniform register is URZ, and the game's mesh programs' RED of
[UR4] have both. The SPIR-V evaluator of the tests takes
OpArrayLength, and a new test loads, stores and adds through a table
pointer, and checks that a vertex program's is refused as before.

Run on the Windows host with an RTX 5080, the input recording that
loads a save of one game, with mesh draws on, 120 s: the four programs
translate and no program is refused, nothing is skipped, and every
picture from the forest's first seconds on has the trees in leaf,
where they were bare before. The frame rate went from 32 to 26 a
second (the median of the 5 s rates), with the foliage drawn. No
fault, and the save stayed unchanged. shader_sm86 passes on the host.

The four dispatches cost frames where nothing draws what they make:
with mesh draws off, as by default, the same recording went from 32.7
to 26.9 frames a second (the GPU busy 11.0 ms of 36.5 a present, 9.4
of 30.8 before, the GPU thread's memcpy from 24% to 41% of its
samples). The program dispatched most often loses the resident path
because the CPU reads one of its own buffers, so the renderer copies
its 2.3 MB of table windows in and out at each dispatch. On a Radeon
890M, whose dispatches all bind in place, the culling dispatches are
skipped as their inputs change while they bind, and its frame rate in
the forest is as before, 7 to 10 a second.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebased-by: AO55 <AO55@reden-emu.dev>
One game maps one physical memory pool through sixteen virtual pools at
the same offsets, and its cutscenes draw their post-processing targets
through one of them over bytes that the frame's shadow map, drawn
earlier through another, used before. A compute program's result
published over those bytes lands every older image there first, the
shadow map too. Its landing stamped the guest memory written at every
GPU address that shows it, and the composite target drawn after the
shadow map read as written: its next use loaded the old bytes over its
pixels. The upscaler then took a picture of old frames, and every frame
of the cutscene showed pieces of them squeezed into bands, the rest
white.

A landing already left the newer targets over its bytes as they were,
but found them only at its own GPU addresses. It now looks for them at
every GPU address that shows the same guest memory, as the publish that
started it does.

Run on a Radeon 890M from a save in front of a character whose talk
starts a cutscene, with one A press after the load and more to go
through the dialogue: every cutscene frame was the same broken picture
before, and now shows the close-ups, the camera cuts, the depth of field
and the dialogue boxes. The same input recording on the Windows host
with an RTX 5080 and mesh draws on, 170 s: the cutscene showed the same
broken picture there before, and now plays as on the Radeon, through its
conversation, with no fault and the save unchanged. A new case of
tests/vulkan_headless.c draws two targets through two addresses of the
same memory and checks that the older one's write-back keeps the newer
one's pixels: it fails with the search at the landing's own addresses
alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A bank under a pending write in place isn't in g_cb (g_cb_later): the windows came from
what an earlier dispatch left there, and stores through the table's pointers went nowhere.
vulkan_headless has a case that stores through such a pointer.

Change-Id: I73a54a5eed10e6da5f76109eaf14d094f9dc0baf
Signed-off-by: AF52 <AF52@reden-emu.dev>
global_dynamic cleared an ATOMG's destination before it read the data: with both in one
register, as an increment that takes the old count has them, the atomic added 0.
test_global_table has that case.

Change-Id: I23f60566a5a3318b1f987f707a46678c3cef08ab
Signed-off-by: AF52 <AF52@reden-emu.dev>
A storage image published after a dispatch made a new device-local
buffer (vk_own_res_new), and the CPU landing its bytes destroyed it
(res_release): one buffer per published image, about 24 a frame in an
Ounce game's race, each a VMA allocation of its own. The allocation was
21% of the race's GPU thread, most of it VMA's dedicated path.

The freed buffers are pooled now. A publish takes the nearest one of at
least the requested size, and a landing returns its buffer to the pool
at the frame's recycle, where the destroy was deferred before. A full
pool frees as before.

Tested on an RTX 2080: an Ounce game's race had vk_surf_publish at 10.4%
of the GPU thread, from 28.9%, and vk_own_res_new's allocation gone.
With perf attached it raced at about 15 frames a second, from 13.4 (one
run each). The race drew as before. ctest passes, including memory_own
and the vulkan headless and storage tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mem_own_prepare checked each pool block of a range against every block
of the address space (pool_mapped_elsewhere_nl) to find a view of the
range's pages at another address, one scan of every block for every
block, about 6% of an Ounce game's race's GPU thread.

The aliased ranges are built lazily from the blocks already (g_alias),
for mem_alias_peers. mem_own_prepare now builds them when stale and
searches them by address for the range, in log time.

Tested on an RTX 2080: an Ounce game's race had own_begin at 3.7% of
the GPU thread, from 9.9%, and mem_own_prepare at 0.2%, from 6.3%. The
race drew as before. ctest passes, including memory_own and memory_alias.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A constant buffer's bytes are the CPU's, in one run, read by many draws.
cb_get's miss path ran the general buffer path (vk_buf_get_uniform): the
mirror check, the buffer cache's index and entry, the write tracking, a
content hash, and a buffer of its own once stable. In an Ounce game's
race that path was 10.7% of the GPU thread.

A miss now copies the bytes straight into staging when no result is
pending, the mirror does not hold them and the run is whole, and falls
back to the general path otherwise. Unified memory still reads them in
place.

Tested on an RTX 2080: an Ounce game's race's frame rate moved from 15
to 19 frames a second (one run each). ctest passes, including the vulkan
headless and storage tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A texture's memo kept what its handle resolved to while nothing it read
changed. Its hit check dropped every memo once any fragment program's
storage image was pending, with the global g_gfx_img_any flag. A race
that draws its targets and writes storage images in the same frame
re-resolved every texture of every draw.

A pending storage image over the texture's own memory invalidates it.
One elsewhere does not. The hit check now asks vk_gfx_image_pending
about the texture's guest bytes, the same per-address check the buffer
path already uses.

Tested on an RTX 2080: an Ounce game's race moved from about 15 to about
20 frames a second (two runs). ctest passes, including the vulkan
headless and storage tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
own_begin took guest memory the GPU now holds by cutting the entries
over the range out of the sorted ownership array and inserting the new
entries one by one, each insert a memmove of the suffix. In an Ounce
game's race the cut and the inserts were 3.4% of the GPU thread.

The range is replaced in one move now: the entries over it are found,
the edges trimmed, and the suffix moved once for the net change in
count. A range re-owned with the same count of entries moves nothing.

Tested on an RTX 2080: an Ounce game's race had own_begin's cut_nl and
insert_nl at 3.4% of the GPU thread, now gone. ctest passes, including
the memory and vulkan tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gmem_r32 read every four byte word through gmem_read, which checks the
pending results and lands the owned bytes first. Most words are the CPU's
alone: nothing is pending or owned over them. Read those straight from
guest memory when no result is pending, no release is queued and the page
has no owner, and leave the rest to the general path. The page owner check
matches what the general path's staging does for an untrapped page.

Tested on an RTX 2080: Pokemon Legends Z-A's street scene moved from 33 to
36 frames a second (one run each). ctest passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vkr_mem_pending, the check a guest read makes to see whether its pending
results must be landed first, answered yes for every range while any
storage image was pending. Storage images were the one kind of pending
result that did not count its pages in g_pend_any, so a game that draws
its targets and writes storage images in the same frame landed every
guest read, as the texture memo did before it was keyed to its own
memory.

The storage images now count their pages as the compute, graphics, UMA
and release results do, and vkr_mem_pending asks the table alone.

Tested on an RTX 2080: Pokemon Legends Z-A's street scene was unchanged
(it writes few storage images). ctest passes, including the vulkan
headless, storage and image-out tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
aliases_build_nl sorted g_alias.r even when no pool block is mapped, so
its first build passed NULL to qsort. UBSan flags that, as the memory
tests do when built with the sanitizers. Sort only when there are runs
to sort, at the offset sort and again at the address sort.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A table of scope vulkan is the game's .ini's, and its setting @NAME lines
name Vulkan extensions: each becomes a text setting keyed by the name in
lowercase (vk_ext_transform_feedback), auto=Auto|on=On|off=Off, auto by
default, read at startup. --vk-registry checks each name against the
Khronos registry (a Vulkan device extension) and gives the help what the
registry says of it: its number, and what promoted, deprecated or
obsoleted it. g_vk_extension_settings lists them for the renderer, with
the Vulkan version each was promoted to. cmake/settings.cmake passes the
vk.xml of the Vulkan-Headers the renderer builds with.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Issue 1473. Each of the 69 device extensions the renderer names has a
setting in [Graphics], vk_ext_<name>, on the Vulkan Extensions page (a
submenu, as LLVM Internals is the launcher's). auto leaves the extension
to extension_bans.txt: used where the driver has it and no ban holds. on
goes over every ban on it, off takes it out of the device's list before
anything reads it; the driver still says whether it is there.

vk_extension_settings applies them beside the bans (extension_bans.c).
A value not auto, on or off stops the game, as does off for one the
renderer can't run without on the device: the swapchain of a window, a
portability driver's subset, and what Vulkan 1.3 took in on a 1.2 device.
After the bans the log has a line per extension with its value in effect
and why.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs_check failed on every platform: check-docs.py took a vulkan table's setting @NAME
for a setting with no key. It keys one as settingsgen does, the name in lowercase and
auto, and settings.md gets the row it then asks of each.

Change-Id: I9dd5639eb4dcb02125f819669bfe38da6c1f1653
Signed-off-by: AF52 <AF52@reden-emu.dev>
Graphics' Vulkan Extensions is the first page with nothing after it on its line, so on
a Windows checkout its name kept the \r and no icon matched: gui_sdl_events aborted.

Change-Id: Id7e2ce818826f5acdaf225a735fd9e812db6bcb0
Signed-off-by: AF52 <AF52@reden-emu.dev>
snake's and check_shipped's were left above the functions added before them.

Change-Id: I895319c3c3a5552d6fba3da9e8b2229ba90eb041
Signed-off-by: AF52 <AF52@reden-emu.dev>
The wait for submitted work queued a fence in every queue, and a queue stopped at an event
the calling thread signals later never reached its own: a game stopped at its title
screen. A single piece of work behind every queue's ends the wait instead.

Change-Id: Ic3686ceaba13e931394a7bb62afa02902a25d802
Signed-off-by: AF52 <AF52@reden-emu.dev>
The scan of a bucket jumps to snx_a64_row, which fills the instruction and runs the body;
only a word a body refuses reaches snx_a64_rest. A decode takes 134 instructions where it
took 146 over the text of two programs (21.7 M words), every word decoded the same.

Change-Id: I554ef2da62a98b05985172d858b971756740ba77
Signed-off-by: AF52 <AF52@reden-emu.dev>
A decode zeroes the instruction whole, and SnxA64Insn is 104 bytes where its 72 int
arguments made it 312: a decode takes 101 instructions where it took 134. Every type
promotes to int, so the code that reads an argument computes with the same value.

Change-Id: I290450bb374d6259ffb3562fe0ae420543a36770
Signed-off-by: AF52 <AF52@reden-emu.dev>
A JUMP_SLOT holds the module's stub that calls the linker until the import is bound (the
PLT's first entry): a game runs it at each import's first call, and it had no code.

Change-Id: I9e0afa5937ebd173f717f3484d15b50348f6712f
Rebased-by: AO55 <AO55@reden-emu.dev>
Signed-off-by: AF52 <AF52@reden-emu.dev>
Brings in the 1046 upstream commits since 20d29ea4 (2026-11-04).

The fork keeps no 3DS, Vita, GBA, GNU ABI or Android app driver, so their new
upstream files are left out. Where upstream now does what the fork did on its
own, the upstream mechanism is kept:

- NVN replay: upstream's cooperative queue waits (nvnCommandBufferWaitEvent,
  sync waits) replace the fork's GPU-thread event wait and nvn_replay_block.
  gpu_timestamps still stamps counter reports with the submission's tick.
- Ounce (Switch 2) programs: upstream's NPDM detection, SM86 translation, root
  tables, GOB order (g_gob_native) and DLSS handling replace the fork's NVN2
  and Ampere lowering paths in the NVN and Vulkan code. Raiders keeps its
  title-based CPU target and layout only when its NPDM is not an Ounce one.
- Point size, the guest-size copy of scaled targets for compute, DMA GOB
  columns, uploads ahead of passes, query copies at submit and compute warps
  of 32 follow upstream.

Kept from the fork: GRID0+ (friends, bcat, ssl), keyboard and mouse, the
launcher, smooth motion, gpu_timestamps, texel reads between records, loop
limits and the AMD workarounds, float contraction control, owned-range tags
over many entries, the frame's released buffers in its memory bound, and the
inkypaint settings and docs. The fork's raw RC() results now use the table.

Not built or run yet in this commit: the merge resolution only.
changes yeah
Sign in to join this conversation.
No description provided.