150 Commits
Author SHA1 Message Date
Adrià eb1a15b5cc Merge pull request #6314 from eliyarson/feat/relinker-game-patches
feat(relinker): add conversion-time game patches
2026-10-19 00:37:51 +02:00
Adrià 8a456334f6 Merge pull request #6240 from ArjenS-LA/fix/guest-registry-weak-imports
fix(relinker): preserve weak imports in guest module registries
2026-10-19 00:06:30 +02:00
Adrià fd58ca321e Merge pull request #6190 from devavijitsingh/feat/web-batch-conversion
feat(web): convert multiple app ZIPs as one bundle
2026-10-18 22:18:18 +02:00
Eli Yarson 346b0a92ca feat(relinker): add conversion-time game patches
A per-game relinker-patches.toml (or --patches) replaces verified bytes in
the input executable and bundled modules before conversion. Entries are
checked against the expected bytes and against every in-place writer,
the ELF header range and relocation targets. An <output-stem>.patches.toml
manifest records the applied entries, and --verify-patches checks an input
or a converted output. With no patch file the output is unchanged.
2026-10-18 14:57:13 -03:00
Dean c3591adf97 Merge pull request #7510 from AlxcBTW/pr/crash-stack-words-v4
feat(libc): dump the faulting thread's stack words in Windows crash reports
2026-10-19 06:52:21 +13:00
Karim Masmoudi 57e52c1f03 fix(relinker): report processor 0 from RDTSCP under --to-rosetta
Rosetta sets RDTSCP's ECX to its constant TSC_AUX, 0xAAAAAAAB, which is
not a processor index. --to-rosetta already makes RDPID return processor
0 for the same reason, so code reading the processor through RDTSCP saw
a different value from code reading it through RDPID.

--to-rosetta now moves RDTSCP into an optional stub that runs the
instruction unchanged and then loads 0 into ECX with a MOV, which
leaves the counter in EDX:EAX and the flags as they were. A site with no
movable instruction after it for the jump is kept, as for RDPID. The
Intel target and a plain relink are unchanged.
2026-10-18 18:27:15 +02:00
Yunus Shaikh 0172d28496 Merge main into feat/videoout-performance-overlay 2026-10-18 05:08:24 -07:00
AlxcBTW 127ee82f02 feat(libc): dump the faulting thread's stack words in Windows crash reports
APS5_CRASH_STACK_BYTES=<n> prints n bytes of stack words from rsp after the
stack return address candidates, then eight words at every distinct stack word
that points at readable, non-executable memory outside the thread's stack.
Off when the variable is unset, empty or 0.
2026-10-18 12:20:10 +02:00
Dean 883cb1ac52 Merge pull request #6231 from ArjenS-LA/fix/explicit-homebrew-module-directories
fix(relinker): allow explicit module directories without standard folders
2026-10-18 18:58:22 +13:00
Dean 66e71b63d1 Merge pull request #5390 from hugodearaujo/feat/agc-sparse-unaligned-import
feat(agc): import shared ranges whose backing offset is not 64 KiB aligned
2026-10-18 18:22:50 +13:00
Dean Galvin 489c64ecb5 Merge main into fix/explicit-homebrew-module-directories 2026-10-18 17:43:12 +13:00
thuanquangandClaude Opus 5.5 a7499e072f fix(relinker): skip a dumper's backup copy of a module beside the module
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 10:41:02 +07:00
Dean c4fea909a5 Merge pull request #7335 from EagleBearerYS/prep/np-trophies-part2
feat(libSceNpTrophy2,libSceNpUniversalDataSystem): record trophy unlocks and statistics
2026-10-18 15:58:22 +13:00
Dean 199e2ceb2f Merge pull request #7262 from EagleBearerYS/prep/np-trophies
feat(libSceNpTrophy2): report the title's trophy data from trophyNN.ucp
2026-10-18 15:00:53 +13:00
Dean 97c37af020 Merge pull request #6239 from ArjenS-LA/fix/audit-named-homebrew-imports
fix(tools): audit ordinary homebrew import names
2026-10-18 12:57:29 +13:00
Yunus Shaikh be9ade0f01 docs: say which posted trophy unlocks are refused and what stops a title
USAGE.md describes the refused posted unlocks and their log line, and
says that the icon queries and a damaged or unwritable unlock or
statistics file stop the game with an error. The debt entries of
libSceNpTrophy2 and libSceNpUniversalDataSystem no longer say that any
posted id is stored. Both USAGE.md and the libSceNpTrophy2 entry say
that without trophy data the platinum is not unlocked when the other
trophies are.
2026-10-17 23:29:24 +00:00
Yunus Shaikh 75ca9e469a docs: describe trophy statistics in USAGE 2026-10-17 23:29:17 +00:00
Yunus Shaikh 42ddbdf89e docs: describe trophy unlocks in USAGE 2026-10-17 23:28:50 +00:00
Yunus Shaikh 61e12c75fd docs: describe trophy data in USAGE 2026-10-17 23:26:06 +00:00
Yunus Shaikh 2a3946dbb0 Merge main into feat/videoout-performance-overlay
Main adds StorageTextureCacheBudget where this branch adds the public
LargestDeviceLocalHeap wrapper, in both the header and the source.
Keep both.
2026-10-17 15:57:45 -07:00
Dean c756343a89 Merge pull request #7255 from klosixgaming-arch/patch-1
docs(playgo): PPSA03490 needs APS5_PLAYGO_UNLISTED_CHUNKS=absent
2026-10-18 10:39:04 +13:00
Dean 8690d92f07 Merge pull request #7071 from SleglJan/fix/storage-budget-pressure
fix(agc): let the storage image cache budget follow the heap's use like the sampled one
2026-10-18 10:29:01 +13:00
klosixgaming-arch 6f7ec9b143 docs(playgo): PPSA03490 needs APS5_PLAYGO_UNLISTED_CHUNKS=absent
PPSA03490 (Demon Slayer: Kimetsu no Yaiba - The Hinokami Chronicles) has no playgo-* files in sce_sys. Its startup code asks scePlayGoGetLocus about chunk IDs 0, 1, 2, ... and stops when it gets SCE_PLAYGO_ERROR_BAD_CHUNK_ID, appending each ID to an array. With APS5_PLAYGO_UNLISTED_CHUNKS=installed no ID ever fails, the array keeps growing and startup aborts with 'Ran out of memory allocating 5565054976 bytes with alignment 65536'. With =absent the walk ends and the title gets past its logos to the menu and intro.

