Commit Graph
5577 Commits
Author SHA1 Message Date
Dean d0bec2e448 Merge pull request #378 from DotDebian/fix/posix-file-errno
fix(libkernel): return -1 and set errno from the POSIX open, stat, unlink and rmdir
2026-10-04 14:01:57 +13:00
Dean a6cdfa1c7f Merge pull request #352 from arreina/pr/savedata-delete-dir-name
fix(savedata): reject invalid directory names in sceSaveDataDelete
2026-10-04 14:01:40 +13:00
Dean e5676b3f0e Merge pull request #315 from RomainROCH/codex/fix-semaphore-overflow
fix(libkernel): avoid semaphore count overflow
2026-10-04 14:01:19 +13:00
Dean e50c18a42d Merge pull request #314 from RomainROCH/codex/fix-fgetpos-error
fix(libc): propagate file position errors
2026-10-04 14:01:01 +13:00
Dean 1dd1be67e3 Merge pull request #262 from RomainROCH/codex/fix-aligned-delete
fix(libc): release aligned allocations through the application heap
2026-10-04 14:00:42 +13:00
Dean Galvin bb1531fc34 fix(agc): consume the write-watch faults of the driver's own CPU stores
A store the driver makes with the CPU into watched guest memory (a
GuestMemory::Write, a changed-bytes write-back, a completion action's label
store, the copy HLE's CPU path) faults its pages dirty in the write watch and
stamps the range with MarkWritten. The faults stayed behind: collects are
memoized per packet, so the next walk over those pages came later and stamped
them again, as a CPU write made after every check in between.

PPSA21564 fast-clears its normal G-buffer every frame with a register DCC key
fill on the GPU. While that fill is still pending, the first draw into the
target materializes the clear with a CPU store of the clear texels and a
refresh of the resident image. A dozen draws later a walk found the store's
faults, the target read as changed, and the image was uploaded again from
guest memory, dropping the draws recorded in between. Lighting then sampled
cleared normals and the level's moon and rocks went unlit in about half the
frames.

The driver's stores now consume those faults themselves: a walk before the
store stamps earlier CPU writes as such, a walk after it takes the store's
own faults as a driver store, and the range is stamped as before.

On Windows the arena's range also holds host regions that were already in
use when it was reserved (heaps, thread stacks). They are not write-watched,
so a store into one is stamped as before, without a walk.
2026-10-04 11:36:05 +13:00
Dean 85959469a4 Merge pull request #478 from oneandonlydean/fix/libc-unwind-c-personality
fix(libc): run the cleanups of frames that use the C personality
2026-10-04 11:34:58 +13:00
Dean 1e54dae613 Merge pull request #466 from oneandonlydean/perf/agc-shared-dcc-keys
perf(agc): keep a surface's storage image when another descriptor names uncompressed DCC keys
2026-10-04 11:34:41 +13:00
Dean 53d1ebc10f Merge pull request #459 from oneandonlydean/perf/agc-own-stack-verify
perf(agc): answer verifications of the caller's own live stack without a page query
2026-10-04 11:34:24 +13:00
Dean c416d9e221 Merge pull request #458 from oneandonlydean/perf/agc-dcc-keys-without-wait
perf(agc): read DCC keys behind the driver's own pending key store without a wait
2026-10-04 11:34:07 +13:00
Dean 0990e9a695 Merge pull request #456 from oneandonlydean/feat/shader-replay-code-words
feat(agc): let agc_shader_replay write a request's code words for other disassemblers
2026-10-04 11:33:49 +13:00
Dean 7fc6f0e10c Merge pull request #445 from oneandonlydean/fix/recompiler-readfirstlane-empty-exec
fix(recompiler): v_readfirstlane_b32 of an empty EXEC reads lane 0
2026-10-04 11:33:32 +13:00
Dean b6673c793c Merge pull request #444 from oneandonlydean/perf/agc-lazy-check-messages
perf(agc): build check failure messages only when a check fails
2026-10-04 11:33:15 +13:00
Dean 98004c632d Merge pull request #443 from oneandonlydean/fix/agc-write-data-pfp
fix(agc): accept WRITE_DATA with ENGINE_SEL = PFP
2026-10-04 11:32:58 +13:00
Dean d8e2609831 Merge pull request #442 from oneandonlydean/fix/agc-host-page-query-gap
fix(agc): describe the pages after a gap in a Linux host page query
2026-10-04 11:32:41 +13:00
Dean be7d33be9c Merge pull request #441 from oneandonlydean/fix/agc-partial-block-write-coverage
fix(agc): keep a surface's results in the 64 KiB block it shares with its neighbour
2026-10-04 11:32:24 +13:00
Dean 3bc8e94324 Merge pull request #439 from oneandonlydean/fix/agc-dma-copy-on-gpu
fix(agc): record large memory-to-memory DMA_DATA copies on the GPU in queue order
2026-10-04 11:32:07 +13:00
Dean 1961af9f9c Merge pull request #415 from oneandonlydean/perf/recompiler-srt-memo-table
perf(recompiler): memoize SRT evaluation in a flat table and inline IrValue's hot accessors
2026-10-04 11:31:50 +13:00
Dean 27c5026367 Merge pull request #414 from oneandonlydean/fix/recompiler-descriptor-phi-split
fix(recompiler): split image reads whose T# or S# is a Phi of SRT reads
2026-10-04 11:31:33 +13:00
Dean 0990ee4e93 Merge pull request #410 from oneandonlydean/perf/agc-interleaved-vertex-copy
perf(agc): copy the interleaved attributes of a vertex buffer once per draw
2026-10-04 11:31:16 +13:00
Dean d8243c3502 Merge pull request #418 from oneandonlydean/fix/relinker-linux-argv
fix(relinker): hand the guest the real argv on Linux
2026-10-04 11:30:37 +13:00
Dean 7f5c3ec9b7 Merge pull request #417 from oneandonlydean/fix/agc-flip-after-gpu
fix(agc): complete a flip only once the frame's GPU work has finished
2026-10-04 11:30:22 +13:00
Dean fc2cbb25ac Merge pull request #413 from oneandonlydean/fix/recompiler-early-return-merge
fix(recompiler): give an early-return selection that joins its parent's merge a merge of its own
2026-10-04 11:30:06 +13:00
Dean ef1d2c03bc Merge pull request #408 from oneandonlydean/perf/agc-flat-queue-registers
perf(agc): keep a queue's registers in flat arrays instead of a std::map
2026-10-04 11:29:51 +13:00
Akhil MoolaandClaude Opus 5.5 ac66e70882 feat(libSceAudioPropagation): implement the no-acoustic-propagation path with recovered signatures
The 22 exports used by PPSA21567 take the call shapes recovered from its
call sites (#481): destroys take the system and the object, attribute
setters take a count, SourceCreate takes only an output handle,
UnregisterMaterial only the material.

The system lives in the title's CPU memory (16-byte header, no GPU memory)
and its handle is that address; rooms, portals, sources and materials are
counter handles. Attributes are validated and have no effect; no rays are
requested and sources report no audio paths. Non-empty ray results, path
calculation and audio paths throw, SourceRender stays unimplemented, and
invalid input throws because no error code is known. Objects left when
their system is destroyed become unusable; their later destroy or
unregister is a no-op.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-03 15:28:36 -06:00
Adrià FranchandClaude c533508c64 test(agc): keep shader memory test tables inside one guest page
Co-Authored-By: Claude <[email protected]>
2026-10-03 18:49:56 +02:00
Adrià FranchandClaude 81961ca91b perf(shader): build a shader's front end once on first use
Co-Authored-By: Claude <[email protected]>
2026-10-03 18:44:58 +02:00
Dean Galvin 6670c52571 fix(libc): run the cleanups of frames that use the C personality
GCC gives C code built with -fexceptions, and cleanup-only functions
after link-time optimization, the C personality __gcc_personality_v0.
The unwinder accepted only its own C++ personality, so an exception
thrown through such a frame was never caught.

libc now provides the C personality, which never catches and installs
the frame's cleanup landing pad in the cleanup phase, and the unwinder
calls it for those frames.
2026-10-04 05:32:55 +13:00
Dean Galvin a431082abc perf(agc): keep a surface's storage image when another descriptor names uncompressed DCC keys
PPSA21564's galaxy map renders a 1920x1080 surface as a color target whose
CB names DCC keys at one address and then writes it from a compute shader
whose T# names keys at another. Both key ranges read uncompressed every
frame, but the storage cache remade the surface's image whenever a
descriptor named metadata other than the image's, so the image was
flushed, destroyed, created and uploaded twice a frame (1231 constructions
in a 56 s scene), with the views and draw recipes built on it thrown away
each time.

A descriptor naming other keys now keeps the image when the move is
unobservable: the image's own keys and the named keys both read
uncompressed, and its content was neither uploaded nor filled under a
clear code. That is exactly the content an image made under the named
keys would hold once this one's pending results were stored. Any other
case (a fast clear of either key range, a register clear, an image
holding a clear) still remakes the image as before, so clears of the new
keys reach it and pending results are stored first.

Every proof that stands in for a lookup checks the same rule: the sampled
view hit, the fast revalidation of views and storage elements (storage
elements now record their descriptor's keys), the own-object refresh, and
the draw recipe's resident targets. Named-key scans keep per-image proofs,
so a repeated check costs no scan while the key bytes are unstamped.

agc_dcc_key_sharing drives KeysServeSurface, the rule ServesKeysAt uses,
through a model of the storage cache.
2026-10-04 03:20:46 +13:00
Dean Galvin 5a8165282f perf(agc): answer verifications of the caller's own live stack without a page query
Driver::Submit checks the title's submission packet, which the title
passes on its own thread stack. Host thread stacks are neither registry
mappings nor write-watched, so no page-state cache covers them and on
Linux every check scans /proc/self/maps line by line: about 1.5 ms per
submission on the render thread of PPSA21564 (66% of that thread's
samples in perf at the title).

A range between the calling thread's current frame and its stack's top
holds the frames of every caller, so it is mapped readable and writable
for as long as the call lasts; verify() now accepts it without a query.
A thread on another stack (a fiber's, a signal stack) has its frame
outside the thread's bounds and still gets the page query, as does any
range that runs past the stack's top or starts below the frame.

GetCurrentThreadStackLimits needs _WIN32_WINNT 0x0602 on MinGW, as
libkernel already sets; GuestMemory.cpp is compiled by several targets,
so the definition is a property of the source file.
2026-10-04 03:02:25 +13:00
Dean Galvin 3886b7b31d perf(shader): hash only the recompiler's inputs into the shader cache version
SourceVersion hashed every libSceAgcDriver source, so any driver-only
change sent the shader disk cache cold: 88 of the last 200 merges on main
did; with the inputs below, 51 of them would have. It now covers:

- core/shader/recompiler/** (sources, headers, CMake);
- prx/libc/include/HostThreadLocal.hpp, the one header the recompiler
  includes from outside its directory (checked against the ninja deps);
- the checked-out commits of SPIRV-Headers and glslang, plus SPIRV-Tools
  when ANYPS5_ENABLE_SPIRV_TOOLS is on (the submodule HEAD files are build
  dependencies, so moving a submodule regenerates the version);
- the compiler, build type, architecture and C++ flags.

Everything else the driver passes to the recompiler arrives in the
RecompileRequest, which the per-entry key covers. Two build-time checks keep
that true, failing the version step with a message naming the file:

- a recompiler source that includes a project header outside the hashed set;
- a driver source that calls or using-declares a ShaderRecompiler name not
  on the reviewed list, pulls in the whole namespace, or sets an environment
  variable (which could flip a recompiler APS5_* switch behind the key).

APS5_* switches are collected from every hashed source. The version script
sets cmake_minimum_required: without it CMake 3.x runs it with CMP0054 OLD
and reads the quoted section names in its if() tests as variables.
2026-10-04 03:02:24 +13:00
Dean Galvin 04f12028dc fix(agc): run a wait-free submission of another queue after queue 0's earlier submissions
PPSA21564 submits the queue 0 work of each intro video frame F first, then 1
to 5 ms later a 12 MiB DMA_DATA on queue 0x3a that refills the video texture
F sampled, for frame F + 2 (two textures, used in turn). Nothing orders them
but time: no label, wait or flip lies between the copy and the draw, which
is the first packet of the frame's first submission. A GPU that keeps up
starts each submission as it arrives, so the draw reads its texture right
after the frame is submitted, and the copy submitted after it lands later,
every frame.

Here the queue workers record independently, so the copy was recorded either
before or after the draw depending on how far queue 0's worker lagged: the
video showed the new frame or the one before, and every switch between the
two was a frame shown backwards.

A submission with no waits on another queue now starts only after queue 0
has run every submission it received earlier, as on a GPU that keeps up.
While queue 0 is blocked in a wait, the held submission is released when its
queue stores the awaited label (it or a later submission of that queue), or
when nothing else could store it: no other worker is running and no recorded
GPU work or completion writes it. A GPU that keeps up would be blocked at
that wait too and run the other queue's submission meanwhile, so the order
holds only while queue 0 still has work it would already have done, and no
wait can deadlock on it.
2026-10-04 01:46:55 +13:00
Alberto RuizandClaude Opus 5.5 9879deca69 fix(audio): bound ATRAC9 decoding to the superframe
LibAtrac9 read its bitstream without a length, so a corrupt ATRAC9 frame
made the decoder read past the end of the guest's buffer. Update the
submodule to 946e05a ("Prevent bitstream overruns"), whose decode
functions take the buffer size, and pass the bytes left in the
superframe from NGS2, AJM and Audiodec. The callers already reject a
frame that consumes more than the superframe holds.

ngs2_atrac9 places a synthetic corrupt superframe right before an
inaccessible page and expects the render to report the decode failure;
with the previous LibAtrac9 it crashes with a segmentation fault.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01R5WJS4ZdQynAJesCZKH5hb
2026-10-03 14:25:49 +02:00
SP4C3B4R-8andClaude Opus 5.5 579db05081 fix(libSceAgcDriver): accept scissors that apply the zero window offset
PA_SC_WINDOW_OFFSET is already required to be zero, so a generic,
window or viewport scissor whose WINDOW_OFFSET_DISABLE bit is clear
selects the same rectangle as one that sets it. Only the reserved
bits are still rejected.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018m6Ad8zkQKPKZmyUQK9vfE
2026-10-03 13:15:28 +02:00
Adrià FranchandClaude b29fe003a1 feat(shader): implement the D16 format buffer stores
buffer_store_format_d16_{x,xy,xyz,xyzw}, buffer_store_format_d16_hi_x
and tbuffer_store_format_d16_{x,xy,xyz,xyzw} take one 16-bit half per
component (two per VGPR; hi_x takes the high half). As on hardware,
float, norm and scaled formats read the half as f16, widen it exactly
to f32 and then encode it like a 32-bit formatted store; uint formats
zero-extend it and sint formats sign-extend it before saturating, and
16-bit float components store it unchanged.

Co-Authored-By: Claude <[email protected]>
2026-10-03 11:37:15 +02:00
Adrià FranchandClaude 4d90c0bc8e fix(shader): convert formatted buffer stores to the element format
buffer_store_format_* and tbuffer_store_format_* wrote the register
bits as they were: an 8_UNORM store of 1.0f wrote 0x00 (the low byte of
0x3f800000), packed formats such as 2_10_10_10 overwrote the whole word
with each component, and the components the instruction does not
provide were left untouched. Each component is now encoded as the
hardware does: unorm/snorm (and uscaled/sscaled, which store the same
way) round x*M exactly to nearest even after clamping, with NaN as 0;
uint/sint saturate; f16 and the 11/10-bit floats truncate toward zero
and saturate. The whole element is written, with the missing components
as 0, and packed formats are composed into one word.

Co-Authored-By: Claude <[email protected]>
2026-10-03 11:37:12 +02:00
Adrià FranchandClaude 5c8c5d2578 feat(shader): implement the D16 format buffer loads
buffer_load_format_d16_{x,xy,xyz,xyzw}, buffer_load_format_d16_hi_x and
tbuffer_load_format_d16_{x,xy,xyz,xyzw} convert each component to 16
bits and pack two per VGPR. The conversions follow the hardware:
unorm/snorm round the exact value to nearest even, scaled integers
round to nearest even and saturate at 65504, 32-bit floats truncate
toward zero (saturating at 65504), and 32-bit integers saturate to 16
bits. All of it is done with integer ops so it does not depend on the
driver's f16 rounding. _x and _hi_x keep the other half, xyz keeps the
upper half of its second register, and a descriptor constant one is
f16 1.0 for non-integer formats.

Co-Authored-By: Claude <[email protected]>
2026-10-03 11:37:10 +02:00
Adrià FranchandClaude 504a2fd8af feat(shader): implement the D16 byte/short loads and high-half stores
buffer/flat/global/scratch_load_{ubyte,sbyte,short}_d16(_hi),
buffer/flat/global/scratch_store_{byte,short}_d16_hi and
ds_read_{u8,i8}_d16(_hi), ds_write_b8_d16_hi threw in the decoder. They use
the same 16-bit destination/source select as the existing ds_read_u16_d16
and ds_write_b16_d16_hi: a load writes one half and keeps the other, a
_d16_hi store takes its data from the high half.

Co-Authored-By: Claude <[email protected]>
2026-10-03 11:37:07 +02:00
Adrià FranchandClaude 1b7e0e487e feat(shader): implement v_movrelsd_b32, v_movrelsd_2_b32, v_swap_b32 and v_swaprel_b32
v_movrelsd moves VGPR[src + M0] to VGPR[dst + M0]. The _2 form and
v_swaprel take the source offset from M0[9:0] and the destination
offset from M0[25:16]; v_swaprel and v_swap exchange the two registers.
They reuse the select-over-registers lowering of v_movrels/v_movreld,
now shared as readRelativeVector/writeRelativeVector.

Co-Authored-By: Claude <[email protected]>
2026-10-03 11:37:02 +02:00
Dean Galvin fb6b131def perf(agc): read DCC keys behind the driver's own pending key store without a wait
A CB metadata pass (and a resident target's register-clear check) read the
DCC keys with CurrentDccKeys, which waited for the GPU whenever recorded
work wrote the key range. In the intro video of PPSA21564 about 800 passes
per 10 s waited about 1.8 ms each, and every one of those waits was behind
a key store whose result the driver already knew: its own uncompressed key
store, or a title fill of uniform keys recorded on the GPU.

Pending-write notes now carry a serial in recording order, and the key
memo remembers the note of the store it describes. When the newest
pending note over the keys is that store's own note, nothing recorded
after it writes the keys, so they read as the store's keys without a
wait. Any later writer, a range the store does not cover, or a unit
shadow over the keys waits as before.
2026-10-03 21:45:10 +13:00
Dean Galvin 8fafe96888 feat(agc): let agc_shader_replay write a request's code words for other disassemblers
--code writes the shader's code as <request name>.code in the working directory, as raw
little-endian words for llvm-mc -triple amdgcn -mcpu=gfx1030 --disassemble. --asm prints only
the first word of each instruction.
2026-10-03 21:45:10 +13:00
MichonandClaude Opus 5.5 057bcb1b42 fix(agc): refuse depth bounds outside [0, 1] without VK_EXT_depth_range_unrestricted
Clamping them changed the result where the stored depth is exactly 0 or 1.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-03 10:40:47 +02:00
MichonandClaude Opus 5.5 c15238ddc0 feat(agc): depth bounds test and depth bias
DB_DEPTH_CONTROL's DEPTH_BOUNDS_ENABLE now runs the Vulkan depth bounds
test with DB_DEPTH_BOUNDS_MIN/MAX, and PA_SU_SC_MODE_CNTL's
POLY_OFFSET_FRONT/BACK_ENABLE enable depth bias from
PA_SU_POLY_OFFSET_FRONT/BACK_SCALE/OFFSET and _CLAMP. Both are dynamic
state, so draws that differ only in their values share a pipeline.

The hardware slope scale is in 1/16 units. Depth bias with units other
than the depth format's (PA_SU_POLY_OFFSET_DB_FMT_CNTL), or that differs
between front and back faces that are both drawn, is refused. The
registers join the draw key. Depth-conditional color writes are still
refused.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-03 10:40:47 +02:00
Alexey d3ec1f15fb Merge pull request #371 from DotDebian/feat/smem-get-waveid-in-workgroup
feat(shader): implement s_get_waveid_in_workgroup
2026-10-03 11:16:32 +03:00
Alexey 87f016b0da Merge pull request #370 from DotDebian/fix/pthread-attr-get
fix(libkernel): report the thread's priority and affinity from scePthreadAttrGet
2026-10-03 11:02:46 +03:00
Alexey 5335ce0316 Merge pull request #368 from DotDebian/feat/mimg-image-atomics
feat(shader): implement the missing integer image atomics
2026-10-03 11:02:17 +03:00
Alexey 9e062154d3 Merge pull request #366 from DotDebian/feat/shader-vop1-pipeflush-clrexcp
feat(shader): decode v_pipeflush and v_clrexcp as no-ops
2026-10-03 11:01:34 +03:00
Alexey b4b261a806 Merge pull request #365 from DotDebian/feat/vopc-f64-compares
feat(shader): implement the VOPC f64 compares
2026-10-03 11:01:18 +03:00
Alexey e1bfb3973f Merge pull request #364 from DotDebian/feat/pthread-barrierattr
feat(libkernel): implement the pthread_barrierattr functions
2026-10-03 11:01:01 +03:00
Alexey a818beedf5 Merge pull request #341 from DotDebian/feat/kernel-cancel-sema
feat(libkernel): implement sceKernelCancelSema
2026-10-03 10:58:13 +03:00