Commit Graph
14017 Commits
Author SHA1 Message Date
Hussein Kadhim c9e1fa0ce1 fix(shader): 32-bit flat atomics in the LDS aperture take the workgroup lock
A flat_atomic_* whose address lands in the LDS aperture updated the dword without the lock, so it could lose updates against a ds_add_u64 or a 64-bit flat atomic on the same dwords. It takes the lock like the 32-bit ds atomics when the program has a 64-bit LDS atomic; programs without one emit the same SPIR-V as before.
2026-10-11 01:53:37 +03:00
Jan ŠléglandClaude Opus 5.5 60301adc6d test(agc-driver): add a split-lane case with per-lane operands to the LDS mixed-width atomic test
On RADV the race between ds_add_u64 under the workgroup lock and a
concurrent ds_add_u32 only shows when the lanes get their operands from
per-lane buffer loads: with v_mov_b32 constants or loads from one address
no increment is lost there. The new case has the split-lane kernel's
parity split and loads each lane's (0xffffffff, 0, 1, 0) row from the input
buffer at tid * 16 with buffer_load_dwordx4, so the input buffer now holds
256 rows. With SpirvMemoryInstructions.cpp reverted it fails on RADV and
on the RTX 3080; with the change it passes on both.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fnrk5Dazjb2tLooVSpdRQq
2026-10-11 01:53:37 +03:00
Hussein Kadhim 5253c499dc test(agc-driver): add the issue's split-lane kernel to the LDS mixed-width atomic test
Even lanes run ds_add_u64 and odd lanes run ds_add_u32 on the slot's high
dword, one pass per dispatch, as in the reported kernel, and the dispatch
is repeated 32 times from one compiled shader.
2026-10-11 01:53:37 +03:00
Hussein Kadhim 22f02606e3 test(agc-driver): unroll the LDS mixed-width atomic kernels so they validate with SPIR-V Tools enabled
With ANYPS5_ENABLE_SPIRV_TOOLS=ON the scalar loop around the ds_add_u64 lock loop made
SPIRV-Tools' block merge pass merge the loop header with its multi-block continue
target, and validation after optimization rejected the module. The 16 iterations are
now emitted inline; the expected sums and the divergent exec masks are unchanged.
2026-10-11 01:53:37 +03:00
Hussein Kadhim cffe4bf070 docs(technical-debt): state the measured LDS atomic overlap as the slot's high dword 2026-10-11 01:53:37 +03:00
Hussein Kadhim 34e4aaf133 fix(shader): LDS 32-bit atomics take the workgroup lock of the program's 64-bit LDS atomics
The hardware serialises 32-bit and 64-bit LDS atomics on one address; the lock that makes the 64-bit forms atomic did not order 32-bit atomics, which lost increments between the two halves of a 64-bit update (#2297).
2026-10-11 01:53:36 +03:00
Adrià 91b1341319 Merge pull request #3079 from MarcZX100/codex/carry-3068
feat(libc): implement Dinkumware mutex and condition exports
2026-10-11 00:52:49 +02:00
Adrià 73e5078c3b Merge pull request #2819 from MarcZX100/codex/mkdir-trailing-slash-2743
fix(libkernel): accept trailing slashes in sceKernelMkdir
2026-10-11 00:52:01 +02:00
john.maiaandClaude Opus 5.5 23c91d948e perf(agc): store write-back changes sixteen bytes at a time
GuestMemory::WriteChanged stores only the bytes the GPU changed, so that CPU writes to the bytes
around them survive. It found them a byte at a time inside every changed 256-byte block and
stored each run with memcpy. Where changed and unchanged bytes interleave (the low bytes of
floats), every run is a few bytes long, and that loop took 43% of the GPU submission thread in
Disney Epic Mickey: Rebrushed's first level (0.9-1.0 ms per MiB).

Each 16-byte chunk is now compared with SSE2. A chunk with no change is skipped, a chunk that
changed entirely is stored whole, and a mixed one is stored with MASKMOVDQU, which writes only the
bytes selected by the mask. An SFENCE after the loop orders those non-temporal stores before the
stores that follow. Bytes the GPU did not change are still never written.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_0134RWCyiyydJBbfKz8g9Bwe
2026-10-10 23:51:26 +01:00
fma-rc d90dff97a8 fix(libc): keep EINVAL from strerror_r for an unknown error with a short buffer 2026-10-11 00:50:49 +02:00
Abdulrahman Elkordy 87ca3a2cf1 fix(relinker): count unnamed imports only against the library they declare
An import whose module matches no needed library has no library name,
and the Windows startup stub counted it against every library, so a
missing library with nothing imported from it was still never skipped.
Every such import in the executables of Record of Lodoss War, Resident
Evil 4, PRAGMATA and Returnal declares a module that exists under
another file name (libSceJson for libSceJson2.prx, for example), and
none declares libSceXml or Party.

The relinker now keeps the declared module names of those imports, for
the executable and each guest module, and the stub counts a host
library as imported from when its name up to the first dot matches one
of them, ignoring case. A module declared as libGuest still keeps a
missing libGuest.xyz required, as guest_module_identity checks.
Imports without a module ID declare nothing and count against no
library. The rule and the title data are from xXPBSXx.
2026-10-10 17:49:47 -05:00
Abdulrahman Elkordy 8ebf892849 fix(relinker): start on Windows without a missing library nothing imports from
The Windows startup stub stopped at the first DT_NEEDED library it could
not load, even when no import is searched in that library. Titles list
libraries they import nothing from (Road of Death needs libSceXml.prx,
Resident Evil 4 needs Party.prx), so they stopped with GetLastError 126
before running. A host library that no import's search list contains is
now skipped with a message when it is not found; its handle stays null
and is never read. Missing libraries that something imports from, other
load errors and guest modules still stop the start.
2026-10-10 17:49:47 -05:00
Adrià 7250918fea Merge pull request #2827 from Get-fix/fix/libkernel-execvp
fix(libkernel): export execvp
2026-10-11 00:49:40 +02:00
MarcZX100 b603d19bc4 fix(libc): match console mutex failure behavior 2026-10-10 22:47:34 +00:00
MarcZX100 f4e393a4e4 fix(libc): clear destroyed thread handles 2026-10-10 22:46:48 +00:00
MarcZX100 583b3de28f fix(libc): return thread errors for invalid operations 2026-10-10 22:46:48 +00:00
MarcZX100 64889ae192 fix(libc): map mutex deadlocks to busy 2026-10-10 22:46:48 +00:00
MarcZX100 697e3bf797 fix(libc): match console Dinkumware handle ABI 2026-10-10 22:46:48 +00:00
DavidandClaude Fable 5.1 9277d06705 feat(libc): implement the Dinkumware mutex and condition exports
Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-10-10 22:46:48 +00:00
Adrià 33301449c7 Merge pull request #2757 from TheAggie/fix/agc-mesh-strip-restart
fix(agc): honour primitive restart in mesh-path triangle strips
2026-10-11 00:46:32 +02:00
Adrià a28a79c731 Merge pull request #2792 from alfalfa-star/perf/agc-copied-writers-cpu-writeback
perf(agc): list a dispatch or draw as a copied writer only while it has a CPU write-back
2026-10-11 00:46:03 +02:00
Adrià 4f3acc7b02 Merge pull request #2797 from Celegans12/perf/dominance-intersection-storage
perf(recompiler): reuse dominance intersection storage
2026-10-11 00:45:47 +02:00
Adrià edcf6bd0b7 Merge pull request #2813 from SleglJan/perf/resource-tracker-memory-users
perf(recompiler): index memory users once per indirect image planning pass
2026-10-11 00:45:25 +02:00
Adrià 99a82eb0e4 Merge pull request #3124 from babyhuey/feat/libc-tzset
feat(libc): implement tzset
2026-10-11 00:43:54 +02:00
ChadandClaude Sonnet 5.5 879188b172 ci: re-run flaky macOS write_watch_threads timeout
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-10 17:43:45 -05:00
Adrià 926ad9e35f Merge pull request #2699 from alfalfa-star/fix/agc-fast-clear-snapshot-watched
perf(agc): read a fast-cleared surface's guest bytes only when the import is compared
2026-10-11 00:43:29 +02:00
Chad 7ea5898f10 fix(agc): ignore the count passed to the indirect register GetSize functions 2026-10-10 17:42:05 -05:00
Adrià 06b489d9c5 Merge pull request #2332 from simonbbby/fix/relinker-address-taken-roots
fix(relinker): treat address-taken code as reachable in unused-filter=1
2026-10-11 00:41:42 +02:00
Adrià 617256e97f Merge pull request #2283 from MathiasDevelopes/fix/agc-count-copied-buffers-in-batch-budget
fix(agc): count copied guest buffers and draw snapshots in the batch byte budget
2026-10-11 00:41:22 +02:00
Adrià d2f43cb87b Merge pull request #2744 from PhialsBasement/feat/ngs2-silent-waveform-blocks
feat(libSceNgs2.native): render silent waveform blocks with flag 0x10
2026-10-11 00:40:04 +02:00
Adrià Franch 2cd63a7ec2 test(libSceNgs2.native): pass a non-null data pointer for dataless blocks
AddWaveformBlocks rejects a null data pointer before reaching the silence
path, so TestSilenceBlock aborted and its dataless rejection passed for the
wrong reason.
2026-10-11 00:38:22 +02:00
Jan ŠléglandClaude Opus 5.5 2e19053f63 feat(agc): present 16-bit float display buffers
PPSA11386 registers 3840x2160 tiled display buffers in pixel format
0xC001000622000000, R16G16B16A16 float in KytyPS5 and SharpProspero
(0xC001000600000000 is the blue-first variant), and stops on "VideoOut:
unsupported display pixel format". The buffer is eight bytes per texel; its
tiled layout is assumed to be the 8-byte SW_64KB_R_X equation applied to
full coordinates, as addrlib applies it. The values are taken as linear
light and encoded with the sRGB curve for the 8-bit output. The encoding
compares the raw half-float bits against two tables of 255 thresholds
(color and alpha) that the CPU decode and the color transfer shader share,
so both give the same bytes on any driver; negative and NaN values give 0.
Guest-memory detile, the resident image path and the CPU decode all handle
both formats; DCC metadata on a float buffer throws. Neither the layout nor
the transfer is verified against console frames.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fnrk5Dazjb2tLooVSpdRQq
2026-10-11 00:38:12 +02:00
Adrià Franch 271a8f291e fix(libSceNgs2.native): throw for a dataless silence-flag block on an ATRAC9 voice
GatherSuperframe finishes a block with no data at once, so such a block
would not play num_samples of silence (requested by @oneandonlydean).
2026-10-11 00:37:58 +02:00
PhialsBasementandClaude Code 2d9b6aebb7 feat(libSceNgs2.native): render silent waveform blocks with flag 0x10
A waveform block that declares samples with no data threw as not
fitting them. PPSA04867 adds such a block with flags 0x11 (data_size 0,
num_samples 16385) and terminates the process on the throw, followed by
a fully specified block under the same flags, which takes the ordinary
path. Accept flag 0x10, named SILENCE here: a dataless block under it
renders num_samples frames of silence and finishes like a complete
block, reporting its bytes through decoded_data_size. A dataless block
without the flag keeps throwing. No public reference names the flag;
the assumption is recorded in TechnicalDebt.

Co-Authored-By: Claude Code <[email protected]>
2026-10-11 00:37:42 +02:00
Hannah Lyons 502dae1ef3 feat(libc): implement tzset 2026-10-10 18:37:10 -04:00
simonbbby cfd61a5977 fix(relinker): treat address-taken code as reachable in unused-filter=1
The CFG used by unused-filter=1 followed only direct branches, so code reached
through lea, relative-relocated pointers or jump tables was unreachable and its
imports were dropped. It now roots RIP-relative lea targets, relative relocation
targets and relative jump tables, and counts any RIP-relative reference to a GOT
slot as an access. Address-taken targets are walked after the direct control
flow, and a target that does not decode as an instruction is not code.
2026-10-11 00:35:27 +02:00
Adrià 4fb937abe9 Merge pull request #1961 from Raghav314/fix/agc-import-gpu-memory-at-map
fix(agc): import GPU-mapped guest memory when it is mapped
2026-10-11 00:34:16 +02:00
Adrià a1f82d238b Merge pull request #2386 from krishnaraya4/fix/agc-packed-16bit-channel-order
fix(agc): sample 5_6_5, 1_5_5_5 and 4_4_4_4 textures in AMD's channel order
2026-10-11 00:34:09 +02:00
Adrià 015beb3c95 Merge pull request #2233 from TideOPL/pr/pooled-buffer-exact-size
fix(agc): give pooled buffers a VkBuffer of exactly the requested size
2026-10-11 00:33:25 +02:00
d731f5034e test(agc): pass the gpu argument to GuestAllocations::Mutation().Add
Co-authored-by: orishamir <[email protected]>
Co-Authored-By: Claude <[email protected]>
2026-10-11 00:33:12 +02:00
MathiasDevelopesandClaude Opus 5.5 078b6d886f style(agc): drop the comments the conventions check rejects
Comments are reserved for technical debt (docs/dev/TechnicalDebt.md), so
the ones the previous commit added to the recorder, the snapshot keep and
the tests go.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01HZHkb8kUwnHAuBBbHywvJf
2026-10-11 00:33:07 +02:00
MathiasDevelopesandClaude Opus 5.5 4940de5436 fix(agc): count memory shared by a batch's keeps once and test the three keep sites
A ShaderResources from the resource caches is the same object for every
draw or dispatch that uses it, and Recorder::ReusableDrawSnapshot hands
the next draw the same snapshot buffer, so passing their bytes with each
Keep counted one allocation once per use and submitted the batch before
it held the budget. Recorder::KeepBytes counts an owner's bytes once per
batch, and the dispatch, draw and snapshot keeps use it.

The recorded kept bytes test runs a dispatch and a draw that copy a
guest buffer and two draws that snapshot one on the device, and fails
when any of the three sites stops counting or a reused snapshot counts
twice. The BdaResources check pins the copied region it sets up.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01HZHkb8kUwnHAuBBbHywvJf
2026-10-11 00:33:07 +02:00
MathiasDevelopesandClaude Sonnet 5.5 00fafd4379 fix(agc): count copied guest buffers and draw snapshots in the batch byte budget
The recorder bounds the bytes a batch keeps alive (KeptBytesBudget) and
waits for older batches past twice that. A recorded dispatch or draw kept
its ShaderResources, and a draw its snapshot buffers, with a size of 0, so
the host-visible copies of guest buffers they own never counted. A title
that binds a 124 MiB writable guest buffer in every draw then held about
ninety copies, 11 GB, until the GPU caught up, and aborted with
VK_ERROR_OUT_OF_HOST_MEMORY from vkAllocateMemory.

GuestBufferMemory reports the bytes of its copied regions, and the
dispatch and draw keeps and the draw snapshots pass their bytes to
Recorder::Keep, so the existing bound applies to them.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-11 00:33:07 +02:00
Adrià f38a036eb1 Merge pull request #2206 from StarMrGamer/fix/relinker-syscall-number
fix(relinker): report the syscall number of a forbidden syscall instruction
2026-10-11 00:31:12 +02:00
StarMrGamer 1a45dee292 fix(relinker): resolve the syscall number through prefixed instructions
The lookback classifies preceding instructions at their decoded opcode
offset, the same place the forbidden-instruction check looks since #1935,
so a legacy-prefixed mov rax, imm or mov r10, rcx is recognized. The REX
byte stays part of the patterns, so mov r8 and mov r8d cannot masquerade
as rax loads. Anything unrecognized still stops the inference.

Adds prefixed fixtures to both test suites: a prefixed constant stub that
must report syscall number 9, and a prefixed clobbered stub that must
report no number.

AI-assisted: yes. The submitting author is responsible for every changed line.
2026-10-11 00:27:44 +02:00
StarMrGamer f7a9629e68 fix(relinker): report the syscall number of a forbidden syscall instruction
The syscall check names only the code offset, so a title that links a FreeBSD
libc (the ps5-payload-dev SDK statically links one into every homebrew binary)
stops with no indication of which call it reached. Those stubs load the number
with a constant before the instruction (mov rax, 9 for link), so decode the
nearest constant load into rax and add it to the message:

  Forbidden syscall instruction at code offset 0xa: syscall number 9

The number is reported only when it can be established. The constant load must
be the instruction directly before the syscall, or one mov r10, rcx (the SDK's
first-argument move, which does not write rax) in front of it; any other
instruction stops the inference instead of returning a stale value, so
mov rax, 9; add rax, 1; syscall reports no number rather than 9. Only the three
invocation opcodes report a number: sysret is a return and keeps the current
message, as does a stub that loads rax from a register, like the SDK's generic
syscall() wrapper. The check still throws; only the text changes.

Tested: relinker-only build, full ctest on Linux x86-64 (45/45). The C++
syscall_scanner test covers the opcode matrix and the review regression; the
Python test_syscall_number covers the same contract through the harness the
relinker lane already runs on Ubuntu, Windows and macOS, where the C++ fixture
helpers (sys/mman.h, posix_spawn) do not build.

AI-assisted: yes
2026-10-11 00:27:44 +02:00
Adrià 379d8b4e8f Merge pull request #1873 from fisherjoey/feat/queue-thread-priority
feat(agc): opt-in raised priority for the queue workers and the presenter
2026-10-11 00:27:26 +02:00
Adrià 13851b58b4 Merge pull request #1940 from Dextroid17/feat/aperture-sources
fix(shader): decode the scalar aperture sources 235-238 instead of failing the shader
2026-10-11 00:26:50 +02:00
Adrià 4d27834ff9 Merge pull request #2119 from mugurc/macos-rosetta
feat(relinker): convert for Rosetta with --to-rosetta
2026-10-11 00:26:25 +02:00
Adrià 496536cb9f Merge pull request #1529 from johnmaia/fix/relinker-declared-host-imports
fix(relinker): keep Linux imports declared from host modules off guest exports
2026-10-11 00:25:46 +02:00