AI-assisted: yes. Written with AI assistance and reviewed by me.
2026-10-17 14:53:58 -05:00
hugodearaujo ef622e2f8f feat(agc): import shared ranges whose backing offset is not 64 KiB aligned
A sparse import binds whole 64 KiB blocks, so a range whose memfd offset
is not a multiple of 64 KiB fell back to one UDMABUF_CREATE and, above
udmabuf's size limit, to copies. The sparse buffer now starts at the
block below the range: HostImport::lead holds that distance, the
import's device address points at the range itself, and every offset
into the import's buffer goes through HostImportOffset.
2026-10-17 15:03:33 -03:00
ArjenS-LA 0eb94a28cd fix(tools): preserve registry validation when integrating main 2026-10-17 10:44:01 -07:00
MarcZX100 38ed5aa701 docs(usage): explain unlisted PlayGo chunk choices 2026-10-17 14:02:26 +00:00
Dean 1fcfc267af Merge pull request #7128 from Pouare514/fix/import-audit-host-deps
fix(tools): walk host-to-host .prx dependencies of built libs in import audit
2026-10-18 02:26:04 +13:00
Pouare514 778153c29e fix(import-audit): walk host-to-host .prx dependencies of built libs 2026-10-17 14:47:42 +02:00
XairRrR a9377e34ba feat(pad): touch the left or right touchpad half from the input command file
APS5_PAD_INPUT_FILE commands can set bit 0x200000 or 0x400000 to put a
finger on the left or right half of the touchpad, as the TouchLeft and
TouchRight keys do, so scripted runs can press touchpad combinations.
tools/pad_input.py queues them as touch-left and touch-right.

AI-assisted: yes
2026-10-17 13:27:54 +02:00
Jan ŠléglandClaude Fable 5.1 39c23664bd fix(agc): let the storage image cache budget follow the heap's use like the sampled one
StorageTextureBudget gave the storage image cache a quarter of the VK_EXT_memory_budget
budget of the largest device-local heap (capped at TextureCacheBudget, never below 512 MiB)
whatever else the heap held, while SampledTextureBudget takes what that budget leaves after
the heap's other use. On a 10 GB card the storage cache kept 2024-2170 MiB into a level load
whose depth and render target allocations then failed with VK_ERROR_OUT_OF_DEVICE_MEMORY
with the heap at its reported budget where a run logged it.

The storage image budget is now what the reported budget leaves after the heap's use other
than the cached storage images, the unused part of the sampled textures' 2 GiB floor and an
eighth of the budget; the caps at a quarter of the budget and at TextureCacheBudget and the
512 MiB floor stay. The sampled budget still reserves TextureCacheBudget for the storage
cache, at least the storage cap, and the storage budget reserves the sampled textures alive,
so neither counts bytes the other may take; while the sampled textures alive stay within
their floor the sampled budget falls first, then the storage budget, and above it both fall
together. The budget line also prints when the storage image budget moves by more than a
tenth, with its previous value, and StorageTextureCacheBudget is exported for the execution
test.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-17 12:33:05 +02:00
Adrià 7c3bfa8632 Merge pull request #5962 from nikowolf123/feat/libc-crash-register-text
feat(libc): print the text that registers point at in Windows crash reports
2026-10-17 06:51:43 +02:00
Dean 4ffa54c1f3 Merge pull request #6873 from parl0v/docs/texture-cache-budget
docs(usage): describe the texture cache budgets and APS5_TEXTURE_CACHE_MIB
2026-10-17 17:25:12 +13:00
Dean aeb8f62b86 Merge pull request #6568 from xXPBSXx/docs/usage-shader-cache-size
docs(usage): state that the shader cache directory has no size limit
2026-10-17 16:45:44 +13:00
NikoandClaude Opus 5.5 b263cbbb1b feat(libc): print the text that registers point at in Windows crash reports
Unreal titles end in their own libc fatal path with the UTF-16
LowLevelFatalError message in a register, and the crash report shows
only the first 64 bytes of it as hex words, so the message is lost
(#4238: Demon Slayer PPSA03490, Stray PPSA02100).

For every general register that points at readable memory starting
with at least four printable ASCII characters, as UTF-16LE or as single
bytes, the report now prints the text up to a NUL, the first other
character, 512 characters or the end of readable memory (each page is
checked with VirtualQuery before it is read).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 23:33:43 +02:00
Alexej Szpevák 819d5c4a6d docs(usage): describe app0.zar 2026-10-16 20:03:32 +02:00
Josip Parlov 264e026c5d docs(usage): describe the texture cache budgets and APS5_TEXTURE_CACHE_MIB 2026-10-16 17:09:11 +02:00
ArjenS-LA ef3c83d6be fix(tools): resolve named audit imports through NIDs 2026-10-16 04:44:34 -07:00
Adrià FranchandClaude 57ff6a63b2 fix(agc): record nothing in the pipeline journal without its file lock
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-16 12:52:28 +02:00
Adrià FranchandClaude Fable 5.1 4aafda8e3b perf(agc): journal the pipelines of a run and build them ahead on the next one
A graphics pipeline the store builds or a compute pipeline a dispatch builds is
appended to pipelines.journal next to the shader cache entries, as the
materialized result of each stage (the specialized SPIR-V, bindings and push
constants) plus the recipe the pipeline was built from: the stages'
identities, vertex input layout, descriptor set layout keys and the state
fields the Pipeline constructor reads. When a VulkanDevice is created with a
window (a headless device waits for its first draw or dispatch, since the
window's device usually replaces it first) the journal is loaded and its
pipelines are built on a pool of threads while the title loads, so the first
draw or dispatch of a configuration seen on an earlier run finds its pipeline
resident instead of compiling it on the queue worker.

The pipeline stores key on RecompileResult::Identity, a hash of the module
words, specialization constants, subgroup width and bindings that is the same
on every run (SharedSpirv::ContentHash, computed once per shared module),
rather than on the process-lifetime variant ids; a generated stage is keyed
like any other. CachedPipeline builds outside the store's mutex and the
library parts and link are built outside the library store's mutex, so replay
threads and queue workers build in parallel; a concurrent build of the same
key keeps the first inserted. A replayed pipeline enters the store at its
least recently used end and a full store takes none, and its optimized relink
waits for the first draw that binds it, so the title's own pipelines come
first in both. The compute pipeline creation moves into
VulkanDevice::createComputePipeline, shared by dispatches and the replay. The
store key also covers the color component mapping, the depth target's sample
count and a depth bias clamp, which the constructor reads.

The file names the device it was written for (the properties the driver's
pipeline cache file is named by) and starts over for another; a torn tail is
cut at a record boundary; two runs sharing the directory take turns on a lock
file and keep each other's records; a read failure never starts the file
over. A device cancels its replay before it is replaced or destroyed, and a
replaced device destroys its pipelines then rather than at the driver's stop.

APS5_NO_PIPELINE_JOURNAL=1 disables it; APS5_PIPELINE_JOURNAL_THREADS,
APS5_PIPELINE_JOURNAL_ENTRIES (the first recorded), APS5_PIPELINE_STORE_ENTRIES
and APS5_PIPELINE_JOURNAL_MAX_MIB bound it; APS5_PROFILE_DRAW prints a
[pipeline-journal] summary. APS5_VERIFY_SET_LAYOUTS=1 now also checks a
dispatch's set layout against the one described from its shader. The lavapipe
test suite, which shares one cache directory, runs with the journal off except
for the journal's own tests.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P6hw3kRAuQdfcU9YCZgaoK
2026-10-16 12:52:28 +02:00
fdfawef324andClaude Opus 5.5 13b171cab5 feat(agc): keep the last submissions per queue and dump them on a stall or crash
A GPU hang or a crash in a title leaves no record of what the queues
were last given: APS5_TRACE_GPU prints every submission (too much to
leave on), and the WAIT_REG_MEM timeout message shows only the packet
before the wait on the waiting queue.

Each queue now keeps a ring of its last 16 submissions
(APS5_PM4_RING=<n>, 0 to 4096, 0 disables): the TraceMs time in tenths
of a millisecond, serial, size, guest address and a copy of the first
512 dwords after indirect buffers are inlined, recorded under the
driver lock next to the serial, REWIND tails included. The ring of a
queue and the failure report registration are set up at the top of
Submit, before any output is reserved, so recording under the lock
does not allocate. Disabled, Submit only tests a static flag; enabled,
it costs one bounded copy per submission.

DumpSubmissionRings decodes the kept dwords with Pm4::PacketWords and
the new Pm4::KnownName, which returns the decoder's names as views of
static strings (empty for an unknown opcode, printed as UNKNOWN_0x%02x);
Pm4::Name now builds its std::string from it. Every line is formatted
with integer and string conversions only into a 512-byte stack buffer
and written with one WriteFile / write(2) on the stderr handle, so the
dump does not allocate from the C runtime heap, lines from other
threads do not interleave and the CRT stream lock is not taken (the
rule of #3871). The header gives the number of queues and the ring
size, and each queue line the submissions recorded and kept.

libc gets a small registry of failure reports
(LibcRegisterFailureReport_nid_no_patch, Unregister, Run); Run runs
the registered reports the first time it is called and returns at once
after that. The Windows crash report runs it after the thread dump of
an unhandled exception, after SIGABRT (which also covers the
APS5_HANG_DUMP_SECS timed dump, since it aborts) and after an invalid
CRT parameter, so an abort after a reported exception does not print
the rings twice. The driver registers its dump at the first submission
and unregisters at static destruction; the dump there waits a bounded
time for each ring lock. What the crash-path dump cannot do (a ring
held by the crashed thread, rings corrupted by the crash, Linux) is
recorded in technical debt.

APS5_STALL_WATCHDOG_SECS=<n> (0 to 86400, 0 disables) makes a waiter
that has not progressed for n seconds dump the rings once per wait: a
WAIT_REG_MEM (progress as for APS5_GPU_WAIT_TIMEOUT_MS: another packet
runs or completes), a REWIND waiting for the title, and a compute
submission held behind queue 0. The last one prints under the driver
lock, so submissions and the other queues wait for it (USAGE.md says
so). Both variables are read at the top of Submit, so an invalid value
of either throws at the first submission and never later inside a GPU
worker. The order wait behind queue 0 releases its order hold on scope
exit, so a throwing dump cannot leave it counted.

No packet semantics change; packet sizes and names are those of the
existing decoder (PM4 type-3 header layout as in Mesa
src/amd/common/sid.h). The queue bound of Submit and of the rings is
one constant, SubmissionQueueEnd.

Tests: agc_driver_pm4_tests gets ten modes, each its own ctest:
agc_driver_pm4_ring (APS5_PM4_RING=4, six submissions on queue 0 and
two on 0x20: the dump holds #3..#6 and #1..#2 in order, nothing
older), agc_driver_pm4_ring_empty (one line), _ring_disabled (one
line), _ring_invalid and agc_driver_pm4_stall_watchdog_invalid
(APS5_STALL_WATCHDOG_SECS=1x: the submission throws and is not
executed), _ring_report (LibcRunFailureReports_nid_no_patch dumps the
rings), _ring_report_heap (Windows: with ucrtbase.dll's HeapAlloc and
HeapReAlloc imports counting calls from the reporting thread, the
failure report of a submission holding INDEX_BUFFER_SIZE names it and
allocates nothing, while Pm4::Name of the same header is seen
allocating), and with APS5_STALL_WATCHDOG_SECS=1 a WAIT_REG_MEM
(agc_driver_pm4_stall_watchdog), a REWIND (_stall_watchdog_rewind) and
a compute submission held behind a queue 0 rendering wait
(_stall_watchdog_order), each held for about 2.5 s, dump once and
complete when released. The PM4 catalog test checks KnownName against
every opcode and custom name. windows_backtrace_failure_report checks
that abort() runs the registered reports once and not an unregistered
one; windows_backtrace_failure_report_once that abort() does not run
them again after an earlier run. With the dump decoding through
Pm4::Name, agc_driver_pm4_ring_report_heap fails with "the failure
report allocated from the C runtime heap"; with Run resetting its
flag, windows_backtrace_failure_report_once prints the report twice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 11:18:26 +02:00
xXPBSXxandClaude Sonnet 5.5 50d8db46ea docs(usage): state that the shader cache directory has no size limit
The Shader cache section says only that subdirectories of other versions are removed after 14 days. housekeeping() in ShaderDiskCache.cpp removes nothing from the current version, and no size or entry limit applies there.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 22:56:35 +02:00
gguerra26 9b92c55edf fix(relinker): lower ANDN in Rosetta conversion 2026-10-15 15:00:43 +02:00
Adrià 7a22c43027 Merge pull request #5695 from YossiYad/fix/relinker-executable-mode
fix(relinker): write Linux and macOS executables with execute permission
2026-10-15 14:15:08 +02:00
ArjenS-LA 00c704697b docs(relinker): keep import class table beside its introduction 2026-10-15 04:41:05 -07:00
Adrià 2693ac2f64 Merge pull request #5582 from JJenkx/fix/pad-command-file-access
fix(tools): preserve controller command access
2026-10-15 13:23:03 +02:00
Yunus Shaikh 70c88b3e0f docs: say that the overlay's DRIVER line can exceed FRAME with several workers 2026-10-15 01:48:16 -07:00
ArjenS-LA 96f506f870 fix(relinker): preserve weak imports in guest module registries 2026-10-14 23:39:04 -07:00
ArjenS-LA f9f6872b8d fix(tools): audit ordinary homebrew import names 2026-10-14 23:38:52 -07:00
ArjenS-LA 1800d3892b fix(relinker): allow explicit module directories without standard folders 2026-10-14 22:51:15 -07:00
Yunus Shaikh 67acc14910 Merge branch 'main' into feat/videoout-performance-overlay
main's StorageTextureBudget calls largestDeviceLocalHeap, the helper this branch made public as LargestDeviceLocalHeap for the overlay's VRAM line. The merge renames that call, so the merged tree builds.
2026-10-14 19:49:56 -07:00